diff --git a/components/app_trace/Kconfig b/components/app_trace/Kconfig index e88128f33..101fa9786 100644 --- a/components/app_trace/Kconfig +++ b/components/app_trace/Kconfig @@ -22,6 +22,12 @@ config ESP32_APPTRACE_ENABLE help Enables/disable application tracing module. +config ESP32_APPTRACE_LOCK_ENABLE + bool + default !SYSVIEW_ENABLE + help + Enables/disable application tracing module internal sync lock. + config ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO int "Timeout for flushing last trace data to host on panic" depends on ESP32_APPTRACE_ENABLE diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index 0a990b0d1..939f3c484 100644 --- a/components/app_trace/app_trace.c +++ b/components/app_trace/app_trace.c @@ -103,7 +103,8 @@ // that task/ISR will fail to complete filling its data chunk before the whole trace block is exposed to the host. To handle such conditions tracing // module prepends all user data chunks with header which contains allocated buffer size and actual data length within it. OpenOCD command // which reads application traces reports error when it reads incompleted user data block. -// Data which are transfered from host to target are also prepended with such header. +// Data which are transfered from host to target are also prepended with a header. Down channel data header is simple and consists of one two bytes field +// containing length of host data following the heder. // 4.3 Data Buffering // ------------------ @@ -159,14 +160,10 @@ #include "soc/dport_reg.h" #include "eri.h" #include "trax.h" -#include "freertos/FreeRTOS.h" -#include "freertos/portmacro.h" -#include "freertos/semphr.h" -#include "freertos/task.h" #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" +#include "freertos/FreeRTOS.h" #include "esp_app_trace.h" -#include "esp_app_trace_util.h" #if CONFIG_ESP32_APPTRACE_ENABLE #define ESP_APPTRACE_MAX_VPRINTF_ARGS 256 @@ -174,7 +171,7 @@ #define ESP_APPTRACE_PRINT_LOCK 0 -#define LOG_LOCAL_LEVEL ESP_LOG_ERROR +#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL #include "esp_log.h" const static char *TAG = "esp_apptrace"; @@ -244,17 +241,13 @@ static volatile uint8_t *s_trax_blocks[] = { #define ESP_APPTRACE_TRAX_BLOCKS_NUM (sizeof(s_trax_blocks)/sizeof(s_trax_blocks[0])) -#define ESP_APPTRACE_TRAX_BLOCK_SIZE 0x4000UL - #define ESP_APPTRACE_TRAX_INBLOCK_START 0 #define ESP_APPTRACE_TRAX_INBLOCK_MARKER() (s_trace_buf.trax.state.markers[s_trace_buf.trax.state.in_block % 2]) #define ESP_APPTRACE_TRAX_INBLOCK_MARKER_UPD(_v_) do {s_trace_buf.trax.state.markers[s_trace_buf.trax.state.in_block % 2] += (_v_);}while(0) #define ESP_APPTRACE_TRAX_INBLOCK_GET() (&s_trace_buf.trax.blocks[s_trace_buf.trax.state.in_block % 2]) -//TODO: menuconfig -#define ESP_APPTRACE_DOWN_BUF_SIZE 32UL - +#define ESP_APPTRACE_TRAX_BLOCK_SIZE (0x4000UL) #if CONFIG_SYSVIEW_ENABLE #define ESP_APPTRACE_USR_DATA_LEN_MAX 255UL #else @@ -324,7 +317,6 @@ typedef struct { // ring buffer control struct for data from host (down buffer) esp_apptrace_rb_t rb_down; // storage for above ring buffer data - uint8_t down_buf[ESP_APPTRACE_DOWN_BUF_SIZE + 1]; esp_apptrace_trax_data_t trax; // TRAX HW transport data } esp_apptrace_buffer_t; @@ -334,13 +326,15 @@ static esp_apptrace_buffer_t s_trace_buf; static esp_apptrace_lock_t s_log_lock = {.irq_stat = 0, .portmux = portMUX_INITIALIZER_UNLOCKED}; #endif -static uint16_t esp_apptrace_trax_write_down_buffer_nolock(uint8_t *data, uint16_t size); -static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, uint32_t tmo); +static uint32_t esp_apptrace_trax_down_buffer_write_nolock(uint8_t *data, uint32_t size); +static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, esp_apptrace_tmo_t *tmo); static inline int esp_apptrace_log_lock() { #if ESP_APPTRACE_PRINT_LOCK - int ret = esp_apptrace_lock_take(&s_log_lock, ESP_APPTRACE_TMO_INFINITE); + esp_apptrace_tmo_t tmo; + esp_apptrace_tmo_init(&tmo, ESP_APPTRACE_TMO_INFINITE); + int ret = esp_apptrace_lock_take(&s_log_lock, &tmo); return ret; #else return 0; @@ -354,40 +348,40 @@ static inline void esp_apptrace_log_unlock() #endif } -esp_err_t esp_apptrace_lock_initialize() +static inline esp_err_t esp_apptrace_lock_initialize() { -#if CONFIG_SYSVIEW_ENABLE == 0 +#if CONFIG_ESP32_APPTRACE_LOCK_ENABLE esp_apptrace_lock_init(&s_trace_buf.lock); #endif return ESP_OK; } -esp_err_t inline esp_apptrace_lock_cleanup() +static inline esp_err_t esp_apptrace_lock_cleanup() { return ESP_OK; } -esp_err_t esp_apptrace_lock(uint32_t *tmo) +esp_err_t esp_apptrace_lock(esp_apptrace_tmo_t *tmo) { -#if CONFIG_SYSVIEW_ENABLE == 0 - unsigned cur, elapsed, start = xthal_get_ccount(); +#if CONFIG_ESP32_APPTRACE_LOCK_ENABLE + //unsigned cur, elapsed, start = xthal_get_ccount(); - esp_err_t ret = esp_apptrace_lock_take(&s_trace_buf.lock, *tmo); + esp_err_t ret = esp_apptrace_lock_take(&s_trace_buf.lock, tmo); if (ret != ESP_OK) { return ESP_FAIL; } // decrease tmo by actual waiting time - cur = xthal_get_ccount(); - if (start <= cur) { - elapsed = cur - start; - } else { - elapsed = ULONG_MAX - start + cur; - } - if (ESP_APPTRACE_CPUTICKS2US(elapsed) > *tmo) { - *tmo = 0; - } else { - *tmo -= ESP_APPTRACE_CPUTICKS2US(elapsed); - } + // cur = xthal_get_ccount(); + // if (start <= cur) { + // elapsed = cur - start; + // } else { + // elapsed = ULONG_MAX - start + cur; + // } + // if (ESP_APPTRACE_CPUTICKS2US(elapsed) > *tmo) { + // *tmo = 0; + // } else { + // *tmo -= ESP_APPTRACE_CPUTICKS2US(elapsed); + // } #endif return ESP_OK; } @@ -395,7 +389,7 @@ esp_err_t esp_apptrace_lock(uint32_t *tmo) esp_err_t esp_apptrace_unlock() { esp_err_t ret = ESP_OK; -#if CONFIG_SYSVIEW_ENABLE == 0 +#if CONFIG_ESP32_APPTRACE_LOCK_ENABLE ret = esp_apptrace_lock_give(&s_trace_buf.lock); #endif return ret; @@ -476,7 +470,8 @@ static esp_err_t esp_apptrace_trax_block_switch() uint32_t host_to_read = ESP_APPTRACE_TRAX_BLOCK_LEN_GET(ctrl_reg); if (host_to_read != 0 || acked_block != (s_trace_buf.trax.state.in_block & ESP_APPTRACE_TRAX_BLOCK_ID_MSK)) { ESP_APPTRACE_LOGD("HC[%d]: Can not switch %x %d %x %x/%lx, m %d", xPortGetCoreID(), ctrl_reg, host_to_read, acked_block, - s_trace_buf.trax.state.in_block & ESP_APPTRACE_TRAX_BLOCK_ID_MSK, s_trace_buf.trax.state.in_block, s_trace_buf.trax.state.markers[prev_block_num]); + s_trace_buf.trax.state.in_block & ESP_APPTRACE_TRAX_BLOCK_ID_MSK, s_trace_buf.trax.state.in_block, + s_trace_buf.trax.state.markers[prev_block_num]); res = ESP_ERR_NO_MEM; goto _on_func_exit; } @@ -491,12 +486,15 @@ static esp_err_t esp_apptrace_trax_block_switch() if (ctrl_reg & ESP_APPTRACE_TRAX_HOST_DATA && hdr->block_sz > 0) { // TODO: add support for multiple blocks from host, currently there is no need for that uint8_t *p = s_trace_buf.trax.blocks[new_block_num].start + s_trace_buf.trax.blocks[new_block_num].sz; - ESP_APPTRACE_LOGD("Recvd %d bytes from host [%x %x %x .. %x %x]", hdr->block_sz, + ESP_APPTRACE_LOGD("Recvd %d bytes from host [%x %x %x %x %x %x %x %x .. %x %x %x %x %x %x %x %x]", hdr->block_sz, *(s_trace_buf.trax.blocks[new_block_num].start+0), *(s_trace_buf.trax.blocks[new_block_num].start+1), - *(s_trace_buf.trax.blocks[new_block_num].start+2), *(p-2), *(p-1)); - uint32_t sz = esp_apptrace_trax_write_down_buffer_nolock((uint8_t *)(hdr+1), hdr->block_sz); + *(s_trace_buf.trax.blocks[new_block_num].start+2), *(s_trace_buf.trax.blocks[new_block_num].start+3), + *(s_trace_buf.trax.blocks[new_block_num].start+4), *(s_trace_buf.trax.blocks[new_block_num].start+5), + *(s_trace_buf.trax.blocks[new_block_num].start+6), *(s_trace_buf.trax.blocks[new_block_num].start+7), + *(p-8), *(p-7), *(p-6), *(p-5), *(p-4), *(p-3), *(p-2), *(p-1)); + uint32_t sz = esp_apptrace_trax_down_buffer_write_nolock((uint8_t *)(hdr+1), hdr->block_sz); if (sz != hdr->block_sz) { - ESP_APPTRACE_LOGE("Failed to write %d bytes to down buffer!", hdr->block_sz - sz); + ESP_APPTRACE_LOGE("Failed to write %d bytes to down buffer (%d %d)!", hdr->block_sz - sz, hdr->block_sz, sz); } hdr->block_sz = 0; } @@ -548,15 +546,12 @@ _on_func_exit: return res; } -static esp_err_t esp_apptrace_trax_block_switch_waitus(uint32_t tmo) +static esp_err_t esp_apptrace_trax_block_switch_waitus(esp_apptrace_tmo_t *tmo) { int res; - esp_apptrace_tmo_t sleeping_tmo; - - esp_apptrace_tmo_init(&sleeping_tmo, tmo); while ((res = esp_apptrace_trax_block_switch()) != ESP_OK) { - res = esp_apptrace_tmo_check(&sleeping_tmo); + res = esp_apptrace_tmo_check(tmo); if (res != ESP_OK) { break; } @@ -564,58 +559,79 @@ static esp_err_t esp_apptrace_trax_block_switch_waitus(uint32_t tmo) return res; } -static inline void esp_apptrace_trax_down_buf_init() +static uint8_t *esp_apptrace_trax_down_buffer_get(uint32_t *size, esp_apptrace_tmo_t *tmo) { - esp_apptrace_rb_init(&s_trace_buf.rb_down, s_trace_buf.down_buf, sizeof(s_trace_buf.down_buf)); -} + uint8_t *ptr = NULL; -static inline uint8_t *esp_apptrace_trax_get_down_rdptr(uint32_t *size, uint32_t *tmo) -{ int res = esp_apptrace_lock(tmo); if (res != ESP_OK) { return NULL; } - - // may need to flush - uint32_t ctrl_reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); - if (ctrl_reg & ESP_APPTRACE_TRAX_HOST_DATA) { - ESP_APPTRACE_LOGD("force flush"); - res = esp_apptrace_trax_block_switch_waitus(*tmo); - if (res != ESP_OK) { - ESP_APPTRACE_LOGE("Failed to switch to another block to recv data from host!"); + while (1) { + uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down); + if (sz != 0) { + ptr = esp_apptrace_rb_consume(&s_trace_buf.rb_down, sz > *size ? *size : sz); + if (!ptr) { + assert(false && "Failed to consume bytes from down buffer!"); + } + *size = sz; + break; + } + // may need to flush + uint32_t ctrl_reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); + if (ctrl_reg & ESP_APPTRACE_TRAX_HOST_DATA) { + ESP_APPTRACE_LOGD("force flush"); + res = esp_apptrace_trax_block_switch_waitus(tmo); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to switch to another block to recv data from host!"); + /*do not return error because data can be in down buffer already*/ + } + } else { + // check tmo only if there is no data from host + res = esp_apptrace_tmo_check(tmo); + if (res != ESP_OK) { + return NULL; + } } } - uint8_t *ptr = NULL; - uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down); - if (sz > 0) { - ptr = esp_apptrace_rb_consume(&s_trace_buf.rb_down, sz > *size ? *size : sz); - if (!ptr) { - assert(false && "Failed to consume bytes from down buffer!"); - } - } - *size = sz; - if (esp_apptrace_unlock() != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static inline esp_err_t esp_apptrace_trax_put_down_rdptr(uint8_t *ptr, uint32_t size, uint32_t *tmo) +static inline esp_err_t esp_apptrace_trax_down_buffer_put(uint8_t *ptr, esp_apptrace_tmo_t *tmo) { /* nothing todo */ return ESP_OK; } -static uint16_t esp_apptrace_trax_write_down_buffer_nolock(uint8_t *data, uint16_t size) +static uint32_t esp_apptrace_trax_down_buffer_write_nolock(uint8_t *data, uint32_t size) { - uint8_t *ptr = esp_apptrace_rb_produce(&s_trace_buf.rb_down, size); - if (ptr) { - memcpy(ptr, data, size); - } else { - return 0; + uint32_t total_sz = 0; + + while (total_sz < size) { + // ESP_APPTRACE_LOGE("esp_apptrace_trax_down_buffer_write_nolock WRS %d-%d-%d %d", s_trace_buf.rb_down.wr, s_trace_buf.rb_down.rd, + // s_trace_buf.rb_down.cur_size, size); + uint32_t wr_sz = esp_apptrace_rb_write_size_get(&s_trace_buf.rb_down); + if (wr_sz == 0) { + break; + } + + if (wr_sz > size - total_sz) { + wr_sz = size - total_sz; + } + // ESP_APPTRACE_LOGE("esp_apptrace_trax_down_buffer_write_nolock wr %d", wr_sz); + uint8_t *ptr = esp_apptrace_rb_produce(&s_trace_buf.rb_down, wr_sz); + if (!ptr) { + assert(false && "Failed to produce bytes to down buffer!"); + } + // ESP_APPTRACE_LOGE("esp_apptrace_trax_down_buffer_write_nolock wr %d to 0x%x from 0x%x", wr_sz, ptr, data + total_sz + wr_sz); + memcpy(ptr, data + total_sz, wr_sz); + total_sz += wr_sz; + // ESP_APPTRACE_LOGE("esp_apptrace_trax_down_buffer_write_nolock wr %d/%d", wr_sz, total_sz); } - return size; + return total_sz; } static inline uint8_t *esp_apptrace_data_header_init(uint8_t *ptr, uint16_t usr_size) @@ -626,7 +642,7 @@ static inline uint8_t *esp_apptrace_data_header_init(uint8_t *ptr, uint16_t usr_ return ptr + sizeof(esp_tracedata_hdr_t); } -static inline uint8_t *esp_apptrace_trax_wait4buf(uint16_t size, uint32_t tmo, int *pended) +static inline uint8_t *esp_apptrace_trax_wait4buf(uint16_t size, esp_apptrace_tmo_t *tmo, int *pended) { uint8_t *ptr = NULL; @@ -665,7 +681,7 @@ static inline uint8_t *esp_apptrace_trax_wait4buf(uint16_t size, uint32_t tmo, i return ptr; } -static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) +static uint8_t *esp_apptrace_trax_get_buffer(uint32_t size, esp_apptrace_tmo_t *tmo) { uint8_t *buf_ptr = NULL; @@ -691,14 +707,14 @@ static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) buf_ptr = esp_apptrace_rb_produce(&s_trace_buf.trax.rb_pend, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); if (buf_ptr == NULL) { int pended_buf; - buf_ptr = esp_apptrace_trax_wait4buf(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), *tmo, &pended_buf); + buf_ptr = esp_apptrace_trax_wait4buf(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), tmo, &pended_buf); if (buf_ptr) { if (pended_buf) { #if CONFIG_ESP32_APPTRACE_PENDING_DATA_SIZE_MAX > ESP_APPTRACE_TRAX_BLOCK_SIZE esp_apptrace_trax_pend_chunk_sz_update(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); #endif } else { - ESP_APPTRACE_LOGD("Got %d bytes from TRAX buffer", size); + ESP_APPTRACE_LOGD("Get %d bytes from TRAX buffer", size); // update cur block marker ESP_APPTRACE_TRAX_INBLOCK_MARKER_UPD(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); } @@ -723,7 +739,7 @@ static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) if (buf_ptr == NULL) { int pended_buf; ESP_APPTRACE_LOGD("TRAX full. Get %d bytes from pend buffer", size); - buf_ptr = esp_apptrace_trax_wait4buf(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), *tmo, &pended_buf); + buf_ptr = esp_apptrace_trax_wait4buf(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), tmo, &pended_buf); if (buf_ptr) { if (pended_buf) { #if CONFIG_ESP32_APPTRACE_PENDING_DATA_SIZE_MAX > ESP_APPTRACE_TRAX_BLOCK_SIZE @@ -737,7 +753,7 @@ static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) } } } else { - ESP_APPTRACE_LOGD("Get %d bytes from TRAX buffer!", size); + ESP_APPTRACE_LOGD("Get %d bytes from TRAX buffer", size); // fit to curr TRAX nlock buf_ptr = ESP_APPTRACE_TRAX_INBLOCK_GET()->start + ESP_APPTRACE_TRAX_INBLOCK_MARKER(); // update cur block marker @@ -755,7 +771,7 @@ static uint8_t *esp_apptrace_trax_get_buffer(size_t size, uint32_t *tmo) return buf_ptr; } -static esp_err_t esp_apptrace_trax_put_buffer(uint8_t *ptr, uint32_t *tmo) +static esp_err_t esp_apptrace_trax_put_buffer(uint8_t *ptr, esp_apptrace_tmo_t *tmo) { int res = ESP_OK; esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)(ptr - sizeof(esp_tracedata_hdr_t)); @@ -772,7 +788,7 @@ static esp_err_t esp_apptrace_trax_put_buffer(uint8_t *ptr, uint32_t *tmo) return res; } -static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, uint32_t tmo) +static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, esp_apptrace_tmo_t *tmo) { int res = ESP_OK; @@ -782,7 +798,7 @@ static esp_err_t esp_apptrace_trax_flush(uint32_t min_sz, uint32_t tmo) } // switch TRAX block while size of data is more than min size while (ESP_APPTRACE_TRAX_INBLOCK_MARKER() > 0) { - ESP_APPTRACE_LOGD("Try to flush %d bytes. Wait until block switch for %u us", ESP_APPTRACE_TRAX_INBLOCK_MARKER(), tmo); + ESP_APPTRACE_LOGD("Try to flush %d bytes. Wait until block switch for %u us", ESP_APPTRACE_TRAX_INBLOCK_MARKER(), tmo->tmo); res = esp_apptrace_trax_block_switch_waitus(tmo); if (res != ESP_OK) { ESP_APPTRACE_LOGE("Failed to switch to another block!"); @@ -810,7 +826,6 @@ static esp_err_t esp_apptrace_trax_dest_init() sizeof(s_trace_buf.trax.pending_chunk_sz)); #endif #endif - esp_apptrace_trax_down_buf_init(); DPORT_WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, DPORT_PRO_TRACEMEM_ENA_M); #if CONFIG_FREERTOS_UNICORE == 0 @@ -849,25 +864,31 @@ esp_err_t esp_apptrace_init() esp_apptrace_trax_init(); #endif + // disabled by default + esp_apptrace_rb_init(&s_trace_buf.rb_down, NULL, 0); + s_trace_buf.inited |= 1 << xPortGetCoreID(); // global and this CPU-specific data are inited return ESP_OK; } -esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, size_t *size, uint32_t user_tmo) +void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size) +{ + esp_apptrace_rb_init(&s_trace_buf.rb_down, buf, size); +} + +esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, uint32_t *size, uint32_t user_tmo) { - uint8_t *ptr = NULL; - uint32_t tmo = user_tmo; int res = ESP_OK; - esp_apptrace_tmo_t sleeping_tmo; + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - uint8_t *(*apptrace_get_down_buffer)(uint32_t *, uint32_t *); - esp_err_t (*apptrace_put_down_buffer)(uint8_t *, uint32_t , uint32_t *); + uint8_t *(*apptrace_get_down_buffer)(uint32_t *, esp_apptrace_tmo_t *); + esp_err_t (*apptrace_put_down_buffer)(uint8_t *, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX - apptrace_get_down_buffer = esp_apptrace_trax_get_down_rdptr; - apptrace_put_down_buffer = esp_apptrace_trax_put_down_rdptr; + apptrace_get_down_buffer = esp_apptrace_trax_down_buffer_get; + apptrace_put_down_buffer = esp_apptrace_trax_down_buffer_put; #else ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); return ESP_ERR_NOT_SUPPORTED; @@ -878,31 +899,72 @@ esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, size_t *size, u } //TODO: callback system - esp_apptrace_tmo_init(&sleeping_tmo, tmo); + esp_apptrace_tmo_init(&tmo, user_tmo); uint32_t act_sz = *size; - while ((ptr = apptrace_get_down_buffer(&act_sz, &tmo)) == NULL ) { - res = esp_apptrace_tmo_check(&sleeping_tmo); - if (res != ESP_OK) { - break; - } - } + *size = 0; + uint8_t * ptr = apptrace_get_down_buffer(&act_sz, &tmo); if (ptr && act_sz > 0) { ESP_APPTRACE_LOGD("Read %d bytes from host", act_sz); memcpy(buf, ptr, act_sz); - res = apptrace_put_down_buffer(ptr, act_sz, &tmo); + res = apptrace_put_down_buffer(ptr, &tmo); *size = act_sz; } return res; } -esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, size_t size, uint32_t user_tmo) +uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t user_tmo) +{ + esp_apptrace_tmo_t tmo; + //TODO: use ptr to HW transport iface struct + uint8_t *(*apptrace_get_down_buffer)(uint32_t *, esp_apptrace_tmo_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_get_down_buffer = esp_apptrace_trax_down_buffer_get; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return NULL; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return NULL; + } + + // ESP_APPTRACE_LOGE("esp_apptrace_down_buffer_get %d", *size); + esp_apptrace_tmo_init(&tmo, user_tmo); + return apptrace_get_down_buffer(size, &tmo); +} + +esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo) +{ + esp_apptrace_tmo_t tmo; + //TODO: use ptr to HW transport iface struct + esp_err_t (*apptrace_put_down_buffer)(uint8_t *, esp_apptrace_tmo_t *); + + if (dest == ESP_APPTRACE_DEST_TRAX) { +#if CONFIG_ESP32_APPTRACE_DEST_TRAX + apptrace_put_down_buffer = esp_apptrace_trax_down_buffer_put; +#else + ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); + return ESP_ERR_NOT_SUPPORTED; +#endif + } else { + ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!"); + return ESP_ERR_NOT_SUPPORTED; + } + + esp_apptrace_tmo_init(&tmo, user_tmo); + return apptrace_put_down_buffer(ptr, &tmo); +} + +esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t user_tmo) { uint8_t *ptr = NULL; - uint32_t tmo = user_tmo; + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); - esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + uint8_t *(*apptrace_get_buffer)(uint32_t, esp_apptrace_tmo_t *); + esp_err_t (*apptrace_put_buffer)(uint8_t *, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX @@ -917,6 +979,7 @@ esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, size_t return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_init(&tmo, user_tmo); ptr = apptrace_get_buffer(size, &tmo); if (ptr == NULL) { return ESP_ERR_NO_MEM; @@ -934,10 +997,10 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c { uint16_t nargs = 0; uint8_t *pout, *p = (uint8_t *)fmt; - uint32_t tmo = user_tmo; + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); - esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + uint8_t *(*apptrace_get_buffer)(uint32_t, esp_apptrace_tmo_t *); + esp_err_t (*apptrace_put_buffer)(uint8_t *, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX @@ -952,6 +1015,7 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_init(&tmo, user_tmo); ESP_APPTRACE_LOGD("fmt %x", fmt); while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) { p++; @@ -995,11 +1059,11 @@ int esp_apptrace_vprintf(const char *fmt, va_list ap) return esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_TRAX, /*ESP_APPTRACE_TMO_INFINITE*/0, fmt, ap); } -uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, size_t size, uint32_t user_tmo) +uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t user_tmo) { - uint32_t tmo = user_tmo; + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - uint8_t *(*apptrace_get_buffer)(size_t, uint32_t *); + uint8_t *(*apptrace_get_buffer)(uint32_t, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX @@ -1013,14 +1077,15 @@ uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, size_t size, uint32_t return NULL; } + esp_apptrace_tmo_init(&tmo, user_tmo); return apptrace_get_buffer(size, &tmo); } esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo) { - uint32_t tmo = user_tmo; + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - esp_err_t (*apptrace_put_buffer)(uint8_t *, uint32_t *); + esp_err_t (*apptrace_put_buffer)(uint8_t *, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX @@ -1034,13 +1099,15 @@ esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32 return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_init(&tmo, user_tmo); return apptrace_put_buffer(ptr, &tmo); } -esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t tmo) +esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t usr_tmo) { + esp_apptrace_tmo_t tmo; //TODO: use ptr to HW transport iface struct - esp_err_t (*apptrace_flush)(uint32_t, uint32_t); + esp_err_t (*apptrace_flush)(uint32_t, esp_apptrace_tmo_t *); if (dest == ESP_APPTRACE_DEST_TRAX) { #if CONFIG_ESP32_APPTRACE_DEST_TRAX @@ -1054,20 +1121,23 @@ esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, u return ESP_ERR_NOT_SUPPORTED; } - return apptrace_flush(min_sz, tmo); + esp_apptrace_tmo_init(&tmo, usr_tmo); + return apptrace_flush(min_sz, &tmo); } -esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo) +esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t usr_tmo) { int res; + esp_apptrace_tmo_t tmo; + esp_apptrace_tmo_init(&tmo, usr_tmo); res = esp_apptrace_lock(&tmo); if (res != ESP_OK) { ESP_APPTRACE_LOGE("Failed to lock apptrace data (%d)!", res); return res; } - res = esp_apptrace_flush_nolock(dest, 0, tmo); + res = esp_apptrace_flush_nolock(dest, 0, esp_apptrace_tmo_remaining_us(&tmo)); if (res != ESP_OK) { ESP_APPTRACE_LOGE("Failed to flush apptrace data (%d)!", res); } diff --git a/components/app_trace/app_trace_util.c b/components/app_trace/app_trace_util.c index 17fe17093..078bd0d7f 100644 --- a/components/app_trace/app_trace_util.c +++ b/components/app_trace/app_trace_util.c @@ -17,38 +17,39 @@ #include "esp_app_trace_util.h" /////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// LOCK //////////////////////////////////////// +///////////////////////////////// TIMEOUT ///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -#define ESP_TEST_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000)) +// TODO: get actual clock from PLL config +#define ESP_APPTRACE_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000)) esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo) { - unsigned cur, elapsed; - - if (tmo->tmo != 0xFFFFFFFF) { - cur = portGET_RUN_TIME_COUNTER_VALUE(); + if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) { + unsigned cur = portGET_RUN_TIME_COUNTER_VALUE(); if (tmo->start <= cur) { - elapsed = cur - tmo->start; + tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start); } else { - elapsed = 0xFFFFFFFF - tmo->start + cur; + tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur); } - if (ESP_TEST_CPUTICKS2US(elapsed) >= tmo->tmo) { + if (tmo->elapsed >= tmo->tmo) { return ESP_ERR_TIMEOUT; } } return ESP_OK; } -esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, uint32_t tmo) +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////// LOCK //////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo) { uint32_t res; #if CONFIG_SYSVIEW_ENABLE uint32_t recCnt; #endif - esp_apptrace_tmo_t sleeping_tmo; - esp_apptrace_tmo_init(&sleeping_tmo, tmo); while (1) { res = (xPortGetCoreID() << portMUX_VAL_SHIFT) | portMUX_MAGIC_VAL; // first disable IRQs on this CPU, this will prevent current task from been @@ -77,7 +78,7 @@ esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, uint32_t tmo) // if mux is locked by other task/ISR enable IRQs and let other guys work portEXIT_CRITICAL_NESTED(irq_stat); - int err = esp_apptrace_tmo_check(&sleeping_tmo); + int err = esp_apptrace_tmo_check(tmo); if (err != ESP_OK) { return err; } @@ -205,3 +206,19 @@ uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb) } return size; } + +uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb) +{ + uint32_t size = 0; + if (rb->rd <= rb->wr) { + // |?R......W??| + size = rb->size - rb->wr; + if (size && rb->rd == 0) { + size--; + } + } else { + // |?W......R??| + size = rb->rd - rb->wr - 1; + } + return size; +} diff --git a/components/app_trace/include/esp_app_trace.h b/components/app_trace/include/esp_app_trace.h index d043f3935..aa35ea6a5 100644 --- a/components/app_trace/include/esp_app_trace.h +++ b/components/app_trace/include/esp_app_trace.h @@ -16,10 +16,7 @@ #include #include "esp_err.h" -#include "freertos/portmacro.h" - -/** Infinite waiting timeout */ -#define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1) +#include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE /** * Application trace data destinations bits. @@ -38,6 +35,16 @@ typedef enum { */ esp_err_t esp_apptrace_init(); +/** + * @brief Configures down buffer. + * @note Needs to be called before initiating any data transfer using esp_apptrace_buffer_get and esp_apptrace_write. + * This function does not protect internal data by lock. + * + * @param buf Address of buffer to use for down channel (host to target) data. + * @param size Size of the buffer. + */ +void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size); + /** * @brief Allocates buffer for trace data. * After data in buffer are ready to be sent off esp_apptrace_buffer_put must be called to indicate it. @@ -48,11 +55,11 @@ esp_err_t esp_apptrace_init(); * * @return non-NULL on success, otherwise NULL. */ -uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, size_t size, uint32_t tmo); +uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t tmo); /** * @brief Indicates that the data in buffer are ready to be sent off. - * This function is a counterpart of must be preceeded by esp_apptrace_buffer_get. + * This function is a counterpart of and must be preceeded by esp_apptrace_buffer_get. * * @param dest Indicates HW interface to send data. Should be identical to the same parameter in call to esp_apptrace_buffer_get. * @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_buffer_get. @@ -72,7 +79,7 @@ esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32 * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, size_t size, uint32_t tmo); +esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t tmo); /** * @brief vprintf-like function to sent log messages to host via specified HW interface. @@ -128,7 +135,30 @@ esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, u * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *data, size_t *size, uint32_t tmo); +esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *data, uint32_t *size, uint32_t tmo); +/** + * @brief Rertrieves incoming data buffer if any. + * After data in buffer are processed esp_apptrace_down_buffer_put must be called to indicate it. + * + * @param dest Indicates HW interface to receive data. + * @param size Address to store size of available data in down buffer. Must be initializaed with requested value. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return non-NULL on success, otherwise NULL. + */ +uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t tmo); + +/** + * @brief Indicates that the data in down buffer are processesd. + * This function is a counterpart of and must be preceeded by esp_apptrace_down_buffer_get. + * + * @param dest Indicates HW interface to receive data. Should be identical to the same parameter in call to esp_apptrace_down_buffer_get. + * @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_down_buffer_get. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * + * @return ESP_OK on success, otherwise see esp_err_t + */ +esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo); #endif diff --git a/components/app_trace/include/esp_app_trace_util.h b/components/app_trace/include/esp_app_trace_util.h index 83359b8b2..979337869 100644 --- a/components/app_trace/include/esp_app_trace_util.h +++ b/components/app_trace/include/esp_app_trace_util.h @@ -14,9 +14,49 @@ #ifndef ESP_APP_TRACE_UTIL_H_ #define ESP_APP_TRACE_UTIL_H_ -#include "freertos/portmacro.h" +#include "freertos/FreeRTOS.h" #include "esp_err.h" +/** Infinite waiting timeout */ +#define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1) + +/** Structure which holds data necessary for measuring time intervals. + * + * After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check() + * periodically to check timeout for expiration. + */ +typedef struct { + uint32_t start; ///< time interval start (in CPU ticks) + uint32_t tmo; ///< timeout value (in us) + uint32_t elapsed; ///< elapsed time (in us) +} esp_apptrace_tmo_t; + +/** + * @brief Initializes timeout structure. + * + * @param tmo Pointer to timeout structure to be initialized. + * @param user_tmo Timeout value (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. +*/ +static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_tmo) +{ + tmo->start = portGET_RUN_TIME_COUNTER_VALUE(); + tmo->tmo = user_tmo; +} + +/** + * @brief Checks timeout for expiration. + * + * @param tmo Pointer to timeout structure to be initialized. + * + * @return ESP_OK on success, otherwise \see esp_err_t + */ +esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo); + +static inline uint32_t esp_apptrace_tmo_remaining_us(esp_apptrace_tmo_t *tmo) +{ + return tmo->tmo != ESP_APPTRACE_TMO_INFINITE ? (tmo->elapsed - tmo->tmo) : ESP_APPTRACE_TMO_INFINITE; +} + /** Tracing module synchronization lock */ typedef struct { volatile unsigned int irq_stat; ///< local (on 1 CPU) IRQ state @@ -38,11 +78,11 @@ static inline void esp_apptrace_lock_init(esp_apptrace_lock_t *lock) * @brief Tries to acquire lock in specified time period. * * @param lock Pointer to lock structure. - * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * @param tmo Pointer to timeout struct. * * @return ESP_OK on success, otherwise \see esp_err_t */ -esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, uint32_t tmo); +esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo); /** * @brief Releases lock. @@ -53,39 +93,6 @@ esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, uint32_t tmo); */ esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock); - -/** Structure which holds data necessary for measuring time intervals. - * - * After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check() - * periodically to check timeout for expiration. - */ -typedef struct { - uint32_t start; ///< time interval start (in ticks) - uint32_t tmo; ///< timeout value (in us) -} esp_apptrace_tmo_t; - -/** - * @brief Initializes timeout structure. - * - * @param tmo Pointer to timeout structure to be initialized. - * @param user_tmo Timeout value (in us). -*/ -static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_tmo) -{ - tmo->start = portGET_RUN_TIME_COUNTER_VALUE(); - tmo->tmo = user_tmo; -} - -/** - * @brief Checks timeout for expiration. - * - * @param tmo Pointer to timeout structure to be initialized. - * - * @return ESP_OK on success, otherwise \see esp_err_t - */ -esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo); - - /** Ring buffer control structure. * * @note For purposes of application tracing module if there is no enough space for user data and write pointer can be wrapped @@ -93,10 +100,10 @@ esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo); */ typedef struct { uint8_t *data; ///< pointer to data storage - uint32_t size; ///< size of data storage - uint32_t cur_size; ///< current size of data storage - uint32_t rd; ///< read pointer - uint32_t wr; ///< write pointer + volatile uint32_t size; ///< size of data storage + volatile uint32_t cur_size; ///< current size of data storage + volatile uint32_t rd; ///< read pointer + volatile uint32_t wr; ///< write pointer } esp_apptrace_rb_t; /** @@ -145,4 +152,15 @@ uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size); */ uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb); +/** + * @brief Gets size of memory which can produced with single call to esp_apptrace_rb_produce(). + * + * @param rb Pointer to ring buffer structure. + * + * @return Size of memory which can produced. + * + * @note Due to write pointer wrapping returned size can be less then the total size of available data. + */ +uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb); + #endif //ESP_APP_TRACE_UTIL_H_ \ No newline at end of file diff --git a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c b/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c index aa018f507..52bc27d06 100644 --- a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c +++ b/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c @@ -322,7 +322,9 @@ void SEGGER_SYSVIEW_X_RTT_Unlock() void SEGGER_SYSVIEW_X_SysView_Lock() { - esp_apptrace_lock_take(&s_sys_view_lock, SEGGER_LOCK_WAIT_TMO); + esp_apptrace_tmo_t tmo; + esp_apptrace_tmo_init(&tmo, SEGGER_LOCK_WAIT_TMO); + esp_apptrace_lock_take(&s_sys_view_lock, &tmo); } void SEGGER_SYSVIEW_X_SysView_Unlock() diff --git a/components/app_trace/sys_view/esp32/SEGGER_RTT_esp32.c b/components/app_trace/sys_view/esp32/SEGGER_RTT_esp32.c index 795af78da..fd674bbb6 100644 --- a/components/app_trace/sys_view/esp32/SEGGER_RTT_esp32.c +++ b/components/app_trace/sys_view/esp32/SEGGER_RTT_esp32.c @@ -36,11 +36,14 @@ const static char *TAG = "segger_rtt"; #endif #endif -#define SEGGER_HOST_WAIT_TMO 500 //us -#define SEGGER_STOP_WAIT_TMO 1000000 //us +// size of down channel data buf +#define SYSVIEW_DOWN_BUF_SIZE 32 +#define SEGGER_HOST_WAIT_TMO 500 //us +#define SEGGER_STOP_WAIT_TMO 1000000 //us static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ]; static uint16_t s_events_buf_filled; +static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE]; /********************************************************************* * @@ -216,6 +219,7 @@ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBu * Buffer name and flags can be reconfigured using the appropriate functions. */ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + esp_apptrace_down_buffer_config(s_down_buf, sizeof(s_down_buf)); return 0; } diff --git a/components/log/README.rst b/components/log/README.rst index f732a9e90..83db32ea6 100644 --- a/components/log/README.rst +++ b/components/log/README.rst @@ -120,7 +120,7 @@ To use logging via JTAG user needs to perform the following steps: 2. Build the program image and download it to target as described in :idf:`Developing With the ESP-IDF` section. 3. Run OpenOCD (see :idf:`OpenOCD setup for ESP32` section). 4. Connect to OpenOCD telnet server. On Linux it can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use `localhost` as `` in the command. -5. Run the following command in OpenOCD telnet session: ``esp108 apptrace start /path/to/trace/file -1 -1 0 0 1``. This command will wait for board reset and transfer tracing data at the highest possible rate. +5. Run the following command in OpenOCD telnet session: ``esp108 apptrace start /path/to/trace/file 0 -1 -1 1``. This command will wait for board reset and transfer tracing data at the highest possible rate. 6. Reset the board. Logging to host will start automatically. 7. ``esp108 apptrace`` command with given arguments will never return (see other command options below), so you must stop it manually by resetting the board or pressing CTRL+C in OpenOCD window (not one with the telnet session). 8. Reset board or press CTRL+C in OpenOCD window (not one with the telnet session) when tracing is completed (for the example code above after the message `"Tracing is finished."` appears on UART). diff --git a/components/xtensa-debug-module/eri.c b/components/xtensa-debug-module/eri.c index fc96b531f..869757278 100644 --- a/components/xtensa-debug-module/eri.c +++ b/components/xtensa-debug-module/eri.c @@ -16,7 +16,7 @@ uint32_t eri_read(int addr) { uint32_t ret; - asm( + asm volatile ( "RER %0,%1" :"=r"(ret):"r"(addr) ); diff --git a/docs/api-guides/app_trace.rst b/docs/api-guides/app_trace.rst index 0c72ec9d9..c8e54a614 100644 --- a/docs/api-guides/app_trace.rst +++ b/docs/api-guides/app_trace.rst @@ -13,7 +13,7 @@ Developers can use this library to send application specific state of execution Tracing components when working over JTAG interface are shown in the figure below. -.. figure:: ../_static/app_trace/overview.png +.. figure:: ../_static/app_trace/overview.jpg :align: center :alt: Tracing Components when Working Over JTAG :figclass: align-center @@ -80,13 +80,13 @@ In general user should decide what type of data should be transferred in every d #include "esp_app_trace.h" ... int number = 10; - char *ptr = (char *)esp_apptrace_buffer_get(32, 100/*tmo in us*/); + char *ptr = (char *)esp_apptrace_buffer_get(ESP_APPTRACE_DEST_TRAX, 32, 100/*tmo in us*/); if (ptr == NULL) { ESP_LOGE("Failed to get buffer!"); return ESP_FAIL; } sprintf(ptr, "Here is the number %d", number); - esp_err_t res = esp_apptrace_buffer_put(ptr, 100/*tmo in us*/); + esp_err_t res = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_TRAX, ptr, 100/*tmo in us*/); if (res != ESP_OK) { /* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */ ESP_LOGE("Failed to put buffer!"); @@ -100,7 +100,11 @@ Also according to his needs user may want to receive data from the host. Piece o #include "esp_app_trace.h" ... char buf[32]; + char down_buf[32]; size_t sz = sizeof(buf); + + /* config down buffer */ + esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); /* check for incoming data and read them if any */ esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_TRAX, buf, &sz, 0/*do not wait*/); if (res != ESP_OK) { @@ -112,6 +116,37 @@ Also according to his needs user may want to receive data from the host. Piece o ... } +``esp_apptrace_read()`` function uses memcpy to copy host data to user buffer. In some cases it can be more optimal to use ``esp_apptrace_down_buffer_get()`` and ``esp_apptrace_down_buffer_put()`` functions. +They allow developers to ocupy chunk of read buffer and process it in-place. The following piece of code shows how to do this. + +.. code-block:: c + + #include "esp_app_trace.h" + ... + char down_buf[32]; + uint32_t *number; + size_t sz = 32; + + /* config down buffer */ + esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); + char *ptr = (char *)esp_apptrace_down_buffer_get(ESP_APPTRACE_DEST_TRAX, &sz, 100/*tmo in us*/); + if (ptr == NULL) { + ESP_LOGE("Failed to get buffer!"); + return ESP_FAIL; + } + if (sz > 4) { + number = (uint32_t *)ptr; + printf("Here is the number %d", *number); + } else { + printf("No data"); + } + esp_err_t res = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_TRAX, ptr, 100/*tmo in us*/); + if (res != ESP_OK) { + /* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */ + ESP_LOGE("Failed to put buffer!"); + return res; + } + 2. The next step is to build the program image and download it to the target as described in :doc:`Build and Flash <../get-started/make-project>`. 3. Run OpenOCD (see :doc:`Debugging <../api-guides/openocd>`). 4. Connect to OpenOCD telnet server. On Linux it can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use ``localhost`` as ```` in the command above. @@ -151,7 +186,7 @@ Sub-commands: Start command syntax: - ``start [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]`` + ``start [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]`` .. list-table:: :widths: 20 80 @@ -159,10 +194,8 @@ Start command syntax: * - Argument - Description - * - outfile1 - - Path to file to save data from PRO CPU. This argument should have the following format: ``file://path/to/file``. - * - outfile2 - - Path to file to save data from APP CPU. This argument should have the following format: ``file://path/to/file``. + * - outfile + - Path to file to save data from both CPUs. This argument should have the following format: ``file://path/to/file``. * - poll_period - Data polling period (in ms). If greater then 0 then command runs in non-blocking mode. By default 1 ms. * - trace_size diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index 29be2173d..43ffa272b 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -88,7 +88,9 @@ CONFIG_APP_OFFSET=0x10000 # CONFIG_OPTIMIZATION_LEVEL_DEBUG=y # CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set -CONFIG_OPTIMIZATION_ASSERTIONS=y +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set # # Component config @@ -100,6 +102,7 @@ CONFIG_OPTIMIZATION_ASSERTIONS=y # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set CONFIG_ESP32_APPTRACE_DEST_NONE=y # CONFIG_ESP32_APPTRACE_ENABLE is not set +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y # # FreeRTOS SystemView Tracing @@ -149,6 +152,16 @@ CONFIG_INT_WDT=y CONFIG_INT_WDT_TIMEOUT_MS=300 CONFIG_INT_WDT_CHECK_CPU1=y # CONFIG_TASK_WDT is not set +CONFIG_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL=0 # CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y # CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set @@ -227,6 +240,7 @@ CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y # CONFIG_FREERTOS_ASSERT_DISABLE is not set CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y # CONFIG_ENABLE_MEMORY_DEBUG is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 CONFIG_FREERTOS_ISR_STACKSIZE=1536 # CONFIG_FREERTOS_LEGACY_HOOKS is not set CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16