ESP32 OTA升级时出现Invalid Segment Length错误求助
问题概述
在基于ESP32的OTA升级开发中,频繁出现两种esp_image错误,错误类型随升级固件不同而变化:
E (207512) esp_image: invalid segment length 0x400e47a4 0x400e47a4: _GLOBAL__sub_I__ZN11UpdateClass16_enablePartitionEPK15esp_partition_t at "
E (61127) esp_image: invalid segment length 0x400e40d0 0x400e40d0: __static_initialization_and_destruction_0(int, int) at "
已排除电源不稳定、固件长度不匹配问题,采用AWS_S3_OTA_Update方案,通过ThingWorx的POST请求获取固件,尝试过更换固件、调整固件长度、检查menuconfig配置等均未解决。
相关代码
char data [1024]; //char array where we will put the bytes sent by the client while (client.available()) { int fini=0; dataContent = client.readBytesUntil('?',data,1024); // read until a certain character " ` " for (int i = 0; i < 1024; i++) { if (i % 16 == 0 && i != 0) { Serial.println(""); } // Serial.printf("%02x ", buff[i]); //lower case Serial.printf("%02X ", data[i]); // upper case // // if(data[i]== 'F' && data[i+1]=='0'){ // // fini = 1; // // break; // // } } // if(fini == 1){ // break; // } break; // break the while loop and feed the rest of the client to the update function } // Check what is the contentLength and if content type is `application/octet-stream` Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType)); // check contentLength and content type if (contentLength && isValidContentType) { // Check if there is enough to OTA Update bool canBegin = Update.begin(contentLength); // If yes, begin if (canBegin) { Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!"); // No activity would appear on the Serial monitor // So be patient. This may take 2 - 5mins to complete size_t written = Update.writeStream(client); if (written == contentLength) { Serial.println("Written : " + String(written) + " successfully"); } else { Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); // retry?? // execOTA(); } if (Update.end()) { Serial.println("OTA done!"); if (Update.isFinished()) { Serial.println("Update successfully completed. Rebooting."); ESP.restart(); } else { Serial.println("Update not finished? Something went wrong!"); } } else { Serial.println("Error Occurred. Error #: " + String(Update.getError())); } } else { // not enough space to begin OTA // Understand the partitions and // space availability Serial.println("Not enough space to begin OTA"); client.flush(); } } else { Serial.println("There was no content in the response"); client.flush(); } } Serial.println("\r"); client.stop(); return return_value;
可能原因分析
响应头清除逻辑错误
代码中用readBytesUntil('?', data, 1024)截断响应头,但HTTP响应头的标准结束符是\r\n\r\n,使用?作为截断符完全不符合协议规范,必然残留部分响应头数据混入固件二进制流,导致ESP32解析镜像时出现段长度错误。固件流起始位置错位
读取部分数据后直接break退出循环,未确保完全读取完所有响应头就将client流传入Update.writeStream,会把未处理的响应头数据写入OTA分区,破坏固件镜像的结构完整性。固件传输过程中的数据损坏
通过ThingWorx转发固件时,若服务未正确处理二进制数据(比如将其当作文本编码传输),可能导致字节丢失、篡改,写入ESP32的固件镜像已损坏,触发段长度校验失败。分区表配置不兼容
尽管检查过menuconfig,但升级固件编译时指定的分区表(如OTA分区大小、类型)可能与ESP32设备当前使用的分区表不匹配,导致镜像段解析时出现长度错误。静态初始化代码冲突
错误日志指向的__static_initialization_and_destruction_0和_GLOBAL__sub_I__ZN11UpdateClass...属于静态初始化相关函数,可能是升级固件的静态变量初始化逻辑与当前运行的OTA代码存在冲突,导致镜像校验不通过。
内容的提问来源于stack exchange,提问作者sab240

