Skip to content

Commit 845ea49

Browse files
committed
[nrf fromlist] drivers: debug: nrf_etr: Add support for RTT backend
Add option to output STM logging on RTT. Upstream PR #: 100570 Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent e06f5ac commit 845ea49

File tree

2 files changed

+160
-27
lines changed

2 files changed

+160
-27
lines changed

drivers/debug/Kconfig.nrf

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,53 @@ config DEBUG_NRF_ETR
1616

1717
if DEBUG_NRF_ETR
1818

19+
DT_CHOSEN_ZEPHYR_CONSOLE := zephyr,console
20+
21+
config DEBUG_NRF_ETR_BACKEND_UART
22+
default y if $(dt_chosen_enabled,$(DT_CHOSEN_ZEPHYR_CONSOLE))
23+
bool "UART backend"
24+
25+
config DEBUG_NRF_ETR_BACKEND_RTT
26+
bool "RTT backend"
27+
select USE_SEGGER_RTT
28+
select SEGGER_RTT_CUSTOM_LOCKING
29+
30+
if DEBUG_NRF_ETR_BACKEND_RTT
31+
32+
config DEBUG_NRF_ETR_BACKEND_RTT_BUFFER
33+
int "Buffer number used for logger output."
34+
range 0 SEGGER_RTT_MAX_NUM_UP_BUFFERS
35+
default 0
36+
help
37+
Select index of up-buffer used for logger output, by default it uses
38+
terminal up-buffer and its settings.
39+
40+
config DEBUG_NRF_ETR_BACKEND_RTT_BUFFER_SIZE
41+
int "Size of reserved up-buffer for logger output."
42+
default 1024
43+
depends on DEBUG_NRF_ETR_BACKEND_RTT_BUFFER > 0
44+
help
45+
Specify reserved size of up-buffer used for logger output.
46+
47+
config DEBUG_NRF_ETR_BACKEND_RTT_RETRY_CNT
48+
int "Number of retries"
49+
default 4
50+
help
51+
Number of TX retries before dropping the data and assuming that
52+
RTT session is inactive.
53+
54+
config DEBUG_NRF_ETR_BACKEND_RTT_RETRY_DELAY_MS
55+
int "Delay between TX retries in milliseconds"
56+
default 5
57+
help
58+
Sleep period between TX retry attempts. During RTT session, host pulls
59+
data periodically. Period starts from 1-2 milliseconds and can be
60+
increased if traffic on RTT increases (also from host to device). In
61+
case of heavy traffic data can be lost and it may be necessary to
62+
increase delay or number of retries.
63+
64+
endif
65+
1966
config DEBUG_NRF_ETR_DECODE
2067
bool "Decode ETR content"
2168
default y if LOG_FRONTEND_STMESP_FSC
@@ -80,6 +127,7 @@ config DEBUG_NRF_ETR_SHELL
80127
select UART_ASYNC_RX_HELPER
81128
select SHELL_LOG_BACKEND_CUSTOM
82129
depends on DEBUG_NRF_ETR_DECODE
130+
depends on DEBUG_NRF_ETR_BACKEND_UART
83131
default y if SHELL
84132
help
85133
Enable shell with Coresight STM logging support.

drivers/debug/debug_nrf_etr.c

Lines changed: 112 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include <dmm.h>
2323
#include <nrfx_tbm.h>
2424
#include <stdio.h>
25+
26+
#ifdef CONFIG_DEBUG_NRF_ETR_BACKEND_RTT
27+
#include <SEGGER_RTT.h>
28+
#endif
29+
2530
LOG_MODULE_REGISTER(cs_etr_tbm);
2631

2732
#define UART_NODE DT_CHOSEN(zephyr_console)
@@ -79,7 +84,7 @@ static uint32_t etr_rd_idx;
7984
/* Counts number of new messages completed in the current formatter frame decoding. */
8085
static uint32_t new_msg_cnt;
8186

82-
static bool volatile use_async_uart;
87+
static bool volatile use_blocking;
8388

8489
static struct k_sem uart_sem;
8590
static const struct device *uart_dev = DEVICE_DT_GET(UART_NODE);
@@ -149,27 +154,101 @@ static shell_transport_handler_t shell_handler;
149154
static void *shell_context;
150155
#endif
151156

157+
#ifdef CONFIG_DEBUG_NRF_ETR_BACKEND_RTT
158+
159+
#define RTT_LOCK() \
160+
COND_CODE_0(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER, (SEGGER_RTT_LOCK()), ())
161+
162+
#define RTT_UNLOCK() \
163+
COND_CODE_0(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER, (SEGGER_RTT_UNLOCK()), ())
164+
165+
static uint8_t rtt_buf[COND_CODE_0(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER, (1),
166+
(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER_SIZE))];
167+
168+
static volatile bool rtt_host_present;
169+
170+
static void rtt_on_failed_write(int retry_cnt, bool in_panic)
171+
{
172+
if (retry_cnt == 0) {
173+
rtt_host_present = false;
174+
} else if (in_panic) {
175+
k_busy_wait(USEC_PER_MSEC * CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_RETRY_DELAY_MS);
176+
} else {
177+
k_msleep(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_RETRY_DELAY_MS);
178+
}
179+
}
180+
181+
static void rtt_on_write(int retry_cnt, bool in_panic)
182+
{
183+
rtt_host_present = true;
184+
if (use_blocking) {
185+
/* In panic mode block on each write until host reads it. This
186+
* way it is ensured that if system resets all messages are read
187+
* by the host. While pending on data being read by the host we
188+
* must also detect situation where host is disconnected.
189+
*/
190+
while (SEGGER_RTT_HasDataUp(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER)) {
191+
rtt_on_failed_write(retry_cnt--, in_panic);
192+
}
193+
}
194+
195+
}
196+
197+
static void rtt_write(uint8_t *data, size_t length, bool in_panic)
198+
{
199+
int ret = 0;
200+
int retry_cnt = CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_RETRY_CNT;
201+
202+
do {
203+
if (!in_panic) {
204+
RTT_LOCK();
205+
ret = SEGGER_RTT_WriteSkipNoLock(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER,
206+
data, length);
207+
RTT_UNLOCK();
208+
} else {
209+
ret = SEGGER_RTT_WriteSkipNoLock(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER,
210+
data, length);
211+
}
212+
213+
if (ret) {
214+
rtt_on_write(retry_cnt, in_panic);
215+
} else if (rtt_host_present) {
216+
retry_cnt--;
217+
rtt_on_failed_write(retry_cnt, in_panic);
218+
} else {
219+
}
220+
} while ((ret == 0) && rtt_host_present);
221+
}
222+
#endif /* CONFIG_DEBUG_NRF_ETR_BACKEND_RTT */
223+
152224
static int log_output_func(uint8_t *buf, size_t size, void *ctx)
153225
{
154-
if (use_async_uart) {
155-
int err;
156-
static uint8_t *tx_buf = (uint8_t *)frame_buf0;
226+
ARG_UNUSED(ctx);
157227

158-
err = k_sem_take(&uart_sem, K_FOREVER);
159-
__ASSERT_NO_MSG(err >= 0);
228+
if (IS_ENABLED(CONFIG_DEBUG_NRF_ETR_BACKEND_UART)) {
229+
if (use_blocking) {
230+
for (int i = 0; i < size; i++) {
231+
uart_poll_out(uart_dev, buf[i]);
232+
}
233+
} else {
234+
int err;
235+
static uint8_t *tx_buf = (uint8_t *)frame_buf0;
160236

161-
memcpy(tx_buf, buf, size);
237+
err = k_sem_take(&uart_sem, K_FOREVER);
238+
__ASSERT_NO_MSG(err >= 0);
162239

163-
err = uart_tx(uart_dev, tx_buf, size, SYS_FOREVER_US);
164-
__ASSERT_NO_MSG(err >= 0);
240+
memcpy(tx_buf, buf, size);
165241

166-
tx_buf = (tx_buf == (uint8_t *)frame_buf0) ?
167-
(uint8_t *)frame_buf1 : (uint8_t *)frame_buf0;
168-
} else {
169-
for (int i = 0; i < size; i++) {
170-
uart_poll_out(uart_dev, buf[i]);
242+
err = uart_tx(uart_dev, tx_buf, size, SYS_FOREVER_US);
243+
__ASSERT_NO_MSG(err >= 0);
244+
245+
tx_buf = (tx_buf == (uint8_t *)frame_buf0) ?
246+
(uint8_t *)frame_buf1 : (uint8_t *)frame_buf0;
171247
}
172248
}
249+
#ifdef CONFIG_DEBUG_NRF_ETR_BACKEND_RTT
250+
rtt_write(buf, size, use_blocking);
251+
#endif
173252

174253
return size;
175254
}
@@ -528,16 +607,16 @@ static void dump_frame(uint8_t *buf)
528607
{
529608
int err;
530609

531-
if (use_async_uart) {
610+
if (use_blocking) {
611+
for (int i = 0; i < CORESIGHT_TRACE_FRAME_SIZE; i++) {
612+
uart_poll_out(uart_dev, buf[i]);
613+
}
614+
} else {
532615
err = k_sem_take(&uart_sem, K_FOREVER);
533616
__ASSERT_NO_MSG(err >= 0);
534617

535618
err = uart_tx(uart_dev, buf, CORESIGHT_TRACE_FRAME_SIZE, SYS_FOREVER_US);
536619
__ASSERT_NO_MSG(err >= 0);
537-
} else {
538-
for (int i = 0; i < CORESIGHT_TRACE_FRAME_SIZE; i++) {
539-
uart_poll_out(uart_dev, buf[i]);
540-
}
541620
}
542621
}
543622

@@ -593,7 +672,7 @@ static void process(void)
593672
}
594673
} else {
595674
dump_frame((uint8_t *)frame_buf);
596-
frame_buf = (use_async_uart && (frame_buf == frame_buf0)) ?
675+
frame_buf = (!use_blocking && (frame_buf == frame_buf0)) ?
597676
frame_buf1 : frame_buf0;
598677
}
599678
}
@@ -649,7 +728,7 @@ void debug_nrf_etr_flush(void)
649728
/* Set flag which forces uart to use blocking polling out instead of
650729
* asynchronous API.
651730
*/
652-
use_async_uart = false;
731+
use_blocking = true;
653732
uint32_t k = irq_lock();
654733

655734
/* Repeat arbitrary number of times to ensure that all that is flushed. */
@@ -754,17 +833,23 @@ static void tbm_event_handler(nrf_tbm_event_t event)
754833

755834
int etr_process_init(void)
756835
{
836+
#ifdef CONFIG_DEBUG_NRF_ETR_BACKEND_RTT
837+
if (CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER > 0) {
838+
SEGGER_RTT_ConfigUpBuffer(CONFIG_DEBUG_NRF_ETR_BACKEND_RTT_BUFFER, "stm_logger",
839+
rtt_buf, sizeof(rtt_buf),
840+
SEGGER_RTT_MODE_NO_BLOCK_SKIP);
841+
}
842+
#endif
757843
int err;
758844

759-
k_sem_init(&uart_sem, 1, 1);
760-
761-
err = uart_callback_set(uart_dev, uart_event_handler, NULL);
762-
use_async_uart = (err == 0);
763-
845+
if (IS_ENABLED(CONFIG_DEBUG_NRF_ETR_BACKEND_UART)) {
846+
err = uart_callback_set(uart_dev, uart_event_handler, NULL);
847+
use_blocking = (err != 0);
848+
k_sem_init(&uart_sem, 1, 1);
849+
}
764850
static const nrfx_tbm_config_t config = {.size = wsize_mask};
765851

766852
nrfx_tbm_init(&config, tbm_event_handler);
767-
768853
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(tbm)), DT_IRQ(DT_NODELABEL(tbm), priority),
769854
nrfx_isr, nrfx_tbm_irq_handler, 0);
770855
irq_enable(DT_IRQN(DT_NODELABEL(tbm)));

0 commit comments

Comments
 (0)