SWO manchester mode
This commit is contained in:
parent
1b35f7f63c
commit
6d91cabcee
|
@ -140,7 +140,7 @@ This information includes:
|
|||
|
||||
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available.
|
||||
#define SWO_MANCHESTER 1 ///< SWO Manchester: 1 = available, 0 = not available.
|
||||
|
||||
/// SWO Trace Buffer Size.
|
||||
#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n).
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#include <hardware/pio.h>
|
||||
#include <hardware/structs/dma.h>
|
||||
|
||||
#include "uart_rx.pio.h"
|
||||
#include "swo_uart_rx.pio.h"
|
||||
#include "swo_manchester_encoding.pio.h"
|
||||
|
||||
static uint32_t
|
||||
swo_baudrate = 115200,
|
||||
|
@ -24,6 +25,10 @@ static bool mode_enabled = false;
|
|||
uint32_t SWO_Mode_UART(uint32_t enable) {
|
||||
//for(;;);//printf("SWO mode %lu\n", enable);
|
||||
if (enable) {
|
||||
if (mode_enabled) { // already inited!
|
||||
return 0;
|
||||
}
|
||||
|
||||
swo_sm = pio_claim_unused_sm(SWO_PIO, false);
|
||||
if (swo_sm == -1) {
|
||||
//for(;;);//printf("E: no PIO\n");
|
||||
|
@ -38,7 +43,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!pio_can_add_program(SWO_PIO, &uart_rx_program)) {
|
||||
if (!pio_can_add_program(SWO_PIO, &swo_uart_rx_program)) {
|
||||
//for(;;);//printf("E: no prg\n");
|
||||
dma_channel_unclaim(swo_dmach);
|
||||
swo_dmach = -1;
|
||||
|
@ -47,8 +52,9 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
swo_pio_off = pio_add_program(SWO_PIO, &uart_rx_program);
|
||||
uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
|
||||
swo_pio_off = pio_add_program(SWO_PIO, &swo_uart_rx_program);
|
||||
swo_uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
|
||||
gpio_set_function(PINOUT_SWO, GPIO_FUNC_PIO1);
|
||||
|
||||
mode_enabled = true;
|
||||
} else {
|
||||
|
@ -65,7 +71,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
|
|||
swo_sm = -1;
|
||||
}
|
||||
if (~swo_pio_off != 0) {
|
||||
pio_remove_program(SWO_PIO, &uart_rx_program, swo_pio_off);
|
||||
pio_remove_program(SWO_PIO, &swo_uart_rx_program, swo_pio_off);
|
||||
swo_pio_off = ~(uint32_t)0;
|
||||
}
|
||||
|
||||
|
@ -82,9 +88,10 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
|
|||
// return: actual baudrate or 0 when not configured
|
||||
uint32_t SWO_Baudrate_UART(uint32_t baudrate) {
|
||||
//for(;;);//printf("SWO baudrate %lu\n", baudrate);
|
||||
swo_baudrate = baudrate;
|
||||
if (!mode_enabled) return 0;
|
||||
|
||||
uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
|
||||
swo_uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
|
||||
|
||||
return baudrate; // should be ok
|
||||
}
|
||||
|
@ -141,3 +148,121 @@ uint32_t SWO_GetCount_UART(void) {
|
|||
return swo_num - remaining;
|
||||
}
|
||||
|
||||
/*** MANCHESTER **************************************************************/
|
||||
|
||||
uint32_t SWO_Mode_Manchester(uint32_t enable) {
|
||||
//for(;;);//printf("SWOM mode %lu\n", enable);
|
||||
if (enable) {
|
||||
if (mode_enabled) { // already inited!
|
||||
return 0;
|
||||
}
|
||||
|
||||
swo_sm = pio_claim_unused_sm(SWO_PIO, false);
|
||||
if (swo_sm == -1) {
|
||||
//for(;;);//printf("E: no PIO\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
swo_dmach = dma_claim_unused_channel(false);
|
||||
if (swo_dmach == -1) {
|
||||
//for(;;);//printf("E: no DMA\n");
|
||||
pio_sm_unclaim(SWO_PIO, swo_sm);
|
||||
swo_sm = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pio_can_add_program(SWO_PIO, &swo_manchester_rx_program)) {
|
||||
//for(;;);//printf("E: no prg\n");
|
||||
dma_channel_unclaim(swo_dmach);
|
||||
swo_dmach = -1;
|
||||
pio_sm_unclaim(SWO_PIO, swo_sm);
|
||||
swo_sm = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
swo_pio_off = pio_add_program(SWO_PIO, &swo_manchester_rx_program);
|
||||
swo_manchester_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, swo_baudrate);
|
||||
gpio_set_function(PINOUT_SWO, GPIO_FUNC_PIO1);
|
||||
|
||||
mode_enabled = true;
|
||||
} else {
|
||||
mode_enabled = false;
|
||||
|
||||
if (swo_dmach >= 0) {
|
||||
dma_channel_unclaim(swo_dmach); // ugh why is it "dma_channel_xyz" and "dma_xyz_channel"
|
||||
swo_dmach = -1;
|
||||
}
|
||||
|
||||
if (swo_sm >= 0) {
|
||||
pio_sm_set_enabled(SWO_PIO, swo_sm, false);
|
||||
pio_sm_unclaim(SWO_PIO, swo_sm);
|
||||
swo_sm = -1;
|
||||
}
|
||||
if (~swo_pio_off != 0) {
|
||||
pio_remove_program(SWO_PIO, &swo_manchester_rx_program, swo_pio_off);
|
||||
swo_pio_off = ~(uint32_t)0;
|
||||
}
|
||||
|
||||
// hi-Z nothing
|
||||
gpio_set_function(PINOUT_SWO, GPIO_FUNC_NULL);
|
||||
gpio_set_pulls(PINOUT_SWO, false, false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t SWO_Baudrate_Manchester(uint32_t baudrate) {
|
||||
//for(;;);//printf("SWOM baudrate %lu\n", baudrate);
|
||||
swo_baudrate = baudrate;
|
||||
if (!mode_enabled) return 0;
|
||||
|
||||
swo_manchester_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate);
|
||||
|
||||
return baudrate; // should be ok
|
||||
}
|
||||
|
||||
uint32_t SWO_Control_Manchester(uint32_t active) {
|
||||
//for(;;);//printf("SWOM control %lu\n", active);
|
||||
if (!mode_enabled) return 0;
|
||||
|
||||
if (active) {
|
||||
pio_sm_set_enabled(SWO_PIO, swo_sm, true);
|
||||
dma_channel_start(swo_dmach);
|
||||
}
|
||||
else {
|
||||
dma_channel_abort(swo_dmach);
|
||||
pio_sm_set_enabled(SWO_PIO, swo_sm, false);
|
||||
swo_num = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SWO_Capture_Manchester(uint8_t* buf, uint32_t num) {
|
||||
//for(;;);//printf("SWOM capture %p 0x%lx\n", buf, num);
|
||||
if (!mode_enabled) return;
|
||||
|
||||
swo_num = num;
|
||||
|
||||
// set up DMA params
|
||||
dma_channel_config dcfg = dma_channel_get_default_config(swo_dmach);
|
||||
channel_config_set_read_increment(&dcfg, false);
|
||||
channel_config_set_write_increment(&dcfg, true);
|
||||
channel_config_set_dreq(&dcfg, pio_get_dreq(SWO_PIO, swo_sm, false));
|
||||
channel_config_set_transfer_data_size(&dcfg, DMA_SIZE_8);
|
||||
dma_channel_configure(swo_dmach, &dcfg, buf, &SWO_PIO->rxf[swo_sm], num, false);
|
||||
}
|
||||
|
||||
uint32_t SWO_GetCount_Manchester(void) {
|
||||
// DMA hw decreases transfer_count by one on every transfer, so it contains
|
||||
// the number of remaining bytes to be received.
|
||||
// however, CMSIS-DAP wants (badly worded) the number of bytes already
|
||||
// received
|
||||
if (!mode_enabled || swo_num == 0) return 0; // not initialized
|
||||
|
||||
uint32_t remaining = dma_hw->ch[swo_dmach].transfer_count;
|
||||
//for(;;);//printf("SWO getcount -> 0x%lx\n", swo_num - remaining);
|
||||
return swo_num - remaining;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program swo_manchester_tx
|
||||
.side_set 1 opt
|
||||
|
||||
; Transmit one bit every 12 cycles. a '0' is encoded as a high-low sequence
|
||||
; (each part lasting half a bit period, or 6 cycles) and a '1' is encoded as a
|
||||
; low-high sequence.
|
||||
;
|
||||
; Side-set bit 0 must be mapped to the GPIO used for TX.
|
||||
; Autopull must be enabled -- this program does not care about the threshold.
|
||||
; The program starts at the public label 'start'.
|
||||
|
||||
.wrap_target
|
||||
do_1:
|
||||
nop side 0 [5] ; Low for 6 cycles (5 delay, +1 for nop)
|
||||
jmp get_bit side 1 [3] ; High for 4 cycles. 'get_bit' takes another 2 cycles
|
||||
do_0:
|
||||
nop side 1 [5] ; Output high for 6 cycles
|
||||
nop side 0 [3] ; Output low for 4 cycles
|
||||
public start:
|
||||
get_bit:
|
||||
out x, 1 ; Always shift out one bit from OSR to X, so we can
|
||||
jmp !x do_0 ; branch on it. Autopull refills the OSR when empty.
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
static inline void swo_manchester_tx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) {
|
||||
pio_sm_set_pins_with_mask(pio, sm, 0, 1u << pin);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||
pio_gpio_init(pio, pin);
|
||||
|
||||
pio_sm_config c = swo_manchester_tx_program_get_default_config(offset);
|
||||
sm_config_set_sideset_pins(&c, pin);
|
||||
sm_config_set_out_shift(&c, true, true, 32);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
pio_sm_init(pio, sm, offset + swo_manchester_tx_offset_start, &c);
|
||||
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
%}
|
||||
|
||||
.program swo_manchester_rx
|
||||
|
||||
; Assumes line is idle low, first bit is 0
|
||||
; One bit is 12 cycles
|
||||
; a '0' is encoded as 10
|
||||
; a '1' is encoded as 01
|
||||
;
|
||||
; Both the IN base and the JMP pin mapping must be pointed at the GPIO used for RX.
|
||||
; Autopush must be enabled.
|
||||
; Before enabling the SM, it should be placed in a 'wait 1, pin` state, so that
|
||||
; it will not start sampling until the initial line idle state ends.
|
||||
|
||||
start_of_0: ; We are 0.25 bits into a 0 - signal is high
|
||||
wait 0 pin 0 ; Wait for the 1->0 transition - at this point we are 0.5 into the bit
|
||||
in y, 1 [8] ; Emit a 0, sleep 3/4 of a bit
|
||||
jmp pin start_of_0 ; If signal is 1 again, it's another 0 bit, otherwise it's a 1
|
||||
|
||||
.wrap_target
|
||||
start_of_1: ; We are 0.25 bits into a 1 - signal is 1
|
||||
wait 1 pin 0 ; Wait for the 0->1 transition - at this point we are 0.5 into the bit
|
||||
in x, 1 [8] ; Emit a 1, sleep 3/4 of a bit
|
||||
jmp pin start_of_0 ; If signal is 0 again, it's another 1 bit otherwise it's a 0
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
static inline void swo_manchester_rx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
pio_gpio_init(pio, pin);
|
||||
|
||||
pio_sm_config c = swo_manchester_rx_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin); // for WAIT
|
||||
sm_config_set_jmp_pin(&c, pin); // for JMP
|
||||
sm_config_set_in_shift(&c, true, true, 32);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
|
||||
// X and Y are set to 0 and 1, to conveniently emit these to ISR/FIFO.
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 1));
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
|
||||
// Assume line is idle low, and first transmitted bit is 0. Put SM in a
|
||||
// wait state before enabling. RX will begin once the first 0 symbol is
|
||||
// detected.
|
||||
pio_sm_exec(pio, sm, pio_encode_wait_pin(1, 0) | pio_encode_delay(2));
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
%}
|
|
@ -4,7 +4,7 @@
|
|||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program uart_rx_mini
|
||||
.program swo_uart_rx_mini
|
||||
|
||||
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
|
||||
; with the correct timing.
|
||||
|
@ -21,12 +21,12 @@ bitloop: ; Loop 8 times
|
|||
#include "hardware/clocks.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
static inline void swo_uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
pio_gpio_init(pio, pin);
|
||||
gpio_pull_up(pin);
|
||||
|
||||
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
|
||||
pio_sm_config c = swo_uart_rx_mini_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||
// Shift to right, autopush enabled
|
||||
sm_config_set_in_shift(&c, true, true, 8);
|
||||
|
@ -40,7 +40,7 @@ static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint
|
|||
}
|
||||
%}
|
||||
|
||||
.program uart_rx
|
||||
.program swo_uart_rx
|
||||
|
||||
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
|
||||
; break conditions more gracefully.
|
||||
|
@ -63,12 +63,12 @@ good_stop: ; No delay before returning to start; a little slack is
|
|||
|
||||
|
||||
% c-sdk {
|
||||
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
static inline void swo_uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
pio_gpio_init(pio, pin);
|
||||
gpio_pull_up(pin);
|
||||
|
||||
pio_sm_config c = uart_rx_program_get_default_config(offset);
|
||||
pio_sm_config c = swo_uart_rx_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||
sm_config_set_jmp_pin(&c, pin); // for JMP
|
||||
// Shift to right, autopull disabled
|
||||
|
@ -83,7 +83,7 @@ static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin,
|
|||
//pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
static inline char uart_rx_program_getc(PIO pio, uint sm) {
|
||||
static inline char swo_uart_rx_program_getc(PIO pio, uint sm) {
|
||||
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
|
||||
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
|
||||
while (pio_sm_is_rx_fifo_empty(pio, sm))
|
Loading…
Reference in New Issue