单片机/MCU论坛
直播中

哆啦r梦

未满1年用户 35经验值
擅长:嵌入式技术 EDA/IC设计
私信 关注
[文章]

RA-Eco-RA6M4部分功能测评3

RA-Eco-RA6M4开发板实战:基于I2C驱动OLED与u8g2图形库移植实现

在嵌入式开发中,OLED屏幕因功耗低、对比度高、响应速度快等优势,常被用于设备状态显示、数据可视化等场景。RA-Eco-RA6M4开发板集成了丰富的外设接口,其中I2C接口为驱动OLED等外设提供了便捷条件。本文将详细介绍如何通过RA6M4的I2C外设驱动SeedStudio SSD1315 OLED屏幕,并完成u8g2图形库的移植,最终实现文字显示功能。

一、硬件准备与连接设计

1.1 核心硬件选型

  • 主控板:RA-Eco-RA6M4开发板(搭载瑞萨RA6M4 MCU,支持I2C、SPI等多种外设接口);
  • OLED屏幕:SeedStudio Grove-OLED-Display-0.96(驱动芯片为SSD1315,兼容SSD1306指令集,分辨率128x64,I2C通信方式);
  • 辅助元件:2个10KΩ上拉电阻(用于稳定I2C总线信号,避免信号衰减)。

1.2 硬件连接方案

RA6M4的I2C0接口为驱动OLED的核心通道,具体引脚定义与连接关系如下表所示:

RA6M4引脚 功能 OLED引脚 辅助电路
P100 I2C0_SCL SCL 串联10KΩ上拉至3.3V
P101 I2C0_SDA SDA 串联10KΩ上拉至3.3V
3.3V 电源 VCC 直接连接
GND 接地 GND 直接连接

连接说明:I2C总线的SCL和SDA线必须添加上拉电阻,这是因为I2C器件通常为开漏输出,上拉电阻可将信号拉高至3.3V,保证总线通信的稳定性;此外,需确保电源与地的连接无误,避免因电源反接损坏器件。

二、u8g2图形库移植核心原理

u8g2是一款开源的单色图形库,支持几乎所有主流单色OLED/LCD控制器,其移植的核心在于实现硬件抽象层(HAL)的接口适配——即根据目标MCU的硬件特性,实现u8g2所需的两个关键回调函数。

2.1 u8g2 HAL层接口需求

u8g2通过回调函数与MCU硬件交互,移植时必须实现以下两类接口:

  1. GPIO与Delay回调函数:负责GPIO引脚电平控制(如软件I2C的SCL/SDA切换)和延时功能(满足通信时序要求);
  2. 通信接口回调函数:负责实现I2C/SPI等物理层通信,完成数据向OLED控制器的传输。

这两类函数需遵循u8g2定义的函数原型:typedef uint8_t (*u8x8_msg_cb)(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr),其中msg参数为u8g2发送的指令(如延时、GPIO控制、数据发送等),arg_intarg_ptr为指令参数。

三、开发环境配置(基于RASC与Keil)

本文采用瑞萨RA Smart Configurator(RASC)配置硬件外设,结合Keil MDK编写代码,具体配置步骤如下:

3.1 外设栈配置(RASC)

  1. 创建工程与添加I2C栈
    • 打开RASC,新建基于RA6M4的工程,在“Stacks”标签页点击“Add”,选择“HAL/Common”下的“I2C Master (r_sci_i2c)”,命名为g_i2c0
    • 配置I2C核心参数:通道设为0,从站地址0x3C(SSD1315默认I2C地址),地址模式7位,通信速率为标准模式(100KHz),SDA输出延时300ns。
  2. 引脚映射
    • 在“Pins”标签页,将g_i2c0的SCL映射至P100,SDA映射至P101,确保引脚方向设为“Output Open Drain”(符合I2C总线要求)。
  3. 中断配置
    • 启用I2C中断,回调函数命名为sci_i2c_master_callback,中断优先级设为12(根据系统需求调整,需高于普通任务)。

