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

TI TMS320F28069 I2C通信故障排查与解决
本文档详细描述了在使用TMS320F28069微控制器通过I2C协议与MPU6050交互时遇到的问题及解决方法。主要问题在于全速运行时,I2C通信在检查发送和接收准备状态时出现异常。通过对I2CA_CheckTxReady()和I2CA_CheckRecieveOk()函数添加延迟来降低查询速率,成功解决了通信异常,确保了I2C通信的稳定进行。

项目场景:

使用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);
}
int WriteDatatoFM24V10(Uint16 *Wdata,Uint32 RomAddress,Uint16 Number) { Uint16 j,timeout = 10; // 检查总线忙 if (I2caRegs.I2CSTR.bit.BB) { return I2C_ERROR_BUS_BUSY; } I2C_ClearStatus(); // 等待发送就绪 while (!I2C_xrdy()&& timeout--) DELAY_US(10); if (timeout == 0) return I2C_ERROR_TIMEOUT; // 配置I2C传输 I2caRegs.I2CSAR = I2C_SLAVE_ADDR;//result = //slave_addr; // 设置从机地址 I2caRegs.I2CCNT = Number + 2; // 设置传输字节数(地址2字节+数据) I2caRegs.I2CDXR = (RomAddress>>8);// & 0xFF; // 发送写入地址高字节 I2caRegs.I2CDXR = (RomAddress & 0xFF); // 发送写入地址低字节 // 启动主发送模式 I2caRegs.I2CMDR.all = 0x6E20; // STT + STP + MST + TRX + IRS if (I2caRegs.I2CSTR.bit.NACK == 1) // return I2C_BUS_BUSY_ERROR; // 发送数据 for (j = 0; j < Number; j++) { while (!I2C_xrdy()&& timeout--) DELAY_US(10); if (timeout == 0) return I2C_ERROR_TIMEOUT; I2caRegs.I2CDXR = *Wdata++; // 检查NACK if (I2caRegs.I2CSTR.bit.NACK) { I2C_ClearStatus(); //I2caRegs.I2CSTR.bit.NACK = 1; // 清除NACK标志 return I2C_ERROR_NACK; } } // 等待传输完成(F-RAM无需额外等待写入完成) while (I2caRegs.I2CSTR.bit.BB) DELAY_US(10); return I2C_SUCCESS; } int ReadDataFromFM24V10(Uint16 *Rdata,Uint32 RomAddress,Uint16 Number) { Uint16 l = 0 ; // 检查总线忙 Uint16 timeout = I2C_ERROR_TIMEOUT; while (I2caRegs.I2CSTR.bit.BB && timeout--) DELAY_US(10); if (timeout == 0) return I2C_ERROR_BUS_BUSY; I2C_ClearStatus(); // first-send address(write) // 等待发送就绪 timeout = I2C_ERROR_TIMEOUT; while (!I2C_xrdy() && timeout--) DELAY_US(1); if (timeout == 0) return I2C_ERROR_TIMEOUT; //1.发送要读的地址设置命令 I2caRegs.I2CSAR = I2C_SLAVE_ADDR; // 设置从机地址 I2caRegs.I2CCNT = 2; // 发送read地址 I2caRegs.I2CCNT = Number + 2; // 设置传输字节数(地址2字节+数据) I2caRegs.I2CDXR = (RomAddress>>8) & 0xFF; // 发送写入地址高字节 I2caRegs.I2CDXR = (RomAddress & 0xFF); // 发送写入地址低字节 // 启动主发送模式(无停止位) I2caRegs.I2CMDR.all = 0x6620; // STT + MST + TRX + IRS // 检查NACK if (I2caRegs.I2CSTR.bit.NACK) { I2C_ClearStatus(); // I2caRegs.I2CSTR.bit.NACK = 1; // 清除NACK标志 return I2C_ERROR_NACK; } // 等待发送完成 timeout = I2C_ERROR_TIMEOUT; while (!I2C_xrdy() && timeout--) DELAY_US(10); if (timeout == 0) return I2C_ERROR_TIMEOUT; //second-restart (read) I2caRegs.I2CSAR = I2C_SLAVE_ADDR; // 设置从机地址 I2caRegs.I2CCNT = Number; // 设置要读取的字节数 // 启动主接收模式 I2caRegs.I2CMDR.all = 0x6C20; // STT + STP + MST + IRS // 检查NACK if (I2caRegs.I2CSTR.bit.NACK) { I2caRegs.I2CSTR.bit.NACK = 1; // 清除NACK标志 return I2C_ERROR_NACK; } // 读取数据 for (l = 0; l < Number; l++) { timeout = I2C_ERROR_TIMEOUT; while (!I2C_rrdy() && timeout--) DELAY_US(10); if (timeout == 0) { I2C_ClearStatus(); return I2C_ERROR_TIMEOUT; } *Rdata++ = I2caRegs.I2CDRR; } // 等待传输完成 timeout = I2C_ERROR_TIMEOUT; while (I2caRegs.I2CSTR.bit.BB && timeout--) DELAY_US(10); if (timeout == 0) { I2C_ClearStatus(); return I2C_ERROR_TIMEOUT; } return I2C_SUCCESS; }void I2CWriteAndRead(void) { //为写入数据赋值 switch(countflag) { case 1: writeBuffer[0] = 0xAA; for (i = 1; i < BUFFER_SIZE - 1; i++) { writeBuffer[i] = i + 30; //写入数据 } writeBuffer[16] = 0xFF; writeBuffer[27] = 0xEE; break; case 2: writeBuffer[0] = 0xAA; for (i = 1; i < BUFFER_SIZE - 1; i++) { writeBuffer[i] = i + 50; //写入数据 } writeBuffer[16] = 0xFF; writeBuffer[27] = 0xEE; case 3: writeBuffer[0] = 0xAA; for (i = 1; i < BUFFER_SIZE - 1; i++) { writeBuffer[i] = i + 80 ; //写入数据 } writeBuffer[16] = 0xFF; writeBuffer[27] = 0xEE; break; default: writeBuffer[0] = 0xAA; for (i = 1; i < BUFFER_SIZE - 1; i++) { writeBuffer[i] = i; //写入数据 } writeBuffer[16] = 0xFF; writeBuffer[27] = 0xEE; break; } result = WriteDatatoFM24V10(writeBuffer, address, BUFFER_SIZE); //result = I2C_WriteData(writeBuffer, address, BUFFER_SIZE); if (result != I2C_SUCCESS) { HandleI2CError(result); } // DELAY_US(200); result = ReadDataFromFM24V10(readBuffer, address, BUFFER_SIZE); // result = I2C_ReadData(readBuffer, address, BUFFER_SIZE); if (result != I2C_SUCCESS) { HandleI2CError(result); } address = (address + BUFFER_SIZE) % FM24V10_SIZE; DELAY_US(200); countflag++; }#define I2C_SLAVE_ADDR 0x50 #define FM24V10_SIZE 0x1FFFF///131072 // eeprom 128k Bytes #define BUFFER_SIZE 28 在28335中使用I2C通信实现对128K*8存储芯片的连续读写
最新发布
09-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值