这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 【nRF7002DK】硬件I2C驱动OLED屏

共3条 1/1 1 跳转至

【nRF7002DK】硬件I2C驱动OLED屏

工程师
2025-03-23 07:56:43     打赏

【前言】

此前使用STM32或者python等驱动过OLED屏,但是在Zephyr上还没有实现过,本篇将跟大家分享如何在Zephry中使用I2C,并实现驱动OLED屏。

启用驱动程序】

1.通过将以下行添加到应用程序配置文件prj.conf中来启用I2C驱动程序。

CONFIG_I2C=y #启动I2C
CONFIG_TFM_SECURE_UART=n         //在534x 因为与I2C设备地址有冲突,所以需要禁用。
CONFIG_TFM_LOG_LEVEL_SILENCE=y

2、在源代码文件中包含I2C API的头文件

#include <zephyr/drivers/i2c.h>

3、展开配置文件->Devicetree并创建一个覆盖文件。

image.png

其内容如下:

&i2c1 {
    status = "okay";
    pinctrl-0 = <&i2c1_default>;
    pinctrl-1 = <&i2c1_sleep>;
    pinctrl-names = "default", "sleep";
    ssd1306: ssd1306@3c {
        compatible = "i2c-device";
        status = "okay";
        reg = <0x3c>;
    };

    clock-frequency = <I2C_BITRATE_FAST>;
};

&pinctrl {
    /omit-if-no-ref/ i2c1_default: i2c1_default {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 1, 14)>,
                    <NRF_PSEL(TWIM_SDA, 1, 15)>;
        };
    };

    /omit-if-no-ref/ i2c1_sleep: i2c1_sleep {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 1, 14)>,
                    <NRF_PSEL(TWIM_SDA, 1, 15)>;
            low-power-enable;
        };
    };
};

做好这些准备后,我移植了一个OLED的驱动到工程中,对相应的收发函数进行修改就行了。

image.png

4、在oled.c中添加定义节点标识符

#define I2C1_NODE DT_NODELABEL(ssd1306)

5、检索API特定的设备结构。

宏调用I2C_DT_SPEC_GET()返回结构i2c_dt_spec,其中包含I2C总线的设备指针以及目标地址。

static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C1_NODE);

6、使用device_is_ready()验证设备是否可以使用。在oled.c中添加一个函数,用于OLED初始化时调用:

int oled_dev_init(void)
{
    if (!device_is_ready(dev_i2c.bus))
    {
        printk("Device %s is not ready\n", dev_i2c.bus->name);
        return -1;
    }
    return 0;
}

此函数在OLED初始时先调用。

7、修改发送函数,由于SSD1306只需要发送数据,所以只需要修改发送函数就行了:

void OLED_WR_Byte(unsigned char dat,unsigned char cmd) {
    unsigned char i2c_tx_buff[2];
    if(cmd) {
        i2c_tx_buff[0] = 0x40;
    } else {
        i2c_tx_buff[0] = 0x00;
    }
    i2c_tx_buff[1] = dat;
    i2c_write_dt(&dev_i2c, i2c_tx_buff, 2);
}

8、修改整屏刷新的函数:

void OLED_Display(void) {

    OLED_WR_Byte(0x21, 0); // 设置列地址
    OLED_WR_Byte(0x00, 0); // 起始列地址
    OLED_WR_Byte(SSD1306_WIDTH - 1, 0); // 结束列地址
    OLED_WR_Byte(0x22, 0); // 设置页地址
    OLED_WR_Byte(0x00, 0); // 起始页地址
    OLED_WR_Byte(OLED_PAGE_SIZE - 1, 0); // 结束页地址
    Flash_OLED_Buffer[0] = 0x40;
//  uint8_t i2c_tx_buff[SSD1306_WIDTH * OLED_PAGE_SIZE +1];
//  i2c_tx_buff[0] = 0x40;
//  memcpy(&i2c_tx_buff[1], OLED_buffer, SSD1306_WIDTH * OLED_PAGE_SIZE);
    // i2c_master_write(SSD1306_ADDR, Flash_OLED_Buffer, SSD1306_WIDTH * OLED_PAGE_SIZE +1);
    i2c_write_dt(&dev_i2c, Flash_OLED_Buffer, SSD1306_WIDTH * OLED_PAGE_SIZE + 1);
}

到此OLED的驱动就移植好了,源码见我的附件。

【测试】

在main.c中添加对oled的头文件的引用,并添加打印函数:

int main(void)
{
	int ret;
	bool led_state = true;
	printk("start !\n");
	if (!gpio_is_ready_dt(&led)) {
		return 0;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return 0;
	}

	OLED_Init();
	OLED_Clear(0);
	GUI_ShowString(0, 0, "hello world", 16, 1);
	OLED_Display();
	while (1)
	{
		ret = gpio_pin_toggle_dt(&led);
		if (ret < 0) {
			return 0;
		}

		led_state = !led_state;
		// printf("LED state: %s\n", led_state ? "ON" : "OFF");
		k_msleep(SLEEP_TIME_MS);
	}
	return 0;
}

接上OLED屏后,就可以看到打印出来对应的效果:

image.png

附工程源码:

ssd1306.zip




关键词: nRF7002DK     OLED     Zephry     IIC    

院士
2025-03-24 14:11:33     打赏
2楼

怎么感觉Zephyr没有调度的操作呢?



工程师
2025-03-26 06:28:48     打赏
3楼

任务调度跟freertos不一样,freertos是基于systick的,而Zephry是基于事件驱动的。


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]