TMS320F28069的硬件I2C一直卡在查询 I2caRegs.I2CSTR.bit.XRDY

项目场景:

使用TMS320F28069的硬件I2C读取MPU6050的数据

问题描述

Uint16 I2CA_ReadBytes( Uint16 SlaveAddress, Uint16 RomAddress,Uint16 number, Uint16 *RamAddr)
{
Uint16 i,Temp;

if (I2caRegs.I2CSTR.bit.BB == 1) //返回总线忙错误状态
{
return I2C_BUS_BUSY_ERROR;
}
while(!I2CA_CheckTxReady());
I2caRegs.I2CSAR = SlaveAddress&0x00ff; //设备从地址
I2caRegs.I2CCNT = 1; //发送一个字节为要读取数据的寄存器地址
I2caRegs.I2CDXR = RomAddress&0x00ff;
I2caRegs.I2CMDR.all = 0x6620; //主机发送模式,自动清除停止位不产生停止信号
if (I2caRegs.I2CSTR.bit.NACK == 1) //送到无应答信号返回错误
return I2C_BUS_BUSY_ERROR;
DELAY_US(5);
while(!I2CA_CheckTxReady()); //调试过程中有时会卡在这一步,表示通讯不正常
I2caRegs.I2CSAR = SlaveAddress&0x00ff;
I2caRegs.I2CCNT = number;
I2caRegs.I2CMDR.all = 0x6C20; //主机接受模式,包含有停止信号
if (I2caRegs.I2CSTR.bit.NACK == 1)
return I2C_BUS_BUSY_ERROR;
for(i=0;i<number;i++)
{
while(!I2CA_CheckRecieveOk());
Temp = I2caRegs.I2CDRR;
if (I2caRegs.I2CSTR.bit.NACK == 1)
return I2C_BUS_BUSY_ERROR;
*RamAddr = Temp;
RamAddr++;
}
return I2C_SUCCESS; //接受数据成功
}
读取数据,调试单步调试代码运行正常,但是全速运行就一直卡在 while(!I2CA_CheckTxReady()); 这一句,或者返回I2C_BUS_BUSY_ERROR。

原因分析:

调试通过说明主从机的时序对上,在查询标志位的时候出错了。查看代码I2CA_CheckTxReady(),发现原来的写法是:
Uint16 I2CA_CheckTxReady(void)
{
Uint16 t,;
t = I2caRegs.I2CSTR.bit.XRDY; // IIC模块发送准备OK
return t;
}
我猜测可能是因为函数出入时间较短,导致I2caRegs.I2CSTR.bit.XRDY寄存器的数据总线一直被占用了,硬件无法更新该标志位。

解决方案:

降低查询速率
Uint16 I2CA_CheckTxReady(void)
{
Uint16 t,i;
t = I2caRegs.I2CSTR.bit.XRDY; // IIC模块发送准备OK
for(i=5;i>0;i–);//添加延时
return t;
}
对于函数I2CA_CheckRecieveOk()同理同样操作,bug就解决了

下面是IIC源码

//###########################################################################
// $ 函数名称:    void I2CA_Init(void)                            $
// $ 函数功能:    IIC模块初始化,设置IIC模块的功能引脚以及设置IIC的工作方式                             $
//###########################################################################
void I2CA_Init(void)
{
    I2caRegs.I2CMDR.all = 0x0000;   // 复位IIC

    EALLOW;
    GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // 使能(SDAA)上拉
    GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;    // 使能 (SCLA)上拉
    GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // 同步 (SDAA)
    GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // 同步 (SCLA)
    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // 配置 GPIO32为 SDAA
    GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // 配置GPIO33 为SCLA
    EDIS;

    // 预分频——时钟模块的频率
    I2caRegs.I2CPSC.all = 7; // 预分频 IIC模块时钟需设置为7-12MHz,本实验设置为 (80/8 = 10MHz)
    I2caRegs.I2CCLKL = 10;   //时钟低电平时间值
    I2caRegs.I2CCLKH = 5;    //时钟高电平时间值

    I2caRegs.I2CMDR.all = 0x0020;   // IIC准备就绪

    DELAY_US(100000);
}


//###########################################################################
// $ 函数名称:    Uint16    I2CA_CheckTxReady()                        $
// $ 函数功能:    IIC模块发送准备OK                              $
//###########################################################################
Uint16  I2CA_CheckTxReady(void)
{
    Uint16  t,i;
    t = I2caRegs.I2CSTR.bit.XRDY;   // IIC模块发送准备OK
    for(i=5;i>0;i--);
    return t;
}


//###########################################################################
// $ 函数名称:    Uint16    I2CA_CheckRecieveOk()                      $
// $ 函数功能:    IIC模块接收准备OK                              $
//###########################################################################
Uint16  I2CA_CheckRecieveOk(void)
{
    Uint16  t,i;
    t = I2caRegs.I2CSTR.bit.RRDY;   //  IIC模块接收准备OK
    for(i=5;i>0;i--);
    return t;
}


