probe: split pioasm and setup code into variant files, and add OEN variant
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c4ca75..f4b8a67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -36,6 +36,7 @@ target_compile_options(picoprobe PRIVATE -Wall) pico_generate_pio_header(picoprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe.pio) +pico_generate_pio_header(picoprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe_oen.pio) target_include_directories(picoprobe PRIVATE src)
diff --git a/README.md b/README.md index 606f874..c938a95 100644 --- a/README.md +++ b/README.md
@@ -3,3 +3,9 @@ # Documentation Picoprobe documentation can be found in the [Pico Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf). See "Appendix A: Using Picoprobe". + +# TODO +- TinyUSB's vendor interface is FIFO-based and not packet-based. Using raw tx/rx callbacks is preferable as this stops DAP command batches from being concatenated, which confused openOCD. +- Instead of polling, move the DAP thread to an asynchronously started/stopped one-shot operation to reduce CPU wakeups +- AutoBaud selection, as PIO is a capable frequency counter +- Possibly include RTT support
diff --git a/src/probe.c b/src/probe.c index de8832d..825320d 100644 --- a/src/probe.c +++ b/src/probe.c
@@ -111,49 +111,13 @@ while(pio_sm_get_pc(pio0, PROBE_SM) != probe.offset + probe_offset_out_idle); } -void probe_gpio_init() -{ -#if defined(PROBE_PIN_RESET) - // Target reset pin: pull up, input to emulate open drain pin - gpio_pull_up(PROBE_PIN_RESET); - // gpio_init will leave the pin cleared and set as input - gpio_init(PROBE_PIN_RESET); -#endif - // Funcsel pins - pio_gpio_init(pio0, PROBE_PIN_SWCLK); - pio_gpio_init(pio0, PROBE_PIN_SWDIO); - // Make sure SWDIO has a pullup on it. Idle state is high - gpio_pull_up(PROBE_PIN_SWDIO); -} - void probe_init() { if (!probe.initted) { uint offset = pio_add_program(pio0, &probe_program); probe.offset = offset; pio_sm_config sm_config = probe_program_get_default_config(offset); - - // Set SWCLK as a sideset pin - sm_config_set_sideset_pins(&sm_config, PROBE_PIN_SWCLK); - - // Set SWDIO offset - sm_config_set_out_pins(&sm_config, PROBE_PIN_SWDIO, 1); - sm_config_set_set_pins(&sm_config, PROBE_PIN_SWDIO, 1); -#ifdef PROBE_PIN_SWDI - sm_config_set_in_pins(&sm_config, PROBE_PIN_SWDI); -#else - sm_config_set_in_pins(&sm_config, PROBE_PIN_SWDIO); -#endif - - // Set SWD and SWDIO pins as output to start. This will be set in the sm - pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 2, true); - - // shift output right, autopull off, autopull threshold - sm_config_set_out_shift(&sm_config, true, false, 0); - // shift input right as swd data is lsb first, autopush off - sm_config_set_in_shift(&sm_config, true, false, 0); - - // Init SM with config + probe_sm_init(&sm_config); pio_sm_init(pio0, PROBE_SM, offset, &sm_config); // Set up divisor
diff --git a/src/probe.h b/src/probe.h index d9d9e55..a76f5c9 100644 --- a/src/probe.h +++ b/src/probe.h
@@ -26,6 +26,14 @@ #ifndef PROBE_H_ #define PROBE_H_ +#if defined(PROBE_IO_RAW) || defined(PROBE_IO_SWDI) +#include "probe.pio.h" +#endif + +#if defined(PROBE_IO_OEN) +#include "probe_oen.pio.h" +#endif + void probe_set_swclk_freq(uint freq_khz); void probe_write_bits(uint bit_count, uint32_t data_byte); uint32_t probe_read_bits(uint bit_count); @@ -33,7 +41,6 @@ void probe_read_mode(void); void probe_write_mode(void); -void probe_gpio_init(void); void probe_init(void); void probe_deinit(void);
diff --git a/src/probe.pio b/src/probe.pio index e8e8683..934d353 100644 --- a/src/probe.pio +++ b/src/probe.pio
@@ -49,3 +49,47 @@ jmp x-- in_posedge_bitloop side 0x0 ; push ; Push to rx fifo when done jmp in_posedge ; Jump back to start + +; Implement probe_gpio_init() and probe_sm_init() methods here - set pins, offsets, sidesets etc +% c-sdk { + +static inline void probe_gpio_init() +{ +#if defined(PROBE_PIN_RESET) + // Target reset pin: pull up, input to emulate open drain pin + gpio_pull_up(PROBE_PIN_RESET); + // gpio_init will leave the pin cleared and set as input + gpio_init(PROBE_PIN_RESET); +#endif + // Funcsel pins + pio_gpio_init(pio0, PROBE_PIN_SWCLK); + pio_gpio_init(pio0, PROBE_PIN_SWDIO); + // Make sure SWDIO has a pullup on it. Idle state is high + gpio_pull_up(PROBE_PIN_SWDIO); +} + +static inline void probe_sm_init(pio_sm_config* sm_config) { + + // Set SWCLK as a sideset pin + sm_config_set_sideset_pins(sm_config, PROBE_PIN_SWCLK); + + // Set SWDIO offset + sm_config_set_out_pins(sm_config, PROBE_PIN_SWDIO, 1); + sm_config_set_set_pins(sm_config, PROBE_PIN_SWDIO, 1); +#ifdef PROBE_IO_SWDI + sm_config_set_in_pins(sm_config, PROBE_PIN_SWDI); +#else + sm_config_set_in_pins(sm_config, PROBE_PIN_SWDIO); +#endif + + + // Set SWD and SWDIO pins as output to start. This will be set in the sm + pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 2, true); + + // shift output right, autopull off, autopull threshold + sm_config_set_out_shift(sm_config, true, false, 0); + // shift input right as swd data is lsb first, autopush off + sm_config_set_in_shift(sm_config, true, false, 0); +} + +%}
diff --git a/src/probe_oen.pio b/src/probe_oen.pio new file mode 100644 index 0000000..ad2dbb5 --- /dev/null +++ b/src/probe_oen.pio
@@ -0,0 +1,73 @@ +; Output-enable active-low variant of the SWD probe + +.program probe +.side_set 2 opt + +; SWDIO_OEN is pin 0, SWCLK pin 1, SWDIO (out) pin 2, SWDI (in) pin 3. +; Pin 0 and 1 are sideset pins +public out_negedge: + set pindirs, 0x1 side 0x0 ; OE_N 0, data high, clock 0 +public out_idle: + pull ; pull nbits - 1 + mov x, osr + pull ; pull data +public out_negedge_bitloop: + out pins, 1 side 0x0 + jmp x-- out_negedge_bitloop side 0x2 ; OE_N 0, clock high + set pins, 1 side 0x0 ; drive data high (idle bus state) + push ; Push to rx fifo just so processor knows when done + jmp out_negedge ; Wait for next transaction + +public in_posedge: + set pindirs, 0x0 side 0x1 ; OE_N 1, data high, clock 0 +public in_idle: + pull + mov x, osr +in_posedge_bitloop: + in pins, 1 side 0x1 ; OE_N 1, clock 0 + jmp x-- in_posedge_bitloop side 0x3 ; OE_N 1, clock 1 + push + jmp in_posedge + + +; Implement probe_gpio_init() and probe_sm_init() methods here - set pins, offsets, sidesets etc +% c-sdk { + +void probe_gpio_init() +{ +#if defined(PROBE_PIN_RESET) + // Target reset pin: pull up, input to emulate open drain pin + gpio_pull_up(PROBE_PIN_RESET); + // gpio_init will leave the pin cleared and set as input + gpio_init(PROBE_PIN_RESET); +#endif + // Funcsel pins + pio_gpio_init(pio0, PROBE_PIN_SWDIOEN); + pio_gpio_init(pio0, PROBE_PIN_SWCLK); + pio_gpio_init(pio0, PROBE_PIN_SWDIO); + + // Make sure SWDIO has a pullup on it. Idle state is high + gpio_pull_up(PROBE_PIN_SWDIO); + gpio_pull_up(PROBE_PIN_SWDIOEN); +} + +void probe_sm_init(pio_sm_config* sm_config) { + + // Set SWDIOEN and SWCLK as sideset pins + sm_config_set_sideset_pins(&sm_config, PROBE_PIN_SWDIOEN); + + // Set SWDIO offset + sm_config_set_out_pins(sm_config, PROBE_PIN_SWDIO, 1); + sm_config_set_set_pins(sm_config, PROBE_PIN_SWDIO, 1); + sm_config_set_in_pins(sm_config, PROBE_PIN_SWDI); + + // Set SWDIOEN, SWD and SWDIO pins as output to start. This will be set in the sm + pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 3, true); + + // shift output right, autopull off, autopull threshold + sm_config_set_out_shift(sm_config, true, false, 0); + // shift input right as swd data is lsb first, autopush off + sm_config_set_in_shift(sm_config, true, false, 0); +} + +%} \ No newline at end of file