3.2 u8g2源码集成

  1. 源码获取与复制:从u8g2官方仓库下载源码,将csrc文件夹复制到工程的“Drivers/u8g2”目录下;
  2. Keil工程配置
    • 打开Keil工程,在“Manage Project Items”中新建“u8g2”分组,添加“Drivers/u8g2”下的所有.c文件;
    • 在“Options for Target”的“C/C++”标签页,添加包含路径“Drivers/u8g2”,确保编译器能找到u8g2头文件。

四、核心代码实现

4.1 GPIO与Delay回调函数实现

该函数主要处理u8g2的延时指令和GPIO初始化,针对RA6M4的BSP函数设计如下:

#include "u8g2.h"
#include "hal_data.h"

// 全局I2C事件标志,用于中断回调同步
static volatile i2c_master_event_t g_master_event = I2C_MASTER_EVENT_ABORTED;

/**
 * [url=home.php?mod=space&uid=2666770]@Brief[/url] u8g2 GPIO与延时回调函数
 * [url=home.php?mod=space&uid=3142012]@param[/url] u8x8:u8g2设备句柄
 * @param msg:u8g2指令类型
 * @param arg_int:指令整数参数
 * @param arg_ptr:指令指针参数
 * [url=home.php?mod=space&uid=1141835]@Return[/url] 1:处理成功;0:未处理
 */
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
        // 初始化阶段延时(确保OLED上电稳定)
        case U8X8_MSG_GPIO_AND_DELAY_INIT:
            R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
            break;
        // 毫秒级延时(满足I2C时序要求)
        case U8X8_MSG_DELAY_MILLI:
            R_BSP_SoftwareDelay(arg_int, BSP_DELAY_UNITS_MILLISECONDS);
            break;
        // 其他未使用指令默认返回0
        default:
            return 0;
    }
    return 1;
}

4.2 I2C通信回调函数实现

该函数负责将u8g2的待发送数据通过RA6M4的硬件I2C发送至OLED,利用32字节缓冲区适配u8g2的传输限制:

/**
 * @brief u8g2 I2C通信回调函数
 * @param u8x8:u8g2设备句柄
 * @param msg:u8g2通信指令
 * @param arg_int:数据长度
 * @param arg_ptr:数据指针
 * @return 1:处理成功;0:未处理
 */
uint8_t u8x8_i2c_transfer(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    static uint8_t i2c_buf[32];  // u8g2单次传输不超过32字节
    static uint8_t buf_idx = 0;  // 缓冲区索引
    uint8_t *data = (uint8_t *)arg_ptr;
    fsp_err_t err = FSP_SUCCESS;
    uint32_t timeout = 100;      // 超时时间100ms

    switch (msg)
    {
        // 接收u8g2待发送数据,存入缓冲区
        case U8X8_MSG_BYTE_SEND:
            while (arg_int-- > 0)
            {
                i2c_buf[buf_idx++] = *data++;
            }
            break;
        // 初始化阶段(此处I2C已由RASC配置,无需额外初始化)
        case U8X8_MSG_BYTE_INIT:
            break;
        // I2C无DC引脚,忽略该指令
        case U8X8_MSG_BYTE_SET_DC:
            break;
        // 开始传输:重置缓冲区索引
        case U8X8_MSG_BYTE_START_TRANSFER:
            buf_idx = 0;
            break;
        // 结束传输:通过硬件I2C发送缓冲区数据
        case U8X8_MSG_BYTE_END_TRANSFER:
            // 发送I2C数据(非阻塞模式,通过中断确认完成)
            err = R_SCI_I2C_Write(&g_i2c0_ctrl, i2c_buf, buf_idx, false);
            assert(FSP_SUCCESS == err);  // 断言检查发送状态

            // 等待传输完成或超时
            while ((I2C_MASTER_EVENT_TX_COMPLETE != g_master_event) && (timeout-- > 0))
            {
                R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
            }

            // 处理传输异常(如总线冲突)
            if (I2C_MASTER_EVENT_ABORTED == g_master_event)
            {
                __BKPT(0);  // 调试断点,便于定位问题
            }

            // 重置事件标志,准备下次传输
            g_master_event = I2C_MASTER_EVENT_ABORTED;
            break;
        default:
            return 0;
    }
    return 1;
}

