diff --git a/bsp/rp2040/DAP_config.h b/bsp/rp2040/DAP_config.h
index 84d9b68..acfb9c3 100644
--- a/bsp/rp2040/DAP_config.h
+++ b/bsp/rp2040/DAP_config.h
@@ -140,7 +140,7 @@ This information includes:
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
/// This information is returned by the command \ref DAP_Info as part of Capabilities.
-#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available.
+#define SWO_MANCHESTER 1 ///< SWO Manchester: 1 = available, 0 = not available.
/// SWO Trace Buffer Size.
#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n).
diff --git a/bsp/rp2040/m_default/dap_swo.c b/bsp/rp2040/m_default/dap_swo.c
index 8f61773..00b6279 100644
--- a/bsp/rp2040/m_default/dap_swo.c
+++ b/bsp/rp2040/m_default/dap_swo.c
@@ -8,7 +8,8 @@
#include
#include
-#include "uart_rx.pio.h"
+#include "swo_uart_rx.pio.h"
+#include "swo_manchester_encoding.pio.h"
static uint32_t
swo_baudrate = 115200,
@@ -24,6 +25,10 @@ static bool mode_enabled = false;
uint32_t SWO_Mode_UART(uint32_t enable) {
//for(;;);//printf("SWO mode %lu\n", enable);
if (enable) {
+ if (mode_enabled) { // already inited!
+ return 0;
+ }
+
swo_sm = pio_claim_unused_sm(SWO_PIO, false);
if (swo_sm == -1) {
//for(;;);//printf("E: no PIO\n");
@@ -38,7 +43,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
return 0;
}
- if (!pio_can_add_program(SWO_PIO, &uart_rx_program)) {
+ if (!pio_can_add_program(SWO_PIO, &swo_uart_rx_program)) {
//for(;;);//printf("E: no prg\n");
dma_channel_unclaim(swo_dmach);
swo_dmach = -1;
@@ -47,8 +52,9 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
return 0;
}
- swo_pio_off = pio_add_program(SWO_PIO, &uart_rx_program);
- uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
+ swo_pio_off = pio_add_program(SWO_PIO, &swo_uart_rx_program);
+ swo_uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
+ gpio_set_function(PINOUT_SWO, GPIO_FUNC_PIO1);
mode_enabled = true;
} else {
@@ -65,7 +71,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
swo_sm = -1;
}
if (~swo_pio_off != 0) {
- pio_remove_program(SWO_PIO, &uart_rx_program, swo_pio_off);
+ pio_remove_program(SWO_PIO, &swo_uart_rx_program, swo_pio_off);
swo_pio_off = ~(uint32_t)0;
}
@@ -82,9 +88,10 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
// return: actual baudrate or 0 when not configured
uint32_t SWO_Baudrate_UART(uint32_t baudrate) {
//for(;;);//printf("SWO baudrate %lu\n", baudrate);
+ swo_baudrate = baudrate;
if (!mode_enabled) return 0;
- uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
+ swo_uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
return baudrate; // should be ok
}
@@ -141,3 +148,121 @@ uint32_t SWO_GetCount_UART(void) {
return swo_num - remaining;
}
+/*** MANCHESTER **************************************************************/
+
+uint32_t SWO_Mode_Manchester(uint32_t enable) {
+ //for(;;);//printf("SWOM mode %lu\n", enable);
+ if (enable) {
+ if (mode_enabled) { // already inited!
+ return 0;
+ }
+
+ swo_sm = pio_claim_unused_sm(SWO_PIO, false);
+ if (swo_sm == -1) {
+ //for(;;);//printf("E: no PIO\n");
+ return 0;
+ }
+
+ swo_dmach = dma_claim_unused_channel(false);
+ if (swo_dmach == -1) {
+ //for(;;);//printf("E: no DMA\n");
+ pio_sm_unclaim(SWO_PIO, swo_sm);
+ swo_sm = -1;
+ return 0;
+ }
+
+ if (!pio_can_add_program(SWO_PIO, &swo_manchester_rx_program)) {
+ //for(;;);//printf("E: no prg\n");
+ dma_channel_unclaim(swo_dmach);
+ swo_dmach = -1;
+ pio_sm_unclaim(SWO_PIO, swo_sm);
+ swo_sm = -1;
+ return 0;
+ }
+
+ swo_pio_off = pio_add_program(SWO_PIO, &swo_manchester_rx_program);
+ swo_manchester_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
+ gpio_set_function(PINOUT_SWO, GPIO_FUNC_PIO1);
+
+ mode_enabled = true;
+ } else {
+ mode_enabled = false;
+
+ if (swo_dmach >= 0) {
+ dma_channel_unclaim(swo_dmach); // ugh why is it "dma_channel_xyz" and "dma_xyz_channel"
+ swo_dmach = -1;
+ }
+
+ if (swo_sm >= 0) {
+ pio_sm_set_enabled(SWO_PIO, swo_sm, false);
+ pio_sm_unclaim(SWO_PIO, swo_sm);
+ swo_sm = -1;
+ }
+ if (~swo_pio_off != 0) {
+ pio_remove_program(SWO_PIO, &swo_manchester_rx_program, swo_pio_off);
+ swo_pio_off = ~(uint32_t)0;
+ }
+
+ // hi-Z nothing
+ gpio_set_function(PINOUT_SWO, GPIO_FUNC_NULL);
+ gpio_set_pulls(PINOUT_SWO, false, false);
+ }
+
+ return 1;
+ return 0;
+}
+
+uint32_t SWO_Baudrate_Manchester(uint32_t baudrate) {
+ //for(;;);//printf("SWOM baudrate %lu\n", baudrate);
+ swo_baudrate = baudrate;
+ if (!mode_enabled) return 0;
+
+ swo_manchester_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
+
+ return baudrate; // should be ok
+}
+
+uint32_t SWO_Control_Manchester(uint32_t active) {
+ //for(;;);//printf("SWOM control %lu\n", active);
+ if (!mode_enabled) return 0;
+
+ if (active) {
+ pio_sm_set_enabled(SWO_PIO, swo_sm, true);
+ dma_channel_start(swo_dmach);
+ }
+ else {
+ dma_channel_abort(swo_dmach);
+ pio_sm_set_enabled(SWO_PIO, swo_sm, false);
+ swo_num = 0;
+ }
+
+ return 1;
+}
+
+void SWO_Capture_Manchester(uint8_t* buf, uint32_t num) {
+ //for(;;);//printf("SWOM capture %p 0x%lx\n", buf, num);
+ if (!mode_enabled) return;
+
+ swo_num = num;
+
+ // set up DMA params
+ dma_channel_config dcfg = dma_channel_get_default_config(swo_dmach);
+ channel_config_set_read_increment(&dcfg, false);
+ channel_config_set_write_increment(&dcfg, true);
+ channel_config_set_dreq(&dcfg, pio_get_dreq(SWO_PIO, swo_sm, false));
+ channel_config_set_transfer_data_size(&dcfg, DMA_SIZE_8);
+ dma_channel_configure(swo_dmach, &dcfg, buf, &SWO_PIO->rxf[swo_sm], num, false);
+}
+
+uint32_t SWO_GetCount_Manchester(void) {
+ // DMA hw decreases transfer_count by one on every transfer, so it contains
+ // the number of remaining bytes to be received.
+ // however, CMSIS-DAP wants (badly worded) the number of bytes already
+ // received
+ if (!mode_enabled || swo_num == 0) return 0; // not initialized
+
+ uint32_t remaining = dma_hw->ch[swo_dmach].transfer_count;
+ //for(;;);//printf("SWO getcount -> 0x%lx\n", swo_num - remaining);
+ return swo_num - remaining;
+}
+
diff --git a/bsp/rp2040/m_default/swo_manchester_encoding.pio b/bsp/rp2040/m_default/swo_manchester_encoding.pio
new file mode 100644
index 0000000..d333714
--- /dev/null
+++ b/bsp/rp2040/m_default/swo_manchester_encoding.pio
@@ -0,0 +1,94 @@
+;
+; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+;
+; SPDX-License-Identifier: BSD-3-Clause
+;
+
+.program swo_manchester_tx
+.side_set 1 opt
+
+; Transmit one bit every 12 cycles. a '0' is encoded as a high-low sequence
+; (each part lasting half a bit period, or 6 cycles) and a '1' is encoded as a
+; low-high sequence.
+;
+; Side-set bit 0 must be mapped to the GPIO used for TX.
+; Autopull must be enabled -- this program does not care about the threshold.
+; The program starts at the public label 'start'.
+
+.wrap_target
+do_1:
+ nop side 0 [5] ; Low for 6 cycles (5 delay, +1 for nop)
+ jmp get_bit side 1 [3] ; High for 4 cycles. 'get_bit' takes another 2 cycles
+do_0:
+ nop side 1 [5] ; Output high for 6 cycles
+ nop side 0 [3] ; Output low for 4 cycles
+public start:
+get_bit:
+ out x, 1 ; Always shift out one bit from OSR to X, so we can
+ jmp !x do_0 ; branch on it. Autopull refills the OSR when empty.
+.wrap
+
+% c-sdk {
+static inline void swo_manchester_tx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) {
+ pio_sm_set_pins_with_mask(pio, sm, 0, 1u << pin);
+ pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
+ pio_gpio_init(pio, pin);
+
+ pio_sm_config c = swo_manchester_tx_program_get_default_config(offset);
+ sm_config_set_sideset_pins(&c, pin);
+ sm_config_set_out_shift(&c, true, true, 32);
+ sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
+ sm_config_set_clkdiv(&c, div);
+ pio_sm_init(pio, sm, offset + swo_manchester_tx_offset_start, &c);
+
+ pio_sm_set_enabled(pio, sm, true);
+}
+%}
+
+.program swo_manchester_rx
+
+; Assumes line is idle low, first bit is 0
+; One bit is 12 cycles
+; a '0' is encoded as 10
+; a '1' is encoded as 01
+;
+; Both the IN base and the JMP pin mapping must be pointed at the GPIO used for RX.
+; Autopush must be enabled.
+; Before enabling the SM, it should be placed in a 'wait 1, pin` state, so that
+; it will not start sampling until the initial line idle state ends.
+
+start_of_0: ; We are 0.25 bits into a 0 - signal is high
+ wait 0 pin 0 ; Wait for the 1->0 transition - at this point we are 0.5 into the bit
+ in y, 1 [8] ; Emit a 0, sleep 3/4 of a bit
+ jmp pin start_of_0 ; If signal is 1 again, it's another 0 bit, otherwise it's a 1
+
+.wrap_target
+start_of_1: ; We are 0.25 bits into a 1 - signal is 1
+ wait 1 pin 0 ; Wait for the 0->1 transition - at this point we are 0.5 into the bit
+ in x, 1 [8] ; Emit a 1, sleep 3/4 of a bit
+ jmp pin start_of_0 ; If signal is 0 again, it's another 1 bit otherwise it's a 0
+.wrap
+
+% c-sdk {
+static inline void swo_manchester_rx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) {
+ pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
+ pio_gpio_init(pio, pin);
+
+ pio_sm_config c = swo_manchester_rx_program_get_default_config(offset);
+ sm_config_set_in_pins(&c, pin); // for WAIT
+ sm_config_set_jmp_pin(&c, pin); // for JMP
+ sm_config_set_in_shift(&c, true, true, 32);
+ sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
+ sm_config_set_clkdiv(&c, div);
+ pio_sm_init(pio, sm, offset, &c);
+
+ // X and Y are set to 0 and 1, to conveniently emit these to ISR/FIFO.
+ pio_sm_exec(pio, sm, pio_encode_set(pio_x, 1));
+ pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
+ // Assume line is idle low, and first transmitted bit is 0. Put SM in a
+ // wait state before enabling. RX will begin once the first 0 symbol is
+ // detected.
+ pio_sm_exec(pio, sm, pio_encode_wait_pin(1, 0) | pio_encode_delay(2));
+ pio_sm_set_enabled(pio, sm, true);
+}
+%}
diff --git a/bsp/rp2040/m_default/uart_rx.pio b/bsp/rp2040/m_default/swo_uart_rx.pio
similarity index 86%
rename from bsp/rp2040/m_default/uart_rx.pio
rename to bsp/rp2040/m_default/swo_uart_rx.pio
index 0bd370e..a9f0ad9 100644
--- a/bsp/rp2040/m_default/uart_rx.pio
+++ b/bsp/rp2040/m_default/swo_uart_rx.pio
@@ -4,7 +4,7 @@
; SPDX-License-Identifier: BSD-3-Clause
;
-.program uart_rx_mini
+.program swo_uart_rx_mini
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
; with the correct timing.
@@ -21,12 +21,12 @@ bitloop: ; Loop 8 times
#include "hardware/clocks.h"
#include "hardware/gpio.h"
-static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
+static inline void swo_uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
- pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
+ pio_sm_config c = swo_uart_rx_mini_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
// Shift to right, autopush enabled
sm_config_set_in_shift(&c, true, true, 8);
@@ -40,7 +40,7 @@ static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint
}
%}
-.program uart_rx
+.program swo_uart_rx
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
; break conditions more gracefully.
@@ -63,12 +63,12 @@ good_stop: ; No delay before returning to start; a little slack is
% c-sdk {
-static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
+static inline void swo_uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
- pio_sm_config c = uart_rx_program_get_default_config(offset);
+ pio_sm_config c = swo_uart_rx_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin); // for JMP
// Shift to right, autopull disabled
@@ -83,7 +83,7 @@ static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin,
//pio_sm_set_enabled(pio, sm, true);
}
-static inline char uart_rx_program_getc(PIO pio, uint sm) {
+static inline char swo_uart_rx_program_getc(PIO pio, uint sm) {
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
while (pio_sm_is_rx_fifo_empty(pio, sm))