SWO support for CMSIS-DAP on the pico (untested as i dont have SWO-capable hardware afaik)
This commit is contained in:
parent
1e0b016c0a
commit
3143c2d065
|
@ -79,6 +79,7 @@ target_sources(${PROJECT} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_sump/_sump.c
|
${CMAKE_CURRENT_SOURCE_DIR}/src/m_sump/_sump.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_sump/cdc_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/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/i2c_tinyusb.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/spi_serprog.c
|
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/spi_serprog.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/tempsensor.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}/libco/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
|
${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/Core/Include/
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Driver/Include/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/
|
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/
|
${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")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||||
|
|
||||||
add_custom_target(fix_db ALL WORKING_DIRECTORY ${OUTPUT_DIR}
|
add_custom_target(fix_db ALL WORKING_DIRECTORY ${OUTPUT_DIR}
|
||||||
|
@ -127,6 +129,8 @@ if(FAMILY STREQUAL "rp2040")
|
||||||
target_link_libraries(${PROJECT} pico_stdio)
|
target_link_libraries(${PROJECT} pico_stdio)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/uart_rx.pio)
|
||||||
|
|
||||||
pico_add_extra_outputs(${PROJECT})
|
pico_add_extra_outputs(${PROJECT})
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -95,6 +95,10 @@ projects. These respective licenses can be found in
|
||||||
supports 7-bit ones).
|
supports 7-bit ones).
|
||||||
- [ ] **1-wire**
|
- [ ] **1-wire**
|
||||||
- [ ] **make modes persistent?**
|
- [ ] **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?
|
- [ ] FT2232 emulation mode?
|
||||||
- watch out, still need a vnd cfg interface! libftdi expects the following stuff: (TODO: acquire detailed protocol description)
|
- 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
|
- interface 0 ("A"): index 1, epin 0x02, epout 0x81
|
||||||
|
|
|
@ -68,6 +68,7 @@ This information includes:
|
||||||
|
|
||||||
#define PINOUT_SWCLK PINOUT_JTAG_TCK
|
#define PINOUT_SWCLK PINOUT_JTAG_TCK
|
||||||
#define PINOUT_SWDIO PINOUT_JTAG_TMS
|
#define PINOUT_SWDIO PINOUT_JTAG_TMS
|
||||||
|
#define PINOUT_SWO PINOUT_JTAG_TDO
|
||||||
|
|
||||||
#define PINOUT_SWCLK_MASK (1UL << PINOUT_SWCLK)
|
#define PINOUT_SWCLK_MASK (1UL << PINOUT_SWCLK)
|
||||||
#define PINOUT_SWDIO_MASK (1UL << PINOUT_SWDIO)
|
#define PINOUT_SWDIO_MASK (1UL << PINOUT_SWDIO)
|
||||||
|
@ -128,10 +129,14 @@ This information includes:
|
||||||
|
|
||||||
/// Indicate that UART Serial Wire Output (SWO) trace is available.
|
/// Indicate that UART Serial Wire Output (SWO) trace is available.
|
||||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||||
#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.
|
/// Maximum SWO UART Baudrate.
|
||||||
#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz.
|
#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz.
|
||||||
|
// ^ 10 MHz
|
||||||
|
|
||||||
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
|
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
|
||||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||||
|
@ -148,7 +153,7 @@ This information includes:
|
||||||
#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available.
|
#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available.
|
||||||
|
|
||||||
/// USART Driver instance number for the UART Communication Port.
|
/// 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.
|
/// UART Receive Buffer Size.
|
||||||
#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive Buffer Size in bytes (must be 2^n).
|
#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive Buffer Size in bytes (must be 2^n).
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
// vim: set et:
|
||||||
|
|
||||||
|
#include "DAP_config.h"
|
||||||
|
#include "DAP.h"
|
||||||
|
|
||||||
|
#include <hardware/dma.h>
|
||||||
|
#include <hardware/gpio.h>
|
||||||
|
#include <hardware/pio.h>
|
||||||
|
#include <hardware/structs/dma.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <libco.h>
|
#include <libco.h>
|
||||||
|
|
||||||
#define THREAD_STACK_SIZE 1024
|
#define THREAD_STACK_SIZE 512
|
||||||
|
|
||||||
void thread_init (void);
|
void thread_init (void);
|
||||||
void thread_yield(void);
|
void thread_yield(void);
|
||||||
|
|
Loading…
Reference in New Issue