您的位置:首页 > 其它

SylixOS iMX6平台I2C总线驱动

2017-03-10 14:33 281 查看
原理概述

I2C总线驱动概述

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数。驱动程序包含初始化I2C总线控制器__i2cHwInit函数,操作函数集(总线传输__i2cTransfer函数,总线控制__i2cMasterCtl函数)。
Imx6ul控制器的硬件描述

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寄存器来获取。
I2C总线传输编程流程

I2C总线驱动传输函数,主要编程流程如图 21所示。



图 21 I2C编程状态
传输大致流程:
1.使能I2C控制器
2.设置为主模式(占用总线)
3.传输消息(总线传输完成产生IIF中断,在中断中判断是否传输完成)
4.传输完成后设置为从模式(释放总线)
5.失能I2C

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



图 22中断处理
技术实现

I2C总线驱动框架

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



图 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所示。



图 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 < pI2cAdapter->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 < 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);
……
}

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

程序清单 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。

附录:

/*********************************************************************************************************
**
**                                    中国软件开源组织
**
**                                   嵌入式实时操作系统
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: iic_drv.c
**
** 创   建   人: ZhuGe.YiFan (诸葛一帆)
**
** 文件创建日期: 2016 年 12 月 17 日
**
** 描        述: imx6ulrm I2C 总线驱动
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#include
#include
#include "bspboard.h"
#include "pinmux/iomuxConfig.h"

/*********************************************************************************************************
I2C 控制器相关定义
********************************************************************************************************/
#define I2C_CHAN_NUM                       (4)                          /*  IIC 通道个数                */
#define I2C_CHAN_1                         (0)                          /*  IIC 通道1                   */
#define I2C_CHAN_2                         (1)                          /*  IIC 通道2                   */
#define I2C_CHAN_3                         (2)                          /*  IIC 通道3                   */
#define I2C_CHAN_4                         (3)                          /*  IIC 通道4                   */

#define I2C_WRITE                          (0)                          /*  传输从机地址时+写位         */
#define I2C_READ                           (1)                          /*  传输从机地址时+读位         */

#define I2C_BUS_FREQ_MAX                   (400000)                     /*  设置时钟频率                */
#define SPECIFIED_RATE                     (100000)                     /*  设置时钟频率                */
#define BIT_I2C_IFDR_IC_MASK               (0x3f)                       /*  时钟频率参数掩码            */

#define BIT_I2C_I2SR_IBB                   (0x0020)                     /*  I2SR寄存器IBB位             */
#define BIT_I2C_I2SR_IAL                   (0x0010)                     /*  I2SR寄存器IAL位             */
#define BIT_I2C_I2SR_IIF                   (0x0002)                     /*  I2SR寄存器IIF位             */
#define BIT_I2C_I2SR_RXAK                  (0x0001)                     /*  I2SR寄存器RXAK位            */
#define BIT_I2C_I2SR_TXAK                  (0x0008)                     /*  I2CR寄存器TXAK位            */

/*********************************************************************************************************
I2C 总线状态
*********************************************************************************************************/
#define __I2C_BUS_STATE_IDLE               0                            /*  总线空闲                    */
#define __I2C_BUS_STATE_START              1                            /*  总线启动                    */
#define __I2C_BUS_STATE_READ               2                            /*  读数据                      */
#define __I2C_BUS_STATE_WRITE              3                            /*  写数据                      */
#define __I2C_BUS_STATE_STOP               4                            /*  总线结束                    */

/*********************************************************************************************************
I2C 寄存器移位相关宏
********************************************************************************************************/
#define BIT_I2C_I2CR_RSTA                  (1 I2CMSG_usLen - 1))
/*  消息的最后一个字节          */
#define __I2C_BUS_IS_MSGEND(pI2cChannel)    (pI2cChannel->iMsgPtr >= pI2cChannel->pi2cmsg->I2CMSG_usLen)
/*  消息结束                    */

/*********************************************************************************************************
全局变量
*********************************************************************************************************/
static __I2C_CHANNEL  __Gi2cChannel[I2C_CHAN_NUM] = {                    /*  I2C通道号数组全局           */
{I2C_CHAN_1},
{I2C_CHAN_2},
{I2C_CHAN_3},
{I2C_CHAN_4}
};

