rt-thread i2c通信点亮oled显示屏

基于rt-thread的i2c开发

i2c使用

i2c是一种半双工同步通信方式,在硬件上包含两条线分别为时钟线SCL和数据线SDA。i2c总线上可以挂载多个从设备,每个从设备都有唯一的地址,主设备通过地址与指定的从设备进行通信。
硬件i2c:有专门的i2c驱动电路,其所使用的管脚都是专用的,其注册过程:

rt_i2c_bus_device_register
	-->rt_i2c_bus_device_device_init
		-->rt_device_register

软件i2c:使用gpio管脚,使用过程中需要调用gpio相关的函数来控制管脚的电平,从而模拟i2c的通信波形,其注册过程如下:

rt_hw_i2c_init
	-->rt_i2c_bit_add_bus
		-->rt_i2c_bus_device_register
			-->rt_i2c_bus_device_device_init
				-->rt_device_register

在这里插入图片描述
如上所示为RTT的i2c框架图,主要分为设备层-框架层-驱动层。

  • 设备层(应用):设备就是杂七杂八的使用I2C的总线的设备。而这些设备可以选择使用RTT驱动框架的API,也可以选择RTT封装好的API

  • 核心层:

    • bit_ops是RTT为软件I2C提供的中间层,它的作用:为底层模拟I2C驱动提供回调接口,为核心层提供统一I2C通信接口
    • 硬件I2C则直接对接核心层,提供统一I2C通信接口
    • dev是提供RTT设备驱动框架的统一的API(实现箭头);RTT在核心层core上,封装了一套API(虚线箭头),供用户直接使用
  • 驱动层:分为硬件I2C驱动和软件I2C驱动

软件i2c驱动层:主要进行软件I2C所用到scl引脚,sda引脚初始化。scl引脚和sda引脚的获取电平和设置电平接口和延时函数(udelay)。并对接bit_opt层提供的操作结构体:struct rt_i2c_bit_ops。并通过rt_i2c_bit_add_bus注册,提供给bit_opt层回调。

​ struct rt_i2c_bit_ops结构体:

struct rt_i2c_bit_ops
{
    void *data;            /* private data for lowlevel routines */
    void (*set_sda)(void *data, rt_int32_t state);
    void (*set_scl)(void *data, rt_int32_t state);
    rt_int32_t (*get_sda)(void *data);
    rt_int32_t (*get_scl)(void *data);

    void (*udelay)(rt_uint32_t us);

    rt_uint32_t delay_us;  /* scl and sda line delay */
    rt_uint32_t timeout;   /* in tick */
};

bit_opt层:可以归纳为驱动层。其主要实现软件I2C的时序等逻辑,并提供对应的I2C的收发处理函数,为drv_soft_i2c层提供提供了(struct rt_i2c_bit_ops)注册接口和(rt_i2c_bit_add_bus)接口,为i2c_core层提供主机模式的数据处理函数i2c_bit_xfer()。rt-thread的软件i2c,如果要对接其他平台,只需要对接好结构体:struct rt_i2c_bit_ops,而软件i2c的逻辑完全不用理会,全部由bit_opt层管理。

硬件i2c驱动层:无需对接bit_ops层,直接对接i2c_core层提供的结构体:struct rt_i2c_bus_device_ops。
i2c驱动框架会将需要发送的数据或者接收的数据封装成一个message进行发送和接收。rt-thread下的message的数据结构如下:

struct rt_i2c_msg
{
    rt_uint16_t addr;   /* 从机地址 */
    rt_uint16_t flags;  /* 读写标志 */
    rt_uint16_t len;    /* 数据长度 */
    rt_uint8_t  *buf;   /* 读写buffer指针 */
};

如上所示,使用rt_i2c_msg将需要的读写数据封装起来,然后调用i2c的发送函数即可,rt-thread的发送函数为:

rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
                          struct rt_i2c_msg         msgs[],
                          rt_uint32_t               num)

以上第一个参数bus为struct rt_i2c_bus_device的指针。i2c设备会被抽象成一个结构体对象来进行描述,rt_i2c_bus_device就是对i2c控制器设备的抽象,具体如下:

struct rt_i2c_bus_device
{
    struct rt_device parent;
    const struct rt_i2c_bus_device_ops *ops;
    rt_uint16_t  flags;
    struct rt_mutex lock;
    rt_uint32_t  timeout;
    rt_uint32_t  retries;
    void *priv;
};

