Merge branch 'test/uart_dma_ota_fix_v6.0' into 'release/v6.0'

refactor(uhci): refactor uart_dma_ota example (v6.0)

See merge request espressif/esp-idf!48755
This commit is contained in:
morris
2026-06-29 10:15:47 +08:00
8 changed files with 88 additions and 75 deletions

View File

@@ -626,6 +626,12 @@ examples/peripherals/twai/twai_utils:
examples/peripherals/uart/uart_dma_ota:
disable:
- if: SOC_UHCI_SUPPORTED != 1
depends_components:
- esp_driver_uart
- esp_driver_dma
- app_update
- esp_ringbuf
- soc
examples/peripherals/uart/uart_echo_rs485:
enable:

View File

@@ -1,3 +1,3 @@
idf_component_register(SRCS "uart_dma_ota_example_main.c"
REQUIRES esp_driver_uart app_update
REQUIRES esp_driver_uart app_update esp_ringbuf
INCLUDE_DIRS ".")

View File

@@ -1,20 +1,22 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "driver/uart.h"
#include "driver/uhci.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
static const char *TAG = "uhci-example";
@@ -22,48 +24,36 @@ static const char *TAG = "uhci-example";
#define EXAMPLE_UART_BAUD_RATE CONFIG_UART_BAUD_RATE
#define EXAMPLE_UART_RX_IO CONFIG_UART_RX_IO
#define UART_DMA_OTA_BUFFER_SIZE (10 * 1024)
typedef enum {
UHCI_EVT_PARTIAL_DATA,
UHCI_EVT_EOF,
} uhci_event_t;
#define UART_DMA_OTA_RINGBUF_SIZE (10 * 1024)
typedef struct {
QueueHandle_t uhci_queue;
size_t receive_size;
uint8_t *ota_data1;
uint8_t *ota_data2;
bool use_ota_data1;
} ota_example_context_t;
RingbufHandle_t ringbuf;
volatile bool rx_eof;
volatile bool rx_overflow;
} ota_rx_context_t;
static bool s_uhci_rx_event_cbs(uhci_controller_handle_t uhci_ctrl, const uhci_rx_event_data_t *edata, void *user_ctx)
{
ota_example_context_t *ctx = (ota_example_context_t *)user_ctx;
BaseType_t xTaskWoken = 0;
uhci_event_t evt = 0;
ota_rx_context_t *ctx = (ota_rx_context_t *)user_ctx;
BaseType_t xTaskWoken = pdFALSE;
if (xRingbufferSendFromISR(ctx->ringbuf, edata->data, edata->recv_size, &xTaskWoken) != pdTRUE) {
ctx->rx_overflow = true;
}
if (edata->flags.totally_received) {
evt = UHCI_EVT_EOF;
} else {
evt = UHCI_EVT_PARTIAL_DATA;
ctx->rx_eof = true;
}
// Choose the buffer to store received data
ctx->receive_size = edata->recv_size;
if (ctx->use_ota_data1) {
ctx->ota_data1 = edata->data;
} else {
ctx->ota_data2 = edata->data;
}
// Toggle the buffer for the next receive
ctx->use_ota_data1 = !ctx->use_ota_data1;
xQueueSendFromISR(ctx->uhci_queue, &evt, &xTaskWoken);
return xTaskWoken;
return xTaskWoken == pdTRUE;
}
static void perform_ota_update(uhci_controller_handle_t uhci_ctrl, ota_example_context_t *ctx)
static bool rx_ringbuf_is_empty(RingbufHandle_t ringbuf)
{
UBaseType_t items_waiting = 0;
vRingbufferGetInfo(ringbuf, NULL, NULL, NULL, NULL, &items_waiting);
return items_waiting == 0;
}
static void perform_ota_update(uhci_controller_handle_t uhci_ctrl, ota_rx_context_t *ctx)
{
const esp_partition_t *ota_partition = esp_ota_get_next_update_partition(NULL);
if (!ota_partition) {
@@ -75,25 +65,32 @@ static void perform_ota_update(uhci_controller_handle_t uhci_ctrl, ota_example_c
ESP_ERROR_CHECK(esp_ota_begin(ota_partition, OTA_SIZE_UNKNOWN, &ota_handle));
ESP_LOGI(TAG, "OTA process started");
uhci_event_t evt;
uint32_t received_size = 0;
uint8_t *pdata = heap_caps_calloc(1, UART_DMA_OTA_BUFFER_SIZE, MALLOC_CAP_DEFAULT);
assert(pdata);
ESP_ERROR_CHECK(uhci_receive(uhci_ctrl, pdata, UART_DMA_OTA_BUFFER_SIZE));
while (1) {
if (xQueueReceive(ctx->uhci_queue, &evt, portMAX_DELAY) == pdTRUE) {
uint8_t *data_to_write = ctx->use_ota_data1 ? ctx->ota_data2 : ctx->ota_data1;
ESP_ERROR_CHECK(esp_ota_write(ota_handle, data_to_write, ctx->receive_size));
received_size += ctx->receive_size;
if (evt == UHCI_EVT_EOF) {
break;
}
size_t total_received_size = 0;
while (1) {
size_t item_size = 0;
uint8_t *data = xRingbufferReceive(ctx->ringbuf, &item_size, pdMS_TO_TICKS(1000));
if (data) {
ESP_ERROR_CHECK(esp_ota_write(ota_handle, data, item_size));
vRingbufferReturnItem(ctx->ringbuf, data);
total_received_size += item_size;
}
if (ctx->rx_overflow) {
ESP_LOGE(TAG, "RX ring buffer overflow, please reduce the baud rate or increase the ring buffer size");
abort();
}
if (ctx->rx_eof && rx_ringbuf_is_empty(ctx->ringbuf)) {
break;
}
}
free(pdata);
ESP_LOGI(TAG, "Total received size: %ld", received_size);
ESP_LOGI(TAG, "Total received size: %zu", total_received_size);
ESP_ERROR_CHECK(esp_ota_end(ota_handle));
ESP_ERROR_CHECK(esp_ota_set_boot_partition(ota_partition));
}
@@ -126,25 +123,24 @@ void app_main(void)
ESP_LOGI(TAG, "UHCI initialized, baud rate is %d, rx pin is %d", uart_config.baud_rate, EXAMPLE_UART_RX_IO);
ota_example_context_t *ctx = calloc(1, sizeof(ota_example_context_t));
assert(ctx);
ctx->uhci_queue = xQueueCreate(2, sizeof(uhci_event_t));
assert(ctx->uhci_queue);
ctx->use_ota_data1 = true; // Start with ota_data1
ota_rx_context_t ctx = {
.ringbuf = xRingbufferCreate(UART_DMA_OTA_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF),
.rx_eof = false,
.rx_overflow = false,
};
assert(ctx.ringbuf);
uhci_event_callbacks_t uhci_cbs = {
.on_rx_trans_event = s_uhci_rx_event_cbs,
};
ESP_ERROR_CHECK(uhci_register_event_callbacks(uhci_ctrl, &uhci_cbs, ctx));
ESP_ERROR_CHECK(uhci_register_event_callbacks(uhci_ctrl, &uhci_cbs, &ctx));
perform_ota_update(uhci_ctrl, ctx);
perform_ota_update(uhci_ctrl, &ctx);
ESP_ERROR_CHECK(uhci_del_controller(uhci_ctrl));
free(ctx);
vRingbufferDelete(ctx.ringbuf);
ESP_LOGI(TAG, "OTA update successful. Rebooting...");
esp_restart();
}

View File

@@ -48,9 +48,11 @@ def test_uart_dma_ota(dut: Dut) -> None:
# We OTA the same binary to another partition and switch to there.
binary_path = os.path.join(dut.app.binary_path, 'uart_dma_ota.bin')
assert os.path.exists(binary_path), f'OTA binary not found at {binary_path}'
binary_size = os.path.getsize(binary_path)
buad_rate = dut.app.sdkconfig.get('UART_BAUD_RATE')
send_file_via_uart(FLASH_PORT, buad_rate, binary_path, PACKET_SIZE)
dut.expect_exact(f'uhci-example: Total received size: {binary_size}')
dut.expect('OTA update successful. Rebooting', timeout=10)
dut.expect('ESP-ROM:', timeout=10)