/*********************************************************************************************************
I2C 时钟频率设置参数数组
*********************************************************************************************************/
static UINT16 __GusI2cClkDiv[50][2] = {
{ 22,   0x20 }, { 24,   0x21 }, { 26,   0x22 }, { 28,   0x23 },
{ 30,   0x00 }, { 32,   0x24 }, { 36,   0x25 }, { 40,   0x26 },
{ 42,   0x03 }, { 44,   0x27 }, { 48,   0x28 }, { 52,   0x05 },
{ 56,   0x29 }, { 60,   0x06 }, { 64,   0x2A }, { 72,   0x2B },
{ 80,   0x2C }, { 88,   0x09 }, { 96,   0x2D }, { 104,  0x0A },
{ 112,  0x2E }, { 128,  0x2F }, { 144,  0x0C }, { 160,  0x30 },
{ 192,  0x31 }, { 224,  0x32 }, { 240,  0x0F }, { 256,  0x33 },
{ 288,  0x10 }, { 320,  0x34 }, { 384,  0x35 }, { 448,  0x36 },
{ 480,  0x13 }, { 512,  0x37 }, { 576,  0x14 }, { 640,  0x38 },
{ 768,  0x39 }, { 896,  0x3A }, { 960,  0x17 }, { 1024, 0x3B },
{ 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};

/*********************************************************************************************************
** 函数名称: __imx6ulI2cStart
** 功能描述: i2c 控制器发送启动字节
** 输 入  : usAddr     地址
**           usFlag     标志
**           uiChannel  通道号
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  __imx6ulI2cStart (UINT16  usAddr,
UINT16  usFlag,
UINT    uiChannel)
{
UINT    uiValue;

__Gi2cChannel[uiChannel].iStatus = __I2C_BUS_STATE_START;           /*  启动总线                    */

switch(uiChannel) {

case I2C_CHAN_1:
API_InterVectorEnable(IMX_INT_I2C1);                            /*  启动总线中断                */
break;

case I2C_CHAN_2:
API_InterVectorEnable(IMX_INT_I2C2);                            /*  启动总线中断                */
break;

case I2C_CHAN_3:
API_InterVectorEnable(IMX_INT_I2C3);                            /*  启动总线中断                */
break;

case I2C_CHAN_4:
API_InterVectorEnable(IMX_INT_I2C4);                            /*  启动总线中断                */
break;

default:
break;
}

uiValue  =  readw(REG_I2C_I2CR(uiChannel));                         /*  使能I2C中断                 */
uiValue |=  BIT_I2C_I2CR_IIEN;
writew(uiValue, REG_I2C_I2CR(uiChannel));

if (usFlag & LW_I2C_M_RD) {                                         /*  读操作                      */
uiValue  =  readw(REG_I2C_I2CR(uiChannel));                     /*  重启总线 需要有此操作       */
uiValue |=  BIT_I2C_I2CR_RSTA;
writew(uiValue, REG_I2C_I2CR(uiChannel));

writew(((usAddr uiChannel));             /*  清中断                      */

uiValue = readw(REG_I2C_I2SR(pI2cChannel->uiChannel));
if ((uiValue & BIT_I2C_I2SR_IAL) > 0) {
/*  中断仲裁                    */
errno = ENXIO;
__imx6ulI2cStop(pI2cChannel->uiChannel);                        /*  停止总线                    */
}

switch (pI2cChannel->iStatus) {                                     /*  处理不同状态                */

case __I2C_BUS_STATE_IDLE:
break;                                                          /*  直接退出                    */

case __I2C_BUS_STATE_START:
if ((__I2C_BUS_IS_LASTMSG(pI2cChannel) &&                       /*  没有待处理的消息            */
(pI2cChannel->pi2cmsg->I2CMSG_usLen == 0))) {
errno = ENXIO;
__imx6ulI2cStop(pI2cChannel->uiChannel);                    /*  停止总线                    */
break;
}
if (pI2cChannel->pi2cmsg->I2CMSG_usFlag & LW_I2C_M_RD) {        /*  进入读状态                  */
pI2cChannel->iStatus = __I2C_BUS_STATE_READ;
uiValue  =  readw(REG_I2C_I2CR(pI2cChannel->uiChannel));     /*  主收模式启动                */
uiValue &= ~BIT_I2C_I2CR_MTX;
writew(uiValue, REG_I2C_I2CR(pI2cChannel->uiChannel));
if (pI2cChannel->pi2cmsg->I2CMSG_usLen == 1) {               /*  若为最后一个消息,不发送ACK */
uiValue  =  readw(REG_I2C_I2CR(pI2cChannel->uiChannel));
uiValue |=  BIT_I2C_I2CR_TXAK;
writew(uiValue, REG_I2C_I2CR(pI2cChannel->uiChannel));
}
readw(REG_I2C_I2DR(pI2cChannel->uiChannel));                 /*  dummy read 空读             */
} else {
pI2cChannel->iStatus = __I2C_BUS_STATE_WRITE;               /*  进入写状态                  */
goto    __prepare_write;
}
break;

case __I2C_BUS_STATE_READ:
if (__I2C_BUS_IS_MSGEND(pI2cChannel)) {                         /*  当前为最后一个字节          */
if (__I2C_BUS_IS_LASTMSG(pI2cChannel)) {                    /*  这是最后一个消息块          */
pI2cChannel->iMsgPtr = 0;
pI2cChannel->iMsgIndex++;                               /*  保证与消息数量相同          */
__imx6ulI2cStop(pI2cChannel->uiChannel);
break;
} else {
pI2cChannel->iMsgPtr = 0;
pI2cChannel->iMsgIndex++;
pI2cChannel->pi2cmsg++;                                 /*  开始接收下一个消息          */
}
} else if (__I2C_BUS_IS_MSGLAST(pI2cChannel)) {                 /*  当前为倒数第二字节          */
if (__I2C_BUS_IS_LASTMSG(pI2cChannel)) {                    /*  这是最后一个消息块          */
uiValue  =  readw(REG_I2C_I2CR(pI2cChannel->uiChannel));
uiValue |=  BIT_I2C_I2CR_TXAK;
writew(uiValue, REG_I2C_I2CR(pI2cChannel->uiChannel));  /*  下一个字节不发送ACK         */
}
}
ucByte = (BYTE)readw(REG_I2C_I2DR(pI2cChannel->uiChannel));     /*  读取数据                    */
pI2cChannel->pi2cmsg->I2CMSG_pucBuffer[pI2cChannel->iMsgPtr] = ucByte;
pI2cChannel->iMsgPtr++;
break;

case __I2C_BUS_STATE_WRITE:
if ((ulStatus & BIT_I2C_I2SR_RXAK) &&                           /*  需要 ACK 但没有接收到 ACK   */
!(pI2cChannel->pi2cmsg->I2CMSG_usFlag &
LW_I2C_M_IGNORE_NAK)) {
errno = ECONNREFUSED;
__imx6ulI2cStop(pI2cChannel->uiChannel);                    /*  停止总线                    */
break;
}

__prepare_write:
if (!__I2C_BUS_IS_MSGEND(pI2cChannel)) {                        /*  当前消息还没有发送完        */
ucByte = pI2cChannel->pi2cmsg->I2CMSG_pucBuffer[pI2cChannel->iMsgPtr];
pI2cChannel->iMsgPtr++;
writew((ucByte), (REG_I2C_I2DR(pI2cChannel->uiChannel)));
} else if (!__I2C_BUS_IS_LASTMSG(pI2cChannel)) {                /*  还有剩余的消息没有发送完    */
pI2cChannel->iMsgPtr = 0;
pI2cChannel->iMsgIndex++;
pI2cChannel->pi2cmsg++;                                     /*  开始发送下一个消息          */
if (pI2cChannel->pi2cmsg->I2CMSG_usFlag &
LW_I2C_M_NOSTART) {                                     /*  不需要起始位                */
if (pI2cChannel->pi2cmsg->I2CMSG_usFlag &
LW_I2C_M_RD) {                                      /*  读操作                      */

/*
*  控制器换向, 必须重启总线
*/
__imx6ulI2cStop(pI2cChannel->uiChannel);            /*  不能进行读操作              */
}
goto    __prepare_write;
} else {
__imx6ulI2cStart(pI2cChannel->pi2cmsg->I2CMSG_usAddr,
pI2cChannel->pi2cmsg->I2CMSG_usFlag,
pI2cChannel->uiChannel);               /*  重启总线                    */
}
} else {
pI2cChannel->iMsgPtr = 0;
pI2cChannel->iMsgIndex++;                                   /*  保证与消息数量相同          */
__imx6ulI2cStop(pI2cChannel->uiChannel);                    /*  发送结束                    */
}
break;

case __I2C_BUS_STATE_STOP:
break;

default:
break;
}

return  (LW_IRQ_HANDLED);
}

/*********************************************************************************************************
** 函数名称: __i2cTryTransfer
** 功能描述: i2c 尝试传输函数
** 输 入  : uiChannel    i2c 通道
**           pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : 完成传输的消息数量
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2cTryTransfer (UINT             uiChannel,
PLW_I2C_ADAPTER  pI2cAdapter,
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
__Gi2cChannel[uiChannel].iStatus    = __I2C_BUS_STATE_START;
__Gi2cChannel[uiChannel].iBpsParam  = SPECIFIED_RATE;
__Gi2cChannel[uiChannel].pi2cmsg    = pI2cMsg;
__Gi2cChannel[uiChannel].iMsgPtr    = 0;
__Gi2cChannel[uiChannel].iMsgNum    = iNum;
__Gi2cChannel[uiChannel].iMsgIndex  = 0;                            /*  从第一个开始发送            */

__imx6ulI2cStart(pI2cMsg->I2CMSG_usAddr,
pI2cMsg->I2CMSG_usFlag,
uiChannel);                                        /*  启动总线                    */

API_SemaphoreBPend(__Gi2cChannel[uiChannel].I2C_hSignal,
LW_OPTION_WAIT_A_SECOND * 3);                    /*  最多等待 3 秒钟             */

switch(uiChannel) {

case I2C_CHAN_1:
API_InterVectorDisable(IMX_INT_I2C1);                           /*  关闭总线中断                */
break;

case I2C_CHAN_2:
API_InterVectorDisable(IMX_INT_I2C2);                           /*  关闭总线中断                */
break;

case I2C_CHAN_3:
API_InterVectorDisable(IMX_INT_I2C3);                           /*  关闭总线中断                */
break;

case I2C_CHAN_4:
API_InterVectorDisable(IMX_INT_I2C4);                           /*  关闭总线中断                */
break;

default:
break;
}

return  (__Gi2cChannel[uiChannel].iMsgIndex);                       /*  返回传输成功的数量          */
}

/*********************************************************************************************************
** 函数名称: __i2cTransfer
** 功能描述: i2c 传输函数
** 输 入  : uiChannel    i2c 通道
**           pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2cTransfer (UINT             uiChannel,
PLW_I2C_ADAPTER  pI2cAdapter,
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
INT  i;

for (i = 0; i < pI2cAdapter->I2CADAPTER_iRetry; i++) {              /*  错误重传                   */
if (__i2cTryTransfer(uiChannel, pI2cAdapter, pI2cMsg, iNum) == iNum) {
return  (iNum);
} else {
API_TimeSleep(LW_OPTION_WAIT_A_TICK);                       /*  等待一个机器周期重试        */
}
}

