sylixOS和鸿蒙,SylixOS iMX6平台I2C总线驱动

I2C总线传输中断处理

I2C总线驱动中断处理,编程流程如图 22所示。

6d40a9d64bb55b8be5f3362b70e08c58.png

图 22中断处理

技术实现

I2C总线驱动框架

I2C总线驱动实现基本功能,只要实现如图 31中的四个函数即可。

ac55866fdb259224c51914d0c3ddc5ef.png

图 31 I2C总线驱动四个基本函数

i2cBusCreate

i2cBusCreate函数初始化目标电路板i2c总线系统,调用i2cBusFuns函数初始化相应I2C总线系统并创建对应I2C适配器。根据在bspimx6ul/bsp/SylixOS/bsp/ulevk_board/bspboard.h中的I2C配置,初始化相应的I2C总线。

i2cBusFuncs

i2cBusFuncs函数用于初始化 i2c总线并获取操作函数集,主要包括了设置芯片管脚复用__i2cIomuxConfig函数,初始化I2C控制器__i2cInit函数,返回操作函数集(总线传输Transfer函数,总线控制MasterCtl函数)。

__i2cInit

__i2cInit函数用于初始化I2C控制器,主要包括了初始化I2C使用的信号量,设置时钟频率,指定作从设备时的地址。

__i2cTransfer

__i2cTransfer函数为I2C传输函数,用于在I2C总线上传输和接收数据。

驱动程序框架

整个驱动程序的框架如图 32所示。

523c1f84aaea8633cce75e14c2ccb884.png

图 32驱动程序流程框架

BSP中驱动配置

根据imx6ul相关芯片手册,配置寄存器地址并定义I2C通道相关信息结构。如程序清单 31所示。

程序清单 31 I2C通道信息/*********************************************************************************************************

i2c 通道相关信息

*********************************************************************************************************/

struct __i2c_channel{

UINT                uiChannel;                                      /*  I2C总线通道号               */

LW_OBJECT_HANDLE    I2C_hSignal;                                    /*  信号量                      */

BOOL                I2C_bIsInit;                                    /*  是否初始化                  */

int                 iStatus;                                        /*  状态                        */

int                 iBpsParam;                                      /*  波特率参数                  */

PLW_I2C_MESSAGE     pi2cmsg;                                        /*  需要处理的消息              */

int                 iMsgPtr;                                        /*  消息内部指针                */

int                 iMsgNum;                                        /*  消息数量                    */

int                 iMsgIndex;                                      /*  当前处理的 msg 下标         */

};

typedef struct __i2c_channel   __I2C_CHANNEL;

typedef struct __i2c_channel  *__PI2C_CHANNEL;

代码实现

I2C总线驱动代码

i2cBusCreate,i2cBusFuncs的具体实现

i2cBusCreate函数与i2cBusFuncs函数初始化I2C,并将返回的操作函数集与i2c适配器绑定。如程序清单 32,程序清单 33所示。

程序清单 32 i2cBusCreate的具体实现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

……

}

程序清单 33 i2cBusFuns的具体实现PLW_I2C_FUNCS  i2cBusFuns (UINT  uiChannel)

{

……

if (__i2cInit(&__Gimx6ulI2cChannels[uiChannel]) != ERROR_NONE) {

return  (LW_NULL);

}

return  (&__Gimx6ulI2cFuncs[uiChannel]);

}

__i2cInit,__i2cHwInit的具体实现

__i2cInit函数用于初始化I2C控制器,主要包括了初始化I2C使用的信号量,设置时钟频率,指定作从设备时的地址。如程序清单 34,程序清单 35所示。

程序清单 34 __i2cInit的具体实现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;

}

……

}

程序清单 35 __i2cHwInit的具体实现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));

……

}

__i2cTransfer,__i2cTryTransfer的具体实现

__i2cTransfer函数为I2C传输函数,用于在I2C总线上传输和接收数据。如程序清单 36,程序清单 37所示。

程序清单 36 __i2cTransfer的具体实现static INT  __i2cTransfer (UINT                uiChannel,

PLW_I2C_ADAPTER  pI2cAdapter,

PLW_I2C_MESSAGE  pI2cMsg,

INT                 iNum)

{

……

/*

*  这里使用了错误重传的功能,若传输失败则多次传输,由于实际应用中传输失败是小概率事件,

*  建议此功能放在用户层实现,在驱动方便仅仅完成数据传输和接收更合适。

*/

for (i = 0; i I2CADAPTER_iRetry; i++) {

if (__i2cTryTransfer(uiChannel, pI2cAdapter, pI2cMsg, iNum) == iNum) {

return  (iNum);

} else {

API_TimeSleep(LW_OPTION_WAIT_A_TICK);                       /*  等待一个机器周期重试        */

}

}

……

}