//###########################################################################
// $ 函数名称:    Uint16 I2CA_WriteBytes( Uint16  SlaveAddress, Uint16 RomAddress,Uint16 number, Uint8 *Wdata)        $
// $ 函数功能:    IIC写数据                                                       $
//###########################################################################
Uint16 I2CA_WriteBytes( Uint16 SlaveAddress, Uint16 RomAddress,Uint16 number, Uint8 *Wdata)
{
   Uint16 i;
   if (I2caRegs.I2CSTR.bit.BB == 1)
   {
      return I2C_BUS_BUSY_ERROR;   //返回总线忙错误状态
   }
   while(!I2CA_CheckTxReady());      //等待数据发送就绪,XRDY=1,表明发送寄存器已经准备好接受新的数据
   I2caRegs.I2CSAR = SlaveAddress&0x00ff;    //设备从地址
   I2caRegs.I2CCNT = number + 1;   //需要发送的字节数
   I2caRegs.I2CDXR = RomAddress&0x00ff;    //第一个发送字节为发送数据的目标寄存器地址
   I2caRegs.I2CMDR.all = 0x6E20;    //发送起始信号,内部数据计数器减到0时,发送停止信号,主机发送模式,使能IIC模式,
   for (i=0; i<number; i++)
   {
      while(!I2CA_CheckTxReady());   //等待数据发送就绪,发送下一个数据
      I2caRegs.I2CDXR = *Wdata&0xFF;
      Wdata++;
      if (I2caRegs.I2CSTR.bit.NACK == 1)    //送到无应答信号返回错误
          return    I2C_BUS_BUSY_ERROR;
   }
   return I2C_SUCCESS;         //发送成功
}


//###########################################################################
// $ 函数名称:    Uint16 I2CA_ReadBytes( Uint16 SlaveAddress, Uint16 RomAddress,Uint16 number, Uint16  *RamAddr)       $
// $ 函数功能:    IIC读数据                                                       $
//###########################################################################
Uint16 I2CA_ReadBytes( Uint16 SlaveAddress, Uint16 RomAddress,Uint16 number, Uint16  *RamAddr)
{
   Uint16  i,Temp;

   if (I2caRegs.I2CSTR.bit.BB == 1)  //返回总线忙错误状态
   {
       return I2C_BUS_BUSY_ERROR;
   }
   while(!I2CA_CheckTxReady());
   I2caRegs.I2CSAR = SlaveAddress&0x00ff;      //设备从地址
   I2caRegs.I2CCNT = 1;        //发送一个字节为要读取数据的寄存器地址
   I2caRegs.I2CDXR = RomAddress&0x00ff;
   I2caRegs.I2CMDR.all = 0x6620;   //主机发送模式,自动清除停止位不产生停止信号
   if (I2caRegs.I2CSTR.bit.NACK == 1)    //送到无应答信号返回错误
        return  I2C_BUS_BUSY_ERROR;
   DELAY_US(5);
   while(!I2CA_CheckTxReady());                  //调试过程中有时会卡在这一步,表示通讯不正常
   I2caRegs.I2CSAR = SlaveAddress&0x00ff;
   I2caRegs.I2CCNT = number;
   I2caRegs.I2CMDR.all = 0x6C20;   //主机接受模式,包含有停止信号
   if (I2caRegs.I2CSTR.bit.NACK == 1)
        return  I2C_BUS_BUSY_ERROR;
   for(i=0;i<number;i++)
   {
      while(!I2CA_CheckRecieveOk());
      Temp = I2caRegs.I2CDRR;
      if (I2caRegs.I2CSTR.bit.NACK == 1)
          return    I2C_BUS_BUSY_ERROR;
      *RamAddr = Temp;
      RamAddr++;
   }
   return I2C_SUCCESS;    //接受数据成功
}


//###########################################################################
// $ 函数名称:    IICwriteBit(Uint16 slaveaddress, Uint16 regaddress, Uint8 bitNum, Uint8 data)       $
// $ 函数功能:    IIC向寄存器的某一位写数据                                                     $
//###########################################################################
void IICwriteBit(Uint16 slaveaddress, Uint16 regaddress, Uint8 bitNum, Uint8 data)
{
    Uint16 a;
    Uint8 b;
    DELAY_US(50);
    I2CA_ReadBytes(slaveaddress,regaddress,1,&a);
    b=(Uint8 )(a&0xff);
    b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
    DELAY_US(50);
    I2CA_WriteBytes(slaveaddress,regaddress,1,&b);
}


//###########################################################################
// $ 函数名称:   IICwriteBits(Uint16 slaveaddress,Uint16 regaddress,Uint8 bitStart,Uint8 length,Uint8 data)      $
// $ 函数功能:    IIC向寄存器的某几位写数据                                                     $
//###########################################################################
void IICwriteBits(Uint16 slaveaddress,Uint16 regaddress,Uint8 bitStart,Uint8 length,Uint8 data)
{

    Uint8 b,mask;
    Uint16 a;
    DELAY_US(50);
    I2CA_ReadBytes(slaveaddress,regaddress,1,&a);
    b=(Uint8 )(a&0xff);
    mask = (0xFF << (bitStart + 1)) | 0xFF >> ((8 - bitStart) + length - 1);
    data <<= (8 - length);
    data >>= (7 - bitStart);
    b &= mask;
    b |= data;
    DELAY_US(50);
    I2CA_WriteBytes(slaveaddress,regaddress,1, &b);
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值