return  (PX_ERROR);
}

/*********************************************************************************************************
** 函数名称: __i2c1Transfer
** 功能描述: i2c1 传输函数
** 输 入  : pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : i2c 传输函数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2c1Transfer (PLW_I2C_ADAPTER  pI2cAdapter,               /*  抽象成Transfer              */
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
return  (__i2cTransfer(I2C_CHAN_1,
pI2cAdapter,
pI2cMsg,
iNum));
}

/*********************************************************************************************************
** 函数名称: __i2c2Transfer
** 功能描述: i2c2 传输函数
** 输 入  : pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : i2c 传输函数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2c2Transfer (PLW_I2C_ADAPTER  pI2cAdapter,               /*  抽象成Transfer              */
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
return  (__i2cTransfer(I2C_CHAN_2,
pI2cAdapter,
pI2cMsg,
iNum));
}

/*********************************************************************************************************
** 函数名称: __i2c3Transfer
** 功能描述: i2c3 传输函数
** 输 入  : pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : i2c 传输函数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2c3Transfer (PLW_I2C_ADAPTER  pI2cAdapter,               /*  抽象成Transfer              */
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
return  (__i2cTransfer(I2C_CHAN_3,
pI2cAdapter,
pI2cMsg,
iNum));
}

/*********************************************************************************************************
** 函数名称: __i2c4Transfer
** 功能描述: i2c4 传输函数
** 输 入  : pI2cAdapter  i2c 适配器
**           pI2cMsg      i2c 传输消息组
**           iNum         消息数量
** 输 出  : i2c 传输函数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2c4Transfer (PLW_I2C_ADAPTER  pI2cAdapter,               /*  抽象成Transfer              */
PLW_I2C_MESSAGE  pI2cMsg,
INT              iNum)
{
return  (__i2cTransfer(I2C_CHAN_4,
pI2cAdapter,
pI2cMsg,
iNum));
}

