10

不爱吃胡萝卜 · 2022年09月02日 · 浙江

【MM32F5270开发板试用】SSD1306 OLED屏幕驱动(I2C)

首先感谢aijishu & 灵动微电子给与的测试机会。本次测试基于SSD1306驱动芯片的OLED屏幕,接口为I2C。

一、硬件

*逐飞科技的Plus-F5270是2022年全国大学生物联网设计竞赛用开发板,它拥有一颗安谋科技“星辰”STAR-MC1架构的灵动微MM32F5277E高性能芯片,集成DSP和FPU。
*
image
板子很漂亮,黑色PCB,所有针脚都引出,板载了很多传感器,能满足不同场景开发需求。
image

OLED采用的驱动芯片为SSD1306,尺寸为0.96,来自HiSpark IoT套件。
HISPARK.png

二、基于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();
    }
}

三、测试

接线如下图。

MM32.jpg

推荐阅读
关注数
6108
内容数
272
灵动MM32 MCU相关技术知识,欢迎关注~
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息