You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:50:56