首先感谢aijishu & 灵动微电子给与的测试机会。本次测试基于SSD1306驱动芯片的OLED屏幕,接口为I2C。
一、硬件
*逐飞科技的Plus-F5270是2022年全国大学生物联网设计竞赛用开发板,它拥有一颗安谋科技“星辰”STAR-MC1架构的灵动微MM32F5277E高性能芯片,集成DSP和FPU。
*
板子很漂亮,黑色PCB,所有针脚都引出,板载了很多传感器,能满足不同场景开发需求。
OLED采用的驱动芯片为SSD1306,尺寸为0.96,来自HiSpark IoT套件。
二、基于MindSDK驱动OLED
从灵动微电子官方下载的plus-f5270_mdk,driver_examples文件夹中提供了如ADC、CRC、DAC等23类驱动的案例。
因为本次驱动的是I2C的OLED,直接选择I2C文件夹,选择一个i2c_master_basic的case作为基础来修改。
1、Pin初始化
I2C1用的是PC6(SCL)、PC7(SDA),所以直接使用MindSDK的代码即可,方便快捷安全。
/* PC6 - I2C1_SCL. */
gpio_init.Pins = GPIO_PIN_6;
gpio_init.PinMode = GPIO_PinMode_AF_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);
/* PC7 - I2C1_SDA. */
gpio_init.Pins = GPIO_PIN_7;
gpio_init.PinMode = GPIO_PinMode_AF_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);
2、I2C初始化
I2C1的初始化,也用MindSDK的代码,改了几个参数(APP_I2C_TARGET_ADDR改成OLED的0x78, 波特率变成400K等),挺顺滑的。
/* Initialize I2C */
void i2c_init(void)
{
/* Setup I2C initialization values. */
//RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_I2C1, true);
I2C_Master_Init_Type i2c_init;
i2c_init.ClockFreqHz = BOARD_I2C_FREQ;
i2c_init.BaudRate = I2C_BaudRate_400K;
/* Initialize I2C master. */
I2C_InitMaster(BOARD_I2C_PORT, &i2c_init);
/* The target device address needs to be configured before enabling. */
I2C_SetTargetAddr(BOARD_I2C_PORT, APP_I2C_TARGET_ADDR);
/* Enable I2C. */
I2C_Enable(BOARD_I2C_PORT, true);
GPIO_WriteBit(GPIOC, GPIO_PIN_7, 0u);
GPIO_WriteBit(GPIOC, GPIO_PIN_6, 0u);
}
3、SSD1306初始化
SSD1306相关驱动来自于gitee大佬的作品(SSD1306),将ssd1306、ssd1306_conf、ssd1306_fonts文件提取出来。
一是增加一个基于NOP的delay实现:
void HAL_Delay(uint32_t ms)
{
uint32_t i, j;
for (i = 0; i < ms; i++)
{
for (j = 0; j < (CLOCK_SYS_FREQ / 1000u); j++)
{
__NOP();
}
}
}
I2C sendData函数基于MindSDK的hal_i2c做了修改:
static uint32_t ssd1306_SendData(uint8_t* data, size_t size)
{
static I2C_MasterXfer_Type app_i2c_xfer = {0};
app_i2c_xfer.WaitTimes = APP_I2C_TIMEOUT_TIME;
app_i2c_xfer.TxBuf = data;
app_i2c_xfer.TxLen = size;
I2C_Enable(BOARD_I2C_PORT, true);
if ( false == I2C_MasterWriteBlocking(BOARD_I2C_PORT, &app_i2c_xfer) )
{
printf("ssd1306_SendData err \r\n");
return 1;
}
return 0;
}
然后直接用SSD1306 Init代码:
// Initialize the oled screen
void ssd1306_Init(void) {
// Reset OLED
//ssd1306_Reset();
// Wait for the screen to boot
HAL_Delay(200);
// Init OLED
ssd1306_SetDisplayOn(0); //display off
ssd1306_WriteCommand(0x20); //Set Memory Addressing Mode
ssd1306_WriteCommand(0x00); // 00b,Horizontal Addressing Mode; 01b,Vertical Addressing Mode;
// 10b,Page Addressing Mode (RESET); 11b,Invalid
ssd1306_WriteCommand(0xB0); //Set Page Start Address for Page Addressing Mode,0-7
#ifdef SSD1306_MIRROR_VERT
ssd1306_WriteCommand(0xC0); // Mirror vertically
#else
ssd1306_WriteCommand(0xC8); //Set COM Output Scan Direction
#endif
ssd1306_WriteCommand(0x00); //---set low column address
ssd1306_WriteCommand(0x10); //---set high column address
ssd1306_WriteCommand(0x40); //--set start line address - CHECK
ssd1306_SetContrast(0xFF);
#ifdef SSD1306_MIRROR_HORIZ
ssd1306_WriteCommand(0xA0); // Mirror horizontally
#else
ssd1306_WriteCommand(0xA1); //--set segment re-map 0 to 127 - CHECK
#endif
#ifdef SSD1306_INVERSE_COLOR
ssd1306_WriteCommand(0xA7); //--set inverse color
#else
ssd1306_WriteCommand(0xA6); //--set normal color
#endif
// Set multiplex ratio.
#if (SSD1306_HEIGHT == 128)
// Found in the Luma Python lib for SH1106.
ssd1306_WriteCommand(0xFF);
#else
ssd1306_WriteCommand(0xA8); //--set multiplex ratio(1 to 64) - CHECK
#endif
#if (SSD1306_HEIGHT == 32)
ssd1306_WriteCommand(0x1F); //
#elif (SSD1306_HEIGHT == 64)
ssd1306_WriteCommand(0x3F); //
#elif (SSD1306_HEIGHT == 128)
ssd1306_WriteCommand(0x3F); // Seems to work for 128px high displays too.
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif
ssd1306_WriteCommand(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_WriteCommand(0xD3); //-set display offset - CHECK
ssd1306_WriteCommand(0x00); //-not offset
ssd1306_WriteCommand(0xD5); //--set display clock divide ratio/oscillator frequency
ssd1306_WriteCommand(0xF0); //--set divide ratio
ssd1306_WriteCommand(0xD9); //--set pre-charge period
ssd1306_WriteCommand(0x11); // 0x22 by default
ssd1306_WriteCommand(0xDA); //--set com pins hardware configuration - CHECK
#if (SSD1306_HEIGHT == 32)
ssd1306_WriteCommand(0x02);
#elif (SSD1306_HEIGHT == 64)
ssd1306_WriteCommand(0x12);
#elif (SSD1306_HEIGHT == 128)
ssd1306_WriteCommand(0x12);
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif
ssd1306_WriteCommand(0xDB); //--set vcomh
ssd1306_WriteCommand(0x30); //0x20,0.77xVcc, 0x30,0.83xVcc
ssd1306_WriteCommand(0x8D); //--set DC-DC enable
ssd1306_WriteCommand(0x14); //
ssd1306_SetDisplayOn(1); //--turn on SSD1306 panel
// Clear screen
ssd1306_Fill(White);
// Flush buffer to screen
ssd1306_UpdateScreen();
// Set default values for screen object
SSD1306.CurrentX = 0;
SSD1306.CurrentY = 0;
SSD1306.Initialized = 1;
}
4、main()
main()主要测试OLED是否工作正常,代码如下:
int main(void)
{
BOARD_Init();
printf("I2C example\r\n");
/* Initialize I2C. */
HAL_Delay(100);
i2c_init();
HAL_Delay(100);
ssd1306_Init();
HAL_Delay(100);
ssd1306_Fill(White);
ssd1306_SetCursor(0, 0);
ssd1306_DrawString("Hello MM32F5270!", Font_7x10, Black);
while (1)
{
printf("press any key to write i2c-eeprom.\r\n");
getchar();
}
}
三、测试
接线如下图。