i2c在用应用层的操作:在完成i2c设备注册后,首先调用通用接口rt_device_find根据设备名查找rt_i2c_bus_device,然后用rt_i2c_msg封装要发送或者接收的数据,最后调用rt_i2c_transfer进行数据收发。

i2c驱动框架

rt-thread的i2c驱动框架中,使用rt_i2c_bus_device对i2c控制器进行抽象。i2c驱动框架仅需关注rt_i2c_bus_device结构体中的rt_device parentrt_i2c_bus_device_ops ops成员。parent成员的作用,是将i2c控制器设备挂载到内核的设备信息链表中进行统一的 管理。ops成员就是I2C设备操作函数的集合,一般为数据的收发函数。ops对应的结构体(I2C控制的操作函数)如下:

struct rt_i2c_bus_device_ops
{
    rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
                             struct rt_i2c_msg msgs[],
                             rt_uint32_t num);
    rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
                            struct rt_i2c_msg msgs[],
                            rt_uint32_t num);
    rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
                                rt_uint32_t,
                                rt_uint32_t);
};

其中,master_xfer函数是对i2c设备进行数据交互的核心函数。rt_i2c_bus_device_register函数向rt-thread内核设备注册设备对象,其一般封装在rt_i2c_bit_add_bus函数中。

rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
                            const char               *bus_name)
{
    bus->ops = &i2c_bit_bus_ops;
    return rt_i2c_bus_device_register(bus, bus_name);
}

rt_i2c_bit_add_bus函数的作用就是向rt-thread内核注册i2c设备内核对象,进行统一管理。在进行注册之前,需要对rt_i2c_bus_device 结构体中的成员函数进行初始化,如上rt_i2c_bus_device 中的rt_i2c_bus_device_ops被初始化为i2c_bit_bus_ops,i2c_bit_bus_ops中存在对i2c设备进行数据交互的核心函数,如下:

static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{
    i2c_bit_xfer,
    RT_NULL,
    RT_NULL
};

rt_i2c_bus_device_register注册函数,调用rt_i2c_bus_device_device_init,其实现为:

rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
                                       const char               *name)
{
    struct rt_device *device;
    RT_ASSERT(bus != RT_NULL);

    device = &bus->parent;

    device->user_data = bus;

    /* set device type */
    device->type    = RT_Device_Class_I2CBUS;
    /* initialize device interface */
#ifdef RT_USING_DEVICE_OPS
    device->ops     = &i2c_ops;
#else
    device->init    = RT_NULL;
    device->open    = RT_NULL;
    device->close   = RT_NULL;
    device->read    = i2c_bus_device_read;
    device->write   = i2c_bus_device_write;
    device->control = i2c_bus_device_control;
#endif

    /* register to device manager */
    rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);

    return RT_EOK;
}

如代码所示 ,rt_device的标准操作函数与i2c设备操作函数一一对应,对应关系:

rt_device_read     --->   i2c_bus_device_read
rt_device_write    --->   i2c_bus_device_write
rt_device_control  --->   i2c_bus_device_control

以rt_device_write为例,其最终调用到底层ops操作函数的过程:

rt_device_write
	i2c_bus_device_write
    	rt_i2c_master_send
    		rt_i2c_transfer
    			master_xfer --> i2c_bit_xfer

其中,master_xfer函数就是i2c控制器与i2c设备进行数据交互的最底层函数。在rt_i2c_bus_device注册中,该函数已经被初始化为i2c_bit_xfer。i2c_bit_xfer函数的实现,根据i2c协议实现响应的读写时序。
在这里插入图片描述
软件i2c代码框架,以stm32某型号为例:
在这里插入图片描述
对应的驱动层的drv_soft_i2c代码调用如下,针对不同硬件的功能函数,统一放在priv成员:
在这里插入图片描述
框架层下的i2c_bit_xfer函数操作过程中对priv对应是ops中的函数进行调用操作。pico的软件i2c操作与stm相似,读写操作在驱动框架层下的i2c_bit_xfer函数中实现,驱动层需要实现rt_i2c_ops中的函数(如:void (*set_sda)、void (*set_scl)、rt_int32_t (*get_sda)、rt_int32_t (*get_scl))。
综上,软件i2c驱动主要针对pin引脚进行设置

