diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5273d9..e21429e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,6 +79,7 @@ target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/m_sump/_sump.c
${CMAKE_CURRENT_SOURCE_DIR}/src/m_sump/cdc_sump.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/cdc_uart.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/dap_swo.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/i2c_tinyusb.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/spi_serprog.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/tempsensor.c
@@ -95,11 +96,12 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/libco/
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/
+ ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Driver/Include/
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/
${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/
)
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
add_custom_target(fix_db ALL WORKING_DIRECTORY ${OUTPUT_DIR}
@@ -127,6 +129,8 @@ if(FAMILY STREQUAL "rp2040")
target_link_libraries(${PROJECT} pico_stdio)
endif()
+ pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/uart_rx.pio)
+
pico_add_extra_outputs(${PROJECT})
else()
diff --git a/README.md b/README.md
index 04210d2..6b05154 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,10 @@ projects. These respective licenses can be found in
supports 7-bit ones).
- [ ] **1-wire**
- [ ] **make modes persistent?**
+- [ ] CMSIS-DAP SWO support?
+ - ~~Needs edits in the CMSIS-DAP code~~ ok no theyre weak symbols
+ - needs PIO stuff tho
+ - SWO = TDO !
- [ ] FT2232 emulation mode?
- watch out, still need a vnd cfg interface! libftdi expects the following stuff: (TODO: acquire detailed protocol description)
- interface 0 ("A"): index 1, epin 0x02, epout 0x81
diff --git a/bsp/rp2040/DAP_config.h b/bsp/rp2040/DAP_config.h
index da4e844..84d9b68 100644
--- a/bsp/rp2040/DAP_config.h
+++ b/bsp/rp2040/DAP_config.h
@@ -68,6 +68,7 @@ This information includes:
#define PINOUT_SWCLK PINOUT_JTAG_TCK
#define PINOUT_SWDIO PINOUT_JTAG_TMS
+#define PINOUT_SWO PINOUT_JTAG_TDO
#define PINOUT_SWCLK_MASK (1UL << PINOUT_SWCLK)
#define PINOUT_SWDIO_MASK (1UL << PINOUT_SWDIO)
@@ -128,10 +129,14 @@ This information includes:
/// Indicate that UART Serial Wire Output (SWO) trace is available.
/// This information is returned by the command \ref DAP_Info as part of Capabilities.
-#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available.
+#define SWO_UART 1 ///< SWO UART: 1 = available, 0 = not available.
+
+// should cause a linker error, because we're not using a hardware UART on the pico for SWO
+#define SWO_UART_DRIVER 9999
/// Maximum SWO UART Baudrate.
#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz.
+// ^ 10 MHz
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
/// This information is returned by the command \ref DAP_Info as part of Capabilities.
@@ -148,7 +153,7 @@ This information includes:
#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available.
/// USART Driver instance number for the UART Communication Port.
-#define DAP_UART_DRIVER 1 ///< USART Driver instance number (Driver_USART#).
+#define DAP_UART_DRIVER 0 ///< USART Driver instance number (Driver_USART#).
/// UART Receive Buffer Size.
#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive 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
new file mode 100644
index 0000000..f7429e4
--- /dev/null
+++ b/bsp/rp2040/m_default/dap_swo.c
@@ -0,0 +1,133 @@
+// vim: set et:
+
+#include "DAP_config.h"
+#include "DAP.h"
+
+#include
+#include
+#include
+#include
+
+#include "uart_rx.pio.h"
+
+static uint32_t
+ swo_baudrate = 115200,
+ swo_pio_off = ~(uint32_t)0, swo_num = 0;
+static int swo_sm = -1, swo_dmach = -1;
+static bool mode_enabled = false;
+
+#define SWO_PIO pio1
+
+// Enable or disable SWO Mode (UART)
+// enable: enable flag
+// return: 1 - Success, 0 - Error
+uint32_t SWO_Mode_UART(uint32_t enable) {
+ if (enable) {
+ swo_sm = pio_claim_unused_sm(SWO_PIO, false);
+ if (swo_sm == -1) return 0;
+
+ swo_dmach = dma_claim_unused_channel(false);
+ if (swo_dmach == -1) {
+ pio_sm_unclaim(SWO_PIO, swo_sm);
+ swo_sm = -1;
+ return 0;
+ }
+
+ if (!pio_can_add_program(SWO_PIO, &uart_rx_program)) {
+ 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, &uart_rx_program);
+ uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
+
+ 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, &uart_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;
+}
+
+// Configure SWO Baudrate (UART)
+// baudrate: requested baudrate
+// return: actual baudrate or 0 when not configured
+uint32_t SWO_Baudrate_UART(uint32_t baudrate) {
+ if (!mode_enabled) return 0;
+
+ uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
+
+ return baudrate; // should be ok
+}
+
+// Control SWO Capture (UART)
+// active: active flag
+// return: 1 - Success, 0 - Error
+uint32_t SWO_Control_UART(uint32_t 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;
+}
+
+// Start SWO Capture (UART)
+// buf: pointer to buffer for capturing
+// num: number of bytes to capture
+void SWO_Capture_UART(uint8_t* buf, uint32_t 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);
+}
+
+// Get SWO Pending Trace Count (UART)
+// return: number of pending trace data bytes
+uint32_t SWO_GetCount_UART(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;
+ return swo_num - remaining;
+}
+
diff --git a/bsp/rp2040/m_default/uart_rx.pio b/bsp/rp2040/m_default/uart_rx.pio
new file mode 100644
index 0000000..0bd370e
--- /dev/null
+++ b/bsp/rp2040/m_default/uart_rx.pio
@@ -0,0 +1,94 @@
+;
+; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+;
+; SPDX-License-Identifier: BSD-3-Clause
+;
+
+.program uart_rx_mini
+
+; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
+; with the correct timing.
+; IN pin 0 is mapped to the GPIO used as UART RX.
+; Autopush must be enabled, with a threshold of 8.
+
+ wait 0 pin 0 ; Wait for start bit
+ set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
+bitloop: ; Loop 8 times
+ in pins, 1 ; Sample data
+ jmp x-- bitloop [6] ; Each iteration is 8 cycles
+
+% c-sdk {
+#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) {
+ 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);
+ sm_config_set_in_pins(&c, pin); // for WAIT, IN
+ // Shift to right, autopush enabled
+ sm_config_set_in_shift(&c, true, true, 8);
+ sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
+ // SM transmits 1 bit per 8 execution cycles.
+ float div = (float)clock_get_hz(clk_sys) / (8 * baud);
+ sm_config_set_clkdiv(&c, div);
+
+ pio_sm_init(pio, sm, offset, &c);
+ pio_sm_set_enabled(pio, sm, true);
+}
+%}
+
+.program uart_rx
+
+; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
+; break conditions more gracefully.
+; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
+
+start:
+ wait 0 pin 0 ; Stall until start bit is asserted
+ set x, 7 [10] ; Preload bit counter, then delay until halfway through
+bitloop: ; the first data bit (12 cycles incl wait, set).
+ in pins, 1 ; Shift data bit into ISR
+ jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
+ jmp pin good_stop ; Check stop bit (should be high)
+
+ irq 4 rel ; Either a framing error or a break. Set a sticky flag,
+ wait 1 pin 0 ; and wait for line to return to idle state.
+ jmp start ; Don't push data if we didn't see good framing.
+
+good_stop: ; No delay before returning to start; a little slack is
+ push ; important in case the TX clock is slightly too fast.
+
+
+% c-sdk {
+static inline void 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);
+ sm_config_set_in_pins(&c, pin); // for WAIT, IN
+ sm_config_set_jmp_pin(&c, pin); // for JMP
+ // Shift to right, autopull disabled
+ sm_config_set_in_shift(&c, true, false, 32);
+ // Deeper FIFO as we're not doing any TX
+ sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
+ // SM transmits 1 bit per 8 execution cycles.
+ float div = (float)clock_get_hz(clk_sys) / (8 * baud);
+ sm_config_set_clkdiv(&c, div);
+
+ pio_sm_init(pio, sm, offset, &c);
+ //pio_sm_set_enabled(pio, sm, true);
+}
+
+static inline char 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))
+ tight_loop_contents();
+ return (char)*rxfifo_shift;
+}
+
+%}
diff --git a/src/thread.h b/src/thread.h
index 0b60f05..846c6fa 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -5,7 +5,7 @@
#include
-#define THREAD_STACK_SIZE 1024
+#define THREAD_STACK_SIZE 512
void thread_init (void);
void thread_yield(void);