traceswo decoding
This commit is contained in:
parent
54ee00b0f6
commit
541861e978
|
@ -16,6 +16,9 @@ JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
|
|||
by the microprocessor. The probe connects to a host computer using a
|
||||
standard USB interface. The user is able to control exactly what happens
|
||||
using the GNU source level debugging software, GDB.
|
||||
Serial Wire Output (SWO) allows the target to write tracing and logging to the host
|
||||
without using usb or serial port. Decoding SWO in the probe itself
|
||||
makes [SWO viewing as simple as connecting to a serial port](https://github.com/blacksphere/blackmagic/wiki/Serial-Wire-Output).
|
||||
|
||||
See online documentation at https://github.com/blacksphere/blackmagic/wiki
|
||||
|
||||
|
|
|
@ -79,9 +79,9 @@ const struct command_s cmd_list[] = {
|
|||
#endif
|
||||
#ifdef PLATFORM_HAS_TRACESWO
|
||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate)" },
|
||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
||||
#else
|
||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, Manchester mode" },
|
||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, Manchester mode: (decode channel ...)" },
|
||||
#endif
|
||||
#endif
|
||||
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
||||
|
@ -363,19 +363,49 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
|
|||
extern char serial_no[9];
|
||||
#endif
|
||||
(void)t;
|
||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||
if (argc > 1) {
|
||||
uint32_t baudrate = atoi(argv[1]);
|
||||
traceswo_init(baudrate);
|
||||
} else {
|
||||
gdb_outf("Missing baudrate parameter in command\n");
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
uint32_t baudrate = SWO_DEFAULT_BAUD;
|
||||
#endif
|
||||
uint32_t swo_channelmask = 0; /* swo decoding off */
|
||||
uint8_t decode_arg = 1;
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
/* argument: optional baud rate for async mode */
|
||||
if ((argc > 1) && (*argv[1] >= '0') && (*argv[1] <= '9')) {
|
||||
baudrate = atoi(argv[1]);
|
||||
if (baudrate == 0) baudrate = SWO_DEFAULT_BAUD;
|
||||
decode_arg = 2;
|
||||
}
|
||||
#endif
|
||||
/* argument: 'decode' literal */
|
||||
if((argc > decode_arg) && !strncmp(argv[decode_arg], "decode", strlen(argv[decode_arg]))) {
|
||||
swo_channelmask = 0xFFFFFFFF; /* decoding all channels */
|
||||
/* arguments: channels to decode */
|
||||
if (argc > decode_arg + 1) {
|
||||
swo_channelmask = 0x0;
|
||||
for (int i = decode_arg+1; i < argc; i++) { /* create bitmask of channels to decode */
|
||||
int channel = atoi(argv[i]);
|
||||
if ((channel >= 0) && (channel <= 31))
|
||||
swo_channelmask |= (uint32_t)0x1 << channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED) && defined(ENABLE_DEBUG)
|
||||
if (debug_bmp) {
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
gdb_outf("baudrate: %lu ", baudrate);
|
||||
#endif
|
||||
gdb_outf("channel mask: ");
|
||||
for (int8_t i=31;i>=0;i--) {
|
||||
uint8_t bit = (swo_channelmask >> i) & 0x1;
|
||||
gdb_outf("%u", bit);
|
||||
}
|
||||
gdb_outf("\n");
|
||||
}
|
||||
#endif
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
traceswo_init(baudrate, swo_channelmask);
|
||||
#else
|
||||
(void)argv;
|
||||
traceswo_init();
|
||||
if (argc > 1) {
|
||||
gdb_outf("Superfluous parameter(s) ignored\n");
|
||||
}
|
||||
traceswo_init(swo_channelmask);
|
||||
#endif
|
||||
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
|
||||
return true;
|
||||
|
|
|
@ -23,11 +23,20 @@
|
|||
#include <libopencm3/usb/usbd.h>
|
||||
|
||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||
void traceswo_init(uint32_t baudrate);
|
||||
/* Default line rate, used as default for a request without baudrate */
|
||||
#define SWO_DEFAULT_BAUD (2250000)
|
||||
void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask);
|
||||
#else
|
||||
void traceswo_init(void);
|
||||
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
|
||||
|
|
|
@ -16,6 +16,7 @@ LDFLAGS = -lopencm3_stm32f4 \
|
|||
VPATH += platforms/stm32
|
||||
|
||||
SRC += cdcacm.c \
|
||||
traceswodecode.c \
|
||||
traceswo.c \
|
||||
usbuart.c \
|
||||
serialno.c \
|
||||
|
|
|
@ -16,6 +16,7 @@ LDFLAGS = -lopencm3_stm32f4 \
|
|||
VPATH += platforms/stm32
|
||||
|
||||
SRC += cdcacm.c \
|
||||
traceswodecode.c \
|
||||
traceswo.c \
|
||||
usbuart.c \
|
||||
serialno.c \
|
||||
|
|
|
@ -21,6 +21,7 @@ endif
|
|||
VPATH += platforms/stm32
|
||||
|
||||
SRC += cdcacm.c \
|
||||
traceswodecode.c \
|
||||
traceswo.c \
|
||||
usbuart.c \
|
||||
serialno.c \
|
||||
|
|
|
@ -32,6 +32,7 @@ SRC += cdcacm.c \
|
|||
serialno.c \
|
||||
timing.c \
|
||||
timing_stm32.c \
|
||||
traceswodecode.c \
|
||||
traceswoasync.c \
|
||||
stlink_common.c \
|
||||
|
||||
|
|
|
@ -39,7 +39,10 @@
|
|||
#include <libopencm3/stm32/timer.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
||||
void traceswo_init(void)
|
||||
/* SWO decoding */
|
||||
static bool decoding = false;
|
||||
|
||||
void traceswo_init(uint32_t swo_chan_bitmask)
|
||||
{
|
||||
TRACE_TIM_CLK_EN();
|
||||
|
||||
|
@ -73,6 +76,9 @@ void traceswo_init(void)
|
|||
timer_ic_enable(TRACE_TIM, TIM_IC2);
|
||||
|
||||
timer_enable_counter(TRACE_TIM);
|
||||
|
||||
traceswo_setmask(swo_chan_bitmask);
|
||||
decoding = (swo_chan_bitmask != 0);
|
||||
}
|
||||
|
||||
static uint8_t trace_usb_buf[64];
|
||||
|
@ -80,7 +86,9 @@ static uint8_t trace_usb_buf_size;
|
|||
|
||||
void trace_buf_push(uint8_t *buf, int len)
|
||||
{
|
||||
if (usbd_ep_write_packet(usbdev, 0x85, buf, len) != len) {
|
||||
if (decoding)
|
||||
traceswo_decode(usbdev, CDCACM_UART_ENDPOINT, buf, len);
|
||||
else if (usbd_ep_write_packet(usbdev, 0x85, buf, len) != len) {
|
||||
if (trace_usb_buf_size + len > 64) {
|
||||
/* Stall if upstream to too slow. */
|
||||
usbd_ep_stall_set(usbdev, 0x85, 1);
|
||||
|
@ -97,7 +105,10 @@ void trace_buf_drain(usbd_device *dev, uint8_t ep)
|
|||
if (!trace_usb_buf_size)
|
||||
return;
|
||||
|
||||
usbd_ep_write_packet(dev, ep, trace_usb_buf, trace_usb_buf_size);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,6 @@
|
|||
|
||||
/* For speed this is set to the USB transfer size */
|
||||
#define FULL_SWO_PACKET (64)
|
||||
/* Default line rate....used as default for a request without baudrate */
|
||||
#define DEFAULTSPEED (2250000)
|
||||
|
||||
static volatile uint32_t w; /* Packet currently received via UART */
|
||||
static volatile uint32_t r; /* Packet currently waiting to transmit to USB */
|
||||
|
@ -50,6 +48,8 @@ static volatile uint32_t r; /* Packet currently waiting to transmit to USB */
|
|||
static uint8_t trace_rx_buf[NUM_TRACE_PACKETS * FULL_SWO_PACKET];
|
||||
/* Packet pingpong buffer used for receiving packets */
|
||||
static uint8_t pingpong_buf[2 * FULL_SWO_PACKET];
|
||||
/* SWO decoding */
|
||||
static bool decoding = false;
|
||||
|
||||
void trace_buf_drain(usbd_device *dev, uint8_t ep)
|
||||
{
|
||||
|
@ -59,10 +59,20 @@ void trace_buf_drain(usbd_device *dev, uint8_t ep)
|
|||
if (__atomic_test_and_set (&inBufDrain, __ATOMIC_RELAXED))
|
||||
return;
|
||||
/* Attempt to write everything we buffered */
|
||||
if ((w != r) && (usbd_ep_write_packet(dev, ep,
|
||||
if (w != r) {
|
||||
uint16_t rc;
|
||||
if (decoding)
|
||||
/* write decoded swo packets to the uart port */
|
||||
rc = traceswo_decode(dev, CDCACM_UART_ENDPOINT,
|
||||
&trace_rx_buf[r * FULL_SWO_PACKET],
|
||||
FULL_SWO_PACKET)))
|
||||
r =(r + 1) % NUM_TRACE_PACKETS;
|
||||
FULL_SWO_PACKET);
|
||||
else
|
||||
/* write raw swo packets to the trace port */
|
||||
rc = usbd_ep_write_packet(dev, ep,
|
||||
&trace_rx_buf[r * FULL_SWO_PACKET],
|
||||
FULL_SWO_PACKET);
|
||||
if (rc) r = (r + 1) % NUM_TRACE_PACKETS;
|
||||
}
|
||||
__atomic_clear (&inBufDrain, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
|
@ -115,10 +125,10 @@ void SWO_DMA_ISR(void)
|
|||
trace_buf_drain(usbdev, 0x85);
|
||||
}
|
||||
|
||||
void traceswo_init(uint32_t baudrate)
|
||||
void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask)
|
||||
{
|
||||
if (!baudrate)
|
||||
baudrate = DEFAULTSPEED;
|
||||
baudrate = SWO_DEFAULT_BAUD;
|
||||
|
||||
rcc_periph_clock_enable(SWO_UART_CLK);
|
||||
rcc_periph_clock_enable(SWO_DMA_CLK);
|
||||
|
@ -130,4 +140,6 @@ void traceswo_init(uint32_t baudrate)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Print decoded swo stream on the usb serial */
|
||||
|
||||
#include "general.h"
|
||||
#include "cdcacm.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;
|
||||
for (int i = 0; i<len; i++) {
|
||||
uint8_t ch=((uint8_t*)buf)[i];
|
||||
if (swo_pkt_len == 0) { /* header */
|
||||
uint32_t channel = (uint32_t)ch >> 3; /* channel number */
|
||||
uint32_t size = ch & 0x7; /* drop channel number */
|
||||
if (size == 0x01) swo_pkt_len = 1; /* SWO packet 0x01XX */
|
||||
else if (size == 0x02) swo_pkt_len = 2; /* SWO packet 0x02XXXX */
|
||||
else if (size == 0x03) 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 (cdcacm_get_config() && cdcacm_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 */
|
|
@ -25,6 +25,7 @@ SRC += cdcacm.c \
|
|||
serialno.c \
|
||||
timing.c \
|
||||
timing_stm32.c \
|
||||
traceswodecode.c \
|
||||
traceswoasync.c \
|
||||
platform_common.c \
|
||||
|
||||
|
|
Loading…
Reference in New Issue