如何通过ESP32 Rainmaker实现ATSAM4的OTA升级且不刷写ESP32
实现ESP32转发ATSAM4 OTA固件的方案
核心思路是绕开ESP Rainmaker默认的ESP32 OTA刷写流程,自定义处理OTA事件,将ATSAM4固件下载后通过通信接口转发给目标芯片,具体步骤如下:
1. 拦截Rainmaker的OTA事件,自定义处理逻辑
Rainmaker的OTA默认会自动刷写ESP32自身固件,需注册自定义回调函数识别ATSAM4的OTA包并跳过默认流程:
- 在初始化Rainmaker后,调用
esp_rmaker_ota_set_cb注册OTA回调 - 在回调的
ESP_RMAKER_OTA_START事件中,读取OTA包元数据(比如自定义的fw_type字段),判断是否为ATSAM4固件 - 如果是ATSAM4固件,返回
ESP_RMAKER_OTA_SKIP阻止默认刷写;否则按默认逻辑处理
示例代码:
static esp_err_t custom_ota_cb(esp_rmaker_ota_cb_event_t event, void *data) { if (event == ESP_RMAKER_OTA_START) { esp_rmaker_ota_data_t *ota_data = (esp_rmaker_ota_data_t *)data; // 用元数据中"fw_type"字段区分固件类型,"sam4"代表ATSAM4固件 const char *fw_type = esp_rmaker_ota_get_metadata(ota_data, "fw_type"); if (fw_type && strcmp(fw_type, "sam4") == 0) { return ESP_RMAKER_OTA_SKIP; } } return ESP_RMAKER_OTA_CONTINUE; } // 在Rainmaker初始化后注册回调 esp_rmaker_ota_set_cb(custom_ota_cb, NULL);
2. 下载ATSAM4固件到ESP32专用存储分区
需提前在ESP32分区表中定义专门存储ATSAM4固件的分区,避免和自身OTA分区冲突:
- 修改
partitions.csv,添加类似分区:
地址和大小根据实际固件调整,确保空间充足sam4_fw, data, fat, 0x100000, 0x200000, - 在自定义逻辑中获取ATSAM4固件的下载URL,通过
esp_http_client分块下载到该分区 - 下载完成后,用OTA元数据中的
sha256字段验证固件哈希,确保数据完整性
3. 与ATSAM4建立通信并转发固件
根据选用的通信方式(UART/SPI/I2C),实现固件转发逻辑:
前置准备(ATSAM4端)
- 实现ISP模式触发逻辑:比如通过串口指令或GPIO电平触发进入固件升级模式
- 实现分块接收、校验、写入Flash的逻辑,支持ACK反馈
ESP32端处理
- 发送触发指令,等待ATSAM4返回进入升级模式的确认信号
- 从
sam4_fw分区读取固件数据,分块发送给ATSAM4,每块发送后等待ACK - 加入CRC校验,每块数据附带校验值,ATSAM4验证后再写入
示例UART转发代码片段:
#define SAM4_UART_NUM UART_NUM_1 #define FW_BLOCK_SIZE 512 void sam4_fw_transfer(void) { // 触发ATSAM4进入ISP模式 uart_write_bytes(SAM4_UART_NUM, "ENTER_ISP\r\n", strlen("ENTER_ISP\r\n")); uint8_t ack_buf[16]; uart_read_bytes(SAM4_UART_NUM, ack_buf, sizeof(ack_buf), portMAX_DELAY); if (strcmp((char *)ack_buf, "ISP_READY") != 0) { return; } // 映射分区并读取固件数据 spi_flash_mmap_handle_t mmap_handle; uint32_t fw_addr = 0x100000; // 对应sam4_fw分区起始地址 uint32_t fw_size = 0x200000; uint8_t *fw_data; spi_flash_mmap(fw_addr, fw_size, SPI_FLASH_MMAP_DATA, (void **)&fw_data, &mmap_handle); for (int i = 0; i < fw_size; i += FW_BLOCK_SIZE) { uint32_t block_len = MIN(FW_BLOCK_SIZE, fw_size - i); // 发送块长度、数据、CRC uart_write_bytes(SAM4_UART_NUM, (const char *)&block_len, sizeof(block_len)); uart_write_bytes(SAM4_UART_NUM, fw_data + i, block_len); uint32_t crc = crc32_le(0, fw_data + i, block_len); uart_write_bytes(SAM4_UART_NUM, (const char *)&crc, sizeof(crc)); // 等待ACK,失败则重试 uart_read_bytes(SAM4_UART_NUM, ack_buf, sizeof(ack_buf), portMAX_DELAY); if (strcmp((char *)ack_buf, "BLOCK_OK") != 0) { i -= FW_BLOCK_SIZE; continue; } } // 发送升级完成指令 uart_write_bytes(SAM4_UART_NUM, "UPGRADE_DONE\r\n", strlen("UPGRADE_DONE\r\n")); spi_flash_munmap(mmap_handle); }
4. 上报ATSAM4升级状态到Rainmaker
升级完成后,通过Rainmaker自定义参数上报ATSAM4固件版本或升级状态:
- 在Rainmaker设备中添加自定义参数,比如
sam4_fw_version - 升级成功后调用
esp_rmaker_param_update_and_report更新参数值
示例代码:
// 创建自定义参数 esp_rmaker_param_t *sam4_version_param = esp_rmaker_param_create("sam4_fw_version", NULL, esp_rmaker_str("v1.0"), PROP_FLAG_READ | PROP_FLAG_WRITE); esp_rmaker_device_add_param(device, sam4_version_param); // 升级成功后更新并上报 esp_rmaker_param_update_and_report(sam4_version_param, esp_rmaker_str("v1.1"));
关键注意事项
- 分区表配置:确保ATSAM4固件存储分区不与ESP32自身的OTA、应用分区重叠
- 固件校验:下载后必须验证哈希值,避免转发损坏的固件
- 通信可靠性:添加重传机制,处理通信过程中的丢包或错误
- ATSAM4 ISP兼容性:确保ATSAM4的ISP逻辑支持分块写入和校验,避免升级失败
内容的提问来源于stack exchange,提问作者JOO
相关产品推荐
相关产品推荐

