I2C通讯协议(Inter-Integrated Circuit),SDA和SCL两路引脚,硬件实现简单,可扩展性强,被广泛地使用在系统内多个集成电路(IC)间的通讯,如:触摸IC,音频Codec,陀螺仪加速度计等等。
在Env环境menuconfig中 RT-Thread Components->Device Drivers 设备驱动默认为n,所以需要开启。
先在Kconfig中添加如下语句,然后在Env环境menuconfig中 Hardware Drivers Config->On-Chip Peripheral Drivers 使能I2C,本章使用I2C1
设备驱动框架:i2c_core.c i2c_dev.c BSP接口:drv_i2c.c fsl_lpi2c.c fsl_lpi2c_edma.c(本章没用dma)
笔者查阅了文件,发现 drv_adc.c 这个文件,驱动部分需要修改的很多,索性来个大改
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;
}
这里初始化时钟源和传输函数接口重新修改封装,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;
}
底层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总线设备应答