/**
 * @brief I2C中断回调函数(同步传输状态)
 */
void sci_i2c_master_callback(i2c_master_callback_args_t *p_args)
{
    if (NULL != p_args)
    {
        g_master_event = p_args->event;
    }
}

4.3 OLED初始化与显示逻辑

hal_entry函数中完成u8g2初始化、OLED启动,并实现文字显示功能:

void hal_entry(void)
{
    u8g2_t u8g2;  // 定义u8g2设备实例

    /* 1. 初始化u8g2:适配SSD1315(兼容SSD1306 vcomh0配置) */
    u8g2_Setup_ssd1306_i2c_128x64_vcomh0_f(
        &u8g2,        // 设备实例
        U8G2_R0,      // 屏幕旋转方向(0度)
        u8x8_i2c_transfer,  // 通信回调函数
        u8x8_gpio_and_delay // GPIO与延时回调函数
    );

    /* 2. 初始化OLED屏幕 */
    u8g2_InitDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0);  // 关闭省电模式(点亮屏幕)
    u8g2_ClearDisplay(&u8g2);     // 清屏

    /* 3. 配置显示内容:设置字体并显示文字 */
    u8g2_SetFont(&u8g2, u8g2_font_wqy16_t_gb2312);  // 16号中文宋体
    u8g2_DrawUTF8(&u8g2, 10, 20, "电子发烧友 2025"); // 坐标(10,20)显示中文
    u8g2_DrawUTF8(&u8g2, 10, 40, "RA6M4 OLED Demo"); // 坐标(10,40)显示英文
    u8g2_SendBuffer(&u8g2);       // 将缓冲区数据发送至OLED

    /* 4. 主循环:保持程序运行 */
    while (1)
    {
        R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
    }
}

五、测试与问题排查

5.1 测试效果

编译下载程序后,OLED屏幕成功点亮,清晰显示“电子发烧友 2025”和“RA6M4 OLED Demo”两行文字,无闪烁、错位现象,说明I2C通信正常,u8g2移植成功。

5.2 常见问题与解决方法

  1. 屏幕无反应

    • 检查I2C引脚连接是否与配置一致(P100=SCL,P101=SDA);
    • 确认上拉电阻是否焊接(无电阻可能导致I2C信号无法拉高);
    • 验证u8g2初始化函数是否正确(需使用vcomh0版本,其他函数可能不兼容SSD1315)。
  2. 文字显示乱码

    • 检查字体文件是否正确添加(u8g2_font_wqy16_t_gb2312需依赖u8g2_fonts.c);
    • 确认u8g2_DrawUTF8的坐标是否超出屏幕范围(128x64屏幕,X最大127,Y最大63)。
  3. I2C传输失败

    • 查看中断回调函数是否正确注册(RASC中需关联sci_i2c_master_callback);
    • 增加超时时间(若总线干扰大,可将超时调整至200ms)。

六、总结与扩展

本文通过RA-Eco-RA6M4的I2C外设实现了SSD1315 OLED的驱动,核心在于理解u8g2的HAL层设计思想,通过两个回调函数完成硬件适配。该方案的优势在于u8g2的跨平台特性——只需修改回调函数中的硬件操作部分,即可快速移植到其他MCU(如STM32、ESP32)。

后续可基于此方案扩展功能:

  • 图形绘制:利用u8g2的u8g2_DrawLineu8g2_DrawCircle等函数绘制波形、图标;
  • 动态显示:通过定时器更新显示内容,实现数据实时刷新;
  • 多设备兼容:基于同一I2C总线连接温湿度传感器、EEPROM等外设,实现多设备协同工作。

更多回帖

发帖
×
20
完善资料,
赚取积分