ESP32通过EC200U模块FOTA更新时出现镜像段长度错误求助
ESP32通过EC200U模块FOTA更新时镜像段长度错误问题
问题现象
使用ESP32通过GSM EC200U模块发送AT指令执行FOTA更新,接收bin文件时出现镜像验证失败,报错信息:
E (1379450) esp_image: invalid segment length 0xd43c2149 esp_ota_end failed: ESP_ERR_OTA_VALIDATE_FAILED
相关代码片段
bool downloadFirmware(const char *url, const esp_partition_t *partition) { printf("Fetching firmware binary...\n"); // Initialize UART commands uint8_t *httpInitCmd = (uint8_t *)"AT+QHTTPURL=65,80\r\n"; uart_write_bytes(UART_NUM_1, (const char *)httpInitCmd, strlen((const char *)httpInitCmd)); vTaskDelay(pdMS_TO_TICKS(1000)); uint8_t *response = (uint8_t *)malloc(BUF_SIZE); if (response == NULL) { printf("Failed to allocate memory for response\n"); return false; } // Read initial response int len = uart_read_bytes(UART_NUM_1, response, BUF_SIZE, 1000 / portTICK_RATE_MS); if (len > 0) { response[len] = '\0'; printf("Response received: %s\n", response); if (strstr((const char *)response, "CONNECT") == NULL) { printf("Failed to get CONNECT response\n"); free(response); } } // Send URL uart_write_bytes(UART_NUM_1, url, strlen((const char *)url)); vTaskDelay(pdMS_TO_TICKS(5000)); len = uart_read_bytes(UART_NUM_1, response, BUF_SIZE, 1000 / portTICK_RATE_MS); if (len > 0) { response[len] = '\0'; printf("Response received: %s\n", response); if (strstr((const char *)response, "OK") == NULL) { printf("Failed to get OK response after sending URL\n"); free(response); } } // Initiate HTTP GET uint8_t *httpGetCmd = (uint8_t *)"AT+QHTTPGET=80\r\n"; if (!checkForOKresponse(httpGetCmd)) { free(response); } len = uart_read_bytes(UART_NUM_1, response, BUF_SIZE, 1000 / portTICK_RATE_MS); if (len > 0) { response[len] = '\0'; printf("HTTP GET Response: %s\n", response); if (strstr((const char *)response, "+QHTTPGET: 0,200") == NULL) { printf("Failed to get 200 OK for HTTP GET\n"); free(response); } } // Read the firmware binary data uint8_t *httpReadCmd = (uint8_t *)"AT+QHTTPREAD\r\n"; uart_write_bytes(UART_NUM_1, (const char *)httpReadCmd, strlen((const char *)httpReadCmd)); vTaskDelay(pdMS_TO_TICKS(1000)); int totalBytesRead = 0; int startIndex = -1; // To keep track of the index where 0xE9 is found(magic string) while (totalBytesRead < BUF_SIZE) { len = uart_read_bytes(UART_NUM_1, response + totalBytesRead, BUF_SIZE - totalBytesRead, 5000 / portTICK_RATE_MS); if (len > 0) { printf("Data read (%d bytes): ", len); for (int i = 0; i < len; i++) { printf("%02X", response[totalBytesRead + i]); if (response[totalBytesRead + i] == 0xE9 && startIndex == -1) { startIndex = totalBytesRead + i; } } printf("\n"); totalBytesRead += len; } else { break; } } if (startIndex != -1) { printf("HTTP READ Response received (%d bytes) starting from 0xE9\n", totalBytesRead - startIndex); // Begin OTA process if (isPartitionEmpty(partition)) { esp_ota_handle_t updateHandle; esp_err_t otaBeginResult = esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &updateHandle); if (otaBeginResult != ESP_OK) { printf("esp_ota_begin failed: %s\n", esp_err_to_name(otaBeginResult)); free(response); return false; } totalBytesRead -= startIndex; uint8_t *dataToWrite = response + startIndex; // Write the initial chunk esp_err_t otaWriteResult = esp_ota_write(updateHandle, (const void *)dataToWrite, totalBytesRead); if (otaWriteResult != ESP_OK) { printf("esp_ota_write failed: %s\n", esp_err_to_name(otaWriteResult)); esp_ota_end(updateHandle); free(response); return false; } printf("Initial data written: %d bytes\n", totalBytesRead); // Read and write the remaining data while (true) { len = uart_read_bytes(UART_NUM_1, response, BUF_SIZE, 5000 / portTICK_RATE_MS); if (len > 0) { printf("Writing data (%d bytes): ", len); for (int i = 0; i < len; i++) { printf("%02X", response[i]); } printf("\n"); otaWriteResult = esp_ota_write(updateHandle, (const void *)response, len); if (otaWriteResult != ESP_OK) { printf("esp_ota_write failed: %s\n", esp_err_to_name(otaWriteResult)); esp_ota_end(updateHandle); free(response); return false; } } else { break; } } esp_err_t otaEndResult = esp_ota_end(updateHandle); if (otaEndResult != ESP_OK) { printf("esp_ota_end failed: %s\n", esp_err_to_name(otaEndResult)); free(response); return false; } printf("OTA Update successful\n"); free(response); return true; } else { printf("Partition is not empty, skipping update\n"); free(response); return false; } } else { printf("No response starting with 0xE9 received\n"); free(response); return false; } }
问题分析与解决方案
核心原因
报错invalid segment length说明写入OTA分区的bin文件数据损坏,大概率是UART接收时混入了EC200U的AT响应头/尾字符,或者数据接收不完整、顺序错乱。
具体修复点
过滤AT响应中的非二进制数据
发送AT+QHTTPREAD后,EC200U会先返回+QHTTPREAD: <length>,然后是二进制数据,最后以OK结尾。当前代码仅以0xE9作为bin起始标记,可能混入响应头或结尾的OK字符。需先解析响应头获取总长度,再精准接收纯二进制数据,跳过非bin内容。UART接收完整性控制
替换固定延时接收逻辑,改为基于总长度的循环接收:先读取+QHTTPREAD:行提取总字节数,然后循环接收直到累计字节数等于总长度,避免数据截断或重复读取。OTA写入长度校验
维护累计写入字节数,确保最终写入长度与+QHTTPREAD返回的总长度一致,避免写入多余数据。移除不必要的分区检查
ESP32的OTA分区支持直接覆盖旧固件,无需检查是否为空,可删除isPartitionEmpty判断,简化流程。
修复后的关键代码示例
// 读取QHTTPREAD响应头,获取总长度 int total_size = 0; int len = uart_read_bytes(UART_NUM_1, response, BUF_SIZE, 2000 / portTICK_RATE_MS); if (len > 0) { response[len] = '\0'; // 解析+QHTTPREAD: <length> if (sscanf((char*)response, "+QHTTPREAD: %d", &total_size) == 1) { printf("Total firmware size: %d bytes\n", total_size); } else { printf("Failed to parse firmware size\n"); free(response); return false; } } // 初始化OTA流程 esp_ota_handle_t updateHandle; esp_err_t otaBeginResult = esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &updateHandle); if (otaBeginResult != ESP_OK) { printf("esp_ota_begin failed: %s\n", esp_err_to_name(otaBeginResult)); free(response); return false; } // 循环接收完整二进制数据 int received = 0; while (received < total_size) { int to_read = min(BUF_SIZE, total_size - received); len = uart_read_bytes(UART_NUM_1, response, to_read, 5000 / portTICK_RATE_MS); if (len <= 0) { printf("UART receive timeout, received %d/%d bytes\n", received, total_size); esp_ota_end(updateHandle); free(response); return false; } // 最后一次接收时截断结尾的OK字符 if (received + len >= total_size) { char* ok_ptr = strstr((char*)response, "OK"); if (ok_ptr != NULL) { len = ok_ptr - (char*)response; } } // 写入OTA分区 esp_err_t otaWriteResult = esp_ota_write(updateHandle, response, len); if (otaWriteResult != ESP_OK) { printf("esp_ota_write failed: %s\n", esp_err_to_name(otaWriteResult)); esp_ota_end(updateHandle); free(response); return false; } received += len; printf("Received %d/%d bytes\n", received, total_size); } // 结束OTA并验证 esp_err_t otaEndResult = esp_ota_end(updateHandle); if (otaEndResult != ESP_OK) { printf("esp_ota_end failed: %s\n", esp_err_to_name(otaEndResult)); free(response); return false; }
内容的提问来源于stack exchange,提问作者Rajkumar Verma
相关产品推荐
相关产品推荐

