【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用

I2C通讯协议(Inter-Integrated Circuit),SDA和SCL两路引脚,硬件实现简单,可扩展性强,被广泛地使用在系统内多个集成电路(IC)间的通讯,如:触摸IC,音频Codec,陀螺仪加速度计等等。

开发前准备

  • 硬件平台:nxp rt10xx单片机
  • IDE: Keil

1.Kconfig 修改和menuconfig配置

Env环境menuconfigRT-Thread Components->Device Drivers 设备驱动默认为n,所以需要开启。

【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用_第1张图片

先在Kconfig中添加如下语句,然后在Env环境menuconfigHardware Drivers Config->On-Chip Peripheral Drivers 使能I2C,本章使用I2C1

【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用_第2张图片

2.工程添加I2C驱动框架和BSP驱动接口

设备驱动框架:i2c_core.c i2c_dev.c BSP接口:drv_i2c.c fsl_lpi2c.c fsl_lpi2c_edma.c(本章没用dma)

【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用_第3张图片

3.添加或修改drv_i2c.c

笔者查阅了文件,发现 drv_adc.c 这个文件,驱动部分需要修改的很多,索性来个大改

  • 定义i2c device

struct rt_i2c_msg
{
    rt_uint16_t addr;
    rt_uint16_t flags;
    rt_uint16_t len;
    rt_uint8_t  *buf;
};

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);
};

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;
};

static const struct rt_i2c_bus_device_ops imxrt_i2c_ops =
{
    .master_xfer = imxrt_i2c_mst_xfer,
    .slave_xfer = imxrt_i2c_slv_xfer,
    .i2c_bus_control = imxrt_i2c_bus_control,
};

  • 设备创建注册

int rt_hw_i2c_init(void)
{
    lpi2c_master_config_t masterConfig = {0};

#if   defined(BSP_USING_I2C1)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C1_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C1_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /*HW_I2C1_BADURATE_400kHZ*/
    imxrt_lpi2c_configure(&lpi2c1, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c1.parent, lpi2c1.device_name);
#endif  /* BSP_USING_I2C1 */

#if   defined(BSP_USING_I2C2)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C2_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C2_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /* HW_I2C2_BADURATE_400kHZ */
    imxrt_lpi2c_configure(&lpi2c2, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c2.parent, lpi2c2.device_name);
#endif  /* BSP_USING_I2C2 */

#if !defined(MIMXRT1015_SERIES) /* imxrt1015 only have two i2c bus*/

#if   defined(BSP_USING_I2C3)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C3_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C3_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /* HW_I2C3_BADURATE_400kHZ */
    imxrt_lpi2c_configure(&lpi2c3, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c3.parent, lpi2c3.device_name);
#endif  /* BSP_USING_I2C3 */

#if   defined(BSP_USING_I2C4)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C4_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C4_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /* HW_I2C4_BADURATE_400kHZ */
    imxrt_lpi2c_configure(&lpi2c4, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c4.parent, lpi2c4.device_name);
#endif /* BSP_USING_I2C4 */

#if   defined(BSP_USING_I2C5)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C5_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C5_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /* HW_I2C5_BADURATE_400kHZ */
    lpi2c5.clock_root = kCLOCK_Root_Lpi2c5;
    imxrt_lpi2c_configure(&lpi2c5, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c5.parent, lpi2c5.device_name);
#endif /* BSP_USING_I2C5 */

#if   defined(BSP_USING_I2C6)
    LPI2C_MasterGetDefaultConfig(&masterConfig);
#if   defined(HW_I2C6_BADURATE_400kHZ)
    masterConfig.baudRate_Hz = 400000U;
#elif defined(HW_I2C6_BADURATE_100kHZ)
    masterConfig.baudRate_Hz = 100000U;
#endif  /* HW_I2C6_BADURATE_400kHZ */
    lpi2c6.clock_root = kCLOCK_Root_Lpi2c6;
    imxrt_lpi2c_configure(&lpi2c6, &masterConfig);
    rt_i2c_bus_device_register(&lpi2c6.parent, lpi2c6.device_name);
#endif /* BSP_USING_I2C6 */


#endif /* MIMXRT1015_SERIES */

    return 0;
}
  • 基于imxrt i2c device 驱动相关函数

这里初始化时钟源和传输函数接口重新修改封装,slv 和 control 暂时用不上,就不加了

