2244|1

190

帖子

10

TA的资源

一粒金砂(中级)

楼主
 

【NXP Rapid IoT评测】I2C程序小bug [复制链接]

上一篇 解决了I2C死锁解除的方法,
【NXP Rapid IoT评测】触摸按键没有反应——I2C死锁解除方法
https://bbs.eeworld.com.cn/forum ... 1480&fromuid=194541

但是总线上挂载的外设多时,有时会遇到外设失灵的情况,后来深入分析代码,出现问题在于
ATMO_Platform_I2C_Master_Transfer 这个函数上
  1. static ATMO_I2C_Status_t ATMO_Platform_I2C_Master_Transfer(
  2.                 i2c_direction_t direction, kI2C_Blocking_t blocking, uint32_t instance,
  3.                 uint16_t slaveAddress, const uint8_t* cmdBytes, uint16_t numCmdBytes,
  4.                 uint8_t* dataBytes, uint16_t numDataBytes) {
  5.         status_t platformStatus = kStatus_Fail;
  6.         i2c_master_transfer_t masterStructure;
  7.         uint32_t cmd;

  8.         if (instance > MK64F_NUM_I2C_INSTANCES) {
  9.                 return ATMO_I2C_Status_NotSupported;
  10.         }

  11.         if (ATMO_Platform_I2C_Peripheral[instance].operatingMode
  12.                         == ATMO_I2C_OperatingMode_Slave) {
  13.                 return ATMO_I2C_Status_Invalid;
  14.         }

  15.         if (numCmdBytes > 4) {
  16.                 return ATMO_I2C_Status_NotSupported;
  17.         }

  18.         if ((dataBytes == NULL) || (numDataBytes == 0)) {
  19.                 return ATMO_I2C_Status_Invalid;
  20.         }

  21.         // if either cmdBytes or numCmdBytes is null/zero then set both to null/zero
  22.         if (cmdBytes == NULL) {
  23.                 numCmdBytes = 0;
  24.         } else if (numCmdBytes == 0) {
  25.                 cmdBytes = NULL;
  26.         }

  27.         if (numCmdBytes == 1) {
  28.                 cmd = cmdBytes[0];
  29.         } else if (numCmdBytes == 2) {
  30.                 cmd = (cmdBytes[0] << 8) | cmdBytes[1];
  31.         } else if (numCmdBytes == 3) {
  32.                 cmd = (cmdBytes[0] << 16) | (cmdBytes[1] << 8) | cmdBytes[2];
  33.         } else if (numCmdBytes == 4) {
  34.                 cmd = (cmdBytes[0] << 24) | (cmdBytes[1] << 16) | (cmdBytes[2] << 8)
  35.                                 | cmdBytes[3];
  36.         }

  37.         masterStructure.flags = kI2C_TransferDefaultFlag;
  38.         masterStructure.slaveAddress = slaveAddress;
  39.         masterStructure.direction = direction;
  40.         masterStructure.subaddress = cmd;
  41.         masterStructure.subaddressSize = numCmdBytes;
  42.         masterStructure.data = dataBytes;
  43.         masterStructure.dataSize = numDataBytes;

  44.         if (blocking == kI2C_Blocking) {
  45.                 //ATMO_PLATFORM_DebugUsbPrint("ATMO_Platform_I2C_Master_Transfer kI2C_Blocking\r\n");
  46. [color=#ff0000]                platformStatus = I2C_MasterTransferNonBlocking(peripheralBase[instance],
  47.                                 &masterHandle[instance], &masterStructure);

  48.                 uint32_t timeoutCounter = ATMO_I2C_TIMEOUT;
  49.                 for (int i = 0; i < 1000; i++) {
  50.                 }

  51.                 while ((peripheralBase[instance]->S) & I2C_S_BUSY_MASK
  52.                                 && (timeoutCounter > 0)) {
  53.                         timeoutCounter--;[/color]
  54.                 }

  55.                 if (timeoutCounter == 0) {
  56.                         //ATMO_PLATFORM_DebugUsbPrint("ATMO_Platform_I2C_Master_Transfer ATMO_I2C_Status_Timeout\r\n");
  57.                         return ATMO_I2C_Status_Timeout;
  58.                 }

  59.         } else {
  60.                 platformStatus = I2C_MasterTransferNonBlocking(peripheralBase[instance],
  61.                                 &masterHandle[instance], &masterStructure);

  62.         }
  63.         //ATMO_PLATFORM_DebugUsbPrint("I2C_Master_Transfer Address:%d Status:%d \r\n",slaveAddress,platformStatus);
  64.         return ATMO_Platform_I2C_Convert_Status_PlatformToAtmo(platformStatus);
  65. }
复制代码




