esp32: Apptrace API enhancement

- User down buffer configuration support
 - bugfix: ring buf - avalable write size undeflow
 - SysView down buf support updated
This commit is contained in:
Alexey Gerenkov 2017-07-24 19:57:44 +03:00
parent d515eeac6a
commit c2c9149a24
11 changed files with 388 additions and 194 deletions

View file

@ -22,6 +22,12 @@ config ESP32_APPTRACE_ENABLE
help help
Enables/disable application tracing module. 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 config ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO
int "Timeout for flushing last trace data to host on panic" int "Timeout for flushing last trace data to host on panic"
depends on ESP32_APPTRACE_ENABLE depends on ESP32_APPTRACE_ENABLE

View file

@ -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 // 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 // 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. // 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 // 4.3 Data Buffering
// ------------------ // ------------------
@ -159,14 +160,10 @@
#include "soc/dport_reg.h" #include "soc/dport_reg.h"
#include "eri.h" #include "eri.h"
#include "trax.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_struct.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include "freertos/FreeRTOS.h"
#include "esp_app_trace.h" #include "esp_app_trace.h"
#include "esp_app_trace_util.h"
#if CONFIG_ESP32_APPTRACE_ENABLE #if CONFIG_ESP32_APPTRACE_ENABLE
#define ESP_APPTRACE_MAX_VPRINTF_ARGS 256 #define ESP_APPTRACE_MAX_VPRINTF_ARGS 256
@ -174,7 +171,7 @@
#define ESP_APPTRACE_PRINT_LOCK 0 #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" #include "esp_log.h"
const static char *TAG = "esp_apptrace"; 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_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_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() (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_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]) #define ESP_APPTRACE_TRAX_INBLOCK_GET() (&s_trace_buf.trax.blocks[s_trace_buf.trax.state.in_block % 2])
//TODO: menuconfig #define ESP_APPTRACE_TRAX_BLOCK_SIZE (0x4000UL)
#define ESP_APPTRACE_DOWN_BUF_SIZE 32UL
#if CONFIG_SYSVIEW_ENABLE #if CONFIG_SYSVIEW_ENABLE
#define ESP_APPTRACE_USR_DATA_LEN_MAX 255UL #define ESP_APPTRACE_USR_DATA_LEN_MAX 255UL
#else #else
@ -324,7 +317,6 @@ typedef struct {
// ring buffer control struct for data from host (down buffer) // ring buffer control struct for data from host (down buffer)
esp_apptrace_rb_t rb_down; esp_apptrace_rb_t rb_down;
// storage for above ring buffer data // 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_trax_data_t trax; // TRAX HW transport data
} esp_apptrace_buffer_t; } 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}; static esp_apptrace_lock_t s_log_lock = {.irq_stat = 0, .portmux = portMUX_INITIALIZER_UNLOCKED};
#endif #endif
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);
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);
static inline int esp_apptrace_log_lock() static inline int esp_apptrace_log_lock()
{ {
#if ESP_APPTRACE_PRINT_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; return ret;
#else #else
return 0; return 0;
@ -354,40 +348,40 @@ static inline void esp_apptrace_log_unlock()
#endif #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); esp_apptrace_lock_init(&s_trace_buf.lock);
#endif #endif
return ESP_OK; return ESP_OK;
} }
esp_err_t inline esp_apptrace_lock_cleanup() static inline esp_err_t esp_apptrace_lock_cleanup()
{ {
return ESP_OK; 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 #if CONFIG_ESP32_APPTRACE_LOCK_ENABLE
unsigned cur, elapsed, start = xthal_get_ccount(); //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) { if (ret != ESP_OK) {
return ESP_FAIL; return ESP_FAIL;
} }
// decrease tmo by actual waiting time // decrease tmo by actual waiting time
cur = xthal_get_ccount(); // cur = xthal_get_ccount();
if (start <= cur) { // if (start <= cur) {
elapsed = cur - start; // elapsed = cur - start;
} else { // } else {
elapsed = ULONG_MAX - start + cur; // elapsed = ULONG_MAX - start + cur;
} // }
if (ESP_APPTRACE_CPUTICKS2US(elapsed) > *tmo) { // if (ESP_APPTRACE_CPUTICKS2US(elapsed) > *tmo) {
*tmo = 0; // *tmo = 0;
} else { // } else {
*tmo -= ESP_APPTRACE_CPUTICKS2US(elapsed); // *tmo -= ESP_APPTRACE_CPUTICKS2US(elapsed);
} // }
#endif #endif
return ESP_OK; 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 esp_apptrace_unlock()
{ {
esp_err_t ret = ESP_OK; 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); ret = esp_apptrace_lock_give(&s_trace_buf.lock);
#endif #endif
return ret; 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); 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)) { 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, 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; res = ESP_ERR_NO_MEM;
goto _on_func_exit; 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) { 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 // 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; 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+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)); *(s_trace_buf.trax.blocks[new_block_num].start+2), *(s_trace_buf.trax.blocks[new_block_num].start+3),
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+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) { 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; hdr->block_sz = 0;
} }
@ -548,15 +546,12 @@ _on_func_exit:
return res; 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; int res;
esp_apptrace_tmo_t sleeping_tmo;
esp_apptrace_tmo_init(&sleeping_tmo, tmo);
while ((res = esp_apptrace_trax_block_switch()) != ESP_OK) { 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) { if (res != ESP_OK) {
break; break;
} }
@ -564,58 +559,79 @@ static esp_err_t esp_apptrace_trax_block_switch_waitus(uint32_t tmo)
return res; 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); int res = esp_apptrace_lock(tmo);
if (res != ESP_OK) { if (res != ESP_OK) {
return NULL; return NULL;
} }
while (1) {
// may need to flush uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down);
uint32_t ctrl_reg = eri_read(ESP_APPTRACE_TRAX_CTRL_REG); if (sz != 0) {
if (ctrl_reg & ESP_APPTRACE_TRAX_HOST_DATA) { ptr = esp_apptrace_rb_consume(&s_trace_buf.rb_down, sz > *size ? *size : sz);
ESP_APPTRACE_LOGD("force flush"); if (!ptr) {
res = esp_apptrace_trax_block_switch_waitus(*tmo); assert(false && "Failed to consume bytes from down buffer!");
if (res != ESP_OK) { }
ESP_APPTRACE_LOGE("Failed to switch to another block to recv data from host!"); *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) { if (esp_apptrace_unlock() != ESP_OK) {
assert(false && "Failed to unlock apptrace data!"); assert(false && "Failed to unlock apptrace data!");
} }
return ptr; 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 */ /* nothing todo */
return ESP_OK; 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); uint32_t total_sz = 0;
if (ptr) {
memcpy(ptr, data, size); while (total_sz < size) {
} else { // 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,
return 0; // 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) 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); 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; 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; 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; 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)); buf_ptr = esp_apptrace_rb_produce(&s_trace_buf.trax.rb_pend, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size));
if (buf_ptr == NULL) { if (buf_ptr == NULL) {
int pended_buf; 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 (buf_ptr) {
if (pended_buf) { if (pended_buf) {
#if CONFIG_ESP32_APPTRACE_PENDING_DATA_SIZE_MAX > ESP_APPTRACE_TRAX_BLOCK_SIZE #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)); esp_apptrace_trax_pend_chunk_sz_update(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size));
#endif #endif
} else { } 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 // update cur block marker
ESP_APPTRACE_TRAX_INBLOCK_MARKER_UPD(ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); 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) { if (buf_ptr == NULL) {
int pended_buf; int pended_buf;
ESP_APPTRACE_LOGD("TRAX full. Get %d bytes from pend buffer", size); 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 (buf_ptr) {
if (pended_buf) { if (pended_buf) {
#if CONFIG_ESP32_APPTRACE_PENDING_DATA_SIZE_MAX > ESP_APPTRACE_TRAX_BLOCK_SIZE #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 { } 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 // fit to curr TRAX nlock
buf_ptr = ESP_APPTRACE_TRAX_INBLOCK_GET()->start + ESP_APPTRACE_TRAX_INBLOCK_MARKER(); buf_ptr = ESP_APPTRACE_TRAX_INBLOCK_GET()->start + ESP_APPTRACE_TRAX_INBLOCK_MARKER();
// update cur block 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; 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; int res = ESP_OK;
esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)(ptr - sizeof(esp_tracedata_hdr_t)); 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; 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; 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 // switch TRAX block while size of data is more than min size
while (ESP_APPTRACE_TRAX_INBLOCK_MARKER() > 0) { 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); res = esp_apptrace_trax_block_switch_waitus(tmo);
if (res != ESP_OK) { if (res != ESP_OK) {
ESP_APPTRACE_LOGE("Failed to switch to another block!"); 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)); sizeof(s_trace_buf.trax.pending_chunk_sz));
#endif #endif
#endif #endif
esp_apptrace_trax_down_buf_init();
DPORT_WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, DPORT_PRO_TRACEMEM_ENA_M); DPORT_WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, DPORT_PRO_TRACEMEM_ENA_M);
#if CONFIG_FREERTOS_UNICORE == 0 #if CONFIG_FREERTOS_UNICORE == 0
@ -849,25 +864,31 @@ esp_err_t esp_apptrace_init()
esp_apptrace_trax_init(); esp_apptrace_trax_init();
#endif #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 s_trace_buf.inited |= 1 << xPortGetCoreID(); // global and this CPU-specific data are inited
return ESP_OK; 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; int res = ESP_OK;
esp_apptrace_tmo_t sleeping_tmo; esp_apptrace_tmo_t tmo;
//TODO: use ptr to HW transport iface struct //TODO: use ptr to HW transport iface struct
uint8_t *(*apptrace_get_down_buffer)(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 *, uint32_t , uint32_t *); esp_err_t (*apptrace_put_down_buffer)(uint8_t *, esp_apptrace_tmo_t *);
if (dest == ESP_APPTRACE_DEST_TRAX) { if (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_APPTRACE_DEST_TRAX #if CONFIG_ESP32_APPTRACE_DEST_TRAX
apptrace_get_down_buffer = esp_apptrace_trax_get_down_rdptr; apptrace_get_down_buffer = esp_apptrace_trax_down_buffer_get;
apptrace_put_down_buffer = esp_apptrace_trax_put_down_rdptr; apptrace_put_down_buffer = esp_apptrace_trax_down_buffer_put;
#else #else
ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!"); ESP_APPTRACE_LOGE("Application tracing via TRAX is disabled in menuconfig!");
return ESP_ERR_NOT_SUPPORTED; 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 //TODO: callback system
esp_apptrace_tmo_init(&sleeping_tmo, tmo); esp_apptrace_tmo_init(&tmo, user_tmo);
uint32_t act_sz = *size; uint32_t act_sz = *size;
while ((ptr = apptrace_get_down_buffer(&act_sz, &tmo)) == NULL ) { *size = 0;
res = esp_apptrace_tmo_check(&sleeping_tmo); uint8_t * ptr = apptrace_get_down_buffer(&act_sz, &tmo);
if (res != ESP_OK) {
break;
}
}
if (ptr && act_sz > 0) { if (ptr && act_sz > 0) {
ESP_APPTRACE_LOGD("Read %d bytes from host", act_sz); ESP_APPTRACE_LOGD("Read %d bytes from host", act_sz);
memcpy(buf, ptr, 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; *size = act_sz;
} }
return res; 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; uint8_t *ptr = NULL;
uint32_t tmo = user_tmo; esp_apptrace_tmo_t tmo;
//TODO: use ptr to HW transport iface struct //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 *);
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 (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_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; return ESP_ERR_NOT_SUPPORTED;
} }
esp_apptrace_tmo_init(&tmo, user_tmo);
ptr = apptrace_get_buffer(size, &tmo); ptr = apptrace_get_buffer(size, &tmo);
if (ptr == NULL) { if (ptr == NULL) {
return ESP_ERR_NO_MEM; 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; uint16_t nargs = 0;
uint8_t *pout, *p = (uint8_t *)fmt; 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 //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 *);
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 (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_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; return ESP_ERR_NOT_SUPPORTED;
} }
esp_apptrace_tmo_init(&tmo, user_tmo);
ESP_APPTRACE_LOGD("fmt %x", fmt); ESP_APPTRACE_LOGD("fmt %x", fmt);
while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) { while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) {
p++; 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); 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 //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 (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_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; return NULL;
} }
esp_apptrace_tmo_init(&tmo, user_tmo);
return apptrace_get_buffer(size, &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) 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 //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 (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_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; return ESP_ERR_NOT_SUPPORTED;
} }
esp_apptrace_tmo_init(&tmo, user_tmo);
return apptrace_put_buffer(ptr, &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 //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 (dest == ESP_APPTRACE_DEST_TRAX) {
#if CONFIG_ESP32_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 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; int res;
esp_apptrace_tmo_t tmo;
esp_apptrace_tmo_init(&tmo, usr_tmo);
res = esp_apptrace_lock(&tmo); res = esp_apptrace_lock(&tmo);
if (res != ESP_OK) { if (res != ESP_OK) {
ESP_APPTRACE_LOGE("Failed to lock apptrace data (%d)!", res); ESP_APPTRACE_LOGE("Failed to lock apptrace data (%d)!", res);
return 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) { if (res != ESP_OK) {
ESP_APPTRACE_LOGE("Failed to flush apptrace data (%d)!", res); ESP_APPTRACE_LOGE("Failed to flush apptrace data (%d)!", res);
} }

View file

@ -17,38 +17,39 @@
#include "esp_app_trace_util.h" #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) esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo)
{ {
unsigned cur, elapsed; if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) {
unsigned cur = portGET_RUN_TIME_COUNTER_VALUE();
if (tmo->tmo != 0xFFFFFFFF) {
cur = portGET_RUN_TIME_COUNTER_VALUE();
if (tmo->start <= cur) { if (tmo->start <= cur) {
elapsed = cur - tmo->start; tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start);
} else { } 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_ERR_TIMEOUT;
} }
} }
return ESP_OK; 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; uint32_t res;
#if CONFIG_SYSVIEW_ENABLE #if CONFIG_SYSVIEW_ENABLE
uint32_t recCnt; uint32_t recCnt;
#endif #endif
esp_apptrace_tmo_t sleeping_tmo;
esp_apptrace_tmo_init(&sleeping_tmo, tmo);
while (1) { while (1) {
res = (xPortGetCoreID() << portMUX_VAL_SHIFT) | portMUX_MAGIC_VAL; res = (xPortGetCoreID() << portMUX_VAL_SHIFT) | portMUX_MAGIC_VAL;
// first disable IRQs on this CPU, this will prevent current task from been // 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 // if mux is locked by other task/ISR enable IRQs and let other guys work
portEXIT_CRITICAL_NESTED(irq_stat); portEXIT_CRITICAL_NESTED(irq_stat);
int err = esp_apptrace_tmo_check(&sleeping_tmo); int err = esp_apptrace_tmo_check(tmo);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
@ -205,3 +206,19 @@ uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb)
} }
return size; 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;
}

View file

@ -16,10 +16,7 @@
#include <stdarg.h> #include <stdarg.h>
#include "esp_err.h" #include "esp_err.h"
#include "freertos/portmacro.h" #include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE
/** Infinite waiting timeout */
#define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1)
/** /**
* Application trace data destinations bits. * Application trace data destinations bits.
@ -38,6 +35,16 @@ typedef enum {
*/ */
esp_err_t esp_apptrace_init(); 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. * @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. * 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. * @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. * @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 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. * @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 * @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. * @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 * @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 #endif

View file

@ -14,9 +14,49 @@
#ifndef ESP_APP_TRACE_UTIL_H_ #ifndef ESP_APP_TRACE_UTIL_H_
#define ESP_APP_TRACE_UTIL_H_ #define ESP_APP_TRACE_UTIL_H_
#include "freertos/portmacro.h" #include "freertos/FreeRTOS.h"
#include "esp_err.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 */ /** Tracing module synchronization lock */
typedef struct { typedef struct {
volatile unsigned int irq_stat; ///< local (on 1 CPU) IRQ state 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. * @brief Tries to acquire lock in specified time period.
* *
* @param lock Pointer to lock structure. * @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 * @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. * @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); 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. /** 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 * @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 { typedef struct {
uint8_t *data; ///< pointer to data storage uint8_t *data; ///< pointer to data storage
uint32_t size; ///< size of data storage volatile uint32_t size; ///< size of data storage
uint32_t cur_size; ///< current size of data storage volatile uint32_t cur_size; ///< current size of data storage
uint32_t rd; ///< read pointer volatile uint32_t rd; ///< read pointer
uint32_t wr; ///< write pointer volatile uint32_t wr; ///< write pointer
} esp_apptrace_rb_t; } 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); 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_ #endif //ESP_APP_TRACE_UTIL_H_

View file

@ -322,7 +322,9 @@ void SEGGER_SYSVIEW_X_RTT_Unlock()
void SEGGER_SYSVIEW_X_SysView_Lock() 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() void SEGGER_SYSVIEW_X_SysView_Unlock()

View file

@ -36,11 +36,14 @@ const static char *TAG = "segger_rtt";
#endif #endif
#endif #endif
#define SEGGER_HOST_WAIT_TMO 500 //us // size of down channel data buf
#define SEGGER_STOP_WAIT_TMO 1000000 //us #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 uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
static uint16_t s_events_buf_filled; 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. * 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) { 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; return 0;
} }

View file

@ -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. 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). 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 <oocd_host> 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use `localhost` as `<oocd_host>` in the command. 4. Connect to OpenOCD telnet server. On Linux it can be done using the following command in terminal ``telnet <oocd_host> 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use `localhost` as `<oocd_host>` 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. 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). 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). 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).

View file

@ -16,7 +16,7 @@
uint32_t eri_read(int addr) { uint32_t eri_read(int addr) {
uint32_t ret; uint32_t ret;
asm( asm volatile (
"RER %0,%1" "RER %0,%1"
:"=r"(ret):"r"(addr) :"=r"(ret):"r"(addr)
); );

View file

@ -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. 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 :align: center
:alt: Tracing Components when Working Over JTAG :alt: Tracing Components when Working Over JTAG
:figclass: align-center :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" #include "esp_app_trace.h"
... ...
int number = 10; 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) { if (ptr == NULL) {
ESP_LOGE("Failed to get buffer!"); ESP_LOGE("Failed to get buffer!");
return ESP_FAIL; return ESP_FAIL;
} }
sprintf(ptr, "Here is the number %d", number); 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) { if (res != ESP_OK) {
/* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */ /* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */
ESP_LOGE("Failed to put 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" #include "esp_app_trace.h"
... ...
char buf[32]; char buf[32];
char down_buf[32];
size_t sz = sizeof(buf); 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 */ /* 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*/); esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_TRAX, buf, &sz, 0/*do not wait*/);
if (res != ESP_OK) { 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>`. 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>`). 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 <oocd_host> 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use ``localhost`` as ``<oocd_host>`` in the command above. 4. Connect to OpenOCD telnet server. On Linux it can be done using the following command in terminal ``telnet <oocd_host> 4444``. If telnet session is opened on the same machine which runs OpenOCD you can use ``localhost`` as ``<oocd_host>`` in the command above.
@ -151,7 +186,7 @@ Sub-commands:
Start command syntax: Start command syntax:
``start <outfile1> [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]`` ``start <outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]``
.. list-table:: .. list-table::
:widths: 20 80 :widths: 20 80
@ -159,10 +194,8 @@ Start command syntax:
* - Argument * - Argument
- Description - Description
* - outfile1 * - outfile
- Path to file to save data from PRO CPU. This argument should have the following format: ``file://path/to/file``. - Path to file to save data from both CPUs. 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``.
* - poll_period * - poll_period
- Data polling period (in ms). If greater then 0 then command runs in non-blocking mode. By default 1 ms. - Data polling period (in ms). If greater then 0 then command runs in non-blocking mode. By default 1 ms.
* - trace_size * - trace_size

View file

@ -88,7 +88,9 @@ CONFIG_APP_OFFSET=0x10000
# #
CONFIG_OPTIMIZATION_LEVEL_DEBUG=y CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set # 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 # Component config
@ -100,6 +102,7 @@ CONFIG_OPTIMIZATION_ASSERTIONS=y
# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
CONFIG_ESP32_APPTRACE_DEST_NONE=y CONFIG_ESP32_APPTRACE_DEST_NONE=y
# CONFIG_ESP32_APPTRACE_ENABLE is not set # CONFIG_ESP32_APPTRACE_ENABLE is not set
CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
# #
# FreeRTOS SystemView Tracing # FreeRTOS SystemView Tracing
@ -149,6 +152,16 @@ CONFIG_INT_WDT=y
CONFIG_INT_WDT_TIMEOUT_MS=300 CONFIG_INT_WDT_TIMEOUT_MS=300
CONFIG_INT_WDT_CHECK_CPU1=y CONFIG_INT_WDT_CHECK_CPU1=y
# CONFIG_TASK_WDT is not set # 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 is not set
CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set # 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_ASSERT_DISABLE is not set
CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y
# CONFIG_ENABLE_MEMORY_DEBUG is not set # CONFIG_ENABLE_MEMORY_DEBUG is not set
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024
CONFIG_FREERTOS_ISR_STACKSIZE=1536 CONFIG_FREERTOS_ISR_STACKSIZE=1536
# CONFIG_FREERTOS_LEGACY_HOOKS is not set # CONFIG_FREERTOS_LEGACY_HOOKS is not set
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16