#define LPI2C_CLOCK_SOURCE_SELECT (0U)
#define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U))

static rt_err_t imxrt_lpi2c_configure(struct imxrt_i2c_bus *bus, lpi2c_master_config_t *cfg)
{
    RT_ASSERT(bus != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    bus->parent.ops = &imxrt_i2c_ops;

    CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER);
    LPI2C_MasterInit(bus->I2C, cfg, LPI2C_CLOCK_FREQUENCY);

    return RT_EOK;
}


static rt_size_t imxrt_i2c_mst_xfer(struct rt_i2c_bus_device *bus,
                                    struct rt_i2c_msg msgs[],
                                    rt_uint32_t num)
{
    struct imxrt_i2c_bus *imxrt_i2c;
    lpi2c_master_transfer_t masterXfer = {0};

    rt_size_t i;
    RT_ASSERT(bus != RT_NULL);
    
    imxrt_i2c = (struct imxrt_i2c_bus *) bus;
    imxrt_i2c->msg = msgs;
    imxrt_i2c->msg_ptr = 0;
    imxrt_i2c->msg_cnt = num;
    imxrt_i2c->dptr = 0;

    masterXfer.subaddressSize = 1;
    masterXfer.flags          = kLPI2C_TransferDefaultFlag;

    for (i = 0; i < num; i++)
    {
        masterXfer.slaveAddress = imxrt_i2c->msg[i].addr;
        masterXfer.direction = imxrt_i2c->msg[i].flags;    //读写
        masterXfer.subaddress = imxrt_i2c->msg[i].buf[0];  //通常是设备寄存器 reg

		masterXfer.data = &imxrt_i2c->msg[i].buf[1];
		masterXfer.dataSize = imxrt_i2c->msg[i].len - 1;		
		
        LPI2C_MasterTransferBlocking(imxrt_i2c->I2C,&masterXfer);
    }

    imxrt_i2c->msg = RT_NULL;
    imxrt_i2c->msg_ptr = 0;
    imxrt_i2c->msg_cnt = 0;
    imxrt_i2c->dptr = 0;

    return RT_EOK;
}

static rt_size_t imxrt_i2c_slv_xfer(struct rt_i2c_bus_device *bus,
                                    struct rt_i2c_msg msgs[],
                                    rt_uint32_t num)
{
    return 0;
}
static rt_err_t imxrt_i2c_bus_control(struct rt_i2c_bus_device *bus,
                                      rt_uint32_t cmd,
                                      rt_uint32_t arg)
{
    return RT_ERROR;
}

4.搭建应用层demo

底层IO初始化

IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL,1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA,1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL,0xD8B0u);                      
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA,0xD8B0u); 

应用功能上用的IC是一款codec,测试了下I2C数据写入,利用逻辑分析仪抓包I2C总线是否写入成功

/**************************************************START OF FILE*****************************************************/






/*------------------------------------------------------------------------------------------------------------------
Includes
*/
#include 
#include 


/*------------------------------------------------------------------------------------------------------------------
Macros
*/
#define CODEC_I2C_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */
#define CODEC_ADDR                  0x1A    

/*------------------------------------------------------------------------------------------------------------------
Variables
*/
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */

/*------------------------------------------------------------------------------------------------------------------
Functions
*/
/* 写传感器寄存器 */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data)
{
    rt_uint8_t buf[2];
    struct rt_i2c_msg msgs;

    buf[0] = reg; 
	buf[1] = data;

    msgs.addr = CODEC_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = 2;

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

/* 读传感器寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs;

    msgs.addr = CODEC_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

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

void codecInit(void)
{
    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(CODEC_I2C_BUS_NAME);

    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", CODEC_I2C_BUS_NAME);
    }
    else
    {
		write_reg(i2c_bus,0x62,0xF7);
        rt_thread_mdelay(400);
    }
}
MSH_CMD_EXPORT(codecInit, codec  sample);

/****************************************************END OF FILE*****************************************************/


将I2C信号接入逻辑分析仪,然后输入命令codecInit运行应用,查看结果 ACK,表示I2C总线设备应答

【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用_第4张图片

【RT-Thread】nxp rt10xx 设备驱动框架之--i2c搭建和使用_第5张图片

你可能感兴趣的:(RTOS,RT-Thread,物联网,mcu,arm)