当前位置: 首页 > news >正文

《ESP32调试异常集锦》之移植I2C程序时i2c_master_cmd_begin返回-1

项目场景:

《ESP32从0到1》之I2C通讯(AHT20温湿度传感器)_esp32 i2c-CSDN博客

        之前的程序,测试正常。现将其移植到其他的项目中,运行发现导致重启。


问题描述

        串口调试信息如下:跟踪程序发现在第二次发送0x71获取状态字的时候导致的重启。

[0;32mI (11320) i2c-simple-example: I2C initialized successfully[0m
[0;32mI (11320) I2C_DEBUG: err: 0x0[0m
[0;32mI (11330) i2c-simple-example: status = 0x18[0m
[0;32mI (11330) i2c-simple-example: read status[0m
[0;32mI (11340) I2C_DEBUG: err: 0xFFFFFFFF[0m
ESP_ERROR_CHECK failed: esp_err_t 0xffffffff (ESP_FAIL) at 0x400d7ff7
file: "./components/aht20/aht20.c" line 77
func: ReadAHT20Data
expression: AHT20_register_read(statuscmd, 1,data, 1)abort() was called at PC 0x40090c53 on core 0Backtrace: 0x40081932:0x3ffcc8f0 0x40090c5d:0x3ffcc910 0x40097042:0x3ffcc930 0x40090c53:0x3ffcc9a0 0x400d7ff7:0x3ffcc9d0 0x400d7b73:0x3ffcca10 0x401bc25e:0x3ffccb00 0x401bc2d9:0x3ffccb50ELF file SHA256: 8cf2ff4afRebooting...
ets Jul 29 2019 12:21:46

        因为程序中用了函数ESP_ERROR_CHECK进行了判断,AHT20_register_read返回的并不是0x00所以导致重启。究其原因需要找到为什么AHT20_register_read没有返回0x00.

         AHT20_register_read函数如下所示:

static esp_err_t AHT20_register_read(uint8_t* reg_addr,size_t cmdlen, uint8_t *data, size_t len)
{return i2c_master_write_read_device(I2C_MASTER_NUM, AHT20_SENSOR_ADDR, reg_addr, cmdlen, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

          i2c_master_write_read_device函数如下所示(i2c.c中的函数,未作修改):

esp_err_t i2c_master_write_read_device(i2c_port_t i2c_num, uint8_t device_address,const uint8_t* write_buffer, size_t write_size,uint8_t* read_buffer, size_t read_size,TickType_t ticks_to_wait)
{esp_err_t err = ESP_OK;uint8_t buffer[I2C_TRANS_BUF_MINIMUM_SIZE] = { 0 };i2c_cmd_handle_t handle = i2c_cmd_link_create_static(buffer, sizeof(buffer));assert (handle != NULL);   err = i2c_master_start(handle);if (err != ESP_OK) {goto end;}err = i2c_master_write_byte(handle, device_address << 1 | I2C_MASTER_WRITE, true);if (err != ESP_OK) {goto end;}err = i2c_master_write(handle, write_buffer, write_size, true);if (err != ESP_OK) {goto end;}err = i2c_master_start(handle);if (err != ESP_OK) {goto end;}err = i2c_master_write_byte(handle, device_address << 1 | I2C_MASTER_READ, true);if (err != ESP_OK) {goto end;}err = i2c_master_read(handle, read_buffer, read_size, I2C_MASTER_LAST_NACK);if (err != ESP_OK) {goto end;}i2c_master_stop(handle);err = i2c_master_cmd_begin(i2c_num, handle, ticks_to_wait);
end:i2c_cmd_link_delete_static(handle);return err;
}

        追踪到是i2c_master_cmd_begin出现问题,返回-1,对应到程序中是没有收到ACK.

        之前调试成功的程序烧录到当前项目PCBA上,同样的地方出现重启。

        之前调试用的ESP32-LyraT-Mini V1.2开发板,烧录之前调试通过的程序,依旧同样地方出现重启。

分析:

        1)怀疑是模块问题?更换了新的AHT20模块,问题依旧,可以排除模块问题;

        2)之前的开发板和现在自制的PCBA使用相同的模块出现相同的问题,问题应该不是出现在硬件上;

        3)程序隐形的问题?

                降低频率到200KHz 无作用

CSDN AI针对问题的回复:

问:ESP32调试I2C时i2c_master_write_to_device之后再调用i2c_master_write_read_device会导致i2c_master_cmd_begin返回-1

答:当你在调试ESP32的I2C时,在i2c_master_write_to_device()之后接着调用i2c_master_write_read_device(),如果出现了i2c_master_cmd_begin()返回-1的问题,可能是以下几个原因:

  1. 数据流冲突:这两个函数实际上都在进行I2C传输,如果前一个操作还没有完成,比如缓冲区未清空或者命令还在传输过程中,新的命令会因资源占用而失败。

  2. 顺序错误:I2C协议通常是半双工的,这意味着它不会同时进行读取和写入。如果你在设备正忙于接收数据时试图写入,可能会发生冲突。

  3. 设备响应超时:如果设备在前一次读写操作中设置了较长的延迟响应时间,或者数据包过大导致处理较慢,可能会影响到后续命令的开始。

  4. 错误检测未清除:如果前一次写操作检测到了错误(例如CRC校验错误),ESP32可能会拒绝继续执行直到错误被纠正。

解决策略:

  • 确保每个I2C操作之间有适当的延时,让前一个操作有足够的时间完成。
  • 检查设备的I2C地址和命令模式,确保它们在写入和读取时是一致的。
  • 如果设备支持,可以先发送一个停止条件,等待设备准备好接受下一个命令。
  • 使用ESP32提供的异常处理机制,捕获并处理可能出现的错误。

        从解决策略上,第一个策略最有可能。检查AHT20资料对照实际程序,发现程序并没有按照资料的要求在启动测量之后等待80ms(之前写程序时预留备注但是因为测试通过,侥幸心理并没有做实际的delay操作)。

        修改程序,增加了等待80ms的程序,则AHT20通讯正常,不再返回-1导致重启。

void ReadAHT20Data(float* temp,float* humi)
{uint8_t data[6];uint8_t statuscmd[]={0x71};uint8_t mearcmd[]={0xac,0x33,0x00};   uint16_t timecount=0;uint32_t tmp32;    ESP_ERROR_CHECK(i2c_master_init());ESP_LOGI(I2C_TAG, "I2C initialized successfully");  //发送0x71命令,读取状态字ESP_ERROR_CHECK(AHT20_register_read(statuscmd, 1,data, 1));  ESP_LOGI(I2C_TAG, "status = 0x%X", data[0]);//启动测量ESP_ERROR_CHECK(AHT20_register_write(mearcmd, 3));   //delay 80msvTaskDelay(pdMS_TO_TICKS(80));//实际测试至少30msESP_ERROR_CHECK(AHT20_register_read(statuscmd, 1,data, 1));  ESP_LOGI(I2C_TAG, "status = 0x%X", data[0]);while (((data[0]&0x80)==0x80)&&(timecount < I2C_MASTER_TIMEOUT_MS * 1000) ) // 等待BUSY位清空   {usleep(1); data[0]=0;ESP_ERROR_CHECK(AHT20_register_read(statuscmd, 1,data, 1));  ESP_LOGI(I2C_TAG, "status = 0x%X", data[0]);       timecount++;}   //读取测量数据ESP_ERROR_CHECK(i2c_master_read_from_device(I2C_MASTER_NUM, AHT20_SENSOR_ADDR,data,6,I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS));for(int i=0;i<6;i++){ESP_LOGI(I2C_TAG, "0x%X", data[i]); } ESP_ERROR_CHECK(i2c_driver_delete(I2C_MASTER_NUM));//计算温湿度并打印//接收到的6个字节数据,第一个为状态字节,第二第三及第四字节的高四位为湿度,第四字节的低四位和第五第六字节为温度tmp32=0;tmp32 = ((uint32_t)data[1])<<12 |  ((uint32_t)data[2])<<4 |(data[3]>>4);*humi=(float)tmp32/ 1048576 *100;//ESP_LOGI(I2C_TAG, "tmp32: 0x%lx,humi: %.2f",tmp32,humi); //tmp32为长整型,打印时需要注意tmp32=0;tmp32 = ((uint32_t)(data[3]&0x0f))<<16 |  ((uint32_t)data[4])<<8 |(data[5]);*temp=(float)tmp32/ 1048576 * 200-50;//ESP_LOGI(I2C_TAG, "tmp32: 0x%lx,temp: %.2f",tmp32,temp); ESP_LOGI(I2C_TAG, "I2C de-initialized successfully");
}

解决方案:

        按照AHT20资料,在启动测量后增加了等待80ms的程序。

        I2C的通信需要按照I2C从机模块的时序流程进行编程。否则程序上会存在隐患,可能会因为从机模块的个体差异导致一些莫名的问题。

关注我哦,内容涉及ESP32项目开发、日常调试记录(ESP32\CH592\STM32等)、AI相关学习(准备中..),躺不平就一起卷吧!🙂


http://www.mrgr.cn/news/52751.html

相关文章:

  • fiddler抓包23_重放请求(Replay)
  • 对比长安链、FISCO BCOS、蚂蚁链
  • OpenAI推出Swarm框架:简化多AI智能体系统交互
  • Python | Leetcode Python题解之第491题非递减子序列
  • 【JavaEE】【多线程】volatile,wait/notify
  • 【Qunar风控安全产品的探索之路】
  • 【算法】力扣:K个一组反转链表
  • R01 vue+springboot 高考志愿推荐AI问答大数据平台
  • LabVIEW提高开发效率技巧----VI继承与重载
  • 【RoadRunner】自动驾驶模拟3D场景构建 | 软件简介与视角控制
  • AI学习指南深度学习篇-预训练模型的实践
  • Nodemon 深入解析与使用
  • 【MySQL】聚合函数和分组查询
  • 【ShuQiHere】 机器学习中的网格搜索(Grid Search)超参数调优
  • 手机数据恢复技巧:适用于手机的恢复应用程序
  • 面对配分函数 - 去噪得分匹配篇
  • 在FastAPI网站学python:环境变量 Python Environment Variables
  • React 列表 Keys
  • itext 转换word文档转pdf
  • 231321321