/*********************************************************************************************************
i2c 驱动程序(操作函数集)
*********************************************************************************************************/
static LW_I2C_FUNCS  __Gimx6ulI2cFuncs[I2C_CHAN_NUM] = {
{
__i2c1Transfer,                                         /*  I2C1传输函数                */
}, {
__i2c2Transfer,
}, {
__i2c3Transfer,
}, {
__i2c4Transfer,
}
};

/*********************************************************************************************************
** 函数名称: __i2cSetI2cClk
** 功能描述: 设置时钟频率
** 输 入  : uiChannel  i2c 通道号
**           uiBaud     时钟频率参数
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  __i2cSetI2cClk (UINT  uiChannel, UINT32  uiBaud)
{
/*
*  获取系统时钟
*/
//    UINT32 uiSrcClk = ccmMainClkGet(IPG_PER_CLK);
UINT32 uiSrcClk   = 75 * 1000 * 1000;
UINT32 uiDivider  = uiSrcClk / uiBaud;
UINT8  ucIndex    = 0;
UINT   uiValue    = 0;

/*
*  波特率处理后与数组中对应值匹配,将对应值写入分频寄存器
*/
if (uiDivider < __GusI2cClkDiv[0][0]) {
uiDivider = __GusI2cClkDiv[0][0];
ucIndex   = 0;
printk("Warning :can't find a smaller divider than %d.\n",
uiDivider);
printk("SCL frequency is set at %d - expected was %d.\n",
uiSrcClk / uiDivider, uiBaud);

} else if (uiDivider > __GusI2cClkDiv[49][0]) {
uiDivider = __GusI2cClkDiv[49][0];
ucIndex   = 49;
printk("Warning: can't find a bigger divider than %d.\n",
uiDivider);
printk("SCL frequency is set at %d - expected was %d.\n",
uiSrcClk / uiDivider, uiBaud);

} else {
for (ucIndex = 0; __GusI2cClkDiv[ucIndex][0] < uiDivider; ucIndex++);
uiDivider = __GusI2cClkDiv[ucIndex][0];
}