软件i2c参考:

https://blog.csdn.net/xiaoyuanwuhui/article/details/107430279

硬件i2c代码框架,以pico为例:

同样,以rt_device_write为例,其最终调用到底层ops操作函数的过程:

rt_device_write
	i2c_bus_device_write
    	rt_i2c_master_send
    		rt_i2c_transfer
    			master_xfer --> raspi_i2c_mst_xfer(需要写读写操作函数)

在这里插入图片描述
驱动代码drv_i2c.c

#include "drv_i2c.h"
#include "drv_gpio.h"
#include "hardware/i2c.h"
#define PICO_I2C i2c1
#define LED_PIN 25

//OLED type for init function
enum {
  OLED_128x128 = 1,
  OLED_128x32,
  OLED_128x64,
  OLED_132x64,
  OLED_64x32,
  OLED_96x16,
  OLED_72x40
};

typedef struct mybbi2c
{
    uint8_t iSDA, iSCL; 
    i2c_inst_t * picoI2C; 
} BBI2C;

typedef struct ssoleds
{
    uint8_t oled_addr; 
    uint8_t oled_type;
    uint8_t *ucScreen;
    BBI2C bbi2c;
} SSOLED;

struct raspi_i2c_hw_config
{
    rt_uint32_t bsc_rate;
    rt_uint32_t bsc_address;
    rt_uint32_t sda_pin;
    rt_uint32_t scl_pin;
};

SSOLED oled;
int32_t speed;

void oled_init(BBI2C *pI2C, uint32_t iClock)
{
	if (pI2C == NULL) return;
	if ((pI2C->iSDA + 2 * i2c_hw_index(pI2C->picoI2C))%4 != 0) return ;
	if ((pI2C->iSCL + 3 + 2 * i2c_hw_index(pI2C->picoI2C))%4 != 0) return ;
      i2c_init(pI2C->picoI2C, iClock);
      gpio_set_function(pI2C->iSDA, GPIO_FUNC_I2C);
      gpio_set_function(pI2C->iSCL, GPIO_FUNC_I2C);
      gpio_pull_up(pI2C->iSDA);
      gpio_pull_up(pI2C->iSCL);
      return;
}

static rt_ssize_t raspi_i2c_mst_xfer(struct rt_i2c_bus_device *bus,
                                    struct rt_i2c_msg msgs[],
                                    rt_uint32_t num)
{
    int rc =0;
    oled.oled_type = OLED_128x64;
    oled.oled_addr = ((struct raspi_i2c_hw_config *)bus->priv)->bsc_address;
    oled.bbi2c.picoI2C = PICO_I2C;
    oled.bbi2c.iSDA = ((struct raspi_i2c_hw_config *)bus->priv)->sda_pin;
    oled.bbi2c.iSCL = ((struct raspi_i2c_hw_config *)bus->priv)->scl_pin;

    speed = ((struct raspi_i2c_hw_config *)bus->priv)->bsc_rate;
    // 初始化 init
    oled_init(&oled.bbi2c,(int32_t) speed);
    i2c_write_blocking((&oled.bbi2c)->picoI2C, oled.oled_addr,  msgs->buf, msgs->len, true);
    return 0;
}

static rt_ssize_t raspi_i2c_slv_xfer(struct rt_i2c_bus_device *bus,
                                    struct rt_i2c_msg msgs[],
                                    rt_uint32_t num)
{
    return 0;
}

static rt_err_t raspi_i2c_bus_control(struct rt_i2c_bus_device *bus,
                                      rt_uint32_t cmd,
                                      rt_uint32_t arg)
{
    return RT_EOK;
}

static const struct rt_i2c_bus_device_ops raspi_i2c_ops =
{
    .master_xfer = raspi_i2c_mst_xfer,
    .slave_xfer = raspi_i2c_slv_xfer,
    .i2c_bus_control = raspi_i2c_bus_control,
};

#if defined (BSP_USING_I2C0)
#define I2C0_BUS_NAME    "i2c0"
static struct raspi_i2c_hw_config hw_device0 =
{
    .bsc_num = 0,
    .bsc_rate = 100000,
    .bsc_address = BSC0_BASE,
    .sda_pin = GPIO_PIN_0,
    .scl_pin = GPIO_PIN_1,
    .sda_mode = ALT0,
    .scl_mode = ALT0,
};