在kI2C_Blocking 读写模时 并非是阻塞式等待I2C结果的,仅仅是延时等等吧了for (int i = 0; i < 1000; i++) {
}对于120Mhz 的系统时钟,对于100Kpb的I2C实在时太少了。
同时(peripheralBase[instance]->S) & I2C_S_BUSY_MASK语句仅用共同启动I2C时才会出现。
所以代码,应该修改成如下
  1. if (blocking == kI2C_Blocking) {
  2.                 //ATMO_PLATFORM_DebugUsbPrint("ATMO_Platform_I2C_Master_Transfer kI2C_Blocking\r\n");
  3.                 nakFlag[instance] = false;
  4.                 completionFlag[instance] = false;
  5.                 platformStatus = I2C_MasterTransferNonBlocking(peripheralBase[instance],
  6.                                 &masterHandle[instance], &masterStructure);
  7. #if 0
  8.                 uint32_t timeoutCounter = ATMO_I2C_TIMEOUT;
  9.                 for (int i = 0; i < 1000; i++) {
  10.                 }

  11.                 while ((peripheralBase[instance]->S) & I2C_S_BUSY_MASK
  12.                                 && (timeoutCounter > 0)) {
  13.                         timeoutCounter--;
  14.                 }

  15.                 if (timeoutCounter == 0) {
  16.                         //ATMO_PLATFORM_DebugUsbPrint("ATMO_Platform_I2C_Master_Transfer ATMO_I2C_Status_Timeout\r\n");
  17.                         return ATMO_I2C_Status_Timeout;
  18.                 }
  19. #else
  20.                 /*  wait for transfer completed. */
  21.                 while ((!nakFlag[instance]) && (!completionFlag[instance])) {
  22.                 }
  23.                 nakFlag[instance] = false;
  24.                 if (completionFlag[instance] == true) {
  25.                         completionFlag[instance] = false;
  26.                         //ATMO_PLATFORM_DebugUsbPrint(" 0x%x", masterXfer.slaveAddress);
  27.                 } else {
  28.                         return ATMO_I2C_Status_Timeout;
  29.                 }
  30. #endif
  31.         }
复制代码




同时在中断回调函数上添加以下代码
  1. static void ATMO_Platform_I2C_Master_Callback(I2C_Type* base,
  2.                 i2c_master_handle_t* handle, status_t status, void* userData) {
  3.         ATMO_I2C_MasterTransfer_t masterXfer;
  4.         uint32_t instance = I2C_GetInstance(base);
  5.         ATMO_I2C_Master_Callback_t callback =
  6.                         ATMO_Platform_I2C_Peripheral[instance].cbFunc;
  7.         size_t xferCount;

  8.         /* Signal transfer success when received success status. */
  9.         if (status == kStatus_Success) {
  10.                 completionFlag[instance] = true;

  11.                 if ((handle->transfer.direction == kI2C_Read)
  12.                                 && (status == kStatus_Success)) {
  13.                         I2C_MasterTransferGetCount(base, handle, &xferCount);

  14.                         masterXfer.event = ATMO_I2C_MasterEvent_Complete;
  15.                         masterXfer.data = handle->transfer.data - xferCount;
  16.                         masterXfer.dataSize = xferCount;

  17.                         if (callback != NULL) {
  18.                                 callback(&masterXfer, userData);
  19.                         }
  20.                 } else {
  21.                         if (callback != NULL) {
  22.                                 callback(&masterXfer, userData);
  23.                         }
  24.                 }
  25.         }
  26.         /* Signal transfer failure when received any other status. */
  27.         if ((status == kStatus_I2C_Nak) || (status == kStatus_I2C_Addr_Nak)
  28.                         || (status == kStatus_I2C_ArbitrationLost)
  29.                         || (status == kStatus_I2C_Timeout)) {
  30.                 nakFlag[instance] = true;
  31.         }

  32. }
复制代码


实现阻塞为读写。


同时提供一个扫描I2C总线上设备的代码

  1. ATMO_I2C_Status_t ATMO_I2C_Scan(ATMO_DriverInstanceHandle_t instance)
  2. {
  3.         uint8_t cmdBuf[2]={0};
  4.         uint8_t readBuf[1]={0};
  5.         uint8_t slaveAddress=0;
  6.         ATMO_I2C_Status_t status=ATMO_I2C_Status_Unknown;
  7.         ATMO_PLATFORM_DebugUsbPrint("Driver On I2C%d Line:\r\n    ",instance);
  8.         for(slaveAddress= 0x00;slaveAddress<=0x0f;slaveAddress++){
  9.                 ATMO_PLATFORM_DebugUsbPrint(" %02x",slaveAddress);
  10.         }
  11.         //ATMO_PLATFORM_DebugUsbPrint("\r\n __",0);//slaveAddress == 0; 不存在
  12.         for(slaveAddress= 0x00;slaveAddress<=0x7f;slaveAddress++){
  13.                 status = ATMO_I2C_MasterRead(instance,slaveAddress,cmdBuf,0,readBuf,1,1000);
  14.                 //status = ATMO_I2C_MasterWrite(instance,slaveAddress,cmdBuf,0,readBuf,1,1000);
  15.                 if(slaveAddress%16==0){
  16.                         ATMO_PLATFORM_DebugUsbPrint("\r\n0x%02X",(slaveAddress/16)*16);
  17.                 }
  18.                 if(status != ATMO_I2C_Status_Success){
  19.                         ATMO_PLATFORM_DebugUsbPrint(" __");
  20.                 }else{
  21.                         ATMO_PLATFORM_DebugUsbPrint(" %02x",slaveAddress);
  22.                 }

  23.         }
  24.         ATMO_PLATFORM_DebugUsbPrint("\r\n");
  25.         return ATMO_I2C_Status_Success;
  26. }
复制代码







挂在总线上的外设都能正常读取地址

MPL3115Pressure                                    0x60
TSL2572AmbientLight                              0x39
CCS811AirQuality                                    0x5A
SX9500Touch                                         0x28
FXAS21002Gyroscope                             0x20
ENS210TemperatureHumidity                  0x43
FXOS8700AccelerometerMagnetometer     0x1E




此内容由EEWORLD论坛网友dvd1478原创,如需转载或用于商业用途需征得作者同意并注明出处



此帖出自无线连接论坛

最新回复

资料不错哟,做标记备用。  详情 回复 发表于 2019-3-20 10:17
点赞 关注(1)
 

回复
举报

932

帖子

3

TA的资源

纯净的硅(中级)

沙发
 
资料不错哟,做标记备用。
此帖出自无线连接论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表