/*
*  设置I2C时钟频率
*/
uiValue  =  readw(REG_I2C_IFDR(uiChannel));
uiValue &= ~BIT_I2C_IFDR_IC_MASK;
uiValue |=  __GusI2cClkDiv[ucIndex][1];
writew(uiValue, REG_I2C_IFDR(uiChannel));
}

/*********************************************************************************************************
** 函数名称: __i2cHwInit
** 功能描述:  i2c 控制器初始化
** 输 入  : uiChannel  i2c 通道
** 输 出  : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2cHwInit (UINT  uiChannel)
{
UINT uiValue = 0;

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

writew(0, REG_I2C_I2SR(uiChannel));                                 /*  清零状态寄存器             */

uiValue  =  readw(REG_I2C_I2CR(uiChannel));                         /*  使能I2C                    */
uiValue |=  BIT_I2C_I2CR_IEN;
writew(uiValue, REG_I2C_I2CR(uiChannel));

return  (ERROR_NONE);
}

/*********************************************************************************************************
** 函数名称: __i2cInit
** 功能描述: 初始化 i2c 通道
** 输 入  : pI2cChannel  i2c 通道
** 输 出  : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT  __i2cInit (UINT  uiChannel)
{
__PI2C_CHANNEL  pI2cChannel = &__Gi2cChannel[uiChannel];

if (!pI2cChannel->I2C_bIsInit) {                                    /*  判断通道是否已初始化          */
/*
* 初始化 I2C 使用的信号量
*/
pI2cChannel->I2C_hSignal = API_SemaphoreBCreate("i2c_signal",
LW_FALSE,
LW_OPTION_OBJECT_GLOBAL,
LW_NULL);
if (pI2cChannel->I2C_hSignal == LW_OBJECT_HANDLE_INVALID) {
printk(KERN_ERR "imx6qI2cInit(): failed to create i2c_signal!\n");
goto  __error_handle;
}