struct rt_i2c_bus_device device0 =
{
    .ops = &raspi_i2c_ops,
    .priv =  (void *)&hw_device0,
};
#endif

#if defined (BSP_USING_I2C1)
#define I2C1_BUS_NAME    "i2c1"
static struct raspi_i2c_hw_config hw_device1 =
{
    .bsc_rate = 100000,
    .bsc_address = PKG_USING_SSD1306_I2C_ADDRESS,
    .sda_pin = BSP_I2C1_SDA_PIN,
    .scl_pin = BSP_I2C1_SCL_PIN,
};

struct rt_i2c_bus_device device1 =
{
    .ops = &raspi_i2c_ops,
    .priv =  (void *)&hw_device1,
};
#endif

int rt_hw_i2c_init(void)
{
#if defined(BSP_USING_I2C0)
    rt_i2c_bus_device_register(&device0, I2C0_BUS_NAME);
#endif

#if defined(BSP_USING_I2C1)
    rt_i2c_bus_device_register(&device1, I2C1_BUS_NAME);
#endif

    return 0;
}

INIT_DEVICE_EXPORT(rt_hw_i2c_init);

oled显示代码:

#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>

#define SSD1306_I2C_BUS_NAME          "i2c1"  
#define SSD1306_ADDR                  0x3c    
#define SSD1306_CTRL_CMD     0x00
#define SSD1306_CTRL_DATA    0x40

const unsigned char ucSmallFonts[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x06, 0x00, 0x07, 0x03, 0x00, 0x07,
        0x03, 0x24, 0x7e, 0x24, 0x7e, 0x24, 0x24, 0x2b, 0x6a, 0x12, 0x00, 0x63, 0x13, 0x08, 0x64, 0x63, 0x36, 0x49,
        0x56, 0x20, 0x50, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x41, 0x00, 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00,
        0x08, 0x3e, 0x1c, 0x3e, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0xe0, 0x60, 0x00, 0x00, 0x08, 0x08, 0x08,
        0x08, 0x08, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x51, 0x49, 0x45, 0x3e, 0x00,
        0x42, 0x7f, 0x40, 0x00, 0x62, 0x51, 0x49, 0x49, 0x46, 0x22, 0x49, 0x49, 0x49, 0x36, 0x18, 0x14, 0x12, 0x7f,
        0x10, 0x2f, 0x49, 0x49, 0x49, 0x31, 0x3c, 0x4a, 0x49, 0x49, 0x30, 0x01, 0x71, 0x09, 0x05, 0x03, 0x36, 0x49,
        0x49, 0x49, 0x36, 0x06, 0x49, 0x49, 0x29, 0x1e, 0x00, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x00, 0x00,
        0x08, 0x14, 0x22, 0x41, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x59,
        0x09, 0x06, 0x3e, 0x41, 0x5d, 0x55, 0x1e, 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x7f, 0x49, 0x49, 0x49, 0x36, 0x3e,
        0x41, 0x41, 0x41, 0x22, 0x7f, 0x41, 0x41, 0x41, 0x3e, 0x7f, 0x49, 0x49, 0x49, 0x41, 0x7f, 0x09, 0x09, 0x09,
        0x01, 0x3e, 0x41, 0x49, 0x49, 0x7a, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x41, 0x7f, 0x41, 0x00, 0x30, 0x40,
        0x40, 0x40, 0x3f, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x7f, 0x02, 0x04, 0x02, 0x7f,
        0x7f, 0x02, 0x04, 0x08, 0x7f, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x3e, 0x41, 0x51,
        0x21, 0x5e, 0x7f, 0x09, 0x09, 0x19, 0x66, 0x26, 0x49, 0x49, 0x49, 0x32, 0x01, 0x01, 0x7f, 0x01, 0x01, 0x3f,
        0x40, 0x40, 0x40, 0x3f, 0x1f, 0x20, 0x40, 0x20, 0x1f, 0x3f, 0x40, 0x3c, 0x40, 0x3f, 0x63, 0x14, 0x08, 0x14,
        0x63, 0x07, 0x08, 0x70, 0x08, 0x07, 0x71, 0x49, 0x45, 0x43, 0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x02, 0x04,
        0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x7f, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80,
        0x00, 0x03, 0x07, 0x00, 0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x7f, 0x44, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44,
        0x44, 0x28, 0x38, 0x44, 0x44, 0x44, 0x7f, 0x38, 0x54, 0x54, 0x54, 0x08, 0x08, 0x7e, 0x09, 0x09, 0x00, 0x18,
        0xa4, 0xa4, 0xa4, 0x7c, 0x7f, 0x04, 0x04, 0x78, 0x00, 0x00, 0x00, 0x7d, 0x40, 0x00, 0x40, 0x80, 0x84, 0x7d,
        0x00, 0x7f, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x00, 0x7c, 0x04, 0x18, 0x04, 0x78, 0x7c, 0x04,
        0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0xfc, 0x44, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0xfc,
        0x44, 0x78, 0x44, 0x04, 0x08, 0x08, 0x54, 0x54, 0x54, 0x20, 0x04, 0x3e, 0x44, 0x24, 0x00, 0x3c, 0x40, 0x20,
        0x7c, 0x00, 0x1c, 0x20, 0x40, 0x20, 0x1c, 0x3c, 0x60, 0x30, 0x60, 0x3c, 0x6c, 0x10, 0x10, 0x6c, 0x00, 0x9c,
        0xa0, 0x60, 0x3c, 0x00, 0x64, 0x54, 0x54, 0x4c, 0x00, 0x08, 0x3e, 0x41, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00,
        0x00, 0x00, 0x41, 0x41, 0x3e, 0x08, 0x02, 0x01, 0x02, 0x01, 0x00, 0x3c, 0x26, 0x23, 0x26, 0x3c };


