滇中引水工程建设管理局网站,网站展示效果图,郑州seo价格,怎么自己做一个论坛文章目录 一、前言二、了解 JTAG 和 Ymodem 的工作原理2.1 环境准备2.2 Ymodem 协议工作原理2.3 固件分区准备 三、关键升级函数五、使用shell 测试 一、前言 如果使用 JTAG 串口 结合 Ymodem 协议 实现 ESP32 的固件升级#xff0c;整体逻辑将围绕通过串口传输固件文件并将其… 文章目录 一、前言二、了解 JTAG 和 Ymodem 的工作原理2.1 环境准备2.2 Ymodem 协议工作原理2.3 固件分区准备 三、关键升级函数五、使用shell 测试 一、前言 如果使用 JTAG 串口 结合 Ymodem 协议 实现 ESP32 的固件升级整体逻辑将围绕通过串口传输固件文件并将其烧录到指定的 Flash 分区。以下是完整的实现步骤和代码说明。为什么要使用ymodem因为要对文件进行校验使得数据丢失可以重传为什么保证固件的完整性所以使用ymodem协议。 二、了解 JTAG 和 Ymodem 的工作原理
2.1 环境准备
JTAG 接口工具如 FT2232、J-Link、ESP32 自带的 UART-to-USB。
终端工具支持 Ymodem 协议如 TeraTerm 或 Minicom。
ESP-IDF开发 ESP32 所需的软件框架 参考上一篇文章 ymodem协议 https://blog.csdn.net/mayuxin1314/article/details/143990976
2.2 Ymodem 协议工作原理
发送端PC 端通过 Ymodem 协议将固件文件逐块传输到设备。接收端ESP32 通过 UART 接口接收 Ymodem 数据并逐块校验。目标将接收到的数据写入 OTA 分区。
2.3 固件分区准备
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 200K,
otadata, data, ota, 0x110000, 0x2000,
phy_init, data, phy, 0x112000, 0x1000,
factory, app, factory, 0x120000, 3M,
ota_0, app, ota_0, 0x420000, 3M,
ota_1, app, ota_1, 0x720000, 3M,
font_data, 0x50, 0x22, 0xa20000, 2M,
storage, data, littlefs, 0xc20000, 2M,
三、关键升级函数
// 定义文件名和文件大小变量static esp_ota_handle_t ota_handle;
OtaUpdate_t xOtaUpdate_t;
// xLocaUpdate_Begin 函数初始化 OTA 更新
static enum rym_code xLocaUpdate_Begin(RYM_t *pxRYM_Ag, uint8_t *buf, uint32_t len)
{printf(xLocaUpdate_Begin\r\n);const esp_partition_t *running_partition esp_ota_get_running_partition();const esp_partition_t *ota_partition esp_ota_get_next_update_partition(NULL);if (ota_partition NULL){ESP_LOGE(TAG, 未找到 OTA 分区);return RYM_ERR_CAN;}ESP_LOGI(TAG, 当前分区地址: 0x%08 PRIx32 , OTA 分区地址: 0x%08 PRIx32,running_partition-address, ota_partition-address);parseYModemData(buf,xOtaUpdate_t.ucFilename, xOtaUpdate_t.ulFilesize);ESP_LOGI(TAG, 固件名字 %s 固件内容长度: % PRIu32 字节\r\n,xOtaUpdate_t.ucFilename, xOtaUpdate_t.ulFilesize);// 初始化 OTA 会话esp_err_t err esp_ota_begin(ota_partition, xOtaUpdate_t.ulFilesize, ota_handle);if (err ! ESP_OK) {ESP_LOGE(TAG, OTA 更新初始化失败: %s, esp_err_to_name(err));return RYM_ERR_CAN;}xOtaUpdate_t.bytes_written 0; // 初始化已写入字节数return RYM_CODE_ACK;
}// xLocaUpdate_Data 函数写入固件数据
static enum rym_code xLocaUpdate_Data(RYM_t *pxRYM_Ag, uint8_t *buf, uint32_t len)
{// 检查剩余要写入的字节数uint32_t remaining_bytes xOtaUpdate_t.ulFilesize - xOtaUpdate_t.bytes_written;// 如果接收的数据超过剩余的字节数则只写入剩余部分if (len remaining_bytes) {len remaining_bytes;}// 写入数据到 OTA 分区esp_err_t err esp_ota_write(ota_handle, buf, len);if (err ! ESP_OK) {ESP_LOGE(TAG, OTA 写入失败: %s, esp_err_to_name(err));return RYM_ERR_CAN;}// 更新已写入的字节数xOtaUpdate_t.bytes_written len;ESP_LOGI(TAG, 写入了 %u 字节总计写入 %u/%u 字节, (unsigned int)len, (unsigned int)xOtaUpdate_t.bytes_written, (unsigned int)xOtaUpdate_t.ulFilesize);return RYM_CODE_ACK;
}// xLocaUpdate_End 函数完成 OTA 更新
static enum rym_code xLocaUpdate_End(RYM_t *pxRYM_Ag, uint8_t *buf, uint32_t len)
{esp_err_t err esp_ota_end(ota_handle);if (err ! ESP_OK) {ESP_LOGE(TAG, OTA 更新结束失败: %s, esp_err_to_name(err));return RYM_ERR_CAN;}// 获取当前 OTA 分区的 SHA-256 校验值const esp_partition_t *ota_partition esp_ota_get_next_update_partition(NULL);uint8_t sha256_hash[32];err esp_partition_get_sha256(ota_partition, sha256_hash);if (err ! ESP_OK) {ESP_LOGE(TAG, 获取 SHA-256 校验失败: %s, esp_err_to_name(err));return RYM_ERR_CAN;}// 输出 SHA-256 校验结果供验证ESP_LOGI(TAG, OTA 分区 SHA-256 校验值:);for (int i 0; i 32; i) {printf(%02x, sha256_hash[i]);}printf(\n);// // 将新固件设置为引导分区// const esp_partition_t *ota_partition esp_ota_get_next_update_partition(NULL);err esp_ota_set_boot_partition(ota_partition);if (err ! ESP_OK) {ESP_LOGE(TAG, 设置引导分区失败: %s, esp_err_to_name(err));return RYM_ERR_CAN;}ESP_LOGI(TAG, OTA 更新完成设备将使用新固件引导);// 触发设备重启以加载新固件esp_restart();return RYM_CODE_ACK;
}int ulLocalUpdate()
{int err 0;err RYM_ReadFile(xRYM_Ag, xLocaUpdate_Begin, xLocaUpdate_Data, xLocaUpdate_End);return err;
}
五、使用shell 测试 设置 测试