程序清单 37 __i2cTryTransfer的具体实现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 

if (__i2cTransferMsg(uiChannel, pI2cMsg, iNum) != ERROR_NONE) {

break;

}

}

/*

*  generate STOP by clearing MSTA bit

*  (清除MSTA位使其停止传输)

*/

__i2cTransferStop(uiChannel);

/*

*  disable the controller

*  (禁止I2C控制器)

*/

__i2cTransferDisable(uiChannel);

……

}

__i2cTransferEnable的具体实现

__i2cTransferEnable函数使能I2C,设置时钟频率。

__i2cTransferStart的具体实现

__i2cTransferStart函数设置I2C控制器为主模式(占用总线)。

__i2cTransferMsg的具体实现

i2cTransferMsg函数判断读/写模式,对应不同操作。如程序清单 38所示。

程序清单 38 __i2cTransferMsg的具体实现static INT  __i2cTransferMsg ( UINT               uiChannel,

PLW_I2C_MESSAGE    pI2cMsg,

INT                iNUM)

{

……

if (pI2cMsg->I2CMSG_usFlag & LW_I2C_M_RD) {                         /*  读取操作                    */

/*

*  do repeat-start

*  (重复启动)    (IEN_MSTA_MTX_RSTA)

*/

……

/*

*  send slave address again, but indicate read operation

*  (发送从机器件地址,表明为读操作)

*/

……

if (__i2cTransferTxByte(pucData, uiChannel) != 0) {             /*  发送从机地址,等待返回ACK   */

return -1;

}

/*

*  change to receive mode

*  (设置为接收模式)

*/

……

/*

*  若只有一个字节,设置选择不发送ACK(最后一次传输不发送ACK)

*/

……

/*

*  dummy read

*  (行假读)

*/

*pucData = readw(REG_I2C_I2DR(uiChannel));

/*

*  开始读...

*/

if (__i2cTransferRxBytes(pI2cMsg->I2CMSG_pucBuffer,

uiChannel,

pI2cMsg->I2CMSG_usLen) != 0) {

return (PX_ERROR);

}

} else {                                                            /*  发送操作                    */

/*

*  Step 2: send slave address + read/write at the LSB

*  (发送从机地址+读写LSB   设置为写位)

*/

……

/*

*  将从机地址数据写入寄存器,等待ACK返回

*/

……

/*

*  设定一个长度,循环往寄存器写,等待ACK返回

*/

pucData = pI2cMsg->I2CMSG_pucBuffer;

for (i = 0; i I2CMSG_usLen; i++) {

/*

* send device register value

* (发送寄存器地址 / 信息)

*/

if ((iRet = __i2cTransferTxByte(pucData, uiChannel)) != 0) {

break;

}

pucData++;

}

}

……

}

__i2cTransferTxByte的具体实现

如程序清单 39,程序清单 310所示。

程序清单 39 __i2cTransferTxByte的具体实现static INT  __i2cTransferTxByte (UINT8  *pChar, UINT  uiChannel)

{

UINT uiValue = 0;

/*

*  clear both IAL and IIF bits

*  (清除IAL和IIF位)

*/

……

/*

*  write to data register

*  (向寄存器中写入数据,从机地址 / 发送信息)

*  0x0E <

*  0x07 + ack

*  0x0e <

*  xx + ack

*/

writew((*pChar), (REG_I2C_I2DR(uiChannel)));

/*

*  wait for transfer of byte to complete

*  (等待传输完成)

*/

return __i2cTransferWaitOpDone(uiChannel, 1);

}

程序清单 310 __i2cTransferWaitOpDone的具体实现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);

}

}

……

}

__i2cTransferRxBytes的具体实现

如程序清单 311所示。

程序清单 311 __i2cTransferRxBytes的具体实现static INT  __i2cTransferRxBytes (UINT8  *pChar,

UINT    uiChannel,

INT     iSize)

{

……

/*

*  等待传输完成

*/

for (i = 0; iSize > 0; iSize--, i++) {

if (__i2cTransferWaitOpDone(uiChannel, 0) != 0) {

return (PX_ERROR);

}

/*

*  接下来的两个if指令设置为下一个读取控制寄存器的值

*  若iSize == 1则此次为最后一次且已完成传输(清除MSTA位)

*  若iSize == 2则下次为最后一次传输,不发送ACK信号(禁止TXAK位)

*/

……

/*

*  真正开始读取数据

*/

pChar[i] = readw(REG_I2C_I2DR(uiChannel));

}

……

}

__i2cTransferStop的具体实现

__i2cTransferStop函数设置I2C控制器为从模式(释放总线)。

__i2cTransferDisable的具体实现

__i2cTransferDisable函数失能I2C。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值