/*i2c总线设备句柄*/
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
static rt_bool_t initialized = RT_FALSE;  

static int ssd1306_init(const char *name){
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
        return RT_ERROR;}
    else{
        rt_kprintf("find %s device!\n", name);
        return RT_EOK;}
}

static rt_err_t write_position(struct rt_i2c_bus_device *bus, rt_uint8_t *data, int len)
{
    rt_uint8_t buf[4];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = len;

    buf[0] = data[0]; //cmd
    if (data != RT_NULL)
    {
        buf[1] = data[1];
        buf[2] = data[2];
        buf[3] = data[3];
        buf_size = len;}

    msgs.addr = SSD1306_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;}
    else
    {
        return -RT_ERROR;}
}

static void set_position(int x, int y)
{
    unsigned char temp[4];
    temp[0] = SSD1306_CTRL_CMD; 
    temp[1] = 0xb0 | y; 
    temp[2] = x & 0xf; 
    temp[3] = 0x10 | (x >> 4); 
    write_position(i2c_bus, temp, 4);
} 

static rt_err_t write_data(struct rt_i2c_bus_device *bus, rt_uint8_t *data, int len)
{
    rt_uint8_t buf[129];
    struct rt_i2c_msg msgs;

    msgs.addr = SSD1306_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = data;
    msgs.len = len;

    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;}
    else
    {
        return -RT_ERROR;}
}

static void set_data(int x, int y, char *src){
    unsigned char c, ucTemp[40], Temp[129];
    int i = 0, ilen = 6;
    while(src[i] != 0){
        c = src[i] - 32;
        ucTemp[0] = SSD1306_CTRL_CMD;
        memcpy(&ucTemp[1], &ucSmallFonts[(int) c * 5], 5);
        Temp[0] = 0x40;
        memcpy(&Temp[1], ucTemp, ilen);
        write_data(i2c_bus, Temp, ilen+1);
        i++;}
}

static int write_cmd(struct rt_i2c_bus_device *bus, char type, char byte){
    rt_uint8_t buf[2];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = 2;

    buf[0] = type; //cmd
    buf[1] = byte;
    msgs.addr = SSD1306_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;}
    else
    {
        return -RT_ERROR;}

}

/* 清屏 */
static void clear_screen(){
    int i,n;
    for(int i=0;i<8;i++){
        write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xB0+i);
        write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
        write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x10);
        for(n=0;n<128;n++){
            write_cmd(i2c_bus, SSD1306_CTRL_DATA, 0);}
    }
}

/* oled设备初始化 */
static void init(){
    rt_thread_mdelay(100);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xAE);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x20);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xB0);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xC8);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x10);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x40);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xFF);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA1);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA6);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA8);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x3F);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA4);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD3);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD5);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xF0);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD9);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x22);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xDA);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x12);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xDB);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x20);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x8D);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x14);
    write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xAF);
}