/*
*  初始化 I2C 控制器
*/
if (__i2cHwInit(pI2cChannel->uiChannel) != ERROR_NONE) {
printk(KERN_ERR "imx6ulI2cInit(): failed to init!\n");
goto  __error_handle;
}

switch(pI2cChannel->uiChannel) {

case I2C_CHAN_1:
API_InterVectorConnect(IMX_INT_I2C1,
(PINT_SVR_ROUTINE)__i2cIsr,
(PVOID)uiChannel,
"i2c1_isr");
break;

case I2C_CHAN_2:
API_InterVectorConnect(IMX_INT_I2C2,
(PINT_SVR_ROUTINE)__i2cIsr,
(PVOID)uiChannel,
"i2c2_isr");
break;

case I2C_CHAN_3:
API_InterVectorConnect(IMX_INT_I2C3,
(PINT_SVR_ROUTINE)__i2cIsr,
(PVOID)uiChannel,
"i2c3_isr");
break;

case I2C_CHAN_4:
API_InterVectorConnect(IMX_INT_I2C4,
(PINT_SVR_ROUTINE)__i2cIsr,
(PVOID)uiChannel,
"i2c4_isr");
break;

default:
printk(KERN_ERR "__i2cInit(): I2C channel invalid!\n");
break;
}

pI2cChannel->I2C_bIsInit = LW_TRUE;                             /*  设置已初始化标志              */
}

return  (ERROR_NONE);

__error_handle:

if (pI2cChannel->I2C_hSignal) {
API_SemaphoreBDelete(&pI2cChannel->I2C_hSignal);
pI2cChannel->I2C_hSignal = 0;
}

return  (PX_ERROR);
}

/*********************************************************************************************************
** 函数名称: i2cIomuxConfig
** 功能描述: i2c管脚复用
** 输 入  : uiChannel  通道号
** 输 出  : NONE
** 全局变量: NONE
** 调用模块: NONE
********************************************************************************************************/
static VOID  __i2cIomuxConfig (UINT  uiChannel)
{
switch (uiChannel) {

case I2C_CHAN_1:                                                    /*  i2c1的管脚复用              */
IomuxConfig(__I2C1_SCL_REG,
__I2C1_SCL_MASK,
__I2C1_SCL_VAL);
IomuxConfig(__I2C1_SDA_REG,
__I2C1_SDA_MASK,
__I2C1_SDA_VAL);
break;

case I2C_CHAN_2:                                                     /*  i2c2的管脚复用              */
IomuxConfig(__I2C2_SCL_REG,
__I2C2_SCL_MASK,
__I2C2_SCL_VAL);
IomuxConfig(__I2C2_SDA_REG,
__I2C2_SDA_MASK,
__I2C2_SDA_VAL);
break;

case I2C_CHAN_3:                                                    /*  i2c3的管脚复用              */
IomuxConfig(__I2C3_SCL_REG,
__I2C3_SCL_MASK,
__I2C3_SCL_VAL);
IomuxConfig(__I2C3_SDA_REG,
__I2C3_SDA_MASK,
__I2C3_SDA_VAL);
break;

case I2C_CHAN_4:                                                    /*  i2c4的管脚复用              */
IomuxConfig(__I2C4_SCL_REG,
__I2C4_SCL_MASK,
__I2C4_SCL_VAL);
IomuxConfig(__I2C4_SDA_REG,
__I2C4_SDA_MASK,
__I2C4_SDA_VAL);
break;

default:
printk(KERN_ERR "i2cBusFuns(): I2C channel invalid!\n");
}

return;
}

