diff --git a/src/Makefile b/src/Makefile index 28f12fe6bb1..d75ef1e8e9c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -41,7 +41,7 @@ SRC = \ adiv5.c \ adiv5_jtag.c \ adiv5_swd.c \ - apollo3.c \ + apollo3.c \ adiv6.c \ command.c \ cortex.c \ @@ -106,6 +106,12 @@ ifneq ($(PROBE_HOST), ctxLink) SRC += gdb_if.c endif +# Check if the old name for the SWO encoding setting has been used +ifdef TRACESWO_PROTOCOL + $(warning the TRACESWO_PROTOCOL variable is deprecated, please use SWO_ENCODING instead) + SWO_ENCODING = $(TRACESWO_PROTOCOL) +endif + ifeq (,$(filter all_platforms,$(MAKECMDGOALS))) include $(PLATFORM_DIR)/Makefile.inc endif diff --git a/src/command.c b/src/command.c index 62a6baf926b..4d731f53997 100644 --- a/src/command.c +++ b/src/command.c @@ -47,7 +47,7 @@ #ifdef PLATFORM_HAS_TRACESWO #include "serialno.h" -#include "traceswo.h" +#include "swo.h" #include "usb.h" #endif @@ -68,7 +68,7 @@ static bool cmd_tdi_low_reset(target_s *t, int argc, const char **argv); static bool cmd_target_power(target_s *t, int argc, const char **argv); #endif #ifdef PLATFORM_HAS_TRACESWO -static bool cmd_traceswo(target_s *t, int argc, const char **argv); +static bool cmd_swo(target_s *t, int argc, const char **argv); #endif static bool cmd_heapinfo(target_s *t, int argc, const char **argv); #ifdef ENABLE_RTT @@ -109,11 +109,14 @@ const command_s cmd_list[] = { "MAXERR]]"}, #endif #ifdef PLATFORM_HAS_TRACESWO -#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2 - {"traceswo", cmd_traceswo, "Start trace capture, NRZ mode: [BAUDRATE] [decode [CHANNEL_NR ...]]"}, -#else - {"traceswo", cmd_traceswo, "Start trace capture, Manchester mode: [decode [CHANNEL_NR ...]]"}, +#if SWO_ENCODING == 1 + {"swo", cmd_swo, "Start SWO capture, Manchester mode: [decode [CHANNEL_NR ...]]"}, +#elif SWO_ENCODING == 2 + {"swo", cmd_swo, "Start SWO capture, UART mode: [BAUDRATE] [decode [CHANNEL_NR ...]]"}, +#elif SWO_ENCODING == 3 + {"swo", cmd_swo, "Start SWO capture: [manchester|uart] [BAUDRATE] [decode [CHANNEL_NR ...]]"}, #endif + {"traceswo", cmd_swo, "Deprecated: use swo instead"}, #endif {"heapinfo", cmd_heapinfo, "Set semihosting heapinfo: HEAP_BASE HEAP_LIMIT STACK_BASE STACK_LIMIT"}, #if defined(PLATFORM_HAS_DEBUG) && PC_HOSTED == 0 @@ -603,78 +606,99 @@ static bool cmd_rtt(target_s *t, int argc, const char **argv) #endif #ifdef PLATFORM_HAS_TRACESWO -static bool cmd_traceswo_enable(int argc, const char **argv) +static bool cmd_swo_enable(int argc, const char **argv) { - uint32_t swo_channelmask = 0; /* swo decoding off */ - uint8_t decode_arg = 1; -#if TRACESWO_PROTOCOL == 2 + /* Set up which mode we're going to default to */ +#if SWO_ENCODING == 1 + const swo_coding_e capture_mode = swo_manchester; +#elif SWO_ENCODING == 2 + const swo_coding_e capture_mode = swo_nrz_uart; +#elif SWO_ENCODING == 3 + swo_coding_e capture_mode = swo_none; +#endif + /* Set up the presumed baudrate for the stream */ uint32_t baudrate = SWO_DEFAULT_BAUD; - /* argument: optional baud rate for async mode */ - if (argc > 1 && argv[1][0] >= '0' && argv[1][0] <= '9') { - baudrate = strtoul(argv[1], NULL, 0); - if (baudrate == 0) + /* + * Before we can enable SWO data recovery, potentially with decoding, + * start with the assumption ITM decoding is off + */ + uint32_t itm_stream_mask = 0U; + uint8_t decode_arg = 1U; +#if SWO_ENCODING == 3 + /* Next, determine which decoding mode to use */ + if (argc > decode_arg) { + const size_t arg_length = strlen(argv[decode_arg]); + if (!strncmp(argv[decode_arg], "manchester", arg_length)) + capture_mode = swo_manchester; + if (!strncmp(argv[decode_arg], "uart", arg_length)) + capture_mode = swo_nrz_uart; + } + /* If a mode was given, make sure the rest of the parser skips the mode verb */ + if (capture_mode != swo_none) + ++decode_arg; + /* Otherwise set a default mode up */ + else + capture_mode = swo_nrz_uart; +#endif +#if SWO_ENCODING == 2 || SWO_ENCODING == 3 + /* Handle the optional baud rate argument if present */ + if (capture_mode == swo_nrz_uart && argc > decode_arg && argv[decode_arg][0] >= '0' && argv[decode_arg][0] <= '9') { + baudrate = strtoul(argv[decode_arg], NULL, 0); + if (baudrate == 0U) baudrate = SWO_DEFAULT_BAUD; - decode_arg = 2; + ++decode_arg; } #endif - /* argument: 'decode' literal */ + /* Check if `decode` has been given and if it has, enable ITM decoding */ if (argc > decode_arg && !strncmp(argv[decode_arg], "decode", strlen(argv[decode_arg]))) { - swo_channelmask = 0xffffffffU; /* decoding all channels */ - /* arguments: channels to decode */ + /* Check if there are specific ITM streams to enable and build a bitmask of them */ if (argc > decode_arg + 1) { - swo_channelmask = 0U; - for (size_t i = decode_arg + 1U; i < (size_t)argc; ++i) { /* create bitmask of channels to decode */ - const uint32_t channel = strtoul(argv[i], NULL, 0); - if (channel < 32U) - swo_channelmask |= 1U << channel; + /* For each of the specified streams */ + for (size_t i = decode_arg + 1U; i < (size_t)argc; ++i) { + /* Figure out which the next one is */ + const uint32_t stream = strtoul(argv[i], NULL, 0); + /* If it's a valid ITM stream number, set it in the mask */ + if (stream < 32U) + itm_stream_mask |= 1U << stream; } - } + } else + /* Decode all ITM streams if non given */ + itm_stream_mask = 0xffffffffU; } -#if TRACESWO_PROTOCOL == 2 - traceswo_init(baudrate, swo_channelmask); - gdb_outf("Baudrate: %lu ", traceswo_get_baudrate()); -#else - traceswo_init(swo_channelmask); -#endif + /* Now enable SWO data recovery */ + swo_init(capture_mode, baudrate, itm_stream_mask); + /* And show the user what we've done - first the channel mask from MSb to LSb */ gdb_outf("Channel mask: "); for (size_t i = 0; i < 32U; ++i) { - const uint32_t bit = (swo_channelmask >> (31U - i)) & 1U; - gdb_outf("%" PRIu32, bit); + const char bit = '0' + ((itm_stream_mask >> (31U - i)) & 1U); + gdb_outf("%c", bit); } gdb_outf("\n"); - - gdb_outf("Trace enabled for BMP serial %s, USB EP %u\n", serial_no, TRACE_ENDPOINT); + /* Then the connection information for programs that are scraping BMD's output to know what to connect to */ + gdb_outf("Trace enabled for BMP serial %s, USB EP %u\n", serial_no, SWO_ENDPOINT); return true; } -static bool cmd_traceswo_disable(void) +static bool cmd_swo_disable(void) { -#if TRACESWO_PROTOCOL == 2 - traceswo_deinit(); + swo_deinit(true); gdb_out("Trace disabled\n"); return true; -#else - gdb_out("Not implemented\n"); - return false; -#endif } -static bool cmd_traceswo(target_s *t, int argc, const char **argv) +static bool cmd_swo(target_s *t, int argc, const char **argv) { (void)t; - bool mode = false; - if (argc >= 2) { - if (!parse_enable_or_disable(argv[1], &mode)) { - gdb_out("Usage: traceswo [2000000] [decode [0 1 3 31]]\n"); - return false; - } - } - if (mode) { - return cmd_traceswo_enable(argc - 1, argv + 1); - } else { - return cmd_traceswo_disable(); + bool enable_swo = false; + if (argc >= 2 && !parse_enable_or_disable(argv[1], &enable_swo)) { + gdb_out("Usage: traceswo [2000000] [decode [0 1 3 31]]\n"); + return false; } + + if (enable_swo) + return cmd_swo_enable(argc - 1, argv + 1); + return cmd_swo_disable(); } #endif @@ -682,10 +706,9 @@ static bool cmd_traceswo(target_s *t, int argc, const char **argv) static bool cmd_debug_bmp(target_s *t, int argc, const char **argv) { (void)t; - if (argc == 2) { - if (!parse_enable_or_disable(argv[1], &debug_bmp)) - return false; - } else if (argc > 2) { + if (argc == 2 && !parse_enable_or_disable(argv[1], &debug_bmp)) + return false; + if (argc > 2) { gdb_outf("usage: monitor debug [enable|disable]\n"); return false; } @@ -723,8 +746,8 @@ static bool cmd_heapinfo(target_s *t, int argc, const char **argv) target_addr_t heap_limit = strtoul(argv[2], NULL, 16); target_addr_t stack_base = strtoul(argv[3], NULL, 16); target_addr_t stack_limit = strtoul(argv[4], NULL, 16); - gdb_outf("heap_base: %08" PRIx32 " heap_limit: %08" PRIx32 " stack_base: %08" PRIx32 " stack_limit: %08" PRIx32 - "\n", + gdb_outf("heap_base: %08" PRIx32 " heap_limit: %08" PRIx32 " stack_base: %08" PRIx32 " stack_limit: " + "%08" PRIx32 "\n", heap_base, heap_limit, stack_base, stack_limit); target_set_heapinfo(t, heap_base, heap_limit, stack_base, stack_limit); } else diff --git a/src/platforms/96b_carbon/platform.h b/src/platforms/96b_carbon/platform.h index f3024737f1b..34c93001faf 100644 --- a/src/platforms/96b_carbon/platform.h +++ b/src/platforms/96b_carbon/platform.h @@ -28,7 +28,7 @@ #include "timing_stm32.h" #include "version.h" -#define PLATFORM_IDENT "(Carbon)" +#define PLATFORM_IDENT "(96b Carbon) " /* * Important pin mappings for Carbon implementation: diff --git a/src/platforms/common/aux_serial.c b/src/platforms/common/aux_serial.c index 12d5bf065da..5d44dfb37d1 100644 --- a/src/platforms/common/aux_serial.c +++ b/src/platforms/common/aux_serial.c @@ -37,9 +37,9 @@ #include "aux_serial.h" static char aux_serial_receive_buffer[AUX_UART_BUFFER_SIZE]; -/* Fifo in pointer, writes assumed to be atomic, should be only incremented within RX ISR */ +/* FIFO in pointer, writes assumed to be atomic, should be only incremented within RX ISR */ static uint16_t aux_serial_receive_write_index = 0; -/* Fifo out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */ +/* FIFO out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */ static uint16_t aux_serial_receive_read_index = 0; #if defined(STM32F0) || defined(STM32F1) || defined(STM32F3) || defined(STM32F4) || defined(STM32F7) diff --git a/src/platforms/common/blackpill-f4/Makefile.inc b/src/platforms/common/blackpill-f4/Makefile.inc index 79cbd5e768d..086e1b21608 100644 --- a/src/platforms/common/blackpill-f4/Makefile.inc +++ b/src/platforms/common/blackpill-f4/Makefile.inc @@ -57,18 +57,30 @@ VPATH += \ SRC += \ blackpill-f4.c \ - traceswodecode.c \ serialno.c \ timing.c \ - timing_stm32.c + timing_stm32.c \ + swo.c \ + swo_itm_decode.c -ifeq ($(TRACESWO_PROTOCOL), 1) -SRC += traceswo.c -CFLAGS += -DTRACESWO_PROTOCOL=1 -else -SRC += traceswoasync.c -CFLAGS += -DTRACESWO_PROTOCOL=2 +# If SWO_ENCODING has not been given, default it to including both modes +ifndef SWO_ENCODING + SWO_ENCODING = 3 +endif + +# Include the files for either: Manchester-only (1), UART-only (2) or both modes (3) +ifeq ($(SWO_ENCODING), 1) + SRC += swo_manchester.c +else ifeq ($(SWO_ENCODING), 2) + SRC += swo_uart.c +else ifeq ($(SWO_ENCODING), 3) + SRC += \ + swo_manchester.c \ + swo_uart.c +else # If we got some other value, that's an error so report it + $(error Invalid value for SWO encoding, must be one of 1, 2, or 3) endif +CFLAGS += -DSWO_ENCODING=$(SWO_ENCODING) ifneq ($(BMD_BOOTLOADER), 1) all: blackmagic.bin diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.h b/src/platforms/common/blackpill-f4/blackpill-f4.h index ddb82975eef..9745755981d 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.h +++ b/src/platforms/common/blackpill-f4/blackpill-f4.h @@ -32,6 +32,8 @@ #include "timing.h" #include "timing_stm32.h" +#define PLATFORM_HAS_TRACESWO + #if ENABLE_DEBUG == 1 #define PLATFORM_HAS_DEBUG extern bool debug_bmp; @@ -64,6 +66,8 @@ extern bool debug_bmp; #if ALTERNATIVE_PINOUT < 1 || ALTERNATIVE_PINOUT > 3 #error "Invalid value for ALTERNATIVE_PINOUT. Value is smaller than 1, or larger than 3. Value must be between 1 and 3" #endif +#else +#define ALTERNATIVE_PINOUT 0 #endif /* ALTERNATIVE_PINOUT */ /* @@ -77,21 +81,21 @@ extern bool debug_bmp; * The maximum number of input arguments is 4. * The 3rd and 4th arguments to this function are optional. */ -#ifndef ALTERNATIVE_PINOUT // if ALTERNATIVE_PINOUT is not defined -#define PINOUT_SWITCH(opt0, ...) (opt0) // select the first argument +#if ALTERNATIVE_PINOUT == 0 +#define PINOUT_SWITCH(opt0, ...) (opt0) // Select the first argument #elif ALTERNATIVE_PINOUT == 1 -#define PINOUT_SWITCH(opt0, opt1, ...) (opt1) // select the second argument +#define PINOUT_SWITCH(opt0, opt1, ...) (opt1) // Select the second argument #elif ALTERNATIVE_PINOUT == 2 -#define PINOUT_SWITCH(opt0, opt1, opt2, ...) (opt2) // select the third argument +#define PINOUT_SWITCH(opt0, opt1, opt2, ...) (opt2) // Select the third argument #elif ALTERNATIVE_PINOUT == 3 -#define PINOUT_SWITCH(opt0, opt1, opt2, opt3, ...) (opt3) // select the fourth argument -#endif /* ALTERNATIVE_PINOUT */ +#define PINOUT_SWITCH(opt0, opt1, opt2, opt3, ...) (opt3) // Select the fourth argument +#endif /* * Important pin mappings for STM32 implementation: * * JTAG/SWD * * PB6 or PB5: TDI - * * PB7 or PB6: TDO/TRACESWO + * * PB7 or PB6: TDO/SWO * * PB8 or PB7: TCK/SWCLK * * PB9 or PB8: TMS/SWDIO * * PA6 or PB3: TRST @@ -154,6 +158,10 @@ extern bool debug_bmp; #define NRST_PORT PINOUT_SWITCH(GPIOA, GPIOB) #define NRST_PIN PINOUT_SWITCH(GPIO5, GPIO4) +/* SWO comes in on the same pin as TDO */ +#define SWO_PORT GPIOB +#define SWO_PIN PINOUT_SWITCH(GPIO7, GPIO6) + #define PWR_BR_PORT PINOUT_SWITCH(GPIOA, GPIOB) #define PWR_BR_PIN PINOUT_SWITCH(GPIO1, GPIO9) @@ -278,25 +286,25 @@ extern bool debug_bmp; #define IRQ_PRI_USB (1U << 4U) #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #define IRQ_PRI_SWO_DMA (0U << 4U) -#define PLATFORM_HAS_TRACESWO -#define NUM_TRACE_PACKETS 256U /* 16K buffer */ -//#define TRACESWO_PROTOCOL 2U /* 1 = RZ/Manchester, 2 = NRZ/async/uart */ - -#if TRACESWO_PROTOCOL == 1 - -/* Use TIM4 Input 2 (from PB7/TDO) or Input 1 (from PB6/TDO), AF2, trigger on Rising Edge */ -#define TRACE_TIM TIM4 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4) -#define TRACE_IRQ NVIC_TIM4_IRQ -#define TRACE_ISR(x) tim4_isr(x) -#define TRACE_IC_IN PINOUT_SWITCH(TIM_IC_IN_TI2, TIM_IC_IN_TI1) -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#define TRACE_TIM_PIN_AF GPIO_AF2 - -#elif TRACESWO_PROTOCOL == 2 +/* Use TIM4 Input 2 (from PB7/TDO) or Input 1 (from PB6/TDO), AF2, triggered on rising edge */ +#define SWO_TIM TIM4 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4) +#define SWO_TIM_IRQ NVIC_TIM4_IRQ +#define SWO_TIM_ISR(x) tim4_isr(x) +#define SWO_IC_IN PINOUT_SWITCH(TIM_IC_IN_TI2, TIM_IC_IN_TI1) +#define SWO_IC_RISING PINOUT_SWITCH(TIM_IC2, TIM_IC1) +#define SWO_CC_RISING PINOUT_SWITCH(TIM4_CCR2, TIM4_CCR1) +#define SWO_ITR_RISING PINOUT_SWITCH(TIM_DIER_CC2IE, TIM_DIER_CC1IE) +#define SWO_STATUS_RISING PINOUT_SWITCH(TIM_SR_CC2IF, TIM_SR_CC1IF) +#define SWO_IC_FALLING PINOUT_SWITCH(TIM_IC1, TIM_IC2) +#define SWO_CC_FALLING PINOUT_SWITCH(TIM4_CCR1, TIM4_CCR2) +#define SWO_STATUS_FALLING PINOUT_SWITCH(TIM_SR_CC1IF, TIM_SR_CC2IF) +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN PINOUT_SWITCH(TIM_SMCR_TS_TI2FP2, TIM_SMCR_TS_TI1FP1) +#define SWO_TIM_PIN_AF GPIO_AF2 /* On F411 use USART1_RX mapped on PB7 for async capture */ #define SWO_UART USBUSART1 @@ -307,14 +315,12 @@ extern bool debug_bmp; #define SWO_UART_PIN_AF GPIO_AF7 /* Bind to the same DMA Rx channel */ -#define SWO_DMA_BUS USBUSART1_DMA_BUS -#define SWO_DMA_CLK USBUSART1_DMA_CLK -#define SWO_DMA_CHAN USBUSART1_DMA_RX_CHAN -#define SWO_DMA_IRQ USBUSART1_DMA_RX_IRQ -#define SWO_DMA_ISR(x) USBUSART1_DMA_RX_ISRx(x) -#define SWO_DMA_TRG DMA_SxCR_CHSEL_4 - -#endif /* TRACESWO_PROTOCOL */ +#define SWO_DMA_BUS USBUSART1_DMA_BUS +#define SWO_DMA_CLK USBUSART1_DMA_CLK +#define SWO_DMA_CHAN USBUSART1_DMA_RX_CHAN +#define SWO_DMA_IRQ USBUSART1_DMA_RX_IRQ +#define SWO_DMA_ISR(x) USBUSART1_DMA_RX_ISRx(x) +#define SWO_DMA_TRG DMA_SxCR_CHSEL_4 #define SET_RUN_STATE(state) \ { \ diff --git a/src/platforms/common/blackpill-f4/meson.build b/src/platforms/common/blackpill-f4/meson.build index a554b3f1d03..2d399facc76 100644 --- a/src/platforms/common/blackpill-f4/meson.build +++ b/src/platforms/common/blackpill-f4/meson.build @@ -67,14 +67,13 @@ if on_carrier_board endif trace_protocol = get_option('trace_protocol') -if trace_protocol == '3' - trace_protocol = '2' +probe_blackpill_args += [f'-DSWO_ENCODING=@trace_protocol@'] +probe_blackpill_dependencies = [platform_stm32_swo] +if trace_protocol in ['1', '3'] + probe_blackpill_dependencies += platform_stm32_swo_manchester endif -probe_blackpill_args += [f'-DTRACESWO_PROTOCOL=@trace_protocol@'] -if trace_protocol == '1' - probe_blackpill_dependencies = fixme_platform_stm32_traceswo -else - probe_blackpill_dependencies = fixme_platform_stm32_traceswoasync +if trace_protocol in ['2', '3'] + probe_blackpill_dependencies += platform_stm32_swo_uart endif if bmd_bootloader diff --git a/src/platforms/common/stm32/meson.build b/src/platforms/common/stm32/meson.build index 1cd416fcb56..dec705b59c6 100644 --- a/src/platforms/common/stm32/meson.build +++ b/src/platforms/common/stm32/meson.build @@ -34,14 +34,14 @@ platform_stm32_sources = files( 'gdb_if.c', 'serialno.c', 'timing_stm32.c', - 'traceswodecode.c', ) -# TODO: add proper traceswoasync support -# This is a temporary hack to allow selecting traceswoasync vs traceswo implementation -fixme_platform_stm32_traceswo = declare_dependency(sources: files('traceswo.c')) -fixme_platform_stm32_traceswoasync = declare_dependency(sources: files('traceswoasync.c')) -fixme_platform_stm32f7_traceswoasync = declare_dependency(sources: files('traceswoasync_f723.c')) +platform_stm32_swo = declare_dependency(sources: files( + 'swo.c', + 'swo_itm_decode.c', +)) +platform_stm32_swo_manchester = declare_dependency(sources: files('swo_manchester.c')) +platform_stm32_swo_uart = declare_dependency(sources: files('swo_uart.c')) # RTT support handling if get_option('rtt_support') diff --git a/src/platforms/common/stm32/swo.c b/src/platforms/common/stm32/swo.c new file mode 100644 index 00000000000..8b32a52f510 --- /dev/null +++ b/src/platforms/common/stm32/swo.c @@ -0,0 +1,171 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2024 1BitSquared + * Modified by Rachel Mant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "general.h" +#include "platform.h" +#include "gdb_packet.h" +#include "swo.h" +#include "swo_internal.h" + +#include +#include +#include + +/* + * Management and muxing layer for the SWO implementations + * + * SWO_ENCODING takes 3 possible states guaranteed by the build system: + * 1: Manchester coded SWO only + * 2: UART/NRZ coded SWO only + * 3: Both enabled w/ the full switching mechanism provided + * + * It is an error for SWO_ENCODING to be undefined if PLATFORM_HAS_TRACESWO is + * defined by the platform. It is an error to include this file in the build + * under this circumstance as it requires SWO_ENCODING to be defined and valid. + */ + +/* Current SWO decoding mode being used */ +swo_coding_e swo_current_mode; + +/* Whether ITM decoding is engaged */ +bool swo_itm_decoding = false; + +/* + * Dynamically-allocated data buffer, current read index, current write index, + * current fill level, and total available buffer size. We initialise to 0 just + * to get a consistent starting point, but the indexes do not matter once up and + * running. It only matters the post-condition of swo_deinit() that no bytes + * are available and the indicies are equal to each other are kept for entry + * into swo_init() and the successful execution of it all. + */ +uint8_t *swo_buffer; +uint16_t swo_buffer_read_index = 0U; +uint16_t swo_buffer_write_index = 0U; +_Atomic uint16_t swo_buffer_bytes_available = 0U; + +void swo_init(const swo_coding_e swo_mode, const uint32_t baudrate, const uint32_t itm_stream_bitmask) +{ +#if SWO_ENCODING == 1 + (void)baudrate; +#endif + /* Make sure any existing SWO capture is first spun down */ + if (swo_current_mode != swo_none) + swo_deinit(false); + /* If we're spinning this up fresh, allocate a buffer for the data */ + else { + /* + * This needs to be at least 2 endpoint buffers large, more is better to a point but + * it has diminishing returns. Aim for no more than 8KiB of buffer as after that, larger + * is entirely pointless. + */ + swo_buffer = malloc(SWO_BUFFER_SIZE); + /* Check for allocation failure and abort initialisation if we see it failed */ + if (!swo_buffer) { + DEBUG_ERROR("malloc: failed in %s\n", __func__); + return; + } + } + + /* Configure the ITM decoder and state */ + swo_itm_decode_set_mask(itm_stream_bitmask); + swo_itm_decoding = itm_stream_bitmask != 0; + + /* Now determine which mode to enable and initialise it */ +#if SWO_ENCODING == 1 || SWO_ENCODING == 3 + if (swo_mode == swo_manchester) + swo_manchester_init(); +#endif +#if SWO_ENCODING == 2 || SWO_ENCODING == 3 + if (swo_mode == swo_nrz_uart) { + /* Ensure the baud rate is something sensible */ + swo_uart_init(baudrate ? baudrate : SWO_DEFAULT_BAUD); + gdb_outf("Baudrate: %" PRIu32 " ", swo_uart_get_baudrate()); + } +#endif + /* Make a note of which mode we initialised into */ + swo_current_mode = swo_mode; +} + +void swo_deinit(const bool deallocate) +{ +#if SWO_ENCODING == 1 || SWO_ENCODING == 3 + if (swo_current_mode == swo_manchester) + swo_manchester_deinit(); +#endif +#if SWO_ENCODING == 2 || SWO_ENCODING == 3 + if (swo_current_mode == swo_nrz_uart) + swo_uart_deinit(); +#endif + + /* Spin waiting for all data to finish being transmitted */ + while (swo_buffer_bytes_available) { + swo_send_buffer(usbdev, SWO_ENDPOINT); + __WFI(); + } + + /* If we're being asked to give the SWO buffer back, then free it */ + if (deallocate) + free(swo_buffer); + swo_current_mode = swo_none; +} + +void swo_send_buffer(usbd_device *const dev, const uint8_t ep) +{ + /* NOTLINTNEXTLINE(clang-diagnostic-error) */ + static atomic_flag reentry_flag = ATOMIC_FLAG_INIT; + + /* If we are already in this routine then we don't need to come in again */ + if (atomic_flag_test_and_set_explicit(&reentry_flag, memory_order_relaxed)) + return; + + const uint16_t bytes_available = swo_buffer_bytes_available; + /* + * If there is somthing to move, move the next up-to SWO_ENDPOINT_SIZE bytes chunk of it (USB) + * or the whole lot (ITM decoding) as appropriate + */ + if (bytes_available) { + uint16_t result; + /* If we're doing decoding, hand the data to the ITM decoder */ + if (swo_itm_decoding) { + /* If we're in UART mode, hand as much as we can all at once */ + if (swo_current_mode == swo_nrz_uart) + result = swo_itm_decode(dev, CDCACM_UART_ENDPOINT, swo_buffer + swo_buffer_read_index, + MIN(bytes_available, SWO_BUFFER_SIZE - swo_buffer_read_index)); + /* Otherwise, if we're in Manchester mode, manage the amount moved the same as we do USB */ + else + result = swo_itm_decode(dev, CDCACM_UART_ENDPOINT, swo_buffer + swo_buffer_read_index, + MIN(bytes_available, SWO_ENDPOINT_SIZE)); + } else + /* Otherwise, queue the new data to the SWO data endpoint */ + result = usbd_ep_write_packet( + dev, ep, swo_buffer + swo_buffer_read_index, MIN(bytes_available, SWO_ENDPOINT_SIZE)); + + /* If we actually queued/processed some data, update indicies etc */ + if (result) { + /* + * Update the amount read and consumed */ + swo_buffer_read_index += result; + swo_buffer_read_index &= SWO_BUFFER_SIZE - 1U; + swo_buffer_bytes_available -= result; + } + } + + atomic_flag_clear_explicit(&reentry_flag, memory_order_relaxed); +} diff --git a/src/platforms/common/stm32/swo_internal.h b/src/platforms/common/stm32/swo_internal.h new file mode 100644 index 00000000000..dc9fda16239 --- /dev/null +++ b/src/platforms/common/stm32/swo_internal.h @@ -0,0 +1,49 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2024 1BitSquared + * Written by Rachel Mant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PLATFORMS_COMMON_STM32_SWO_INTERNAL_H +#define PLATFORMS_COMMON_STM32_SWO_INTERNAL_H + +#include "usb.h" + +/* + * Total buffer size for the dynamic buffer + * NB: This *must* result in a value that is a power of two. + */ +#define SWO_BUFFER_SIZE (NUM_SWO_USB_PACKETS * SWO_ENDPOINT_SIZE) + +/* Control variables shared between decoders */ +extern bool swo_itm_decoding; + +/* Dynamically-allocated data buffer, current read index, current write index, and current fill level */ +extern uint8_t *swo_buffer; +extern uint16_t swo_buffer_read_index; +extern uint16_t swo_buffer_write_index; +extern _Atomic uint16_t swo_buffer_bytes_available; + +/* Manchester-mode implementation functions */ +void swo_manchester_init(void); +void swo_manchester_deinit(void); + +/* UART-mode implementation functions */ +void swo_uart_init(uint32_t baudrate); +void swo_uart_deinit(void); + +#endif /* PLATFORMS_COMMON_STM32_SWO_INTERNAL_H */ diff --git a/src/platforms/common/stm32/swo_itm_decode.c b/src/platforms/common/stm32/swo_itm_decode.c new file mode 100644 index 00000000000..1a34f8cea27 --- /dev/null +++ b/src/platforms/common/stm32/swo_itm_decode.c @@ -0,0 +1,80 @@ +/* + * This file is part of the Black Magic Debug project. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file implements decoding of SWO data when that data is an ITM SWIT data stream. + * It puts the decoded data onto the aux USB serial interface for consumption. + */ + +#include "general.h" +#include "usb_serial.h" +#include "swo.h" + +static uint8_t itm_decoded_buffer[CDCACM_PACKET_SIZE]; +static uint16_t itm_decoded_buffer_index = 0; +static uint32_t itm_decode_mask = 0; /* bitmask of channels to print */ +static uint8_t itm_packet_length = 0; /* decoder state */ +static bool itm_decode_packet = false; + +uint16_t swo_itm_decode(usbd_device *usbd_dev, uint8_t ep, const uint8_t *data, uint16_t len) +{ + /* Check if we've got a valid USB device */ + /* XXX: Can this ever actually be false?! */ + if (usbd_dev == NULL) + return 0U; + + /* Step through each byte in the SWO data buffer */ + for (uint16_t idx = 0; idx < len; ++idx) { + /* If we're waiting for a new ITM packet, start decoding the new byte as a header */ + if (itm_packet_length == 0) { + /* Check that the required to be 0 bit of the SWIT packet is, and that the size bits aren't 0 */ + if ((data[idx] & 0x04U) == 0U && (data[idx] & 0x03U) != 0U) { + /* Now extract the stimulus port address (stream number) and payload size */ + uint8_t stream = data[idx] >> 3U; + /* Map 1 -> 1, 2 -> 2, and 3 -> 4 */ + itm_packet_length = 1U << ((data[idx] & 3U) - 1U); + /* Determine if the packet should be displayed */ + itm_decode_packet = (itm_decode_mask & (1U << stream)) != 0U; + } else { + /* If the bit is not 0, this is an invalid SWIT packet, so reset state */ + itm_decode_packet = false; + itm_decoded_buffer_index = 0; + } + } else { + /* If we should actually decode this packet, then forward the data to the decoded data buffer */ + if (itm_decode_packet) { + itm_decoded_buffer[itm_decoded_buffer_index++] = data[idx]; + /* If the buffer has filled up and needs flushing, try to flush the data to the serial endpoint */ + if (itm_decoded_buffer_index == sizeof(itm_decoded_buffer)) { + /* However, if the link is not yet up, drop the packet data silently */ + if (usb_get_config() && gdb_serial_get_dtr()) + usbd_ep_write_packet(usbd_dev, ep, itm_decoded_buffer, itm_decoded_buffer_index); + itm_decoded_buffer_index = 0U; + } + } + /* Mark the byte consumed regardless */ + --itm_packet_length; + } + } + return len; +} + +void swo_itm_decode_set_mask(uint32_t mask) +{ + itm_decode_mask = mask; +} diff --git a/src/platforms/common/stm32/swo_manchester.c b/src/platforms/common/stm32/swo_manchester.c new file mode 100644 index 00000000000..61c71f8a1f8 --- /dev/null +++ b/src/platforms/common/stm32/swo_manchester.c @@ -0,0 +1,301 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2012 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Modified by Uwe Bonnes + * Copyright (C) 2024 1BitSquared + * Modified by Rachel Mant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file implements recovery and capture of Machester encoded SWO trace output + * + * References: + * DDI0403 - ARMv7-M Architecture Reference Manual, version E.e + * - https://developer.arm.com/documentation/ddi0403/latest/ + * DDI0314 - CoreSight Components Technical Reference Manual, version 1.0, rev. H + * - https://developer.arm.com/documentation/ddi0314/latest/ + * + * The basic idea is that SWO comes in on a pin connected to a timer block, + * and because Manchester coding is self-clocking we can determine the timing + * for that input signal when it's active, so: use the timer to capture edge + * transition timings; fire an interrupt each complete cycle; and then use some + * timing analysis on the CPU to extract the SWO data sequence. + * + * We use the first capture channel of a pair to capture the cycle time and + * thee second to capture the high time (mark period). + */ + +#include "general.h" +#include "platform.h" +#include "usb.h" +#include "swo.h" +#include "swo_internal.h" + +#include +#include +#include + +/* How many timer clock cycles the half period of a cycle of the SWO signal is allowed to be off by */ +#define ALLOWED_PERIOD_ERROR 5U + +#define TIM_SR_MASK \ + (TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_TIF | TIM_SR_CC1OF | \ + TIM_SR_CC2OF | TIM_SR_CC3OF | TIM_SR_CC4OF) + +/* Manchester bit capture buffer and current bit index */ +static uint8_t swo_data[16U]; +static uint8_t swo_data_bit_index = 0; +/* Number of timer clock cycles that describe half a bit period as detected */ +static uint32_t swo_half_bit_period = 0U; + +void swo_manchester_init(void) +{ + /* Make sure the timer block is clocked on platforms that don't do this in their `platform_init()` */ + SWO_TIM_CLK_EN(); + +#if defined(STM32F4) || defined(STM32F0) || defined(STM32F3) || defined(STM32F7) + /* Set any required pin alt-function configuration - TIM3/TIM4/TIM5 are AF2 */ + gpio_mode_setup(SWO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SWO_PIN); + gpio_set_af(SWO_PORT, SWO_TIM_PIN_AF, SWO_PIN); +#else + /* Then make sure the IO pin used is properly set up as an input routed to the timer */ + gpio_set_mode(SWO_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SWO_PIN); +#endif + + /* + * Start setting the timer block up by picking a pair of cross-linked capture channels suitable for the input, + * and configure them to consume the input channel for the SWO pin. We use one in rising edge mode and the + * other in falling to get the mark period and cycle period - together these define all elements of a wiggle. + * NB: "SWO_IC" here refers to the Input Capture channels being used + */ + timer_ic_set_input(SWO_TIM, SWO_IC_RISING, SWO_IC_IN); + timer_ic_set_polarity(SWO_TIM, SWO_IC_RISING, TIM_IC_RISING); + timer_ic_set_input(SWO_TIM, SWO_IC_FALLING, SWO_IC_IN); + timer_ic_set_polarity(SWO_TIM, SWO_IC_FALLING, TIM_IC_FALLING); + + /* + * Use reset mode to trigger the timer, which makes the counter reset and start counting anew + * when a rising edge is detected on the input pin via the filtered input channel as a trigger source + */ + timer_slave_set_trigger(SWO_TIM, SWO_TRIG_IN); + timer_slave_set_mode(SWO_TIM, TIM_SMCR_SMS_RM); + + /* Enable capture interrupt */ + nvic_set_priority(SWO_TIM_IRQ, IRQ_PRI_SWO_TIM); + nvic_enable_irq(SWO_TIM_IRQ); + timer_enable_irq(SWO_TIM, SWO_ITR_RISING); + + /* Enable the capture channels */ + timer_ic_enable(SWO_TIM, SWO_IC_RISING); + timer_ic_enable(SWO_TIM, SWO_IC_FALLING); + /* Make sure all the status register bits are cleared prior to enabling the counter */ + timer_clear_flag(SWO_TIM, TIM_SR_MASK); + /* Set the period to an improbable value */ + timer_set_period(SWO_TIM, UINT32_MAX); + + /* Now we've got everything configured and ready, enable the timer */ + timer_enable_counter(SWO_TIM); +} + +void swo_manchester_deinit(void) +{ + /* Disable the timer capturing the incomming data stream */ + timer_disable_counter(SWO_TIM); + timer_slave_set_mode(SWO_TIM, TIM_SMCR_SMS_OFF); + + /* Reset state so that when init is called we wind up in a fresh capture state */ + swo_data_bit_index = 0U; + swo_half_bit_period = 0U; + +#if defined(STM32F4) || defined(STM32F0) || defined(STM32F3) || defined(STM32F7) + gpio_mode_setup(SWO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_PIN); +#else + /* Put the GPIO back into normal service as a GPIO */ + gpio_set_mode(SWO_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SWO_PIN); +#endif +} + +void swo_buffer_data(void) +{ + const uint8_t byte_count = swo_data_bit_index >> 3U; + /* First, see how much space we have in the buffer and move what we can */ + const uint16_t amount = MIN(byte_count, SWO_BUFFER_SIZE - swo_buffer_write_index); + memcpy(swo_buffer + swo_buffer_write_index, swo_data, amount); + swo_buffer_write_index += amount; + swo_buffer_write_index &= SWO_BUFFER_SIZE - 1U; + swo_buffer_bytes_available += amount; + /* Make sure we're sending the data if we've got more than an endpoint buffer's worth */ + if (swo_buffer_bytes_available >= SWO_ENDPOINT_SIZE) { + swo_send_buffer(usbdev, SWO_ENDPOINT); + /* If we have anything left to move, put that at the start of the buffer */ + if (amount != byte_count) { + const uint16_t remainder = byte_count - amount; + memcpy(swo_buffer, swo_data + amount, remainder); + swo_buffer_write_index = remainder; + swo_buffer_bytes_available += remainder; + } + } + swo_data_bit_index = 0U; +} + +void SWO_TIM_ISR(void) +{ + static uint8_t bit_value; + const uint16_t status = TIM_SR(SWO_TIM); + + const uint32_t cycle_period = SWO_CC_RISING; + /* Check that we entered the handler because of a fresh trigger but have not yet had a chance to capture data */ + if ((status & SWO_STATUS_RISING) && cycle_period == 0U) { + /* Clear the rising edge flag and wait for it to set again */ + timer_clear_flag(SWO_TIM, SWO_STATUS_RISING | SWO_STATUS_FALLING | SWO_STATUS_OVERFLOW); + return; + } + + timer_clear_flag(SWO_TIM, SWO_STATUS_RISING | SWO_STATUS_FALLING | SWO_STATUS_OVERFLOW | TIM_SR_UIF); + + const uint32_t mark_period = SWO_CC_FALLING; + const uint32_t space_period = cycle_period - mark_period; + + /* Reset decoder state if crazy things happened */ + if (cycle_period <= mark_period || (swo_half_bit_period && mark_period < swo_half_bit_period) || mark_period == 0U) + goto flush_and_reset; + + /* If the bit time is not yet known */ + if (swo_half_bit_period == 0U) { + /* Are we here because we got an interrupt but not for the rising edge capture channel? */ + if (!(status & SWO_STATUS_RISING)) + /* We're are, so leave early */ + return; + /* + * We're here because of the rising edge, so we've got our first (start) bit. + * Calculate the ratio of the mark period to the space period within a cycle + * + * At this point, the waveform for what's come in should look something like one of these two options: + * ▁▁┊╱▔╲▁┊╱▔ ▁▁┊╱▔╲▁┊▁▁╱▔ + * The first sequence is the start bit followed by a 1, and the second is followed instead by a 0 + */ + const uint32_t adjusted_mark_period = mark_period - ALLOWED_PERIOD_ERROR; + const uint32_t duty_ratio = cycle_period / adjusted_mark_period; + /* + * Check that the duty cycle ratio is between 2:1 and 3:1, indicating an + * aproximately even mark-to-space ratio, taking into account the possibility of + * the double space bit time caused by start + 0 + */ + if (duty_ratio < 2U || duty_ratio > 3U) + return; + /* + * Now we've established a valid duty cycle ratio, store the mark period as the bit timing and + * initialise the capture engine: check whether we captured, the start of a 0 bit to set the next + * bit value, and configure the timer maximum period to 6x the current max half bit period, enabling + * overflow checking now we have an overflow target for the timer + */ + swo_half_bit_period = adjusted_mark_period; + bit_value = space_period >= swo_half_bit_period * 2U ? 0U : 1U; + /* XXX: Need to make sure that this isn't setting a value outside the range of the timer */ + timer_set_period(SWO_TIM, mark_period * 6U); + timer_clear_flag(SWO_TIM, TIM_SR_UIF | SWO_STATUS_OVERFLOW); + timer_enable_irq(SWO_TIM, TIM_DIER_UIE); + } else { + /* + * We start off needing to store a newly captured bit - the value of which is determined in the *previous* + * traversal of this function. We don't yet worry about whether we're starting half way through a bit or not. + * + * If this would start a new byte in the data buffer, zero it to start with + */ + if ((swo_data_bit_index & 7U) == 0U) + swo_data[swo_data_bit_index >> 3U] = 0U; + /* Store the new bit in the buffer and move along */ + swo_data[swo_data_bit_index >> 3U] |= bit_value << (swo_data_bit_index & 7U); + ++swo_data_bit_index; + + /* + * Having stored a bit, check if we've got a long cycle period - this can happen due to any sequence + * involving at least one bit transition (0 -> 1, 1 -> 0), or a 1 -> STOP sequence: + * 0 -> 1: ▁▁╱▔┊▔▔╲▁ + * 1 -> 0: ▔▔╲▁┊▁▁╱▔ + * 1 -> STOP: ▔▔╲▁┊▁▁▁▁ + * + * An even longer non-stop cycle time occurs when a 0 -> 1 -> 0 sequence is encountered: + * ▁▁╱▔┊▔▔╲▁┊▁▁╱▔ + * + * All of these cases need special handling and can appear to this decoder as part of one of the following: + * 0 -> 1 -> 0: ▁▁╱▔┊▔▔╲▁┊▁▁╱▔ (4x half bit periods) + * 0 -> 1 -> 1: ▁▁╱▔┊▔▔╲▁┊╱▔╲▁ (3x half bit periods) + * 0 -> 1 -> STOP: ▁▁╱▔┊▔▔╲▁┊▁▁▁▁ + * 1 -> 1 -> 0: ▔▔╲▁┊╱▔╲▁┊▁▁╱▔ (3x half bit periods) + * 1 -> 1 -> STOP: ▔▔╲▁┊╱▔╲▁┊▁▁▁▁ + * 1 -> 0 -> STOP: ▔▔╲▁┊▁▁╱▔┊╲▁▁▁ + * + * The bit write that has already occured deals with the lead-in part of all of these. + */ + if (cycle_period >= swo_half_bit_period * 3U) { + /* + * Having determined that we're in a long cycle, we need to figure out which kind. + * If the mark period is short, then whether we're starting half way into a bit determines + * if the next is a 1 (not half way in) or a 0 (half way in). This copies the current bit value. + * If the mark period is long, then this can only occur from a 0 -> 1 transition where we're + * half way into the cycle. Anything else indicates a fault occured. + */ + if (mark_period >= swo_half_bit_period * 2U) { + if (bit_value == 1U) + goto flush_and_reset; /* Something bad happened and we lost sync */ + bit_value = 1U; + } + + /* + * We now know the value of the extra bit, if it's from anything other than a short mark, long space, + * then we need to store that next bit. + */ + if (mark_period >= swo_half_bit_period * 2U || space_period < swo_half_bit_period * 2U) { + /* If this would overflow the buffer, then do nothing */ + if (swo_data_bit_index < 128U) { + /* If this would start a new byte in the data buffer, zero it to start with */ + if ((swo_data_bit_index & 7U) == 0U) + swo_data[swo_data_bit_index >> 3U] = 0U; + /* Store the new bit in the buffer and move along */ + swo_data[swo_data_bit_index >> 3U] |= bit_value << (swo_data_bit_index & 7U); + ++swo_data_bit_index; + } + } + /* If it's a long space, we just saw a 1 -> 0 transition */ + if (space_period >= swo_half_bit_period * 2U) { + /* Unless of course this was acompanied by a short mark period, in which case it's a STOP bit */ + if (bit_value == 0U) + goto flush_and_reset; + bit_value = 0U; + } + + /* + * We've now written enough data to the buffer, so we have one final check: + * If the cycle has a long space, we need to determine how long to check for STOP bits. + */ + if (space_period >= swo_half_bit_period * 3U) + goto flush_and_reset; + } + } + + /* If the buffer is not full, and we haven't encountered a STOP bit, we're done here */ + if (swo_data_bit_index < 128U) + return; + +flush_and_reset: + timer_set_period(SWO_TIM, UINT32_MAX); + timer_disable_irq(SWO_TIM, TIM_DIER_UIE); + swo_buffer_data(); + swo_half_bit_period = 0; +} diff --git a/src/platforms/common/stm32/traceswoasync.c b/src/platforms/common/stm32/swo_uart.c similarity index 52% rename from src/platforms/common/stm32/traceswoasync.c rename to src/platforms/common/stm32/swo_uart.c index af8f58225a9..44c64743267 100644 --- a/src/platforms/common/stm32/traceswoasync.c +++ b/src/platforms/common/stm32/swo_uart.c @@ -3,6 +3,8 @@ * * Based on work that is Copyright (C) 2017 Black Sphere Technologies Ltd. * Copyright (C) 2017 Dave Marples + * Copyright (C) 2024 1BitSquared + * Modified by Rachel Mant * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,23 +21,22 @@ */ /* - * This file implements capture of the Trace/SWO output using async signalling. + * This file implements recovery and capture of UART/NRZ encoded SWO trace output * - * ARM DDI 0403D - ARMv7M Architecture Reference Manual - * ARM DDI 0337I - Cortex-M3 Technical Reference Manual - * ARM DDI 0314H - CoreSight Components Technical Reference Manual + * References: + * DDI0403 - ARMv7-M Architecture Reference Manual, version E.e + * - https://developer.arm.com/documentation/ddi0403/latest/ + * DDI0314 - CoreSight Components Technical Reference Manual, version 1.0, rev. H + * - https://developer.arm.com/documentation/ddi0314/latest/ + * + * We use a hardware UART to capture and recover the data, and DMA to buffer it. */ -/* TDO/TRACESWO signal comes into the SWOUSART RX pin. */ - #include "general.h" #include "platform.h" #include "usb.h" -#include "traceswo.h" - -#include -#include -#include +#include "swo.h" +#include "swo_internal.h" #include #include @@ -58,58 +59,40 @@ #define DMA_PL_HIGH DMA_CCR_PL_HIGH #endif -static volatile uint32_t write_index; /* Packet currently received via UART */ -static volatile uint32_t read_index; /* Packet currently waiting to transmit to USB */ -/* Packets arrived from the SWO interface */ -static uint8_t *trace_rx_buf = NULL; -/* Packet pingpong buffer used for receiving packets */ -static uint8_t pingpong_buf[2 * TRACE_ENDPOINT_SIZE]; -/* SWO decoding */ -static bool decoding = false; - -void trace_buf_drain(usbd_device *dev, uint8_t ep) +void swo_uart_init(const uint32_t baudrate) { - static atomic_flag reentry_flag = ATOMIC_FLAG_INIT; - - /* If we are already in this routine then we don't need to come in again */ - if (atomic_flag_test_and_set_explicit(&reentry_flag, memory_order_relaxed)) - return; - /* Attempt to write everything we buffered */ - if (write_index != read_index) { - uint16_t result; - if (decoding) - /* write decoded swo packets to the uart port */ - result = traceswo_decode( - dev, CDCACM_UART_ENDPOINT, &trace_rx_buf[read_index * TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - else - /* write raw swo packets to the trace port */ - result = - usbd_ep_write_packet(dev, ep, &trace_rx_buf[read_index * TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - if (result) - read_index = (read_index + 1U) % NUM_TRACE_PACKETS; - } - atomic_flag_clear_explicit(&reentry_flag, memory_order_relaxed); -} + /* Ensure required peripherals are spun up */ + /* TODO: Move this into platform_init()! */ + rcc_periph_clock_enable(SWO_UART_CLK); + rcc_periph_clock_enable(SWO_DMA_CLK); -uint32_t traceswo_get_baudrate(void) -{ - return usart_get_baudrate(SWO_UART); -} + /* Reconfigure the GPIO over to UART mode */ +#if defined(STM32F4) || defined(STM32F0) || defined(STM32F3) || defined(STM32F7) + gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, SWO_UART_RX_PIN); + gpio_set_output_options(SWO_UART_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, SWO_UART_RX_PIN); + gpio_set_af(SWO_UART_PORT, SWO_UART_PIN_AF, SWO_UART_RX_PIN); +#else + gpio_set_mode(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SWO_UART_RX_PIN); + /* Pull SWO pin high to keep open SWO line ind uart idle state! */ + gpio_set(SWO_UART_PORT, SWO_UART_RX_PIN); +#endif -void traceswo_setspeed(uint32_t baudrate) -{ - dma_disable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); - usart_disable(SWO_UART); + /* Set up the UART for 8N1 at the requested baud rate in RX only */ bmd_usart_set_baudrate(SWO_UART, baudrate); - usart_set_databits(SWO_UART, 8); + usart_set_databits(SWO_UART, 8U); usart_set_stopbits(SWO_UART, USART_STOPBITS_1); usart_set_mode(SWO_UART, USART_MODE_RX); usart_set_parity(SWO_UART, USART_PARITY_NONE); usart_set_flow_control(SWO_UART, USART_FLOWCONTROL_NONE); - /* Set up DMA channel */ + /* Set up DMA channel and tell the DMA subsystem where to put the data received from the UART */ dma_channel_reset(SWO_DMA_BUS, SWO_DMA_CHAN); - dma_set_peripheral_address(SWO_DMA_BUS, SWO_DMA_CHAN, (uint32_t)&SWO_UART_DR); + // NOLINTNEXTLINE(clang-diagnostic-pointer-to-int-cast,performance-no-int-to-ptr) + dma_set_peripheral_address(SWO_DMA_BUS, SWO_DMA_CHAN, (uintptr_t)&SWO_UART_DR); + // NOLINTNEXTLINE(clang-diagnostic-pointer-to-int-cast) + dma_set_memory_address(SWO_DMA_BUS, SWO_DMA_CHAN, (uintptr_t)swo_buffer); + /* Define the buffer length and configure this as a peripheral -> memory transfer */ + dma_set_number_of_data(SWO_DMA_BUS, SWO_DMA_CHAN, SWO_BUFFER_SIZE); #if defined(DMA_STREAM0) dma_set_transfer_mode(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); dma_channel_select(SWO_DMA_BUS, SWO_DMA_CHAN, SWO_DMA_TRG); @@ -119,84 +102,64 @@ void traceswo_setspeed(uint32_t baudrate) dma_set_read_from_peripheral(SWO_DMA_BUS, SWO_DMA_CHAN); #endif dma_enable_memory_increment_mode(SWO_DMA_BUS, SWO_DMA_CHAN); + /* Define it as being bytewise into a circular buffer with high priority */ dma_set_peripheral_size(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_PSIZE_8BIT); dma_set_memory_size(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_MSIZE_8BIT); dma_set_priority(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_PL_HIGH); + dma_enable_circular_mode(SWO_DMA_BUS, SWO_DMA_CHAN); + /* Enable the 50% and 100% interrupts so we can update the buffer counters to initiate the USB half of the picture */ dma_enable_transfer_complete_interrupt(SWO_DMA_BUS, SWO_DMA_CHAN); dma_enable_half_transfer_interrupt(SWO_DMA_BUS, SWO_DMA_CHAN); - dma_enable_circular_mode(SWO_DMA_BUS, SWO_DMA_CHAN); + /* Enable DMA trigger on receive for the UART */ + usart_enable_rx_dma(SWO_UART); - usart_enable(SWO_UART); + /* Enable the interrupts */ + nvic_set_priority(SWO_DMA_IRQ, IRQ_PRI_SWO_DMA); nvic_enable_irq(SWO_DMA_IRQ); - write_index = read_index = 0; - dma_set_memory_address(SWO_DMA_BUS, SWO_DMA_CHAN, (uint32_t)pingpong_buf); - dma_set_number_of_data(SWO_DMA_BUS, SWO_DMA_CHAN, 2 * TRACE_ENDPOINT_SIZE); - dma_enable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); - usart_enable_rx_dma(SWO_UART); -} -void SWO_DMA_ISR(void) -{ - if (dma_get_interrupt_flag(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_HTIF)) { - dma_clear_interrupt_flags(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_HTIF); - memcpy(&trace_rx_buf[write_index * TRACE_ENDPOINT_SIZE], pingpong_buf, TRACE_ENDPOINT_SIZE); - } - if (dma_get_interrupt_flag(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_TCIF)) { - dma_clear_interrupt_flags(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_TCIF); - memcpy( - &trace_rx_buf[write_index * TRACE_ENDPOINT_SIZE], &pingpong_buf[TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - } - write_index = (write_index + 1U) % NUM_TRACE_PACKETS; - trace_buf_drain(usbdev, TRACE_ENDPOINT | USB_REQ_TYPE_IN); + /* Reset the read and write indicies */ + swo_buffer_read_index = 0U; + swo_buffer_write_index = 0U; + + /* Now everything has been configured, enable the UART and its associated DMA channel */ + dma_enable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); + usart_enable(SWO_UART); } -void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask) +void swo_uart_deinit(void) { - /* Skip initial allocation on commands for mode change */ - if (trace_rx_buf == NULL) { - /* Alignment (bytes): 1 for UART DMA, 2-4 for memcpy in usb code, 8 provided by malloc. Not 64 */ - uint8_t *const newbuf = malloc(NUM_TRACE_PACKETS * TRACE_ENDPOINT_SIZE); - if (!newbuf) { - DEBUG_ERROR("malloc: failed in %s\n", __func__); - return; - } - trace_rx_buf = newbuf; - } - - if (!baudrate) - baudrate = SWO_DEFAULT_BAUD; + /* Disable the UART and halt DMA for it, grabbing the number of bytes left in the buffer as we do */ + usart_disable(SWO_UART); + const uint16_t space_remaining = dma_get_number_of_data(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_disable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); - rcc_periph_clock_enable(SWO_UART_CLK); - rcc_periph_clock_enable(SWO_DMA_CLK); + /* Convert the counter into an amount captured and add that to the write index and amount available */ + const uint16_t amount = (SWO_BUFFER_SIZE - space_remaining) & ((SWO_BUFFER_SIZE / 2U) - 1U); + swo_buffer_write_index += amount; + swo_buffer_bytes_available += amount; -#if defined(STM32F1) - gpio_set_mode(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SWO_UART_RX_PIN); - /* Pull SWO pin high to keep open SWO line ind uart idle state! */ - gpio_set(SWO_UART_PORT, SWO_UART_RX_PIN); + /* Put the GPIO back into normal service as a GPIO */ +#if defined(STM32F4) || defined(STM32F0) || defined(STM32F3) || defined(STM32F7) + gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_UART_RX_PIN); #else - gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, SWO_UART_RX_PIN); - gpio_set_output_options(SWO_UART_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, SWO_UART_RX_PIN); - gpio_set_af(SWO_UART_PORT, SWO_UART_PIN_AF, SWO_UART_RX_PIN); + gpio_set_mode(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SWO_UART_RX_PIN); #endif +} - nvic_set_priority(SWO_DMA_IRQ, IRQ_PRI_SWO_DMA); - nvic_enable_irq(SWO_DMA_IRQ); - traceswo_setspeed(baudrate); - traceswo_setmask(swo_chan_bitmask); - decoding = (swo_chan_bitmask != 0); +uint32_t swo_uart_get_baudrate(void) +{ + return usart_get_baudrate(SWO_UART); } -void traceswo_deinit(void) +void SWO_DMA_ISR(void) { - /* Stop peripherals servicing */ - nvic_disable_irq(SWO_DMA_IRQ); - dma_disable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); - usart_disable(SWO_UART); - /* Dump the buffered remains */ - trace_buf_drain(usbdev, TRACE_ENDPOINT | USB_REQ_TYPE_IN); - /* Return this contiguous chunk of SRAM to unshrinkable heap */ - if (trace_rx_buf != NULL) { - free(trace_rx_buf); - trace_rx_buf = NULL; + if (dma_get_interrupt_flag(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_HTIF)) { + dma_clear_interrupt_flags(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_HTIF); + swo_buffer_bytes_available += SWO_BUFFER_SIZE / 2U; + } + if (dma_get_interrupt_flag(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_TCIF)) { + dma_clear_interrupt_flags(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_TCIF); + swo_buffer_bytes_available += SWO_BUFFER_SIZE / 2U; } + swo_send_buffer(usbdev, SWO_ENDPOINT); } diff --git a/src/platforms/common/stm32/traceswo.c b/src/platforms/common/stm32/traceswo.c deleted file mode 100644 index 9b12840abc3..00000000000 --- a/src/platforms/common/stm32/traceswo.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2012 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* This file implements capture of the TRACESWO output. - * - * ARM DDI 0403D - ARMv7M Architecture Reference Manual - * ARM DDI 0337I - Cortex-M3 Technical Reference Manual - * ARM DDI 0314H - CoreSight Components Technical Reference Manual - */ - -/* TDO/TRACESWO signal comes into pin PA6/TIM3_CH1 - * Manchester coding is assumed on TRACESWO, so bit timing can be detected. - * The idea is to use TIM3 input capture modes to capture pulse timings. - * These can be capture directly to RAM by DMA. - * The core can then process the buffer to extract the frame. - */ -#include "general.h" -#include "platform.h" -#include "usb.h" -#include "traceswo.h" - -#include -#include -#include - -/* SWO decoding */ -static bool decoding = false; - -static uint8_t trace_usb_buf[64]; -static uint8_t trace_usb_buf_size; - -void traceswo_init(uint32_t swo_chan_bitmask) -{ - TRACE_TIM_CLK_EN(); - - /* Refer to ST doc RM0008 - STM32F10xx Reference Manual. - * Section 14.3.4 - 14.3.6 (General Purpose Timer - Input Capture) - * - * CCR1 captures cycle time, CCR2 captures high time - */ - - /* Use TI1 as capture input for CH1 and CH2 */ - timer_ic_set_input(TRACE_TIM, TIM_IC1, TRACE_IC_IN); - timer_ic_set_input(TRACE_TIM, TIM_IC2, TRACE_IC_IN); - - /* Capture CH1 on rising edge, CH2 on falling edge */ - timer_ic_set_polarity(TRACE_TIM, TIM_IC1, TIM_IC_RISING); - timer_ic_set_polarity(TRACE_TIM, TIM_IC2, TIM_IC_FALLING); - - /* Trigger on Filtered Timer Input 1 (TI1FP1) */ - timer_slave_set_trigger(TRACE_TIM, TRACE_TRIG_IN); - - /* Slave reset mode: reset counter on trigger */ - timer_slave_set_mode(TRACE_TIM, TIM_SMCR_SMS_RM); - - /* Enable capture interrupt */ - nvic_set_priority(TRACE_IRQ, IRQ_PRI_TRACE); - nvic_enable_irq(TRACE_IRQ); - timer_enable_irq(TRACE_TIM, TIM_DIER_CC1IE); - - /* Enable the capture channels */ - timer_ic_enable(TRACE_TIM, TIM_IC1); - timer_ic_enable(TRACE_TIM, TIM_IC2); - - timer_enable_counter(TRACE_TIM); - -#if defined(STM32F4) || defined(STM32F0) || defined(STM32F3) - /* AF2: TIM3/TIM4/TIM5 */ - gpio_mode_setup(TDO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, TDO_PIN); - gpio_set_af(TDO_PORT, TRACE_TIM_PIN_AF, TDO_PIN); -#endif - - traceswo_setmask(swo_chan_bitmask); - decoding = (swo_chan_bitmask != 0); -} - -void trace_buf_push(uint8_t *buf, int len) -{ - if (decoding) - traceswo_decode(usbdev, CDCACM_UART_ENDPOINT, buf, len); - else if (usbd_ep_write_packet(usbdev, USB_REQ_TYPE_IN | TRACE_ENDPOINT, buf, len) != len) { - if (trace_usb_buf_size + len > 64) { - /* Stall if upstream to too slow. */ - usbd_ep_stall_set(usbdev, USB_REQ_TYPE_IN | TRACE_ENDPOINT, 1); - trace_usb_buf_size = 0; - return; - } - memcpy(trace_usb_buf + trace_usb_buf_size, buf, len); - trace_usb_buf_size += len; - } -} - -void trace_buf_drain(usbd_device *dev, uint8_t ep) -{ - if (!trace_usb_buf_size) - return; - - if (decoding) - traceswo_decode(dev, CDCACM_UART_ENDPOINT, trace_usb_buf, trace_usb_buf_size); - else - usbd_ep_write_packet(dev, ep, trace_usb_buf, trace_usb_buf_size); - trace_usb_buf_size = 0; -} - -#define ALLOWED_DUTY_ERROR 5 - -void TRACE_ISR(void) -{ - uint16_t status = TIM_SR(TRACE_TIM); - static uint16_t bt; - static uint8_t lastbit; - static uint8_t decbuf[17]; - static uint8_t decbuf_pos; - static uint8_t halfbit; - static uint8_t notstart; - - /* Reset decoder state if capture overflowed */ - if (status & (TIM_SR_CC1OF | TIM_SR_UIF)) { - timer_clear_flag(TRACE_TIM, TIM_SR_CC1OF | TIM_SR_UIF); - if (!(status & (TIM_SR_CC2IF | TIM_SR_CC1IF))) - goto flush_and_reset; - } - - const uint16_t cycle = TIM_CCR1(TRACE_TIM); - uint16_t duty = TIM_CCR2(TRACE_TIM); - - /* Reset decoder state if crazy things happened */ - if ((bt && (duty / bt > 2U || duty / bt == 0)) || duty == 0) - goto flush_and_reset; - - if (!(status & TIM_SR_CC1IF)) - notstart = 1; - - if (!bt) { - if (notstart) { - notstart = 0; - return; - } - /* First bit, sync decoder */ - duty -= ALLOWED_DUTY_ERROR; - const uint16_t duty_cycle = cycle / duty; - if (duty_cycle != 2U && duty_cycle != 3U) - return; - bt = duty; - lastbit = 1; - halfbit = 0; - timer_set_period(TRACE_TIM, duty * 6U); - timer_clear_flag(TRACE_TIM, TIM_SR_UIF); - timer_enable_irq(TRACE_TIM, TIM_DIER_UIE); - } else { - /* If high time is extended we need to flip the bit */ - if (duty / bt > 1U) { - if (!halfbit) /* lost sync somehow */ - goto flush_and_reset; - halfbit = 0; - lastbit ^= 1U; - } - decbuf[decbuf_pos >> 3U] |= lastbit << (decbuf_pos & 7U); - ++decbuf_pos; - } - - if (!(status & TIM_SR_CC1IF) || (cycle - duty) / bt > 2) - goto flush_and_reset; - - if ((cycle - duty) / bt > 1) { - /* If low time extended we need to pack another bit. */ - if (halfbit) /* this is a valid stop-bit or we lost sync */ - goto flush_and_reset; - halfbit = 1; - lastbit ^= 1U; - decbuf[decbuf_pos >> 3U] |= lastbit << (decbuf_pos & 7U); - ++decbuf_pos; - } - - if (decbuf_pos < 128U) - return; - -flush_and_reset: - timer_set_period(TRACE_TIM, -1); - timer_disable_irq(TRACE_TIM, TIM_DIER_UIE); - trace_buf_push(decbuf, decbuf_pos >> 3U); - bt = 0; - decbuf_pos = 0; - memset(decbuf, 0, sizeof(decbuf)); -} diff --git a/src/platforms/common/stm32/traceswoasync_f723.c b/src/platforms/common/stm32/traceswoasync_f723.c deleted file mode 100644 index 59c439d3cb8..00000000000 --- a/src/platforms/common/stm32/traceswoasync_f723.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Based on work that is Copyright (C) 2017 Black Sphere Technologies Ltd. - * Copyright (C) 2017 Dave Marples - * Portions (C) 2020-2021 Stoyan Shopov - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* This file implements capture of the TRACESWO output using ASYNC signalling. - * - * ARM DDI 0403D - ARMv7M Architecture Reference Manual - * ARM DDI 0337I - Cortex-M3 Technical Reference Manual - * ARM DDI 0314H - CoreSight Components Technical Reference Manual - */ - -/* TDO/TRACESWO signal comes into the SWOUSART RX pin. - */ - -#include -#include "general.h" -#include "platform.h" -#include "usb.h" -#include "traceswo.h" - -#include -#include -#include -#include -#include -#include - -static volatile uint32_t write_index; /* Packet currently received via UART */ -static volatile uint32_t read_index; /* Packet currently waiting to transmit to USB */ -/* Packets arrived from the SWO interface */ -static uint8_t trace_rx_buf[NUM_TRACE_PACKETS * TRACE_ENDPOINT_SIZE]; -/* Packet pingpong buffer used for receiving packets */ -static uint8_t pingpong_buf[2 * TRACE_ENDPOINT_SIZE]; -/* SWO decoding */ -static bool decoding = false; - -void trace_buf_drain(usbd_device *dev, uint8_t ep) -{ - static atomic_flag reentry_flag = ATOMIC_FLAG_INIT; - - /* If we are already in this routine then we don't need to come in again */ - if (atomic_flag_test_and_set_explicit(&reentry_flag, memory_order_relaxed)) - return; - /* Attempt to write everything we buffered */ - if (write_index != read_index) { - uint16_t result; - if (decoding) - /* write decoded swo packets to the uart port */ - result = traceswo_decode( - dev, CDCACM_UART_ENDPOINT, &trace_rx_buf[read_index * TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - else - /* write raw swo packets to the trace port */ - result = - usbd_ep_write_packet(dev, ep, &trace_rx_buf[read_index * TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - if (result) - read_index = (read_index + 1U) % NUM_TRACE_PACKETS; - } - atomic_flag_clear_explicit(&reentry_flag, memory_order_relaxed); -} - -uint32_t traceswo_get_baudrate(void) -{ - return usart_get_baudrate(SWO_UART); -} - -void traceswo_setspeed(uint32_t baudrate) -{ - dma_disable_stream(SWO_DMA_BUS, SWO_DMA_STREAM); - usart_disable(SWO_UART); - bmd_usart_set_baudrate(SWO_UART, baudrate); - usart_set_databits(SWO_UART, 8); - usart_set_stopbits(SWO_UART, USART_STOPBITS_1); - usart_set_mode(SWO_UART, USART_MODE_RX); - usart_set_parity(SWO_UART, USART_PARITY_NONE); - usart_set_flow_control(SWO_UART, USART_FLOWCONTROL_NONE); - - /* Set up DMA channel*/ - dma_stream_reset(SWO_DMA_BUS, SWO_DMA_STREAM); - dma_set_peripheral_address(SWO_DMA_BUS, SWO_DMA_STREAM, (uint32_t)&SWO_UART_DR); - dma_set_transfer_mode(SWO_DMA_BUS, SWO_DMA_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); - dma_enable_memory_increment_mode(SWO_DMA_BUS, SWO_DMA_STREAM); - dma_set_peripheral_size(SWO_DMA_BUS, SWO_DMA_STREAM, DMA_SxCR_PSIZE_8BIT); - dma_set_memory_size(SWO_DMA_BUS, SWO_DMA_STREAM, DMA_SxCR_MSIZE_8BIT); - dma_set_priority(SWO_DMA_BUS, SWO_DMA_STREAM, DMA_SxCR_PL_VERY_HIGH); - dma_enable_transfer_complete_interrupt(SWO_DMA_BUS, SWO_DMA_STREAM); - dma_enable_half_transfer_interrupt(SWO_DMA_BUS, SWO_DMA_STREAM); - dma_enable_circular_mode(SWO_DMA_BUS, SWO_DMA_STREAM); - - usart_enable(SWO_UART); - nvic_enable_irq(SWO_DMA_IRQ); - write_index = read_index = 0; - dma_set_memory_address(SWO_DMA_BUS, SWO_DMA_STREAM, (uint32_t)pingpong_buf); - dma_set_number_of_data(SWO_DMA_BUS, SWO_DMA_STREAM, 2 * TRACE_ENDPOINT_SIZE); - dma_channel_select(SWO_DMA_BUS, SWO_DMA_STREAM, DMA_SxCR_CHSEL_4); - dma_enable_stream(SWO_DMA_BUS, SWO_DMA_STREAM); - usart_enable_rx_dma(SWO_UART); -} - -void SWO_DMA_ISR(void) -{ - if (DMA_LISR(SWO_DMA_BUS) & DMA_LISR_HTIF0) { - DMA_LIFCR(SWO_DMA_BUS) |= DMA_LISR_HTIF0; - memcpy(&trace_rx_buf[write_index * TRACE_ENDPOINT_SIZE], pingpong_buf, TRACE_ENDPOINT_SIZE); - } - if (DMA_LISR(SWO_DMA_BUS) & DMA_LISR_TCIF0) { - DMA_LIFCR(SWO_DMA_BUS) |= DMA_LISR_TCIF0; - memcpy( - &trace_rx_buf[write_index * TRACE_ENDPOINT_SIZE], &pingpong_buf[TRACE_ENDPOINT_SIZE], TRACE_ENDPOINT_SIZE); - } - write_index = (write_index + 1) % NUM_TRACE_PACKETS; - trace_buf_drain(usbdev, TRACE_ENDPOINT); -} - -void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask) -{ - if (!baudrate) - baudrate = SWO_DEFAULT_BAUD; - - rcc_periph_clock_enable(SWO_UART_CLK); - rcc_periph_clock_enable(SWO_DMA_CLK); - - rcc_periph_clock_enable(RCC_GPIOD); - gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SWO_UART_RX_PIN); - gpio_set_af(SWO_UART_PORT, SWO_UART_PIN_AF, SWO_UART_RX_PIN); - /* Pull SWO pin high to keep open SWO line ind uart idle state!*/ - gpio_set(SWO_UART_PORT, SWO_UART_RX_PIN); - nvic_set_priority(SWO_DMA_IRQ, IRQ_PRI_SWO_DMA); - nvic_enable_irq(SWO_DMA_IRQ); - traceswo_setspeed(baudrate); - traceswo_setmask(swo_chan_bitmask); - decoding = swo_chan_bitmask != 0; -} - -void traceswo_deinit(void) -{ - /* Stop peripherals servicing */ - nvic_disable_irq(SWO_DMA_IRQ); - dma_disable_stream(SWO_DMA_BUS, SWO_DMA_STREAM); - usart_disable(SWO_UART); - /* Dump the buffered remains */ - trace_buf_drain(usbdev, TRACE_ENDPOINT | USB_REQ_TYPE_IN); -} diff --git a/src/platforms/common/stm32/traceswodecode.c b/src/platforms/common/stm32/traceswodecode.c deleted file mode 100644 index 6d04447bcce..00000000000 --- a/src/platforms/common/stm32/traceswodecode.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* Print decoded swo stream on the usb serial */ - -#include "general.h" -#include "usb_serial.h" -#include "traceswo.h" - -/* SWO decoding */ -/* data is static in case swo packet is astride two buffers */ -static uint8_t swo_buf[CDCACM_PACKET_SIZE]; -static int swo_buf_len = 0; -static uint32_t swo_decode = 0; /* bitmask of channels to print */ -static int swo_pkt_len = 0; /* decoder state */ -static bool swo_print = false; - -/* print decoded swo packet on usb serial */ -uint16_t traceswo_decode(usbd_device *usbd_dev, uint8_t addr, const void *buf, uint16_t len) -{ - if (usbd_dev == NULL) - return 0; - const uint8_t *const data = (const uint8_t *)buf; - for (uint16_t i = 0; i < len; i++) { - const uint8_t ch = data[i]; - if (swo_pkt_len == 0) { /* header */ - uint32_t channel = (uint32_t)ch >> 3U; /* channel number */ - uint32_t size = ch & 0x7U; /* drop channel number */ - if (size == 0x01U) - swo_pkt_len = 1; /* SWO packet 0x01XX */ - else if (size == 0x02U) - swo_pkt_len = 2; /* SWO packet 0x02XXXX */ - else if (size == 0x03U) - swo_pkt_len = 4; /* SWO packet 0x03XXXXXXXX */ - swo_print = (swo_pkt_len != 0) && ((swo_decode & (1UL << channel)) != 0UL); - } else if (swo_pkt_len <= 4) { /* data */ - if (swo_print) { - swo_buf[swo_buf_len++] = ch; - if (swo_buf_len == sizeof(swo_buf)) { - if (usb_get_config() && gdb_serial_get_dtr()) /* silently drop if usb not ready */ - usbd_ep_write_packet(usbd_dev, addr, swo_buf, swo_buf_len); - swo_buf_len = 0; - } - } - --swo_pkt_len; - } else { /* recover */ - swo_buf_len = 0; - swo_pkt_len = 0; - } - } - return len; -} - -/* set bitmask of swo channels to be decoded */ -void traceswo_setmask(uint32_t mask) -{ - swo_decode = mask; -} - -/* not truncated */ diff --git a/src/platforms/common/swo.h b/src/platforms/common/swo.h new file mode 100644 index 00000000000..0e6830d85aa --- /dev/null +++ b/src/platforms/common/swo.h @@ -0,0 +1,56 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2012 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Copyright (C) 2024 1BitSquared + * Modified by Rachel Mant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PLATFORMS_COMMON_SWO_H +#define PLATFORMS_COMMON_SWO_H + +#include + +/* Default line rate, used as default for a request without baudrate */ +#define SWO_DEFAULT_BAUD 2250000U + +typedef enum swo_coding { + swo_none, + swo_manchester, + swo_nrz_uart, +} swo_coding_e; + +extern swo_coding_e swo_current_mode; + +/* Initialisation and deinitialisation functions (ties into command.c) */ +void swo_init(swo_coding_e swo_mode, uint32_t baudrate, uint32_t itm_stream_bitmask); +void swo_deinit(bool deallocate); + +/* UART mode baudate functions */ +uint32_t swo_uart_get_baudrate(void); +void bmd_usart_set_baudrate(uint32_t usart, uint32_t baud_rate); + +/* USB callback for the raw data endpoint to ask for a new buffer of data */ +void swo_send_buffer(usbd_device *dev, uint8_t ep); + +/* Set a bitmask of SWO ITM streams to be decoded */ +void swo_itm_decode_set_mask(uint32_t mask); + +/* Decode a new block of ITM data from SWO */ +uint16_t swo_itm_decode(usbd_device *usbd_dev, uint8_t ep, const uint8_t *data, uint16_t len); + +#endif /* PLATFORMS_COMMON_SWO_H */ diff --git a/src/platforms/common/tm4c/meson.build b/src/platforms/common/tm4c/meson.build index 0834ced13aa..61e0363f636 100644 --- a/src/platforms/common/tm4c/meson.build +++ b/src/platforms/common/tm4c/meson.build @@ -32,7 +32,7 @@ platform_tm4c_includes = include_directories('.') platform_tm4c_sources = files( 'gdb_if.c', - 'traceswo.c', + 'swo_uart.c', ) platform_tm4c_args = [ diff --git a/src/platforms/common/tm4c/traceswo.c b/src/platforms/common/tm4c/swo_uart.c similarity index 53% rename from src/platforms/common/tm4c/traceswo.c rename to src/platforms/common/tm4c/swo_uart.c index c7a2c8d300d..1fe72b6a962 100644 --- a/src/platforms/common/tm4c/traceswo.c +++ b/src/platforms/common/tm4c/swo_uart.c @@ -20,7 +20,8 @@ * along with this program. If not, see . */ -/* This file implements capture of the TRACESWO output. +/* + * This file implements capture of the Trace/SWO output using async signalling. * * ARM DDI 0403D - ARMv7M Architecture Reference Manual * ARM DDI 0337I - Cortex-M3 Technical Reference Manual @@ -30,66 +31,75 @@ #include "general.h" #include "platform.h" #include "usb.h" +#include "swo.h" #include #include #include #include -#include -void traceswo_init(void) +void swo_init(const swo_coding_e swo_mode, const uint32_t baudrate, const uint32_t itm_stream_bitmask) { + /* Neither mode switching nor ITM decoding is implemented on this platform (yet) */ + (void)swo_mode; + (void)itm_stream_bitmask; + + /* Ensure required peripherals are spun up */ + /* TODO: Move this into platform_init()! */ periph_clock_enable(RCC_GPIOD); - periph_clock_enable(TRACEUART_CLK); + periph_clock_enable(SWO_UART_CLK); __asm__("nop"); __asm__("nop"); __asm__("nop"); - gpio_mode_setup(SWO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_PIN); - gpio_set_af(SWO_PORT, 1, SWO_PIN); /* U2RX */ + /* Reconfigure the GPIO over to UART mode */ + gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_UART_RX_PIN); + gpio_set_af(SWO_UART_PORT, SWO_UART_PIN_AF, SWO_UART_RX_PIN); - uart_disable(TRACEUART); + /* Set up the UART for 8N1 at the requested baud rate */ + uart_clock_from_sysclk(SWO_UART); + uart_set_baudrate(SWO_UART, baudrate); + uart_set_databits(SWO_UART, 8U); + uart_set_stopbits(SWO_UART, 1U); + uart_set_parity(SWO_UART, UART_PARITY_NONE); - /* Setup UART parameters. */ - uart_clock_from_sysclk(TRACEUART); - uart_set_baudrate(TRACEUART, 800000); - uart_set_databits(TRACEUART, 8); - uart_set_stopbits(TRACEUART, 1); - uart_set_parity(TRACEUART, UART_PARITY_NONE); + /* Make use of the hardware FIFO for some additional buffering (up to 8 bytes) */ + uart_enable_fifo(SWO_UART); - // Enable FIFO - uart_enable_fifo(TRACEUART); + /* Configure the FIFO interrupts for ½ full (RX) and ⅞ empty (TX) */ + uart_set_fifo_trigger_levels(SWO_UART, UART_FIFO_RX_TRIG_1_2, UART_FIFO_TX_TRIG_7_8); - // Set FIFO interrupt trigger levels to 4/8 full for RX buffer and - // 7/8 empty (1/8 full) for TX buffer - uart_set_fifo_trigger_levels(TRACEUART, UART_FIFO_RX_TRIG_1_2, UART_FIFO_TX_TRIG_7_8); + /* Clear and enable the RX and RX timeout interrupts */ + uart_clear_interrupt_flag(SWO_UART, UART_INT_RX | UART_INT_RT); + uart_enable_interrupts(SWO_UART, UART_INT_RX | UART_INT_RT); - uart_clear_interrupt_flag(TRACEUART, UART_INT_RX | UART_INT_RT); + /* Actually enable the interrupts */ + nvic_set_priority(SWO_UART_IRQ, IRQ_PRI_SWO_UART); + nvic_enable_irq(SWO_UART_IRQ); - /* Enable interrupts */ - uart_enable_interrupts(TRACEUART, UART_INT_RX | UART_INT_RT); + /* Un-stall USB endpoint */ + usbd_ep_stall_set(usbdev, USB_REQ_TYPE_IN | SWO_ENDPOINT, 0U); /* Finally enable the USART. */ - uart_enable(TRACEUART); - - nvic_set_priority(TRACEUART_IRQ, 0); - nvic_enable_irq(TRACEUART_IRQ); - - /* Un-stall USB endpoint */ - usbd_ep_stall_set(usbdev, USB_REQ_TYPE_IN | TRACE_ENDPOINT, 0); + uart_enable(SWO_UART); + /* XXX: What is this even reconfiguring?! */ gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3); } -void traceswo_baud(unsigned int baud) +void swo_deinit(const bool deallocate) { - uart_set_baudrate(TRACEUART, baud); - uart_set_databits(TRACEUART, 8); + (void)deallocate; + /* Disable the UART */ + uart_disable(SWO_UART); + /* Put the GPIO back into normal service as a GPIO */ + gpio_mode_setup(SWO_UART_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SWO_UART_RX_PIN); + gpio_set_af(SWO_UART_PORT, 0U, SWO_UART_RX_PIN); } -uint32_t traceswo_get_baudrate(void) +uint32_t swo_uart_get_baudrate(void) { - return uart_get_baudrate(TRACEUART); + return uart_get_baudrate(SWO_UART); } #define FIFO_SIZE 256U @@ -116,13 +126,13 @@ void trace_buf_push(void) if (len > 64U) len = 64; - if (usbd_ep_write_packet(usbdev, USB_REQ_TYPE_IN | TRACE_ENDPOINT, (uint8_t *)&buf_rx[buf_rx_out], len) == len) { + if (usbd_ep_write_packet(usbdev, USB_REQ_TYPE_IN | SWO_ENDPOINT, (uint8_t *)&buf_rx[buf_rx_out], len) == len) { buf_rx_out += len; buf_rx_out %= FIFO_SIZE; } } -void trace_buf_drain(usbd_device *dev, uint8_t ep) +void swo_send_buffer(usbd_device *dev, uint8_t ep) { (void)dev; (void)ep; @@ -134,12 +144,12 @@ void trace_tick(void) trace_buf_push(); } -void TRACEUART_ISR(void) +void SWO_UART_ISR(void) { - uint32_t flush = uart_is_interrupt_source(TRACEUART, UART_INT_RT); + uint32_t flush = uart_is_interrupt_source(SWO_UART, UART_INT_RT); - while (!uart_is_rx_fifo_empty(TRACEUART)) { - const uint32_t c = uart_recv(TRACEUART); + while (!uart_is_rx_fifo_empty(SWO_UART)) { + const uint32_t c = uart_recv(SWO_UART); /* If the next increment of rx_in would put it at the same point * as rx_out, the FIFO is considered full. diff --git a/src/platforms/common/traceswo.h b/src/platforms/common/traceswo.h deleted file mode 100644 index ef8ac3a4eca..00000000000 --- a/src/platforms/common/traceswo.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2012 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef PLATFORMS_COMMON_TRACESWO_H -#define PLATFORMS_COMMON_TRACESWO_H - -#include - -#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2 -/* Default line rate, used as default for a request without baudrate */ -#define SWO_DEFAULT_BAUD 2250000U -void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask); -void traceswo_deinit(void); -uint32_t traceswo_get_baudrate(void); -void bmd_usart_set_baudrate(uint32_t usart, uint32_t baud_rate); -#else -void traceswo_init(uint32_t swo_chan_bitmask); -#endif - -void trace_buf_drain(usbd_device *dev, uint8_t ep); - -/* Set bitmask of SWO channels to be decoded */ -void traceswo_setmask(uint32_t mask); - -/* Print decoded SWO packet on USB serial */ -uint16_t traceswo_decode(usbd_device *usbd_dev, uint8_t addr, const void *buf, uint16_t len); - -#endif /* PLATFORMS_COMMON_TRACESWO_H */ diff --git a/src/platforms/common/usb.h b/src/platforms/common/usb.h index 4ac49108185..19611dc5384 100644 --- a/src/platforms/common/usb.h +++ b/src/platforms/common/usb.h @@ -29,10 +29,12 @@ extern uint16_t usb_config; #if defined(USB_HS) #define CDCACM_PACKET_SIZE 512U -#define TRACE_ENDPOINT_SIZE 512U +#define SWO_ENDPOINT_SIZE 512U +#define NUM_SWO_USB_PACKETS 16U /* 8KiB of data buffer */ #else #define CDCACM_PACKET_SIZE 64U -#define TRACE_ENDPOINT_SIZE 64U +#define SWO_ENDPOINT_SIZE 64U +#define NUM_SWO_USB_PACKETS 4U /* 512B of data buffer */ #endif #if !defined(USB_MAX_INTERVAL) @@ -41,7 +43,7 @@ extern uint16_t usb_config; #define CDCACM_GDB_ENDPOINT 1U #define CDCACM_UART_ENDPOINT 2U -#define TRACE_ENDPOINT 3U +#define SWO_ENDPOINT 3U /* * AN4879, table 6: most STM32F4 families (excluding F412, F413, F423) * have OTG_FS DWC2 configured with "4 bidirectional endpoints" (including EP0), @@ -57,7 +59,7 @@ extern uint16_t usb_config; #define UART_IF_NO 2U #define DFU_IF_NO 4U #ifdef PLATFORM_HAS_TRACESWO -#define TRACE_IF_NO 5U +#define SWO_IF_NO 5U #define TOTAL_INTERFACES 6U #else #define TOTAL_INTERFACES 5U diff --git a/src/platforms/common/usb_descriptors.h b/src/platforms/common/usb_descriptors.h index 9595460cff9..af99d576ba6 100644 --- a/src/platforms/common/usb_descriptors.h +++ b/src/platforms/common/usb_descriptors.h @@ -337,16 +337,16 @@ static const usb_iface_assoc_descriptor_s dfu_assoc = { static const usb_endpoint_descriptor_s trace_endp = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = TRACE_ENDPOINT | USB_REQ_TYPE_IN, + .bEndpointAddress = SWO_ENDPOINT | USB_REQ_TYPE_IN, .bmAttributes = USB_ENDPOINT_ATTR_BULK, - .wMaxPacketSize = TRACE_ENDPOINT_SIZE, + .wMaxPacketSize = SWO_ENDPOINT_SIZE, .bInterval = 0, }; const usb_interface_descriptor_s trace_iface = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = TRACE_IF_NO, + .bInterfaceNumber = SWO_IF_NO, .bAlternateSetting = 0, .bNumEndpoints = 1, .bInterfaceClass = 0xff, @@ -360,7 +360,7 @@ const usb_interface_descriptor_s trace_iface = { static const usb_iface_assoc_descriptor_s trace_assoc = { .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - .bFirstInterface = TRACE_IF_NO, + .bFirstInterface = SWO_IF_NO, .bInterfaceCount = 1, .bFunctionClass = 0xff, .bFunctionSubClass = 0xff, @@ -443,7 +443,7 @@ static const char *const usb_strings[] = { #define PROPERTY_DEVICE_INTERFACE_GUID u"DeviceInterfaceGUID" #define VALUE_DFU_INTERFACE_GUID u"{76be5ca1-e304-4b32-be5f-d9369d3d201a}" #ifdef PLATFORM_HAS_TRACESWO -#define VALUE_TRACE_INTERFACE_GUID u"{76be5ca1-e305-4b32-be5f-d9369d3d201a}" +#define VALUE_SWO_INTERFACE_GUID u"{76be5ca1-e305-4b32-be5f-d9369d3d201a}" #endif static const struct { @@ -498,8 +498,8 @@ static const struct { .wPropertyDataType = REG_SZ, .wPropertyNameLength = ARRAY_LENGTH(PROPERTY_DEVICE_INTERFACE_GUID) * 2U, .PropertyName = PROPERTY_DEVICE_INTERFACE_GUID, - .wPropertyDataLength = ARRAY_LENGTH(VALUE_TRACE_INTERFACE_GUID) * 2U, - .PropertyData = VALUE_TRACE_INTERFACE_GUID, + .wPropertyDataLength = ARRAY_LENGTH(VALUE_SWO_INTERFACE_GUID) * 2U, + .PropertyData = VALUE_SWO_INTERFACE_GUID, }, }; #endif @@ -519,7 +519,7 @@ static const microsoft_os_descriptor_function_subset_header microsoft_os_descrip { .wLength = MICROSOFT_OS_DESCRIPTOR_FUNCTION_SUBSET_HEADER_SIZE, .wDescriptorType = MICROSOFT_OS_SUBSET_HEADER_FUNCTION, - .bFirstInterface = TRACE_IF_NO, + .bFirstInterface = SWO_IF_NO, .bReserved = 0, .wTotalLength = 0, @@ -560,7 +560,7 @@ static const microsoft_os_descriptor_set_information microsoft_os_descriptor_set #ifdef PLATFORM_HAS_TRACESWO MICROSOFT_OS_DESCRIPTOR_FUNCTION_SUBSET_HEADER_SIZE + MICROSOFT_OS_FEATURE_COMPATIBLE_ID_DESCRIPTOR_SIZE + MICROSOFT_OS_FEATURE_REGISTRY_PROPERTY_DESCRIPTOR_SIZE_BASE + - (ARRAY_LENGTH(PROPERTY_DEVICE_INTERFACE_GUID) * 2U) + (ARRAY_LENGTH(VALUE_TRACE_INTERFACE_GUID) * 2U) + + (ARRAY_LENGTH(PROPERTY_DEVICE_INTERFACE_GUID) * 2U) + (ARRAY_LENGTH(VALUE_SWO_INTERFACE_GUID) * 2U) + #endif MICROSOFT_OS_DESCRIPTOR_FUNCTION_SUBSET_HEADER_SIZE + MICROSOFT_OS_FEATURE_COMPATIBLE_ID_DESCRIPTOR_SIZE + MICROSOFT_OS_FEATURE_REGISTRY_PROPERTY_DESCRIPTOR_SIZE_BASE + diff --git a/src/platforms/common/usb_serial.c b/src/platforms/common/usb_serial.c index 46550a3b4d4..0502c832c90 100644 --- a/src/platforms/common/usb_serial.c +++ b/src/platforms/common/usb_serial.c @@ -46,7 +46,7 @@ #include "gdb_if.h" #include "usb_serial.h" #ifdef PLATFORM_HAS_TRACESWO -#include "traceswo.h" +#include "swo.h" #endif #include "aux_serial.h" #include "rtt.h" @@ -211,7 +211,7 @@ void usb_serial_set_config(usbd_device *dev, uint16_t value) #ifdef PLATFORM_HAS_TRACESWO /* Trace interface */ - usbd_ep_setup(dev, TRACE_ENDPOINT | USB_REQ_TYPE_IN, USB_ENDPOINT_ATTR_BULK, TRACE_ENDPOINT_SIZE, trace_buf_drain); + usbd_ep_setup(dev, SWO_ENDPOINT | USB_REQ_TYPE_IN, USB_ENDPOINT_ATTR_BULK, SWO_ENDPOINT_SIZE, swo_send_buffer); #endif usbd_register_control_callback(dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, diff --git a/src/platforms/ctxlink/Makefile.inc b/src/platforms/ctxlink/Makefile.inc index 5c6279415ee..053beb32881 100644 --- a/src/platforms/ctxlink/Makefile.inc +++ b/src/platforms/ctxlink/Makefile.inc @@ -17,19 +17,31 @@ LDFLAGS = -lopencm3_stm32f4 \ VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - serialno.c \ - timing.c \ - timing_stm32.c - -ifeq ($(TRACESWO_PROTOCOL), 1) -SRC += traceswo.c -CFLAGS += -DTRACESWO_PROTOCOL=1 -else -SRC += traceswoasync.c -CFLAGS += -DTRACESWO_PROTOCOL=2 + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_itm_decode.c + +# If SWO_ENCODING has not been given, default it to including both modes +ifndef SWO_ENCODING + SWO_ENCODING = 3 +endif + +# Include the files for either: Manchester-only (1), UART-only (2) or both modes (3) +ifeq ($(SWO_ENCODING), 1) + SRC += swo_manchester.c +else ifeq ($(SWO_ENCODING), 2) + SRC += swo_uart.c +else ifeq ($(SWO_ENCODING), 3) + SRC += \ + swo_manchester.c \ + swo_uart.c +else # If we got some other value, that's an error so report it + $(error Invalid value for SWO encoding, must be one of 1, 2, or 3) endif +CFLAGS += -DSWO_ENCODING=$(SWO_ENCODING) all: blackmagic.bin diff --git a/src/platforms/ctxlink/meson.build b/src/platforms/ctxlink/meson.build index 4a4c1418cba..49bdeba87f0 100644 --- a/src/platforms/ctxlink/meson.build +++ b/src/platforms/ctxlink/meson.build @@ -37,14 +37,13 @@ probe_ctxlink_args = [ ] trace_protocol = get_option('trace_protocol') -if trace_protocol == '3' - trace_protocol = '2' +probe_ctxlink_args += [f'-DSWO_ENCODING=@trace_protocol@'] +probe_ctxlink_dependencies = [platform_stm32_swo] +if trace_protocol in ['1', '3'] + probe_ctxlink_dependencies += platform_stm32_swo_manchester endif -probe_ctxlink_args += [f'-DTRACESWO_PROTOCOL=@trace_protocol@'] -if trace_protocol == '1' - probe_ctxlink_dependencies = fixme_platform_stm32_traceswo -else - probe_ctxlink_dependencies = fixme_platform_stm32_traceswoasync +if trace_protocol in ['2', '3'] + probe_ctxlink_dependencies += platform_stm32_swo_uart endif probe_ctxlink_commonn_link_args = [ diff --git a/src/platforms/ctxlink/platform.h b/src/platforms/ctxlink/platform.h index 3df76450985..c689f75e3c1 100644 --- a/src/platforms/ctxlink/platform.h +++ b/src/platforms/ctxlink/platform.h @@ -46,7 +46,7 @@ * TDI = PA3 (output) * TMS = PA4 (input/output for SWDIO) * TCK = PA5 (output SWCLK) - * TDO = PC6 (input) + * TDO = PC7 (input SWO) * TMS_DIR = PA1 (output) controls target buffer direction * TPWR = PB0 (analog input) * VBAT = PA0 (analog input) @@ -81,6 +81,9 @@ #define NRST_SENSE_PORT GPIOA #define NRST_SENSE_PIN GPIO7 +#define SWO_PORT GPIOC +#define SWO_PIN GPIO7 + #define LED_PORT GPIOC #define LED_PORT_UART GPIOB #define LED_UART GPIO2 @@ -177,33 +180,27 @@ #define IRQ_PRI_USB (1U << 4U) #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #define IRQ_PRI_SWO_DMA (0U << 4U) -#define PLATFORM_HAS_TRACESWO -#define NUM_TRACE_PACKETS 256U /* 16K buffer */ - -#if TRACESWO_PROTOCOL == 1 - -/* Use TIM3 Input 2 from PC7/TDO, AF2, trigger on Rising Edge */ -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR(x) tim3_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_IC_RISING TIM_IC1 -#define TRACE_CC_RISING TIM3_CCR1 -#define TRACE_ITR_RISING TIM_DIER_CC1IE -#define TRACE_STATUS_RISING TIM_SR_CC1IF -#define TRACE_IC_FALLING TIM_IC2 -#define TRACE_CC_FALLING TIM3_CCR2 -#define TRACE_STATUS_FALLING TIM_SR_CC2IF -#define TRACE_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 - -#elif TRACESWO_PROTOCOL == 2 - -/* On ctxLink use USART6_RX mapped on PC7 for async capture */ +/* Use TIM3 Input 2 from PC7/TDO, AF2, trigger on rising edge */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR(x) tim3_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI2 +#define SWO_IC_RISING TIM_IC2 +#define SWO_CC_RISING TIM3_CCR2 +#define SWO_ITR_RISING TIM_DIER_CC2IE +#define SWO_STATUS_RISING TIM_SR_CC2IF +#define SWO_IC_FALLING TIM_IC1 +#define SWO_CC_FALLING TIM3_CCR1 +#define SWO_STATUS_FALLING TIM_SR_CC1IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI2FP2 +#define SWO_TIM_PIN_AF GPIO_AF2 + +/* On ctxLink use USART6 RX mapped on PC7 for async capture */ #define SWO_UART USART6 #define SWO_UART_CLK RCC_USART6 #define SWO_UART_DR USART6_DR @@ -212,14 +209,12 @@ #define SWO_UART_PIN_AF GPIO_AF8 /* Bind to the same DMA Rx channel */ -#define SWO_DMA_BUS DMA2 -#define SWO_DMA_CLK RCC_DMA2 -#define SWO_DMA_CHAN DMA_STREAM1 -#define SWO_DMA_IRQ NVIC_DMA2_STREAM1_IRQ -#define SWO_DMA_ISR dma2_stream1_isr -#define SWO_DMA_TRG DMA_SxCR_CHSEL_5 - -#endif /* TRACESWO_PROTOCOL */ +#define SWO_DMA_BUS DMA2 +#define SWO_DMA_CLK RCC_DMA2 +#define SWO_DMA_CHAN DMA_STREAM1 +#define SWO_DMA_IRQ NVIC_DMA2_STREAM1_IRQ +#define SWO_DMA_ISR dma2_stream1_isr +#define SWO_DMA_TRG DMA_SxCR_CHSEL_5 #define SET_RUN_STATE(state) \ { \ diff --git a/src/platforms/f072/Makefile.inc b/src/platforms/f072/Makefile.inc index 5e07ad24f47..9878e486559 100644 --- a/src/platforms/f072/Makefile.inc +++ b/src/platforms/f072/Makefile.inc @@ -14,12 +14,14 @@ LDFLAGS = -lopencm3_stm32f0 -Lplatforms/f072 \ VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - traceswo.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ + platform.c \ + atomic.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_manchester.c \ + swo_itm_decode.c all: blackmagic.bin blackmagic.elf: libopencm3_stm32f0 diff --git a/src/platforms/f072/atomic.c b/src/platforms/f072/atomic.c new file mode 100644 index 00000000000..4b5e7621918 --- /dev/null +++ b/src/platforms/f072/atomic.c @@ -0,0 +1,166 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2024 1BitSquared + * Written by Rachel Mant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file implements the libatomic special functions that are otherwise missing + * for this platform. libatomic itself is not included in most compiler distributions + * for arm-none-eabi, so we implement our own for sanity. + */ + +#include +#include +#include + +#include + +/* Use a sequential consistency barrier on Cortex-M0 (no special-case for relaxed or aquire-release */ +__attribute__((always_inline, artificial)) static inline void pre_barrier(int model) +{ + (void)model; + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} + +__attribute__((always_inline, artificial)) static inline void post_barrier(int model) +{ + (void)model; + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} + +/* Sequence barriers only issue a fence in sequential consistency mode */ +__attribute__((always_inline, artificial)) static inline void pre_seq_barrier(int model) +{ + if (model == __ATOMIC_SEQ_CST) + __atomic_thread_fence(model); +} + +__attribute__((always_inline, artificial)) static inline void post_seq_barrier(int model) +{ + if (model == __ATOMIC_SEQ_CST) + __atomic_thread_fence(model); +} + +/* Begin a protected block (disables interrupts) */ +__attribute__((always_inline, artificial)) static inline uint32_t protect_begin(const void *const ptr) +{ + (void)ptr; + const uint32_t primask = cm_is_masked_interrupts() ? 1U : 0U; + cm_disable_interrupts(); + return primask; +} + +/* End a protected block (re-enables interrupts if they were enabled at the start of the critical section */ +__attribute__((always_inline, artificial)) static inline void protect_end(const void *const ptr, uint32_t primask) +{ + (void)ptr; + if (primask == 0U) + cm_enable_interrupts(); +} + +uint16_t atomic_fetch_add_2(uint16_t *const atomic_value, const uint16_t add_value, const int model) +{ + /* Create a model-appropriate sync barrier to start */ + pre_barrier(model); + /* Now grab the current value of the atomic to be modified */ + uint16_t new_value; + uint16_t current_value = *atomic_value; + /* Try, in a loop, doing the addition to the value */ + do { + new_value = current_value + add_value; + /* + * Try to replace the value store by the atomic by the updated value computed here - if this fails + * then we get the new value returned in current_value and can try again. + */ + } while (!atomic_compare_exchange_weak_explicit( + atomic_value, ¤t_value, new_value, memory_order_relaxed, memory_order_relaxed)); + /* Create a model-appropriate sync barrier to finish */ + post_barrier(model); + /* Finally, return the value that was in the atomic to complete the operation's contract */ + return current_value; +} + +uint16_t atomic_fetch_sub_2(uint16_t *const atomic_value, const uint16_t sub_value, const int model) +{ + /* Create a model-appropriate sync barrier to start */ + pre_barrier(model); + /* Now grab the current value of the atomic to be modified */ + uint16_t new_value; + uint16_t current_value = *atomic_value; + /* Try, in a loop, doing the addition to the value */ + do { + new_value = current_value - sub_value; + /* + * Try to replace the value store by the atomic by the updated value computed here - if this fails + * then we get the new value returned in current_value and can try again. + */ + } while (!atomic_compare_exchange_weak_explicit( + atomic_value, ¤t_value, new_value, memory_order_relaxed, memory_order_relaxed)); + /* Create a model-appropriate sync barrier to finish */ + post_barrier(model); + /* Finally, return the value that was in the atomic to complete the operation's contract */ + return current_value; +} + +bool atomic_compare_exchange_2(uint16_t *const atomic_value, uint16_t *const expected_value, const uint16_t new_value, + const bool weak, const int success_model, const int failure_model) +{ + (void)weak; + (void)failure_model; + /* Create a model-appropriate sequence barrier to start, and begin a protected block */ + pre_seq_barrier(success_model); + const uint32_t protect_state = protect_begin(atomic_value); + + /* Read out the current value of the atomic, compare it to the expected */ + const uint16_t old_value = *atomic_value; + const bool result = old_value == *expected_value; + /* If it's the expected value, write the new value to complete the RMW cycle */ + if (result) + *atomic_value = new_value; + /* Otherwise, uphold the contract required and write the current value to the expected value pointer */ + else + *expected_value = old_value; + + /* Finish up with a model-appropriate sequence barrier having ended the protected block */ + protect_end(atomic_value, protect_state); + post_seq_barrier(success_model); + return result; +} + +/* Alias the functions defined to their special names to satisfy the compiler */ +/* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming) */ +uint16_t __atomic_fetch_add_2(volatile void *atomic_value, uint16_t add_value, int swap_model) + __attribute__((alias("atomic_fetch_add_2"))); +uint16_t __atomic_fetch_sub_2(volatile void *atomic_value, uint16_t add_value, int swap_model) + __attribute__((alias("atomic_fetch_sub_2"))); +bool __atomic_compare_exchange_2(volatile void *atomic_value, void *expected_value, uint16_t new_value, bool weak, + int success_model, int failure_model) __attribute__((alias("atomic_compare_exchange_2"))); +/* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming) */ diff --git a/src/platforms/f072/meson.build b/src/platforms/f072/meson.build index 383594906cb..8a534255c5e 100644 --- a/src/platforms/f072/meson.build +++ b/src/platforms/f072/meson.build @@ -30,7 +30,10 @@ probe_f072_includes = include_directories('.') -probe_f072_sources = files('platform.c') +probe_f072_sources = files( + 'platform.c', + 'atomic.c', +) probe_f072_args = [ '-DDFU_SERIAL_LENGTH=13', @@ -41,12 +44,19 @@ probe_f072_link_args = [ '-T@0@'.format('stm32f07xzb.ld'), ] +probe_f072_dependencies = [ + platform_common, + platform_stm32f0, + platform_stm32_swo, + platform_stm32_swo_manchester, +] + probe_host = declare_dependency( include_directories: probe_f072_includes, sources: probe_f072_sources, compile_args: probe_f072_args, link_args: probe_f072_link_args, - dependencies: [platform_common, platform_stm32f0, fixme_platform_stm32_traceswo], + dependencies: probe_f072_dependencies, ) summary( diff --git a/src/platforms/f072/platform.h b/src/platforms/f072/platform.h index 70ca359e67e..8cde924da40 100644 --- a/src/platforms/f072/platform.h +++ b/src/platforms/f072/platform.h @@ -27,6 +27,7 @@ #include "timing_stm32.h" #define PLATFORM_HAS_TRACESWO +#define SWO_ENCODING 1 /* Use only Manchester mode SWO recovery */ #define PLATFORM_IDENT "(F072-IF) " @@ -38,9 +39,9 @@ * LED2 = PB7 (Red LED : Error) * * TDI = PA0 - * TMS = PA1 (input for SWDP) + * TMS = PA1 (input/output SWDIO) * TCK = PA7/SWCLK - * TDO = PA6 (input for TRACESWO + * TDO = PA6 (input SWO) * nRST = PA5 * * Force DFU mode button: BOOT0 @@ -65,6 +66,9 @@ #define NRST_PORT GPIOA #define NRST_PIN GPIO5 +#define SWO_PORT GPIOA +#define SWO_PIN GPIO6 + #define LED_PORT GPIOB #define LED_PORT_UART GPIOB #define LED_UART GPIO6 @@ -92,7 +96,7 @@ #define IRQ_PRI_USB (1U << 6U) #define IRQ_PRI_USBUSART (2U << 6U) #define IRQ_PRI_USBUSART_DMA (2U << 6U) -#define IRQ_PRI_TRACE (0U << 6U) +#define IRQ_PRI_SWO_TIM (0U << 6U) #define USBUSART USART2 #define USBUSART_CR1 USART2_CR1 @@ -128,13 +132,22 @@ USART2_CR2 |= USART_CR2_SWAP; \ } while (0) -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR tim3_isr -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#define TRACE_TIM_PIN_AF GPIO_AF1 +/* Use TIM3 Input 1 (from PA6/TDO on AF1) */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR tim3_isr +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 +#define SWO_TIM_PIN_AF GPIO_AF1 #if ENABLE_DEBUG == 1 extern bool debug_bmp; diff --git a/src/platforms/f3/Makefile.inc b/src/platforms/f3/Makefile.inc index 5ebc633a017..95fbda10181 100644 --- a/src/platforms/f3/Makefile.inc +++ b/src/platforms/f3/Makefile.inc @@ -16,12 +16,13 @@ LDFLAGS = --specs=nano.specs -lopencm3_stm32f3 -Lplatforms/f3 \ VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - traceswo.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_manchester.c \ + swo_itm_decode.c all: blackmagic.bin blackmagic.elf: libopencm3_stm32f3 diff --git a/src/platforms/f3/meson.build b/src/platforms/f3/meson.build index 717da951aeb..fec311c4c55 100644 --- a/src/platforms/f3/meson.build +++ b/src/platforms/f3/meson.build @@ -46,7 +46,7 @@ probe_host = declare_dependency( sources: probe_f3_sources, compile_args: probe_f3_args, link_args: probe_f3_link_args, - dependencies: [platform_common, platform_stm32f3, fixme_platform_stm32_traceswo], + dependencies: [platform_common, platform_stm32f3, platform_stm32_swo, platform_stm32_swo_manchester], ) summary( diff --git a/src/platforms/f3/platform.h b/src/platforms/f3/platform.h index 94983bd98da..e9d63f447b7 100644 --- a/src/platforms/f3/platform.h +++ b/src/platforms/f3/platform.h @@ -27,6 +27,7 @@ #include "timing_stm32.h" #define PLATFORM_HAS_TRACESWO +#define SWO_ENCODING 1 /* Use only Manchester mode SWO recovery */ #define PLATFORM_IDENT "(F3-IF) " @@ -38,9 +39,9 @@ * LED2 = PB7 (Red LED : Error) * * TDI = PA0 - * TMS = PA1 (input for SWDP) + * TMS = PA1 (input/output SWDIO) * TCK = PA7/SWCLK - * TDO = PA6 (input for TRACESWO + * TDO = PA6 (input SWO) * nRST = PA5 * * Force DFU mode button: BOOT0 @@ -65,6 +66,9 @@ #define NRST_PORT GPIOA #define NRST_PIN GPIO5 +#define SWO_PORT GPIOA +#define SWO_PIN GPIO6 + #define LED_PORT GPIOB #define LED_PORT_UART GPIOB #define LED_UART GPIO6 @@ -91,7 +95,7 @@ #define IRQ_PRI_USB (1U << 4U) #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #define USBUSART USART2 #define USBUSART_CR1 USART2_CR1 @@ -121,13 +125,22 @@ USART2_CR2 |= USART_CR2_SWAP; \ } while (0) -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR tim3_isr -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#define TRACE_TIM_PIN_AF GPIO_AF2 +/* Use TIM3 Input 1 (from PA6/TDO) */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR tim3_isr +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 +#define SWO_TIM_PIN_AF GPIO_AF2 #if ENABLE_DEBUG == 1 extern bool debug_bmp; diff --git a/src/platforms/f4discovery/Makefile.inc b/src/platforms/f4discovery/Makefile.inc index 2525742a9bf..b12c8743992 100644 --- a/src/platforms/f4discovery/Makefile.inc +++ b/src/platforms/f4discovery/Makefile.inc @@ -26,12 +26,13 @@ endif VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - traceswo.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_manchester.c \ + swo_itm_decode.c ifneq ($(BMP_BOOTLOADER), 1) all: blackmagic.bin diff --git a/src/platforms/f4discovery/meson.build b/src/platforms/f4discovery/meson.build index ca7089b6034..8a5a124e59a 100644 --- a/src/platforms/f4discovery/meson.build +++ b/src/platforms/f4discovery/meson.build @@ -57,7 +57,7 @@ probe_host = declare_dependency( sources: probe_f4discovery_sources, compile_args: probe_f4discovery_args, link_args: probe_f4discovery_commonn_link_args + probe_f4discovery_link_args, - dependencies: [platform_common, platform_stm32f4, fixme_platform_stm32_traceswo], + dependencies: [platform_common, platform_stm32f4, platform_stm32_swo, platform_stm32_swo_manchester], ) probe_bootloader = declare_dependency( diff --git a/src/platforms/f4discovery/platform.h b/src/platforms/f4discovery/platform.h index 0036e7c86da..dcf081c8054 100644 --- a/src/platforms/f4discovery/platform.h +++ b/src/platforms/f4discovery/platform.h @@ -28,6 +28,8 @@ #include "timing_stm32.h" #define PLATFORM_HAS_TRACESWO +#define SWO_ENCODING 1 /* Use only Manchester mode SWO recovery */ + #define PLATFORM_IDENT "(F4Discovery) " /* @@ -41,9 +43,9 @@ * nTRST = PC1 * nRST_OUT = PC8 * TDI = PC2 - * TMS = PC4 (input for SWDP) + * TMS = PC4 (input/output SWDIO) * TCK = PC5/SWCLK - * TDO = PC6 (input for TRACESWO + * TDO = PC6 (input SWO) * nRST = PC8 * * Force DFU mode button: PA0 @@ -70,6 +72,9 @@ #define NRST_PORT GPIOC #define NRST_PIN GPIO8 +#define SWO_PORT GPIOC +#define SWO_PIN GPIO6 + #define LED_PORT GPIOD #define LED_PORT_UART GPIOD #define LED_UART GPIO12 @@ -124,15 +129,24 @@ #define IRQ_PRI_USB (1U << 4U) #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) - -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR(x) tim3_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#define TRACE_TIM_PIN_AF GPIO_AF2 +#define IRQ_PRI_SWO_TIM (0U << 4U) + +/* Use TIM3 Input 1 (from PC6/TDO) */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR(x) tim3_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 +#define SWO_TIM_PIN_AF GPIO_AF2 #define SET_RUN_STATE(state) \ { \ diff --git a/src/platforms/hydrabus/Makefile.inc b/src/platforms/hydrabus/Makefile.inc index 66b21464047..a2f7c66d193 100644 --- a/src/platforms/hydrabus/Makefile.inc +++ b/src/platforms/hydrabus/Makefile.inc @@ -16,12 +16,13 @@ LDFLAGS = -lopencm3_stm32f4 -Lplatforms/hydrabus \ VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - traceswo.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_manchester.c \ + swo_itm_decode.c all: blackmagic.bin blackmagic.hex diff --git a/src/platforms/hydrabus/meson.build b/src/platforms/hydrabus/meson.build index 83a5c245045..da2f0a27330 100644 --- a/src/platforms/hydrabus/meson.build +++ b/src/platforms/hydrabus/meson.build @@ -48,7 +48,7 @@ probe_host = declare_dependency( sources: probe_hydrabus_sources, compile_args: probe_hydrabus_args, link_args: probe_hydrabus_link_args, - dependencies: [platform_common, platform_stm32f4, fixme_platform_stm32_traceswo], + dependencies: [platform_common, platform_stm32f4, platform_stm32_swo, platform_stm32_swo_manchester], ) probe_bootloader = declare_dependency( diff --git a/src/platforms/hydrabus/platform.h b/src/platforms/hydrabus/platform.h index 3a3ed298241..5375c5115e4 100644 --- a/src/platforms/hydrabus/platform.h +++ b/src/platforms/hydrabus/platform.h @@ -29,7 +29,9 @@ #include "timing_stm32.h" #define PLATFORM_HAS_TRACESWO -#define PLATFORM_IDENT " (HydraBus))" +#define SWO_ENCODING 1 /* Use only Manchester mode SWO recovery */ + +#define PLATFORM_IDENT "(HydraBus) " /* * Important pin mappings for STM32 implementation: @@ -41,10 +43,11 @@ * * TMS = PC0 (SWDIO) * TCK = PC1 (SWCLK) - * TDO = PC2 (input for TRACESWO) + * TDO = PC2 * TDI = PC3 * nRST = PC4 (nRST / nRESET / "System Reset") * nTRST = PC5 (Test Reset optional) + * SWO = PC6 * * USB VBUS detect: PB13 */ @@ -71,6 +74,9 @@ #define NRST_PORT GPIOC #define NRST_PIN GPIO4 +#define SWO_PORT GPIOC +#define SWO_PIN GPIO6 + #define LED_PORT GPIOA #define LED_PORT_UART GPIOA #define LED_UART GPIO4 @@ -102,7 +108,7 @@ #define IRQ_PRI_USB (1U << 4U) #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #define USBUSART USART1 #define USBUSART_CR1 USART1_CR1 @@ -124,14 +130,22 @@ /* For STM32F4 DMA trigger source must be specified */ #define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4 -/* Use TIM3 Input 1 (from PC6), AF2, trigger on Rising Edge. FIXME: TDO is on PC2. */ -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR(x) tim3_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#define TRACE_TIM_PIN_AF GPIO_AF2 +/* Use TIM3 Input 1 (from PC6), AF2, trigger on rising edge. */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR(x) tim3_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 +#define SWO_TIM_PIN_AF GPIO_AF2 #define SET_RUN_STATE(state) \ { \ diff --git a/src/platforms/launchpad-icdi/Makefile.inc b/src/platforms/launchpad-icdi/Makefile.inc index f74471643c1..7d378d25128 100644 --- a/src/platforms/launchpad-icdi/Makefile.inc +++ b/src/platforms/launchpad-icdi/Makefile.inc @@ -16,9 +16,9 @@ LDFLAGS = -lopencm3_lm4f -Lplatforms/launchpad-icdi \ VPATH += platforms/common/tm4c -SRC += \ +SRC += \ platform.c \ - timing.c \ - traceswo.o + timing.c \ + swo_uart.o all: blackmagic.bin diff --git a/src/platforms/launchpad-icdi/platform.h b/src/platforms/launchpad-icdi/platform.h index 929112a8e95..84fb1d73b91 100644 --- a/src/platforms/launchpad-icdi/platform.h +++ b/src/platforms/launchpad-icdi/platform.h @@ -23,23 +23,26 @@ #include "timing.h" +#define PLATFORM_HAS_TRACESWO +#define SWO_ENCODING 2 /* Use only UART mode SWO recovery */ + #define PLATFORM_IDENT "(Launchpad ICDI) " extern uint8_t running_status; -#define TMS_PORT GPIOA_BASE +#define TMS_PORT GPIOA #define TMS_PIN GPIO3 -#define TCK_PORT GPIOA_BASE +#define TCK_PORT GPIOA #define TCK_PIN GPIO2 -#define TDI_PORT GPIOA_BASE +#define TDI_PORT GPIOA #define TDI_PIN GPIO5 -#define TDO_PORT GPIOA_BASE +#define TDO_PORT GPIOA #define TDO_PIN GPIO4 -#define SWO_PORT GPIOD_BASE +#define SWO_PORT GPIOD #define SWO_PIN GPIO6 #define SWDIO_PORT TMS_PORT @@ -48,7 +51,7 @@ extern uint8_t running_status; #define SWCLK_PORT TCK_PORT #define SWCLK_PIN TCK_PIN -#define NRST_PORT GPIOA_BASE +#define NRST_PORT GPIOA #define NRST_PIN GPIO6 #define TMS_SET_MODE() \ @@ -72,7 +75,8 @@ extern uint8_t running_status; #define USB_IRQ NVIC_USB0_IRQ #define USB_ISR usb0_isr -#define IRQ_PRI_USB (2 << 4) +#define IRQ_PRI_USB (2U << 4U) +#define IRQ_PRI_SWO_UART (0U << 4U) #define USBUART UART0 #define USBUART_CLK RCC_UART0 @@ -89,10 +93,13 @@ extern uint8_t running_status; gpio_mode_setup(GPIOA_BASE, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO1); \ } while (0) -#define TRACEUART UART2 -#define TRACEUART_CLK RCC_UART2 -#define TRACEUART_IRQ NVIC_UART2_IRQ -#define TRACEUART_ISR uart2_isr +#define SWO_UART UART2 +#define SWO_UART_CLK RCC_UART2 +#define SWO_UART_PORT GPIOD +#define SWO_UART_RX_PIN GPIO6 +#define SWO_UART_PIN_AF 1U +#define SWO_UART_IRQ NVIC_UART2_IRQ +#define SWO_UART_ISR(x) uart2_isr(x) #define SET_RUN_STATE(state) \ { \ @@ -103,16 +110,14 @@ extern uint8_t running_status; } #define SET_ERROR_STATE(state) SET_IDLE_STATE(state) -#define PLATFORM_HAS_TRACESWO - inline static void gpio_set_val(uint32_t port, uint8_t pin, uint8_t val) { - gpio_write(port, pin, val == 0 ? 0 : 0xff); + gpio_write(port, pin, val == 0U ? 0U : 0xffU); } inline static uint8_t gpio_get(uint32_t port, uint8_t pin) { - return !(gpio_read(port, pin) == 0); + return gpio_read(port, pin) != 0U; } #define disconnect_usb() \ diff --git a/src/platforms/native/Makefile.inc b/src/platforms/native/Makefile.inc index 8eb8047dcf5..064d0bb141b 100644 --- a/src/platforms/native/Makefile.inc +++ b/src/platforms/native/Makefile.inc @@ -4,7 +4,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \ -DSTM32F1 -DBLACKMAGIC -I../deps/libopencm3/include \ - -Iplatforms/common/stm32 -DDFU_SERIAL_LENGTH=9 -DTRACESWO_PROTOCOL=1 + -Iplatforms/common/stm32 -DDFU_SERIAL_LENGTH=9 -DSWO_ENCODING=1 LDFLAGS_BOOT := $(LDFLAGS) -lopencm3_stm32f1 -Lplatforms/native \ -Tnative.ld --specs=nano.specs -nostartfiles -lc \ @@ -21,12 +21,31 @@ endif VPATH += platforms/common/stm32 SRC += \ - platform.c \ - traceswodecode.c \ - traceswo.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_itm_decode.c + +# If SWO_ENCODING has not been given, default it to including both modes +ifndef SWO_ENCODING + SWO_ENCODING = 3 +endif + +# Include the files for either: Manchester-only (1), UART-only (2) or both modes (3) +ifeq ($(SWO_ENCODING), 1) + SRC += swo_manchester.c +else ifeq ($(SWO_ENCODING), 2) + SRC += swo_uart.c +else ifeq ($(SWO_ENCODING), 3) + SRC += \ + swo_manchester.c \ + swo_uart.c +else # If we got some other value, that's an error so report it + $(error Invalid value for SWO encoding, must be one of 1, 2, or 3) +endif +CFLAGS += -DTRACESWO_PROTOCOL=$(SWO_ENCODING) all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex diff --git a/src/platforms/native/meson.build b/src/platforms/native/meson.build index 525c8e9cacb..473ba65d4dd 100644 --- a/src/platforms/native/meson.build +++ b/src/platforms/native/meson.build @@ -40,11 +40,13 @@ probe_native_args = [ ] trace_protocol = get_option('trace_protocol') +probe_native_args += [f'-DSWO_ENCODING=@trace_protocol@'] +probe_native_dependencies = [platform_stm32_swo] if trace_protocol in ['1', '3'] - probe_native_args += [f'-DTRACESWO_PROTOCOL=1'] - probe_native_dependencies = fixme_platform_stm32_traceswo -else - error('Unsupported SWO mode requested') + probe_native_dependencies += platform_stm32_swo_manchester +endif +if trace_protocol in ['2', '3'] + probe_native_dependencies += platform_stm32_swo_uart endif probe_native_common_link_args = [ diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c index 055466fc25b..e889527e872 100644 --- a/src/platforms/native/platform.c +++ b/src/platforms/native/platform.c @@ -156,6 +156,8 @@ void platform_init(void) rcc_periph_clock_enable(RCC_GPIOC); if (hwversion >= 1) rcc_periph_clock_enable(RCC_TIM1); + /* Make sure to power up the timer used for trace */ + rcc_periph_clock_enable(RCC_TIM3); rcc_periph_clock_enable(RCC_AFIO); rcc_periph_clock_enable(RCC_CRC); @@ -165,6 +167,7 @@ void platform_init(void) gpio_set_mode(JTAG_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TMS_DIR_PIN | TCK_PIN | TDI_PIN); gpio_set_mode(JTAG_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_INPUT_FLOAT, TMS_PIN); + gpio_set_mode(JTAG_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TDO_PIN); /* This needs some fixing... */ /* Toggle required to sort out line drivers... */ @@ -262,7 +265,7 @@ void platform_init(void) gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO0); } /* Set up the NVIC vector table for the firmware */ - SCB_VTOR = (uint32_t)&vector_table; // NOLINT(clang-diagnostic-pointer-to-int-cast) + SCB_VTOR = (uintptr_t)&vector_table; // NOLINT(clang-diagnostic-pointer-to-int-cast, performance-no-int-to-ptr) platform_timing_init(); blackmagic_usb_init(); @@ -567,3 +570,13 @@ static void setup_vbus_irq(void) exti15_10_isr(); } + +void dma1_channel5_isr(void) +{ + if (hwversion < 6) + usart1_rx_dma_isr(); +#if SWO_ENCODING != 1 + else + swo_dma_isr(); +#endif +} diff --git a/src/platforms/native/platform.h b/src/platforms/native/platform.h index 00a03d03d8f..e2c393c7a33 100644 --- a/src/platforms/native/platform.h +++ b/src/platforms/native/platform.h @@ -134,6 +134,14 @@ extern int hwversion; #define NRST_SENSE_PORT HW_SWITCH(6, GPIOA, GPIOC) #define NRST_SENSE_PIN HW_SWITCH(6, GPIO7, GPIO13) +/* + * SWO comes in on PB7 (TIM4 CH2) before HW6, and PA10 (TIM1 CH3) after - + * however, because of Shenanigans™ with timers and other pins, this has to + * reuse TDO (PA6, TIM3 CH1) to not wind up clobbering timers and timer pins + */ +#define SWO_PORT GPIOA +#define SWO_PIN GPIO6 + /* * These are the control output pin definitions for TPWR. * TPWR is sensed via PB0 by sampling ADC1's channel 8. @@ -252,7 +260,8 @@ extern int hwversion; #define IRQ_PRI_USBUSART (2U << 4U) #define IRQ_PRI_USBUSART_DMA (2U << 4U) #define IRQ_PRI_USB_VBUS (14U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) +#define IRQ_PRI_SWO_DMA (0U << 4U) #define USBUSART HW_SWITCH(6, USBUSART1, USBUSART2) #define USBUSART_IRQ HW_SWITCH(6, NVIC_USART1_IRQ, NVIC_USART2_IRQ) @@ -276,7 +285,7 @@ extern int hwversion; #define USBUSART1_DMA_TX_ISR(x) dma1_channel4_isr(x) #define USBUSART1_DMA_RX_CHAN DMA_CHANNEL5 #define USBUSART1_DMA_RX_IRQ NVIC_DMA1_CHANNEL5_IRQ -#define USBUSART1_DMA_RX_ISR(x) dma1_channel5_isr(x) +#define USBUSART1_DMA_RX_ISR(x) usart1_rx_dma_isr(x) #define USBUSART2 USART2 #define USBUSART2_IRQ NVIC_USART2_IRQ @@ -288,20 +297,47 @@ extern int hwversion; #define USBUSART2_DMA_RX_IRQ NVIC_DMA1_CHANNEL6_IRQ #define USBUSART2_DMA_RX_ISR(x) dma1_channel6_isr(x) -#if TRACESWO_PROTOCOL == 1 -/* Use TIM3 Input 1 (from PA6/TDO) */ -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR(x) tim3_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 -#endif +/* Use TIM3 Input 1 (from PA6/TDO) for Manchester data recovery */ +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR(x) tim3_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 + +/* Use PA10 (USART1) on HW6+ for UART/NRZ/Async data recovery */ +#define SWO_UART HW_SWITCH(6, 0U, USART1) +#define SWO_UART_CLK RCC_USART1 +#define SWO_UART_DR USART1_DR +#define SWO_UART_PORT GPIOA +#define SWO_UART_RX_PIN GPIO10 + +#define SWO_DMA_BUS DMA1 +#define SWO_DMA_CLK RCC_DMA1 +#define SWO_DMA_CHAN DMA_CHANNEL5 +#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL5_IRQ +#define SWO_DMA_ISR(x) swo_dma_isr(x) #define SET_RUN_STATE(state) running_status = (state) #define SET_IDLE_STATE(state) gpio_set_val(LED_PORT, LED_IDLE_RUN, state) #define SET_ERROR_STATE(state) gpio_set_val(LED_PORT, LED_ERROR, state) +/* + * These are bounce declarations for the ISR handlers competing for dma1_channel5_isr(). + * The actual handler is defined in platform.c, the USART1 RX handler in aux_serial.c, + * and the SWO DMA handler in swo_uart.c. + */ +void usart1_rx_dma_isr(void); +void swo_dma_isr(void); + /* Frequency constants (in Hz) for the bitbanging routines */ #define BITBANG_CALIBRATED_FREQS /* diff --git a/src/platforms/stlink/Makefile.inc b/src/platforms/stlink/Makefile.inc index ff3ce06ba29..91df677ce6e 100644 --- a/src/platforms/stlink/Makefile.inc +++ b/src/platforms/stlink/Makefile.inc @@ -3,55 +3,66 @@ ST_BOOTLOADER ?= CC = $(CROSS_COMPILE)gcc OBJCOPY = $(CROSS_COMPILE)objcopy -OPT_FLAGS = -Os CFLAGS += -mcpu=cortex-m3 -mthumb -DSTM32F1 -I../deps/libopencm3/include \ -I platforms/common/stm32 LDFLAGS_BOOT := $(LDFLAGS) -lopencm3_stm32f1 -Lplatforms/stlink \ -Tstlink.ld --specs=nano.specs -nostartfiles -lc \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \ -L../deps/libopencm3/lib + ifeq ($(ST_BOOTLOADER), 1) -$(info Load address 0x08004000 for original ST-LinkV2 Bootloader) -CFLAGS += -DST_BOOTLOADER -DDFU_SERIAL_LENGTH=25 -LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000 + $(info Load address 0x08004000 for original ST-LinkV2 Bootloader) + CFLAGS += -DST_BOOTLOADER -DDFU_SERIAL_LENGTH=25 + LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000 else -CFLAGS += -DDFU_SERIAL_LENGTH=9 -LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000 + CFLAGS += -DDFU_SERIAL_LENGTH=9 + LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000 endif ifeq ($(ENABLE_DEBUG), 1) -LDFLAGS += --specs=rdimon.specs + LDFLAGS += --specs=rdimon.specs else -LDFLAGS += --specs=nosys.specs + LDFLAGS += --specs=nosys.specs endif ifeq ($(SWIM_AS_UART), 1) -SWIM_NRST_AS_UART=1 -$(warning Deprecation: SWIM_AS_UART has been renamed to SWIM_NRST_AS_UART; it might be ignored in the future) + SWIM_NRST_AS_UART=1 + $(warning Deprecation: SWIM_AS_UART has been renamed to SWIM_NRST_AS_UART; it might be ignored in the future) endif ifeq ($(SWIM_NRST_AS_UART), 1) -CFLAGS += -DSWIM_NRST_AS_UART=1 -else -ifeq ($(TRACESWO_PROTOCOL), 1) -SRC += traceswo.c -CFLAGS += -DTRACESWO_PROTOCOL=1 + CFLAGS += -DSWIM_NRST_AS_UART=1 else -SRC += traceswoasync.c -CFLAGS += -DTRACESWO_PROTOCOL=2 -endif + # If SWO_ENCODING has not been given, default it to including both modes + ifndef SWO_ENCODING + SWO_ENCODING = 3 + endif + + # Include the files for either: Manchester-only (1), UART-only (2) or both modes (3) + ifeq ($(SWO_ENCODING), 1) + SRC += swo_manchester.c + else ifeq ($(SWO_ENCODING), 2) + SRC += swo_uart.c + else ifeq ($(SWO_ENCODING), 3) + SRC += \ + swo_manchester.c \ + swo_uart.c + else # If we got some other value, that's an error so report it + $(error Invalid value for SWO encoding, must be one of 1, 2, or 3) + endif + CFLAGS += -DSWO_ENCODING=$(SWO_ENCODING) endif ifeq ($(BLUEPILL), 1) -CFLAGS += -DBLUEPILL=1 + CFLAGS += -DBLUEPILL=1 endif ifeq ($(STLINK_FORCE_CLONE), 1) -CFLAGS += -DSTLINK_FORCE_CLONE=1 + CFLAGS += -DSTLINK_FORCE_CLONE=1 endif ifeq ($(STLINK_V2_ISOL), 1) -CFLAGS += -DSTLINK_V2_ISOL=1 + CFLAGS += -DSTLINK_V2_ISOL=1 endif VPATH += platforms/common/stm32 diff --git a/src/platforms/stlink/meson.build b/src/platforms/stlink/meson.build index 8ec3c5901b7..ab8b3529796 100644 --- a/src/platforms/stlink/meson.build +++ b/src/platforms/stlink/meson.build @@ -65,26 +65,23 @@ if probe == 'bluepill' probe_stlink_args += ['-DBLUEPILL=1'] endif -probe_stlink_dependencies = [platform_common, platform_stm32f1] +probe_stlink_dependencies = [platform_common, platform_stm32f1, platform_stm32_swo] stlink_swim_nrst_as_uart = get_option('stlink_swim_nrst_as_uart') trace_protocol = get_option('trace_protocol') -if trace_protocol == '3' - trace_protocol = '2' -endif if probe == 'stlink' and stlink_swim_nrst_as_uart probe_stlink_args += ['-DSWIM_NRST_AS_UART=1'] - probe_stlink_dependencies += fixme_platform_stm32_traceswo - probe_stlink_args += ['-DTRACESWO_PROTOCOL=1'] -elif trace_protocol == '1' - probe_stlink_dependencies += fixme_platform_stm32_traceswo - probe_stlink_args += ['-DTRACESWO_PROTOCOL=1'] -elif trace_protocol == '2' - probe_stlink_dependencies += fixme_platform_stm32_traceswoasync - probe_stlink_args += ['-DTRACESWO_PROTOCOL=2'] + probe_stlink_dependencies += platform_stm32_swo_manchester + probe_stlink_args += ['-DSWO_ENCODING=1'] else - error('Unsupported SWO mode requested') + probe_stlink_args += [f'-DSWO_ENCODING=@trace_protocol@'] + if trace_protocol in ['1', '3'] + probe_stlink_dependencies += platform_stm32_swo_manchester + endif + if trace_protocol in ['2', '3'] + probe_stlink_dependencies += platform_stm32_swo_uart + endif endif probe_host = declare_dependency( diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h index a2cd754916f..8068c717d2a 100644 --- a/src/platforms/stlink/platform.h +++ b/src/platforms/stlink/platform.h @@ -31,6 +31,10 @@ #include #include +#ifndef SWIM_AS_UART +#define PLATFORM_HAS_TRACESWO +#endif + #if ENABLE_DEBUG == 1 #define PLATFORM_HAS_DEBUG extern bool debug_bmp; @@ -67,6 +71,9 @@ extern bool debug_bmp; #define NRST_PIN_CLONE GPIO6 #endif +#define SWO_PORT GPIOA +#define SWO_PIN GPIO6 + #ifdef BLUEPILL #define LED_PORT GPIOC #else @@ -127,7 +134,7 @@ extern bool debug_bmp; #define IRQ_PRI_USBUSART_DMA (2U << 4U) #define IRQ_PRI_USB_VBUS (14U << 4U) #define IRQ_PRI_SWO_DMA (0U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #ifdef SWIM_NRST_AS_UART #define USBUSART USART1 @@ -166,23 +173,21 @@ extern bool debug_bmp; #define USBUSART_DMA_BUS DMA1 #define USBUSART_DMA_CLK RCC_DMA1 -#ifndef SWIM_AS_UART -#define PLATFORM_HAS_TRACESWO 1 -#endif -#define NUM_TRACE_PACKETS 128U /* This is an 8K buffer */ -//#define TRACESWO_PROTOCOL 2U /* 1 = Manchester, 2 = NRZ / async */ - -#if TRACESWO_PROTOCOL == 1 - /* Use TIM3 Input 1 (from PA6/TDO) */ -#define TRACE_TIM TIM3 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) -#define TRACE_IRQ NVIC_TIM3_IRQ -#define TRACE_ISR(x) tim3_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI1 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI1FP1 - -#elif TRACESWO_PROTOCOL == 2 +#define SWO_TIM TIM3 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) +#define SWO_TIM_IRQ NVIC_TIM3_IRQ +#define SWO_TIM_ISR(x) tim3_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI1 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM3_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM3_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI1FP1 /* On F103, only USART1 is on AHB2 and can reach 4.5MBaud at 72 MHz. */ #define SWO_UART USART1 @@ -192,13 +197,11 @@ extern bool debug_bmp; #define SWO_UART_RX_PIN GPIO10 /* This DMA channel is set by the USART in use */ -#define SWO_DMA_BUS DMA1 -#define SWO_DMA_CLK RCC_DMA1 -#define SWO_DMA_CHAN DMA_CHANNEL5 -#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL5_IRQ -#define SWO_DMA_ISR(x) dma1_channel5_isr(x) - -#endif /* TRACESWO_PROTOCOL */ +#define SWO_DMA_BUS DMA1 +#define SWO_DMA_CLK RCC_DMA1 +#define SWO_DMA_CHAN DMA_CHANNEL5 +#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL5_IRQ +#define SWO_DMA_ISR(x) dma1_channel5_isr(x) extern uint16_t led_idle_run; #define LED_IDLE_RUN led_idle_run diff --git a/src/platforms/stlinkv3/Makefile.inc b/src/platforms/stlinkv3/Makefile.inc index 55ed6709cfb..3df3a5536d0 100644 --- a/src/platforms/stlinkv3/Makefile.inc +++ b/src/platforms/stlinkv3/Makefile.inc @@ -5,7 +5,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy OPT_FLAGS = -Og -g CFLAGS += -mcpu=cortex-m7 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard \ -DSTM32F7 -DDFU_SERIAL_LENGTH=25 -I../deps/libopencm3/include \ - -I platforms/common/stm32 -DTRACESWO_PROTOCOL=2 + -I platforms/common/stm32 LDFLAGS_BOOT := $(LDFLAGS) -mfpu=fpv5-sp-d16 -mfloat-abi=hard \ --specs=nano.specs -lopencm3_stm32f7 -Lplatforms/stlinkv3 \ -Tstlinkv3.ld -nostartfiles -lc \ @@ -30,13 +30,14 @@ endif VPATH += platforms/common/stm32 -SRC += \ - platform.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ - traceswoasync_f723.c \ - traceswodecode.c \ +SRC += \ + platform.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_uart.c \ + swo_itm_decode.c .PHONY: libopencm3_stm32f7 diff --git a/src/platforms/stlinkv3/meson.build b/src/platforms/stlinkv3/meson.build index 7299637a141..d5b4a09da57 100644 --- a/src/platforms/stlinkv3/meson.build +++ b/src/platforms/stlinkv3/meson.build @@ -63,8 +63,7 @@ if trace_protocol == '3' trace_protocol = '2' endif if trace_protocol == '2' - probe_stlinkv3_dependencies = fixme_platform_stm32f7_traceswoasync - probe_stlinkv3_args += ['-DTRACESWO_PROTOCOL=2'] + probe_stlinkv3_dependencies = [platform_stm32_swo, platform_stm32_swo_uart] else error('Unsupported SWO protocol requested') endif @@ -74,7 +73,7 @@ probe_host = declare_dependency( sources: probe_stlinkv3_sources, compile_args: probe_stlinkv3_args, link_args: probe_stlinkv3_common_link_args + probe_stlinkv3_link_args, - dependencies: [platform_common, platform_stm32f7, fixme_platform_stm32f7_traceswoasync], + dependencies: [platform_common, platform_stm32f7, probe_stlinkv3_dependencies], ) probe_bootloader = declare_dependency( diff --git a/src/platforms/stlinkv3/platform.c b/src/platforms/stlinkv3/platform.c index 3e58a0c7bd4..6e603b1c953 100644 --- a/src/platforms/stlinkv3/platform.c +++ b/src/platforms/stlinkv3/platform.c @@ -1,8 +1,9 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2022-2023 1BitSquared + * Copyright (C) 2022-2024 1BitSquared * Portions (C) 2020-2021 Stoyan Shopov + * Modified by Rachel Mant * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,8 +19,8 @@ * along with this program. If not, see . */ -/* This file provides the platform specific functions for the STLINK-V3 - * implementation. +/* + * This file provides the platform specific functions for the ST-Link v3 implementation. */ #include "general.h" @@ -114,7 +115,7 @@ int platform_hwversion(void) void platform_nrst_set_val(bool assert) { - gpio_set_val(SRST_PORT, SRST_PIN, !assert); + gpio_set_val(NRST_PORT, NRST_PIN, !assert); if (assert) { for (volatile size_t i = 0; i < 10000; i++) continue; @@ -123,7 +124,7 @@ void platform_nrst_set_val(bool assert) bool platform_nrst_get_val() { - return gpio_get(SRST_PORT, SRST_PIN) == 0; + return gpio_get(NRST_PORT, NRST_PIN) == 0; } const char *platform_target_voltage(void) @@ -182,9 +183,9 @@ void platform_init(void) adc_power_on(ADC1); /* Configure srst pin. */ - gpio_set_output_options(SRST_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, SRST_PIN); - gpio_mode_setup(SRST_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SRST_PIN); - gpio_set(SRST_PORT, SRST_PIN); + gpio_set_output_options(NRST_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, NRST_PIN); + gpio_mode_setup(NRST_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, NRST_PIN); + gpio_set(NRST_PORT, NRST_PIN); gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TMS_PIN); gpio_set_output_options(TMS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, TMS_PIN); @@ -243,12 +244,13 @@ void platform_init(void) regval |= (usart6_clksel & RCC_DCKCFGR2_UARTxSEL_MASK) << RCC_DCKCFGR2_USART6SEL_SHIFT; RCC_DCKCFGR2 = regval; - /* Relocate interrupt vector table here */ - SCB_VTOR = (uintptr_t)&vector_table; + /* Set up the NVIC vector table for the firmware */ + SCB_VTOR = (uintptr_t)&vector_table; // NOLINT(clang-diagnostic-pointer-to-int-cast, performance-no-int-to-ptr) platform_timing_init(); blackmagic_usb_init(); aux_serial_init(); + /* By default, do not drive the swd bus too fast. */ platform_max_frequency_set(6000000); } diff --git a/src/platforms/stlinkv3/platform.h b/src/platforms/stlinkv3/platform.h index 48d6189d922..78643bd4fba 100644 --- a/src/platforms/stlinkv3/platform.h +++ b/src/platforms/stlinkv3/platform.h @@ -32,12 +32,15 @@ #include #include +#define PLATFORM_HAS_TRACESWO +#define SWO_ENCODING 2 /* Use only UART mode SWO recovery */ + #if ENABLE_DEBUG == 1 #define PLATFORM_HAS_DEBUG extern bool debug_bmp; #endif -#define PLATFORM_IDENT "STLINK-V3 " +#define PLATFORM_IDENT "(ST-Link v3) " #define BOOTMAGIC0 0xb007da7aU #define BOOTMAGIC1 0xbaadfeedU @@ -61,8 +64,11 @@ extern bool debug_bmp; #define SWDIO_PIN TMS_PIN #define SWCLK_PIN TCK_PIN -#define SRST_PORT GPIOA -#define SRST_PIN GPIO6 +#define NRST_PORT GPIOA +#define NRST_PIN GPIO6 + +#define SWO_PORT GPIOD +#define SWO_PIN GPIO2 #define TMS_DRIVE_PORT GPIOA #define TMS_DRIVE_PIN GPIO7 @@ -79,11 +85,8 @@ extern bool debug_bmp; #define MCO1_PIN GPIO8 #define MCO1_AF 0 -#define PLATFORM_HAS_TRACESWO 1 -#define NUM_TRACE_PACKETS (16) - #define SWDIO_MODE_REG GPIO_MODER(TMS_PORT) -#define SWDIO_MODE_REG_MULT (1 << (9 << 1)) +#define SWDIO_MODE_REG_MULT (1U << (9U << 1U)) #define TMS_SET_MODE() \ gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TMS_PIN); \ @@ -181,8 +184,8 @@ extern const struct _usbd_driver stm32f723_usb_driver; /* This DMA channel is set by the USART in use */ #define SWO_DMA_BUS DMA1 #define SWO_DMA_CLK RCC_DMA1 -#define SWO_DMA_CHAN DMA_CHANNEL4 -#define SWO_DMA_STREAM DMA_STREAM0 +#define SWO_DMA_CHAN DMA_STREAM0 +#define SWO_DMA_TRG DMA_SxCR_CHSEL_4 #define SWO_DMA_IRQ NVIC_DMA1_STREAM0_IRQ #define SWO_DMA_ISR(x) dma1_stream0_isr(x) diff --git a/src/platforms/swlink/Makefile.inc b/src/platforms/swlink/Makefile.inc index 00fbf5336be..21c7b437875 100644 --- a/src/platforms/swlink/Makefile.inc +++ b/src/platforms/swlink/Makefile.inc @@ -19,21 +19,33 @@ endif VPATH += platforms/common/stm32 -SRC += \ - platform.c \ - serialno.c \ - timing.c \ - timing_stm32.c \ - traceswodecode.c \ - platform_common.c - -ifeq ($(TRACESWO_PROTOCOL), 1) -SRC += traceswo.c -CFLAGS += -DTRACESWO_PROTOCOL=1 -else -SRC += traceswoasync.c -CFLAGS += -DTRACESWO_PROTOCOL=2 +SRC += \ + platform.c \ + platform_common.c \ + serialno.c \ + timing.c \ + timing_stm32.c \ + swo.c \ + swo_itm_decode.c + +# If SWO_ENCODING has not been given, default it to including both modes +ifndef SWO_ENCODING + SWO_ENCODING = 3 +endif + +# Include the files for either: Manchester-only (1), UART-only (2) or both modes (3) +ifeq ($(SWO_ENCODING), 1) + SRC += swo_manchester.c +else ifeq ($(SWO_ENCODING), 2) + SRC += swo_uart.c +else ifeq ($(SWO_ENCODING), 3) + SRC += \ + swo_manchester.c \ + swo_uart.c +else # If we got some other value, that's an error so report it + $(error Invalid value for SWO encoding, must be one of 1, 2, or 3) endif +CFLAGS += -DSWO_ENCODING=$(SWO_ENCODING) all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex diff --git a/src/platforms/swlink/meson.build b/src/platforms/swlink/meson.build index 389a1098755..19dff6f0e5b 100644 --- a/src/platforms/swlink/meson.build +++ b/src/platforms/swlink/meson.build @@ -54,13 +54,13 @@ probe_swlink_link_args = [ ] trace_protocol = get_option('trace_protocol') -if trace_protocol == '3' - trace_protocol = '2' +probe_swlink_args += [f'-DSWO_ENCODING=@trace_protocol@'] +probe_swlink_dependencies = [platform_stm32_swo] +if trace_protocol in ['1', '3'] + probe_swlink_dependencies += platform_stm32_swo_manchester endif -if trace_protocol == '2' - probe_swlink_args += '-DTRACESWO_PROTOCOL=2' -else - error('Unsupported SWO protocol requested') +if trace_protocol in ['2', '3'] + probe_swlink_dependencies += platform_stm32_swo_uart endif probe_host = declare_dependency( @@ -68,7 +68,7 @@ probe_host = declare_dependency( sources: probe_swlink_sources, compile_args: probe_swlink_args, link_args: probe_swlink_common_link_args + probe_swlink_link_args, - dependencies: [platform_common, platform_stm32f1, fixme_platform_stm32_traceswoasync], + dependencies: [platform_common, platform_stm32f1, probe_swlink_dependencies], ) probe_bootloader = declare_dependency( diff --git a/src/platforms/swlink/platform.h b/src/platforms/swlink/platform.h index 62a5f408665..65d774b74a6 100644 --- a/src/platforms/swlink/platform.h +++ b/src/platforms/swlink/platform.h @@ -28,6 +28,8 @@ #include "timing.h" #include "timing_stm32.h" +#define PLATFORM_HAS_TRACESWO + #if ENABLE_DEBUG == 1 #define PLATFORM_HAS_DEBUG extern bool debug_bmp; @@ -52,6 +54,9 @@ extern bool debug_bmp; #define SWDIO_PIN TMS_PIN #define SWCLK_PIN TCK_PIN +#define SWO_PORT GPIOB +#define SWO_PIN GPIO3 + /* Use PC14 for a "dummy" UART LED so we can observere at least with scope */ #define LED_PORT_UART GPIOC #define LED_UART GPIO14 @@ -96,7 +101,7 @@ extern bool debug_bmp; #define IRQ_PRI_USBUSART_DMA (2U << 4U) #define IRQ_PRI_USB_VBUS (14U << 4U) #define IRQ_PRI_SWO_DMA (0U << 4U) -#define IRQ_PRI_TRACE (0U << 4U) +#define IRQ_PRI_SWO_TIM (0U << 4U) #define USBUSART USART1 #define USBUSART_CR1 USART1_CR1 @@ -118,22 +123,21 @@ extern bool debug_bmp; #define USBUSART_DMA_RX_IRQ NVIC_DMA1_CHANNEL5_IRQ #define USBUSART_DMA_RX_ISR(x) dma1_channel5_isr(x) -#define PLATFORM_HAS_TRACESWO 1 -#define NUM_TRACE_PACKETS 128U /* This is an 8K buffer */ -//#define TRACESWO_PROTOCOL 2U /* 1 = Manchester, 2 = NRZ / async */ - -#if TRACESWO_PROTOCOL == 1 - /* Use TIM2 Input 2 (from PB3/TDO with Remap) */ -#define TRACE_TIM TIM2 -#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM2) -#define TRACE_IRQ NVIC_TIM2_IRQ -#define TRACE_ISR(x) tim2_isr(x) -#define TRACE_IC_IN TIM_IC_IN_TI2 -#define TRACE_TRIG_IN TIM_SMCR_TS_TI2FP2 -/* was TIM_SMCR_TS_IT1FP2 from 2010 API */ - -#elif TRACESWO_PROTOCOL == 2 +#define SWO_TIM TIM2 +#define SWO_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM2) +#define SWO_TIM_IRQ NVIC_TIM2_IRQ +#define SWO_TIM_ISR(x) tim2_isr(x) +#define SWO_IC_IN TIM_IC_IN_TI2 +#define SWO_IC_RISING TIM_IC1 +#define SWO_CC_RISING TIM2_CCR1 +#define SWO_ITR_RISING TIM_DIER_CC1IE +#define SWO_STATUS_RISING TIM_SR_CC1IF +#define SWO_IC_FALLING TIM_IC2 +#define SWO_CC_FALLING TIM2_CCR2 +#define SWO_STATUS_FALLING TIM_SR_CC2IF +#define SWO_STATUS_OVERFLOW (TIM_SR_CC1OF | TIM_SR_CC2OF) +#define SWO_TRIG_IN TIM_SMCR_TS_TI2FP2 /* * On F103, only USART1 is on AHB2 and can reach 4.5MBaud at 72 MHz. @@ -147,13 +151,11 @@ extern bool debug_bmp; #define SWO_UART_RX_PIN GPIO3 /* This DMA channel is set by the USART in use */ -#define SWO_DMA_BUS DMA1 -#define SWO_DMA_CLK RCC_DMA1 -#define SWO_DMA_CHAN DMA_CHANNEL6 -#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL6_IRQ -#define SWO_DMA_ISR(x) dma1_channel6_isr(x) - -#endif /* TRACESWO_PROTOCOL */ +#define SWO_DMA_BUS DMA1 +#define SWO_DMA_CLK RCC_DMA1 +#define SWO_DMA_CHAN DMA_CHANNEL6 +#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL6_IRQ +#define SWO_DMA_ISR(x) dma1_channel6_isr(x) #define LED_PORT GPIOC #define LED_IDLE_RUN GPIO15 diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 968aab68eea..318aa84753c 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -1,9 +1,9 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2015 Black Sphere Technologies Ltd. + * Copyright (C) 2015 Black Sphere Technologies Ltd. * Written by Gareth McMullin - * Copyright (C) 2018-2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * Copyright (C) 2018-2021 Uwe Bonnes * Copyright (C) 2022-2024 1BitSquared * Modified by Rachel Mant *