From 3143c2d0659041be4f2ce152086602ed99bb5ec2 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sun, 8 Aug 2021 18:10:44 +0200 Subject: [PATCH] SWO support for CMSIS-DAP on the pico (untested as i dont have SWO-capable hardware afaik) --- CMakeLists.txt | 6 +- README.md | 4 + bsp/rp2040/DAP_config.h | 9 ++- bsp/rp2040/m_default/dap_swo.c | 133 +++++++++++++++++++++++++++++++ bsp/rp2040/m_default/uart_rx.pio | 94 ++++++++++++++++++++++ src/thread.h | 2 +- 6 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 bsp/rp2040/m_default/dap_swo.c create mode 100644 bsp/rp2040/m_default/uart_rx.pio 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);