I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数。驱动程序包含初始化I2C总线控制器__i2cHwInit函数,操作函数集(总线传输__i2cTransfer函数,总线控制__i2cMasterCtl函数)。
imx6ul处理器内部集成了一个I2C控制器,通过五个寄存器来进行控制:
I2Cx_IADR I2C地址寄存器
I2Cx_IFDR I2C分频寄存器
I2Cx_I2CR I2C控制寄存器
I2Cx_I2SR I2C状态寄存器
I2Cx_I2DR I2C数据寄存器
通过I2Cx_I2CR,I2Cx_IFDR,I2Cx_I2DR,I2Cx_IADR寄存器操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过I2Cx_I2SR寄存器来获取。
图 21 I2C编程状态
imx6ul的I2C总线驱动代码在bspimx6ul/driver_module/iic_drv/src/目录下,如图 31所示:
图 31 I2C总线驱动目录
imx6ul的I2C总线驱动代码在bspimx6ul/driver_module/iic_drv/src/目录下,如__所示:
I2C总线驱动实现基本功能,只要实现如图 32中的四个函数即可。
图 32 I2C总线驱动四个基本函数
该函数初始化目标电路板i2c总线系统,调用i2cBusFuns函数初始化相应I2C总线系统并创建对应I2C适配器。根据在bspimx6ul/bsp/SylixOS/bsp/ulevk_board/bspboard.h中的I2C配置,初始化相应的I2C总线。
该函数用于初始化 i2c 总线并获取操作函数集,主要包括了设置芯片管脚复用__i2cIomuxConfig函数,初始化I2C控制器__i2cInit函数,返回操作函数集(总线传输Transfer函数,总线控制MasterCtl函数)。
VOID i2cBusCreate (VOID) { /* * 打开I2Cx的总线驱动配置,在bspimx6ul/bsp/SylixOS/bsp/ulevk_board/bspboard.h文件中配置 */ …… #ifdef CONFIG_BSP_I2C0 pI2cFuncs = i2cBusFuns(0); /* 创建 i2c0总线适配器 */ if (pI2cFuncs) { API_I2cAdapterCreate("/bus/i2c/0", pI2cFuncs, 10, 1); } #endif …… } |
PLW_I2C_FUNCS i2cBusFuns (UINT uiChannel) * 设置芯片管脚分配,SylixOS 计数从零开始,而 IMX6UL 手册是从 1 开始,需要注意 if (__i2cInit(&__Gimx6ulI2cChannels[uiChannel]) != ERROR_NONE) { |
static VOID __i2cIomuxConfig (UINT uiChannel) { …… case 0: /* i2c1的管脚复用 */ IomuxConfig(__I2C1_SCL_REG, __I2C1_SCL_MASK, __I2C1_SCL_VAL); IomuxConfig(__I2C1_SDA_REG, __I2C1_SDA_MASK, __I2C1_SDA_VAL); break; …… } |
static INT __i2cInit (__IMX6UL_I2C_CHANNEL pI2cChannel) { …… /* * 初始化 I2C 控制器 */ if (__i2cHwInit(pI2cChannel->uiChannel) != ERROR_NONE) { printk(KERN_ERR "imx6ulI2cInit(): failed to init!\n"); goto __error_handle; } …… } |
static INT __i2cHwInit (UINT uiChannel) { …… /* * 设置时钟频率 */ __i2cSetI2cClk(uiChannel, I2C_BUS_FREQ_MAX);
/* * 指定从设备地址 */ uiValue = readw(REG_I2C_IADR(uiChannel)); uiValue &= ~IMXUL_DEFAULT_SLAVE_ID_MASK; uiValue |= IMXUL_DEFAULT_SLAVE_ID; writew(uiValue, REG_I2C_IADR(uiChannel)); …… } |
static INT __i2cTryTransfer (UINT uiChannel, PLW_I2C_ADAPTER pI2cAdapter, PLW_I2C_MESSAGE pI2cMsg, INT iNum) { …… /* * 设置I2C时钟频率,清状态位,使能I2C * 并判断总线状态,若IBB位为0 (总线空闲)继续,否则取消本次传输 */ if (__i2cTransferEnable(uiChannel) != 0) { return (PX_ERROR); }
/* * 设置为主模式+传输模式 * 设置完后IBB位自动置1(总线繁忙),开始传输 */ if (__i2cTransferStart(uiChannel) != 0) { return (PX_ERROR); }
/* * 完成设备地址发送后,进入收发消息函数 */ for (i = 0; i < iNum; i++, pI2cMsg++) { if (__i2cTransferMsg(uiChannel, pI2cMsg, iNum) != ERROR_NONE) { break; } }
/* * generate STOP by clearing MSTA bit * (清除MSTA位使其停止传输) */ __i2cTransferStop(uiChannel);
/* * disable the controller * (禁止I2C控制器) */ __i2cTransferDisable(uiChannel); …… } |
static VOID __i2cSetI2cClk (UINT uiChannel, UINT32 uiBaud) { /* * 获取系统时钟 */ UINT32 uiSrcClk = ccmMainClkGet(IPG_PER_CLK); …… /* * 设置I2C时钟频率 */ uiValue = readw(REG_I2C_IFDR(uiChannel)); uiValue &= ~BIT_I2C_IFDR_IC_MASK; uiValue |= i2c_clk_div[ucIndex][1]; writew(uiValue, REG_I2C_IFDR(uiChannel)); } |
static INT __i2cTransferBusFree (UINT uiChannel) { INT i = WAIT_RXAK_LOOPS;
/* * 一段时间内循环判断 */ while ((readw(REG_I2C_I2SR(uiChannel)) & IBB) && (--i > 0));
if (i <= 0) { printk("Error: I2C Bus not free!\n"); return (ERROR); }
return (ERROR_NONE); } |
static INT __i2cTransferBusBusy (UINT uiChannel) { INT i = WAIT_BUSY_LOOPS;
while (!(readw(REG_I2C_I2SR(uiChannel)) & IBB) && (--i > 0))
if (i <= 0) { printk("I2C Error: timeout in \n"); return (PX_ERROR); }
return (ERROR_NONE); } |
static INT __i2cTransferTxByte (UINT8 *pChar, UINT uiChannel) { UINT uiValue = 0;
/* * clear both IAL and IIF bits * (清除IAL和IIF位) */ …… /* * write to data register * (向寄存器中写入数据,从机地址 / 发送信息) * 0x0E << 1 + write + ack * 0x07 + ack * 0x0e << 1 + read + ack * xx + ack */ writew((*pChar), (REG_I2C_I2DR(uiChannel)));
/* * wait for transfer of byte to complete * (等待传输完成) */ return __i2cTransferWaitOpDone(uiChannel, 1); } |
static INT __i2cTransferWaitOpDone (UINT uiChannel, INT iIsTx) { …… /* * Loop until we get an interrupt * (循环等待,直到我们得到一个中断,若没有产生中断,返回-10) */ while (!(readw(REG_I2C_I2SR(uiChannel)) & IIF) && (--i > 0)); if (i <= 0) { printk("I2C Error: timeout unexpected\n"); return (ERR_NO_IIF); }
/* * Clear the interrupts * (清除中断位) */ …… /* * Check for arbitration lost * (检查仲裁位,产生1为仲裁丢失,返回-3) */ if (readw(REG_I2C_I2SR(uiChannel)) & IAL) { printk("Error Arbitration lost\n"); return (ERR_IAL_LOST); }
/* * Check for ACK received in transmit mode * (传输模式中检查是否收到ACK) */ if (iIsTx) { /* iIsTx参数传入为1 */ if (readw(REG_I2C_I2SR(uiChannel)) & RXAK) { /* * 没有收到ACK,清除MSTA位使其停止传输 */ printk("Error no ack received\n"); __i2cTransferStop(uiChannel); /* 停止 / 将主从模式位设置为0 */
return (ERR_NO_ACK); } } …… } |
static VOID __i2cTransferStop (UINT uiChannel) { …… /* * MSTA位设置为0,即可停止传输 */ uiValue = readw(REG_I2C_I2CR(uiChannel)); uiValue &= ~BIT_I2C_I2CR_MSTA_MASK; uiValue |= BIT_I2C_I2CR_MSTA_0; writew(uiValue, REG_I2C_I2CR(uiChannel)); } |
static VOID __i2cTransferDisable (UINT uiChannel) { …… /* * disable the controller * (禁能I2C) */ uiValue = readw(REG_I2C_I2SR(uiChannel)); uiValue &= ~CLEAR_ALL_MASK; uiValue |= CLEAR_ALL; writew(uiValue, REG_I2C_I2SR(uiChannel)); } |
原文:http://12380892.blog.51cto.com/12370892/1895049