static void i2c_ssd1306(int argc, char* argv[]){
    char name[RT_NAME_MAX];
    if(argc ==3){
        rt_strncpy(name, argv[1], RT_NAME_MAX);}
    else{
        rt_strncpy(name, SSD1306_I2C_BUS_NAME, RT_NAME_MAX);}

    if (!initialized)
    {
        int rc;
        rc = ssd1306_init(name);
        if(rc){return;}}

    char *str = argv[2];
    rt_kprintf("argv[2]:%s\n",argv[2]);
    init();
    clear_screen();
    set_position(0,1);
    set_data(0, 1, argv[2]);
}

MSH_CMD_EXPORT(i2c_ssd1306, i2c SSD1306 sample);

oled显示效果:
在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread中,可以使用DMA来提高I2C传输的效率。具体实现步骤如下: 1. 配置I2C设备 通过RT-Thread的设备驱动框架,可以配置I2C设备。在I2C设备初始化的过程中,需要指定I2C总线号、设备地址等参数。 例如,配置I2C1总线,设备地址为0x50,可以使用以下代码: ```c /* 获取I2C设备 */ struct rt_i2c_bus_device *i2c_bus = (struct rt_i2c_bus_device *)rt_device_find("i2c1"); /* 配置I2C参数 */ struct rt_i2c_msg msgs[2]; rt_uint8_t data[2]; /* 设置读写数据 */ data[0] = 0x00; data[1] = 0x01; /* 设置写数据消息 */ msgs[0].addr = 0x50; msgs[0].flags = RT_I2C_WR; msgs[0].len = 2; msgs[0].buf = data; /* 设置读数据消息 */ msgs[1].addr = 0x50; msgs[1].flags = RT_I2C_RD; msgs[1].len = 2; msgs[1].buf = data; /* 发送I2C消息 */ rt_i2c_transfer(i2c_bus, msgs, 2); ``` 2. 配置DMA设备 通过RT-Thread的设备驱动框架,可以配置DMA设备。在DMA设备初始化的过程中,需要指定DMA通道号、传输方向等参数。 例如,配置DMA1通道3,传输方向为从外设到内存,可以使用以下代码: ```c /* 获取DMA设备 */ struct rt_dma_device *dma_device = (struct rt_dma_device *)rt_device_find("dma1"); /* 配置DMA参数 */ struct rt_dma_config dma_config; dma_config.direction = RT_DMA_DEV_TO_MEM; dma_config.tran_width = RT_DMA_WIDTH_8BITS; dma_config.priority = RT_DMA_PRIORITY_HIGH; dma_config.mburst = RT_DMA_BURST_SINGLE; dma_config.pburst = RT_DMA_BURST_SINGLE; dma_config.src_addr = (rt_uint32_t)(&I2C1->DR); dma_config.dst_addr = (rt_uint32_t)(&data[0]); dma_config.buffer_size = 2; dma_config.callback = NULL; /* 配置DMA通道 */ rt_dma_configure(dma_device, 3, &dma_config); ``` 3. 启用DMA传输 在I2C设备和DMA设备都初始化之后,可以启用DMA传输。可以使用RT-Thread的设备接口函数rt_device_control来启用DMA传输。 例如,启用I2C1总线和DMA1通道3的传输,可以使用以下代码: ```c /* 启用DMA传输 */ rt_i2c_dma_transfer(i2c_bus, msgs, 2, dma_device, 3); ``` 启用DMA传输之后,当I2C总线有数据需要传输时,DMA通道就会自动进行数据传输,从而提高I2C传输的效率。 需要注意的是,启用DMA传输之前,需要先将I2C总线的中断禁用,否则可能会引起冲突。在DMA传输完成后,需要重新启用I2C总线的中断。可以使用以下代码来实现: ```c /* 禁用I2C中断 */ rt_interrupt_disable(I2C1_EV_IRQn); rt_interrupt_disable(I2C1_ER_IRQn); /* 启用DMA传输 */ rt_i2c_dma_transfer(i2c_bus, msgs, 2, dma_device, 3); /* 等待DMA传输完成 */ while (rt_dma_get_status(dma_device, 3) != RT_EOK); /* 启用I2C中断 */ rt_interrupt_enable(I2C1_EV_IRQn); rt_interrupt_enable(I2C1_ER_IRQn); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值