/*********************************************************************************************************
** 函数名称: i2cBusFuns
** 功能描述: 初始化 i2c 总线并获取操作函数集
** 输 入  : uiChannel  通道号
** 输 出  : 总线操作函数集
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_I2C_FUNCS  i2cBusFuns (UINT  uiChannel)
{
/*
*  设置芯片管脚分配,SylixOS 计数从零开始,而 IMX6UL 手册是从 1 开始,需要注意
*/
__i2cIomuxConfig(uiChannel);

if (__i2cInit(uiChannel) != ERROR_NONE) {                           /*  初始化控制器              */
return  (LW_NULL);
}

return  (&__Gimx6ulI2cFuncs[uiChannel]);                            /*  返回操作函数集            */
}

/*********************************************************************************************************
** 函数名称: i2cBusCreate
** 功能描述: 初始化目标电路板i2c总线系统
** 输 入  : NONE
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID i2cBusCreate (VOID)
{
/*
*  具体配置在common中
*/
PLW_I2C_FUNCS    pI2cFuncs;

API_I2cLibInit();                                                   /*  初始化 i2c 组件库           */

#if  CONFIG_BSP_I2C0
pI2cFuncs = i2cBusFuns(0);                                          /*  创建 i2c0总线适配器         */
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/0", pI2cFuncs, 10, 1);           /*  0 对应 I2C0                 */
}
#endif
#if  CONFIG_BSP_I2C1
pI2cFuncs = i2cBusFuns(1);                                          /*  创建 i2c1总线适配器         */
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/1", pI2cFuncs, 10, 1);           /*  1 对应 I2C1                 */
}
#endif
#if  CONFIG_BSP_I2C2
pI2cFuncs = i2cBusFuns(2);                                          /*  创建 i2c2总线适配器         */
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/2", pI2cFuncs, 10, 1);           /*  2 对应 I2C2                 */
}
#endif
#if  CONFIG_BSP_I2C3
pI2cFuncs = i2cBusFuns(3);                                          /*  创建 i2c3总线适配器         */
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/3", pI2cFuncs, 10, 1);           /*  3 对应 I2C3                 */
}
#endif
}

/*********************************************************************************************************
** 函数名称: i2cBusDelete
** 功能描述: 卸载目标电路板i2c总线系统
** 输 入  : NONE
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID i2cBusDelete (VOID)
{
#if  CONFIG_BSP_I2C0
API_I2cAdapterDelete("/bus/i2c/0");                                 /*  0 对应 I2C0                 */
#endif
#if  CONFIG_BSP_I2C1
API_I2cAdapterDelete("/bus/i2c/1");                                 /*  1 对应 I2C1                 */
#endif
#if  CONFIG_BSP_I2C2
API_I2cAdapterDelete("/bus/i2c/2");                                 /*  2 对应 I2C2                 */
#endif
#if  CONFIG_BSP_I2C3
API_I2cAdapterDelete("/bus/i2c/3");                                 /*  3 对应 I2C3                 */
#endif
}

/*********************************************************************************************************
** 函数名称: module_init
** 功能描述: module_init()驱动加载模块
** 输 入  : NONE
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID module_init (VOID)
{
printf("hello_module init!\n");
i2cBusCreate();
}

/*********************************************************************************************************
** 函数名称: module_exit
** 功能描述: module_exit()驱动卸载模块
** 输 入  : NONE
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID module_exit (VOID)
{
printf("hello_module exit!\n");
i2cBusDelete();
}
/*********************************************************************************************************
END
*********************************************************************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: