Skip to content

Commit

Permalink
Enhancement communication host -> probe -> target
Browse files Browse the repository at this point in the history
- LED on Pico Debug Probe does blink on communication
- RTT can be used for host->target as well
  • Loading branch information
rgrr committed Apr 23, 2023
1 parent eb64979 commit b4e967b
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 24 deletions.
6 changes: 5 additions & 1 deletion src/cdc_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
*
*/

/**
* Send probe debug output via CDC to host.
*/

#include <stdarg.h>
#include <stdbool.h>
#include "pico/stdlib.h"
Expand Down Expand Up @@ -72,7 +76,7 @@ void cdc_debug_thread(void *ptr)
}

if (xStreamBufferIsEmpty(stream_printf)) {
// -> end of transmission: flush and sleep for a long time
// -> end of transmission: flush and sleep for a long time (or until new data is available)
tud_cdc_n_write_flush(CDC_DEBUG_N);
xEventGroupWaitBits(events, EV_TX_COMPLETE | EV_STREAM, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));
}
Expand Down
75 changes: 64 additions & 11 deletions src/cdc_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,28 @@
*
*/

/**
* Target (debug) input/output via CDC to host.
*
* Target -> Probe -> Host
* -----------------------
* * target -> probe
* * UART: interrupt handler on_uart_rx() to cdc_uart_put_into_stream()
* * RTT: (rtt_console) to cdc_uart_write()
* * UART/RTT data is written into \a stream_uart via
* * probe -> host: cdc_thread()
* * data is fetched from \a stream_uart and then put into a CDC
* in cdc_thread()
*
* Host -> Probe -> Target
* -----------------------
* * host -> probe
* * data is received from CDC in cdc_thread()
* * probe -> target
* * data is first tried to be transmitted via RTT
* * if that was not successful (no RTT_CB), data is transmitted via UART to the target
*/

#include <pico/stdlib.h>
#include "FreeRTOS.h"
#include "stream_buffer.h"
Expand All @@ -33,6 +55,7 @@

#include "picoprobe_config.h"
#include "led.h"
#include "rtt_console.h"


#define STREAM_UART_SIZE 4096
Expand All @@ -59,7 +82,7 @@ void cdc_thread(void *ptr)

