diff --git a/components/app_trace/Kconfig.apptrace b/components/app_trace/Kconfig.apptrace index ca609cfb72..420987da06 100644 --- a/components/app_trace/Kconfig.apptrace +++ b/components/app_trace/Kconfig.apptrace @@ -36,9 +36,9 @@ menu "Application Level Tracing" config APPTRACE_DEST_UART_NUM int "UART port number" depends on APPTRACE_DEST_UART - range 0 1 if (SOC_UART_NUM <= 2) - range 0 2 if (SOC_UART_NUM <= 3) - range 0 5 if (SOC_UART_NUM <= 6) + range 0 1 if (SOC_UART_HP_NUM <= 2) + range 0 2 if (SOC_UART_HP_NUM <= 3) + range 0 4 if (SOC_UART_HP_NUM <= 5) default 1 help UART communication port number for the apptrace destination. @@ -83,7 +83,7 @@ menu "Application Level Tracing" default 4096 range 2048 32768 help - Size of the UART output ring buffer. + Size of the UART output ring buffer. Must be power of two. This size related to the baudrate, system tick frequency and amount of data to transfer. config APPTRACE_UART_TX_MSG_SIZE @@ -95,16 +95,6 @@ menu "Application Level Tracing" help Maximum size of the single message to transfer. - config APPTRACE_UART_TASK_PRIO - int - prompt "UART Task Priority" if APPTRACE_DEST_UART - depends on APPTRACE_DEST_UART - default 1 - range 1 32 - help - UART task priority. In case of high events rate, - this parameter could be changed up to (configMAX_PRIORITIES-1). - config APPTRACE_TRAX_ENABLE bool depends on IDF_TARGET_ARCH_XTENSA && !ESP32_TRAX && !ESP32S2_TRAX && !ESP32S3_TRAX diff --git a/components/app_trace/include/esp_app_trace.h b/components/app_trace/include/esp_app_trace.h index 45cac0526a..6c895a713e 100644 --- a/components/app_trace/include/esp_app_trace.h +++ b/components/app_trace/include/esp_app_trace.h @@ -274,7 +274,6 @@ int esp_apptrace_feof(void *stream); .baud_rate = CONFIG_APPTRACE_UART_BAUDRATE, \ .tx_buff_size = CONFIG_APPTRACE_UART_TX_BUFF_SIZE, \ .tx_msg_size = CONFIG_APPTRACE_UART_TX_MSG_SIZE, \ - .task_prio = CONFIG_APPTRACE_UART_TASK_PRIO, \ }, \ .flush_tmo = CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO, \ .flush_thresh = CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, \ diff --git a/components/app_trace/include/esp_app_trace_config.h b/components/app_trace/include/esp_app_trace_config.h index 027868d2cb..60e0003200 100644 --- a/components/app_trace/include/esp_app_trace_config.h +++ b/components/app_trace/include/esp_app_trace_config.h @@ -36,10 +36,6 @@ #define CONFIG_APPTRACE_UART_BAUDRATE 1000000 #endif -#ifndef CONFIG_APPTRACE_UART_TASK_PRIO -#define CONFIG_APPTRACE_UART_TASK_PRIO 1 -#endif - #ifndef CONFIG_APPTRACE_UART_TX_GPIO #define CONFIG_APPTRACE_UART_TX_GPIO U1TXD_GPIO_NUM #endif diff --git a/components/app_trace/include/esp_app_trace_types.h b/components/app_trace/include/esp_app_trace_types.h index cd4b2dee6f..5096d19ad8 100644 --- a/components/app_trace/include/esp_app_trace_types.h +++ b/components/app_trace/include/esp_app_trace_types.h @@ -61,7 +61,6 @@ typedef struct { int baud_rate; ///< Baud rate uint32_t tx_buff_size; ///< TX ring buffer size uint32_t tx_msg_size; ///< Maximum size of the single message to transfer. - int task_prio; ///< Task priority } esp_apptrace_uart_config_t; /** diff --git a/components/app_trace/port/port_uart.c b/components/app_trace/port/port_uart.c index c7b7920f80..aaad699a43 100644 --- a/components/app_trace/port/port_uart.c +++ b/components/app_trace/port/port_uart.c @@ -3,45 +3,118 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include -#include "soc/soc.h" +#include +#include "esp_err.h" #include "esp_log.h" #include "esp_cpu.h" -#include "esp_app_trace_config.h" -#include "esp_app_trace_port.h" - +#include "esp_attr.h" +#include "esp_private/uart_share_hw_ctrl.h" +#include "hal/uart_hal.h" +#include "hal/gpio_hal.h" #include "driver/uart.h" +#include "soc/uart_periph.h" +#include "esp_clk_tree.h" +#include "esp_private/esp_clk_tree_common.h" +#include "soc/gpio_periph.h" +#include "esp_rom_gpio.h" #include "hal/uart_ll.h" +#include "esp_intr_alloc.h" +#include "esp_heap_caps.h" +#include "esp_private/esp_gpio_reserve.h" -/** UART HW transport data */ -typedef struct { - uint8_t inited; -#if CONFIG_APPTRACE_LOCK_ENABLE - esp_apptrace_lock_t lock; // sync lock +#include "esp_app_trace_port.h" +#include "esp_app_trace_util.h" +#include "esp_app_trace_types.h" + +static const char *TAG = "esp_apptrace_uart"; + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif - uart_port_t port_num; - /* TX data ring buffer */ - uint8_t *tx_data_buff; - uint32_t tx_data_buff_size; - int32_t tx_data_buff_in; - int32_t tx_data_buff_out; +typedef struct { + uint8_t *buffer; ///< Ring buffer data + uint32_t max_size; ///< Ring buffer maximum size (must be power of 2) + volatile uint32_t count; ///< Number of bytes currently in the buffer + volatile uint32_t head; ///< Write pointer index + volatile uint32_t tail; ///< Read pointer index +} esp_apptrace_uart_rb_t; + +typedef struct { + int inited; + volatile bool tx_busy; ///< TX busy flag + uart_hal_context_t hal_ctx; ///< UART HAL context + esp_apptrace_uart_rb_t tx_ring; ///< TX ring buffer + intr_handle_t intr_handle; ///< Interrupt handle /* TX message buffer */ - uint8_t *tx_msg_buff; - uint32_t tx_msg_buff_size; - uint32_t tx_pending_msg_size; + uint8_t *tx_msg_buff; ///< TX message buffer to provide with get_up_buffer + uint32_t tx_msg_buff_size; ///< TX message buffer size & maximum size of the single message to transfer. + uint32_t tx_pending_msg_size; ///< Pending message size to send with put_up_buffer /* RX message buffer */ - uint8_t *down_buffer; - uint32_t down_buffer_size; + uint8_t *rx_msg_buff; ///< RX message buffer provided with down_buffer_config function + uint32_t rx_msg_buff_size; ///< RX message buffer size provided with down_buffer_config function + +#if CONFIG_APPTRACE_LOCK_ENABLE + esp_apptrace_lock_t lock; ///< Sync lock +#endif - /* Buffer overflow flags */ - bool message_buff_overflow; - bool circular_buff_overflow; } esp_apptrace_uart_data_t; -const static char *TAG = "esp_apptrace_uart"; +static inline bool is_power_of_two(uint32_t n) +{ + return n != 0 && (n & (n - 1)) == 0; +} + +static inline uint32_t ring_buffer_mask(const esp_apptrace_uart_rb_t *rb) +{ + return rb->max_size - 1; +} + +/* Get the length of the data in the ring buffer */ +static inline uint32_t ring_buffer_data_len(const esp_apptrace_uart_rb_t *rb) +{ + return rb->count; +} + +/* Get the length of the free space in the ring buffer */ +static inline uint32_t ring_buffer_free_len(const esp_apptrace_uart_rb_t *rb) +{ + return rb->max_size - rb->count; +} + +static inline void ring_buffer_advance_tail(esp_apptrace_uart_rb_t *rb, uint32_t count) +{ + rb->tail = (rb->tail + count) & ring_buffer_mask(rb); + rb->count -= count; +} + +static inline void ring_buffer_advance_head(esp_apptrace_uart_rb_t *rb, uint32_t count) +{ + rb->head = (rb->head + count) & ring_buffer_mask(rb); + rb->count += count; +} + +static inline uint32_t ring_buffer_calc_to_send(const esp_apptrace_uart_rb_t *rb, uint32_t tx_msg_size) +{ + uint32_t used = ring_buffer_data_len(rb); + if (used == 0) { + return 0; + } + + uint32_t cont = rb->max_size - rb->tail; + uint32_t n = MIN(used, cont); + + /* Apply message size limit if specified */ + if (tx_msg_size && tx_msg_size < n) { + return tx_msg_size; + } + return n; +} static esp_err_t esp_apptrace_uart_lock(void *hw_data, esp_apptrace_tmo_t *tmo) { @@ -61,225 +134,272 @@ static esp_err_t esp_apptrace_uart_unlock(void *hw_data) #if CONFIG_APPTRACE_LOCK_ENABLE esp_apptrace_uart_data_t *uart_data = hw_data; ret = esp_apptrace_lock_give(&uart_data->lock); + assert(ret == ESP_OK && "Failed to unlock apptrace uart lock!"); #endif return ret; } -static inline void esp_apptrace_uart_hw_init(void) +static esp_err_t ring_buffer_put(esp_apptrace_uart_rb_t *rb, const uint8_t *data, uint32_t len) { - ESP_APPTRACE_LOGI("Initialized UART on CPU%d", esp_cpu_get_core_id()); -} - -/*****************************************************************************************/ -/***************************** Apptrace HW iface *****************************************/ -/*****************************************************************************************/ - -static esp_err_t esp_apptrace_send_uart_data(void *hw_data, const char *data, uint32_t size, esp_apptrace_tmo_t *tmo) -{ - esp_apptrace_uart_data_t *uart_data = hw_data; - esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); - if (res != ESP_OK) { - return res; + /* Drop oldest. Make available space if needed */ + uint32_t free_len = ring_buffer_free_len(rb); + if (len > free_len) { + uint32_t need = len - free_len; + ring_buffer_advance_tail(rb, need); } - // We store current out position to handle it without lock - volatile int32_t out_position = uart_data->tx_data_buff_out; - int len_free = uart_data->tx_data_buff_size - (uart_data->tx_data_buff_in - out_position); - if (out_position > uart_data->tx_data_buff_in) { - len_free = out_position - uart_data->tx_data_buff_in; - } - int check_len = uart_data->tx_data_buff_size - uart_data->tx_data_buff_in; - if (size <= len_free) { - if (check_len >= size) { - memcpy(&uart_data->tx_data_buff[uart_data->tx_data_buff_in], data, size); - uart_data->tx_data_buff_in += size; - } else { - memcpy(&uart_data->tx_data_buff[uart_data->tx_data_buff_in], - data, - uart_data->tx_data_buff_size - uart_data->tx_data_buff_in); - memcpy(&uart_data->tx_data_buff[0], - &data[uart_data->tx_data_buff_size - uart_data->tx_data_buff_in], - size - (uart_data->tx_data_buff_size - uart_data->tx_data_buff_in)); - uart_data->tx_data_buff_in = size - (uart_data->tx_data_buff_size - uart_data->tx_data_buff_in); - } - if (uart_data->tx_data_buff_in >= uart_data->tx_data_buff_size) { - uart_data->tx_data_buff_in = 0; - } + uint32_t head = rb->head; + uint32_t space_to_end = rb->max_size - head; + + if (len <= space_to_end) { + memcpy(&rb->buffer[head], data, len); } else { - uart_data->circular_buff_overflow = true; + memcpy(&rb->buffer[head], data, space_to_end); + memcpy(&rb->buffer[0], &data[space_to_end], len - space_to_end); } - if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { - assert(false && "Failed to unlock apptrace data!"); - } + ring_buffer_advance_head(rb, len); return ESP_OK; } -static void send_buff_data(void *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t ring_buffer_init(esp_apptrace_uart_rb_t *rb, uint32_t size) { - esp_apptrace_uart_data_t *uart_data = hw_data; + rb->buffer = heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (!rb->buffer) { + return ESP_ERR_NO_MEM; + } - if (uart_data->tx_data_buff_in == uart_data->tx_data_buff_out) { - return; - } - // We store current in position to handle it without lock - volatile int32_t in_position = uart_data->tx_data_buff_in; - if (in_position > uart_data->tx_data_buff_out) { - int bytes_sent = uart_write_bytes(uart_data->port_num, - &uart_data->tx_data_buff[uart_data->tx_data_buff_out], - in_position - uart_data->tx_data_buff_out); - uart_data->tx_data_buff_out += bytes_sent; - } else { - int bytes_sent = uart_write_bytes(uart_data->port_num, - &uart_data->tx_data_buff[uart_data->tx_data_buff_out], - uart_data->tx_data_buff_size - uart_data->tx_data_buff_out); - uart_data->tx_data_buff_out += bytes_sent; - if (uart_data->tx_data_buff_out >= uart_data->tx_data_buff_size) { - uart_data->tx_data_buff_out = 0; - } - } + rb->max_size = size; + rb->count = 0; + rb->head = 0; + rb->tail = 0; + + return ESP_OK; } -#define APP_TRACE_UART_STOP_WAIT_TMO 1000000 //us - -static void esp_apptrace_send_uart_tx_task(void *arg) +static void IRAM_ATTR esp_apptrace_uart_isr_handler(void *arg) { esp_apptrace_uart_data_t *uart_data = arg; - esp_apptrace_tmo_t tmo; + esp_apptrace_uart_rb_t *rb = &uart_data->tx_ring; - esp_apptrace_tmo_init(&tmo, APP_TRACE_UART_STOP_WAIT_TMO); + uint32_t intr_status = uart_hal_get_intsts_mask(&uart_data->hal_ctx); - vTaskDelay(10); - while (1) { - send_buff_data(uart_data, &tmo); - vTaskDelay(10); - if (uart_data->circular_buff_overflow == true) { - uart_data->circular_buff_overflow = false; - ESP_LOGE(TAG, "Buffer overflow. Please increase UART baudrate, or increase UART TX ring buffer size in menuconfig."); + if (intr_status & UART_INTR_TXFIFO_EMPTY) { + uart_hal_clr_intsts_mask(&uart_data->hal_ctx, UART_INTR_TXFIFO_EMPTY); + + uint32_t to_send = ring_buffer_calc_to_send(rb, uart_data->tx_msg_buff_size); + if (to_send > 0) { + uint32_t written = 0; + uart_hal_write_txfifo(&uart_data->hal_ctx, &rb->buffer[rb->tail], to_send, &written); + ring_buffer_advance_tail(rb, written); } - if (uart_data->message_buff_overflow == true) { - uart_data->message_buff_overflow = false; - ESP_LOGE(TAG, "Message size more then message buffer!"); + + /* If ring buffer is empty, disable TX interrupt */ + if (ring_buffer_data_len(rb) == 0) { + uart_ll_disable_intr_mask(uart_data->hal_ctx.dev, UART_INTR_TXFIFO_EMPTY); + uart_data->tx_busy = false; } } } -static const int APP_TRACE_UART_RX_BUF_SIZE = 4024; - static esp_err_t esp_apptrace_uart_init(void *hw_data, const esp_apptrace_config_t *config) { + esp_err_t ret = ESP_ERR_INVALID_ARG; + uint64_t gpio_mask = 0; esp_apptrace_uart_data_t *uart_data = hw_data; - const esp_apptrace_uart_config_t *apptrace_uart_config = &config->dest_cfg.uart; + const esp_apptrace_uart_config_t *uart_config = &config->dest_cfg.uart; - /* esp_apptrace_uart_init() is called on every core, so ensure to do main initialization only once */ + /* Init function is called on every core, so ensure to do main setup only once */ int core_id = esp_cpu_get_core_id(); if (core_id == 0) { - uart_data->tx_data_buff_size = apptrace_uart_config->tx_buff_size; - uart_data->tx_data_buff = heap_caps_malloc(uart_data->tx_data_buff_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - if (uart_data->tx_data_buff == NULL) { - return ESP_ERR_NO_MEM; + + if (uart_config->uart_num == CONFIG_ESP_CONSOLE_UART_NUM) { + ESP_APPTRACE_LOGE("Application trace UART and console UART cannot use the same port number"); + return ESP_ERR_INVALID_ARG; } - uart_data->tx_data_buff_in = 0; - uart_data->tx_data_buff_out = 0; - uart_data->tx_msg_buff_size = apptrace_uart_config->tx_msg_size; + + if (uart_config->uart_num >= SOC_UART_HP_NUM) { + ESP_APPTRACE_LOGE("UART port number %d is not supported!", uart_config->uart_num); + return ESP_ERR_NOT_SUPPORTED; + } + + if (GPIO_IS_VALID_GPIO(uart_config->tx_pin_num)) { + gpio_mask |= BIT64(uart_config->tx_pin_num); + } + if (GPIO_IS_VALID_GPIO(uart_config->rx_pin_num)) { + gpio_mask |= BIT64(uart_config->rx_pin_num); + } + + if (gpio_mask == 0) { + ESP_LOGE(TAG, "No valid GPIOs to reserve"); + return ESP_ERR_INVALID_STATE; + } + + uint64_t r = esp_gpio_reserve(gpio_mask); + if (r & gpio_mask) { + ESP_LOGE(TAG, "GPIO(s) are already reserved: 0x%"PRIx64, r & gpio_mask); + return ESP_ERR_INVALID_STATE; + } + + uart_data->hal_ctx.dev = UART_LL_GET_HW(uart_config->uart_num); + + HP_UART_BUS_CLK_ATOMIC() { + uart_ll_enable_bus_clock(uart_config->uart_num, true); + uart_ll_reset_register(uart_config->uart_num); + } + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_sclk_enable(uart_data->hal_ctx.dev); + } + + uint32_t sclk_hz; + esp_clk_tree_src_get_freq_hz(UART_SCLK_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sclk_hz); + /* Enable the default clock source */ + esp_clk_tree_enable_src(UART_SCLK_DEFAULT, true); + + /* Initialize UART HAL (sets default 8N1 mode) */ + uart_hal_init(&uart_data->hal_ctx, uart_config->uart_num); + + ESP_LOGI(TAG, "uart_hal_init: %d", uart_config->uart_num); + + HP_UART_SRC_CLK_ATOMIC() { + uart_hal_set_sclk(&uart_data->hal_ctx, UART_SCLK_DEFAULT); + uart_hal_set_baudrate(&uart_data->hal_ctx, uart_config->baud_rate, sclk_hz); + } + + /* Configure FIFO thresholds */ + uart_hal_set_txfifo_empty_thr(&uart_data->hal_ctx, 16); /* Slow down IRQ rate */ + uart_hal_set_rxfifo_full_thr(&uart_data->hal_ctx, 1); + + /* Initialize TX ring buffer */ + if (uart_config->tx_buff_size == 0 || !is_power_of_two(uart_config->tx_buff_size)) { + ESP_APPTRACE_LOGE("TX ring buffer size (%u) must be a power of two and greater than 0", + uart_config->tx_buff_size); + goto err_init_ring_buff; + } + ret = ring_buffer_init(&uart_data->tx_ring, uart_config->tx_buff_size); + if (ret != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to initialize TX ring buffer"); + goto err_init_ring_buff; + } + + /* Initialize TX message buffer for providing with get_up_buffer */ + uart_data->tx_msg_buff_size = uart_config->tx_msg_size; uart_data->tx_msg_buff = heap_caps_malloc(uart_data->tx_msg_buff_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); if (uart_data->tx_msg_buff == NULL) { - return ESP_ERR_NO_MEM; + ESP_APPTRACE_LOGE("Failed to initialize TX message buffer"); + ret = ESP_ERR_NO_MEM; + goto err_alloc_msg_buff; } - uart_data->tx_pending_msg_size = 0; - uart_data->down_buffer_size = 0; - uart_data->message_buff_overflow = false; - uart_data->circular_buff_overflow = false; - assert((uart_data->port_num <= SOC_UART_NUM) && "Not possible to configure UART. Please check selected UART port"); + /* Disable all interrupts and clear status */ + uart_ll_disable_intr_mask(uart_data->hal_ctx.dev, UART_LL_INTR_MASK); + uart_ll_clr_intsts_mask(uart_data->hal_ctx.dev, UART_LL_INTR_MASK); - int source_clk = UART_SCLK_DEFAULT; -#if SOC_UART_LP_NUM > 0 - if (uart_data->port_num >= SOC_UART_HP_NUM) { - source_clk = LP_UART_SCLK_DEFAULT; + /* Install interrupt handler */ + int intr_alloc_flags = 0; + ret = esp_intr_alloc(uart_periph_signal[uart_config->uart_num].irq, intr_alloc_flags, + esp_apptrace_uart_isr_handler, uart_data, &uart_data->intr_handle); + if (ret != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to allocate interrupt: %s", esp_err_to_name(ret)); + goto err_alloc_intr; } -#endif - const uart_config_t uart_config = { - .baud_rate = apptrace_uart_config->baud_rate, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .source_clk = source_clk, - }; - ESP_LOGI(TAG, "UART baud rate: %i", apptrace_uart_config->baud_rate); - // We won't use a buffer for sending data. - esp_err_t __attribute__((unused)) err = uart_driver_install(uart_data->port_num, - APP_TRACE_UART_RX_BUF_SIZE, - APP_TRACE_UART_RX_BUF_SIZE, - 0, - NULL, - 0); - assert((err == ESP_OK) && "Not possible to install UART. Please check and change uart parameters!"); - err = uart_param_config(uart_data->port_num, &uart_config); - assert((err == ESP_OK) && "Not possible to configure UART. Please check and change uart parameters!"); - err = uart_set_pin(uart_data->port_num, - apptrace_uart_config->tx_pin_num, - apptrace_uart_config->rx_pin_num, - UART_PIN_NO_CHANGE, - UART_PIN_NO_CHANGE); - assert((err == ESP_OK) && "Not possible to configure UART RX/TX pins. Please check and change the uart pins!"); + /* Reset FIFOs */ + uart_hal_rxfifo_rst(&uart_data->hal_ctx); + uart_hal_txfifo_rst(&uart_data->hal_ctx); - int uart_prio = apptrace_uart_config->task_prio; - if (uart_prio >= (configMAX_PRIORITIES - 1)) { - uart_prio = configMAX_PRIORITIES - 1; - } - err = xTaskCreate(esp_apptrace_send_uart_tx_task, "app_trace_uart_tx_task", 2500, uart_data, uart_prio, NULL); - assert((err == pdPASS) && "Not possible to configure UART. Not possible to create task!"); + /* Configure GPIO pins for RX and TX */ + const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_config->uart_num, SOC_UART_PERIPH_SIGNAL_TX); + const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_config->uart_num, SOC_UART_PERIPH_SIGNAL_RX); + + /* Configure TX pin */ + gpio_ll_func_sel(&GPIO, uart_config->tx_pin_num, PIN_FUNC_GPIO); + esp_rom_gpio_pad_pullup_only(uart_config->tx_pin_num); + esp_rom_gpio_connect_out_signal(uart_config->tx_pin_num, tx_idx, 0, 0); + + /* Configure RX pin */ + gpio_ll_input_enable(&GPIO, uart_config->rx_pin_num); + esp_rom_gpio_pad_pullup_only(uart_config->rx_pin_num); + esp_rom_gpio_connect_in_signal(uart_config->rx_pin_num, rx_idx, 0); #if CONFIG_APPTRACE_LOCK_ENABLE esp_apptrace_lock_init(&uart_data->lock); #endif + } - // init UART on this CPU - esp_apptrace_uart_hw_init(); + uart_data->inited |= 1 << core_id; + uart_data->tx_busy = false; return ESP_OK; + +err_alloc_intr: + heap_caps_free(uart_data->tx_msg_buff); +err_alloc_msg_buff: + heap_caps_free(uart_data->tx_ring.buffer); +err_init_ring_buff: + esp_clk_tree_enable_src(UART_SCLK_DEFAULT, false); + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_sclk_disable(uart_data->hal_ctx.dev); + } + HP_UART_BUS_CLK_ATOMIC() { + uart_ll_enable_bus_clock(uart_config->uart_num, false); + } + esp_gpio_revoke(gpio_mask); + return ret; } static uint8_t *esp_apptrace_uart_up_buffer_get(void *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) { esp_apptrace_uart_data_t *uart_data = hw_data; - if (size > uart_data->tx_msg_buff_size) { - uart_data->message_buff_overflow = true; + if (size == 0 || size > uart_data->tx_msg_buff_size) { return NULL; } + + if (esp_apptrace_uart_lock(uart_data, tmo) != ESP_OK) { + return NULL; + } + if (uart_data->tx_pending_msg_size != 0) { // A previous message was not sent. + esp_apptrace_uart_unlock(uart_data); return NULL; } - esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); - if (res != ESP_OK) { - return NULL; - } - uint8_t *ptr = uart_data->tx_msg_buff; - // Set the amount of data to send uart_data->tx_pending_msg_size = size; - // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { - assert(false && "Failed to unlock apptrace data!"); - } - return ptr; + esp_apptrace_uart_unlock(uart_data); + + return uart_data->tx_msg_buff; } static esp_err_t esp_apptrace_uart_up_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { esp_apptrace_uart_data_t *uart_data = hw_data; - esp_err_t res = esp_apptrace_send_uart_data(uart_data, (const char *)ptr, uart_data->tx_pending_msg_size, tmo); - // Clear size to indicate that we've sent data + esp_apptrace_uart_rb_t *rb = &uart_data->tx_ring; + + esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); + if (res != ESP_OK) { + return res; + } + + /* Add data to ring buffer */ + ring_buffer_put(rb, ptr, uart_data->tx_pending_msg_size); uart_data->tx_pending_msg_size = 0; - return res; + + esp_apptrace_uart_unlock(uart_data); + + // Trigger transmission if not already in progress + if (!uart_data->tx_busy) { + uart_data->tx_busy = true; + /* Enable TX interrupt */ + uart_ll_clr_intsts_mask(uart_data->hal_ctx.dev, UART_INTR_TXFIFO_EMPTY); + uart_ll_ena_intr_mask(uart_data->hal_ctx.dev, UART_INTR_TXFIFO_EMPTY); + } + + return ESP_OK; } static void esp_apptrace_uart_down_buffer_config(void *hw_data, uint8_t *buf, uint32_t size) @@ -287,44 +407,47 @@ static void esp_apptrace_uart_down_buffer_config(void *hw_data, uint8_t *buf, ui esp_apptrace_uart_data_t *uart_data = hw_data; assert(buf != NULL && "Down buffer cannot be NULL"); + assert(size > 0 && "Down buffer size must be greater than 0"); - uart_data->down_buffer = buf; - uart_data->down_buffer_size = size; + uart_data->rx_msg_buff = buf; + uart_data->rx_msg_buff_size = size; } static uint8_t *esp_apptrace_uart_down_buffer_get(void *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) { esp_apptrace_uart_data_t *uart_data = hw_data; - uint8_t *ptr = NULL; - - if (*size > uart_data->down_buffer_size) { + if (!size || *size == 0) { return NULL; } - esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); - if (res != ESP_OK) { + if (!uart_data->rx_msg_buff) { + ESP_APPTRACE_LOGE("RX message buffer is not configured. Call down_buffer_config() first."); return NULL; } - size_t uart_fifolen = 0; - uart_get_buffered_data_len(uart_data->port_num, &uart_fifolen); - if (uart_fifolen > 0) { - if (*size < uart_fifolen) { - uart_fifolen = *size; - } - *size = uart_fifolen; - ptr = uart_data->down_buffer; - *size = uart_read_bytes(uart_data->port_num, ptr, uart_fifolen, 0); + if (esp_apptrace_uart_lock(uart_data, tmo) != ESP_OK) { + return NULL; } - if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { - assert(false && "Failed to unlock apptrace data!"); + uint32_t rx_len = uart_ll_get_rxfifo_len(uart_data->hal_ctx.dev); + int to_read = MIN(rx_len, MIN(uart_data->rx_msg_buff_size, *size)); + if (to_read) { + uart_hal_read_rxfifo(&uart_data->hal_ctx, uart_data->rx_msg_buff, &to_read); } - return ptr; + *size = to_read; + + esp_apptrace_uart_unlock(uart_data); + + return (*size > 0) ? uart_data->rx_msg_buff : NULL; } static esp_err_t esp_apptrace_uart_down_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { + (void)hw_data; + (void)ptr; + (void)tmo; + + /* No action needed - data was already read in get function */ return ESP_OK; } @@ -337,17 +460,50 @@ static bool esp_apptrace_uart_host_is_connected(void *hw_data) static esp_err_t esp_apptrace_uart_flush_nolock(void *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) { + esp_apptrace_uart_data_t *uart_data = hw_data; + esp_apptrace_uart_rb_t *rb = &uart_data->tx_ring; + + uint32_t pending = ring_buffer_data_len(rb); + if (pending < min_sz) { + ESP_APPTRACE_LOGD("Ignore UART flush request for min %" PRIu32 " bytes. Pending bytes: %" PRIu32, min_sz, pending); + return ESP_OK; + } + + /* Trigger transmission if there's data but not busy */ + if (pending > 0 && !uart_data->tx_busy) { + uart_data->tx_busy = true; + uart_ll_clr_intsts_mask(uart_data->hal_ctx.dev, UART_INTR_TXFIFO_EMPTY); + uart_ll_ena_intr_mask(uart_data->hal_ctx.dev, UART_INTR_TXFIFO_EMPTY); + } + + while (uart_data->tx_busy || ring_buffer_data_len(rb) > 0) { + if (esp_apptrace_tmo_check(tmo) != ESP_OK) { + return ESP_ERR_TIMEOUT; + } + esp_rom_delay_us(100); + } + return ESP_OK; } static esp_err_t esp_apptrace_uart_flush(void *hw_data, esp_apptrace_tmo_t *tmo) { - return ESP_OK; + esp_apptrace_uart_data_t *uart_data = hw_data; + esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); + if (res != ESP_OK) { + return res; + } + + esp_err_t ret = esp_apptrace_uart_flush_nolock(hw_data, 0, tmo); + + esp_apptrace_uart_unlock(uart_data); + + return ret; } esp_apptrace_hw_t *esp_apptrace_uart_hw_get(int num, void **data) { - ESP_LOGD(TAG, "esp_apptrace_uart_hw_get - %i", num); + ESP_APPTRACE_LOGD("esp_apptrace_uart_hw_get - %i", num); static esp_apptrace_uart_data_t s_uart_hw_data; static esp_apptrace_hw_t s_uart_hw = { @@ -361,7 +517,6 @@ esp_apptrace_hw_t *esp_apptrace_uart_hw_get(int num, void **data) .put_down_buffer = esp_apptrace_uart_down_buffer_put, .host_is_connected = esp_apptrace_uart_host_is_connected, }; - s_uart_hw_data.port_num = num; *data = &s_uart_hw_data; return &s_uart_hw; } diff --git a/examples/system/app_trace_basic/main/app_trace_basic_example_main.c b/examples/system/app_trace_basic/main/app_trace_basic_example_main.c index cdd5812c08..9bf8ead446 100644 --- a/examples/system/app_trace_basic/main/app_trace_basic_example_main.c +++ b/examples/system/app_trace_basic/main/app_trace_basic_example_main.c @@ -56,7 +56,7 @@ void app_main(void) if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res)); } - esp_apptrace_flush( 1000); + esp_apptrace_flush(1000); vTaskDelay(50 / portTICK_PERIOD_MS); }