for (;;) {
#if CFG_TUD_CDC_UART
size_t cdc_rx_chars;
uint32_t cdc_rx_chars;

if ( !m_connected) {
// wait here some time (until my terminal program is ready)
Expand All @@ -75,13 +98,16 @@ void cdc_thread(void *ptr)
}
else if (cdc_rx_chars != 0) {
// wait a short period if there are characters host -> probe -> target
xEventGroupWaitBits(events, EV_TX_COMPLETE | EV_STREAM | EV_RX, pdTRUE, pdFALSE, pdMS_TO_TICKS(1));
// waiting is done below
}
else {
// wait until transmission via USB has finished
xEventGroupWaitBits(events, EV_TX_COMPLETE | EV_STREAM | EV_RX, pdTRUE, pdFALSE, pdMS_TO_TICKS(100));
}

//
// probe -> host
//
if ( !xStreamBufferIsEmpty(stream_uart)) {
//
// transmit characters target -> picoprobe -> host
Expand All @@ -103,17 +129,44 @@ void cdc_thread(void *ptr)
}

//
// transmit characters host -> probe -> target
// (actually don't know if this works, but note that in worst case this loop is taken just every 50ms.
// So this is not for high throughput)
// host -> probe -> target
// -----------------------
// Characters are transferred bytewise to keep delays into the other direction low.
// So this is not a high throughput solution...
//
cdc_rx_chars = tud_cdc_n_available(CDC_UART_N);
if (cdc_rx_chars > 0 && uart_is_writable(PICOPROBE_UART_INTERFACE)) {
uint8_t ch;
size_t tx_len;

tx_len = tud_cdc_n_read(CDC_UART_N, &ch, 1);
uart_write_blocking(PICOPROBE_UART_INTERFACE, &ch, tx_len);
if (cdc_rx_chars != 0) {
if (rtt_console_cb_exists()) {
//
// -> data is going thru RTT
//
uint8_t ch;
uint32_t tx_len;

tx_len = tud_cdc_n_read(CDC_UART_N, &ch, sizeof(ch));
if (tx_len != 0) {
rtt_console_send_byte(ch);
}
}
else {
//
// -> data is going thru UART
// assure that the UART has free buffer, otherwise wait (for a short moment)
//
if ( !uart_is_writable(PICOPROBE_UART_INTERFACE)) {
xEventGroupWaitBits(events, EV_TX_COMPLETE | EV_STREAM | EV_RX, pdTRUE, pdFALSE, pdMS_TO_TICKS(1));
}
else {
uint8_t ch;
uint32_t tx_len;

tx_len = tud_cdc_n_read(CDC_UART_N, &ch, sizeof(ch));
if (tx_len != 0) {
led_state(LS_UART_TX_DATA);
uart_write_blocking(PICOPROBE_UART_INTERFACE, &ch, tx_len);
}
}
}
}
#else
xStreamBufferReceive(stream_uart, cdc_tx_buf, sizeof(cdc_tx_buf), pdMS_TO_TICKS(500));
Expand Down
43 changes: 42 additions & 1 deletion src/led.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,43 @@ static uint64_t rtt_data_trigger;
} // rx_data_from_target_init
#else
#define rx_data_from_target()
#define led_tx_off_init()
#define rx_data_from_target_init()
#endif



#ifdef PICOPROBE_LED_TARGET_RX
static TimerHandle_t timer_led_rx_off;
static void *timer_led_rx_off_id;


static void led_rx_off(TimerHandle_t xTimer)
{
gpio_put(PICOPROBE_LED_TARGET_RX, false);
}


static void tx_data_to_target(void)
{
static bool initialized;

if ( !initialized) {
initialized = true;
gpio_init(PICOPROBE_LED_TARGET_RX);
gpio_set_dir(PICOPROBE_LED_TARGET_RX, GPIO_OUT);
}
gpio_put(PICOPROBE_LED_TARGET_RX, true);
xTimerReset(timer_led_rx_off, 10);
} // tx_data_to_target


static void tx_data_to_target_init(void)
{
timer_led_rx_off = xTimerCreate("led_rx_off", pdMS_TO_TICKS(20), pdFALSE, timer_led_rx_off_id, led_rx_off);
} // tx_data_to_target_init
#else
#define tx_data_to_target()
#define tx_data_to_target_init()
#endif


Expand Down Expand Up @@ -252,6 +288,10 @@ void led_state(led_state_t state)
rx_data_from_target();
break;

case LS_UART_TX_DATA:
tx_data_to_target();
break;

case LS_SIGROK_WAIT:
case LS_SIGROK_RUNNING:
case LS_SIGROK_STOPPED:
Expand All @@ -275,6 +315,7 @@ void led_init(uint32_t task_prio)
led(1);

rx_data_from_target_init();
tx_data_to_target_init();

xTaskCreateAffinitySet(led_thread, "LED", configMINIMAL_STACK_SIZE, NULL, task_prio, 1, &task_led);
} // led_init
1 change: 1 addition & 0 deletions src/led.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef enum _led_state {
LS_RTT_CB_FOUND, // found an RTT control block on target
LS_RTT_RX_DATA, // RTT data received from target
LS_UART_RX_DATA, // UART data received from target
LS_UART_TX_DATA, // UART data transmitted to target
LS_MSC_CONNECTED, // MSC connected
LS_MSC_DISCONNECTED, // MSC disconnected
LS_DAPV1_CONNECTED, // DAPV1 connected
Expand Down
114 changes: 103 additions & 11 deletions src/rtt_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <stdio.h>

#include "FreeRTOS.h"
#include "event_groups.h"
#include "stream_buffer.h"
#include "task.h"

#include "target_board.h"
Expand All @@ -43,14 +45,22 @@



#define TARGET_RAM_START g_board_info.target_cfg->ram_regions[0].start
#define TARGET_RAM_END g_board_info.target_cfg->ram_regions[0].end
#define TARGET_RAM_START g_board_info.target_cfg->ram_regions[0].start
#define TARGET_RAM_END g_board_info.target_cfg->ram_regions[0].end

static const uint32_t segger_alignment = 4;
static const uint8_t seggerRTT[16] = "SEGGER RTT\0\0\0\0\0\0";
static uint32_t prev_rtt_cb = 0;
#define STREAM_RTT_SIZE 128
#define STREAM_RTT_TRIGGER 1

static TaskHandle_t task_rtt_console = NULL;
#define EV_RTT_TO_TARGET 0x01

static const uint32_t segger_alignment = 4;
static const uint8_t seggerRTT[16] = "SEGGER RTT\0\0\0\0\0\0";
static uint32_t prev_rtt_cb = 0;
static bool rtt_console_running = false;

static TaskHandle_t task_rtt_console = NULL;
static StreamBufferHandle_t stream_rtt;
static EventGroupHandle_t events;



Expand Down Expand Up @@ -123,25 +133,35 @@ static uint32_t search_for_rtt_cb(void)

static void do_rtt_console(uint32_t rtt_cb)
{
SEGGER_RTT_BUFFER_UP aUp; // Up buffer, transferring information up from target via debug probe to host
uint8_t buf[100];
SEGGER_RTT_BUFFER_UP aUp; // Up buffer, transferring information up from target via debug probe to host
SEGGER_RTT_BUFFER_DOWN aDown; // Down buffer, transferring information from host via debug probe to target
uint8_t buf[128];
bool ok = true;

static_assert(sizeof(uint32_t) == sizeof(unsigned int)); // why doesn't segger use uint32_t?

if (rtt_cb < TARGET_RAM_START || rtt_cb >= TARGET_RAM_END) {
return;
}

ok = ok && swd_read_memory(rtt_cb + offsetof(SEGGER_RTT_CB, aUp),
(uint8_t *)&aUp, sizeof(aUp));
ok = ok && swd_read_memory(rtt_cb + offsetof(SEGGER_RTT_CB, aDown),
(uint8_t *)&aDown, sizeof(aDown));

// do operations
rtt_console_running = true;
while (ok && !sw_unlock_requested()) {
ok = ok && swd_read_memory(rtt_cb + offsetof(SEGGER_RTT_CB, aUp[0].WrOff), (uint8_t *)&(aUp.WrOff), 2*sizeof(unsigned));
ok = ok && swd_read_word(rtt_cb + offsetof(SEGGER_RTT_CB, aUp[0].WrOff), (uint32_t *)&aUp.WrOff);

if (aUp.WrOff == aUp.RdOff) {
vTaskDelay(pdMS_TO_TICKS(10));
// -> no characters available
xEventGroupWaitBits(events, EV_RTT_TO_TARGET, pdTRUE, pdFALSE, pdMS_TO_TICKS(10));
}
else {
//
// fetch characters from target
//
uint32_t cnt;

if (aUp.WrOff > aUp.RdOff) {
Expand All @@ -154,14 +174,45 @@ static void do_rtt_console(uint32_t rtt_cb)

memset(buf, 0, sizeof(buf));
ok = ok && swd_read_memory((uint32_t)aUp.pBuffer + aUp.RdOff, buf, cnt);
ok = ok && swd_write_word(rtt_cb + offsetof(SEGGER_RTT_CB, aUp[0].RdOff), (aUp.RdOff + cnt) % aUp.SizeOfBuffer);
aUp.RdOff = (aUp.RdOff + cnt) % aUp.SizeOfBuffer;
ok = ok && swd_write_word(rtt_cb + offsetof(SEGGER_RTT_CB, aUp[0].RdOff), aUp.RdOff);

// put received data into CDC UART
cdc_uart_write(buf, cnt);

led_state(LS_RTT_RX_DATA);
}

if ( !xStreamBufferIsEmpty(stream_rtt)) {
//
// send data to target
//
ok = ok && swd_read_word(rtt_cb + offsetof(SEGGER_RTT_CB, aDown[0].RdOff), (uint32_t *)&(aDown.RdOff));
if ((aDown.WrOff + 1) % aDown.SizeOfBuffer != aDown.RdOff) {
// -> space left in RTT buffer on target
uint32_t cnt;
size_t r;

if (aDown.WrOff >= aDown.RdOff) {
cnt = aDown.SizeOfBuffer - aDown.WrOff;
}
else {
cnt = (aDown.RdOff - aDown.WrOff) - 1;
}
cnt = MIN(cnt, sizeof(buf));

r = xStreamBufferReceive(stream_rtt, &buf, cnt, 0);
if (r > 0) {
ok = ok && swd_write_memory((uint32_t)aDown.pBuffer + aDown.WrOff, buf, r);
aDown.WrOff = (aDown.WrOff + r) % aDown.SizeOfBuffer;
ok = ok && swd_write_word(rtt_cb + offsetof(SEGGER_RTT_CB, aDown[0].WrOff), aDown.WrOff);

led_state(LS_UART_TX_DATA);
}
}
}
}
rtt_console_running = false;
} // do_rtt_console


Expand Down Expand Up @@ -252,9 +303,50 @@ void rtt_console_thread(void *ptr)



bool rtt_console_cb_exists(void)
{
return rtt_console_running;
} // rtt_console_cb_exists



void rtt_console_send_byte(uint8_t ch)
/**
* Write a byte into the RTT stream.
* If there is no space left in the stream, wait 10ms and then try again.
* If there is still no space, then drop a byte from the stream.
*/
{
size_t available = xStreamBufferSpacesAvailable(stream_rtt);
if (available < sizeof(ch)) {
vTaskDelay(pdMS_TO_TICKS(10));
available = xStreamBufferSpacesAvailable(stream_rtt);
if (available < sizeof(ch)) {
uint8_t dummy;
xStreamBufferReceive(stream_rtt, &dummy, sizeof(dummy), 0);
picoprobe_error("rtt_console_send_byte: drop byte\n");
}
}
xStreamBufferSend(stream_rtt, &ch, sizeof(ch), 0);
xEventGroupSetBits(events, EV_RTT_TO_TARGET);
} // rtt_console_send_byte



void rtt_console_init(uint32_t task_prio)
{
picoprobe_debug("rtt_console_init()\n");

events = xEventGroupCreate();

stream_rtt = xStreamBufferCreate(STREAM_RTT_SIZE, STREAM_RTT_TRIGGER);
if (stream_rtt == NULL) {
picoprobe_error("rtt_console_init: cannot create stream_rtt\n");
}

xTaskCreateAffinitySet(rtt_console_thread, "RTT_CONSOLE", configMINIMAL_STACK_SIZE, NULL, task_prio, 1, &task_rtt_console);
if (task_rtt_console == NULL)
{
picoprobe_error("rtt_console_init: cannot create task_rtt_console\n");
}
} // rtt_console_init
2 changes: 2 additions & 0 deletions src/rtt_console.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@


void rtt_console_init(uint32_t task_prio);
void rtt_console_send_byte(uint8_t ch);
bool rtt_console_cb_exists(void);


#ifdef __cplusplus
Expand Down

0 comments on commit b4e967b

Please sign in to comment.