swd-pio.h (2957B)
1 /** 2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 // based on picoprobe's probe.c 8 9 //#include <pico/stdlib.h> 10 //#include <stdio.h> 11 //#include <string.h> 12 13 #include <hardware/clocks.h> 14 #include <hardware/gpio.h> 15 16 #include "swd-io.pio.h" 17 18 #define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n)) 19 20 #define SWDIO_SM 0 21 #define PIN_OFFSET 2 22 #define PIN_SWCLK (PIN_OFFSET + 0) 23 #define PIN_SWDIO (PIN_OFFSET + 1) 24 25 static uint32_t swdio_offset; 26 27 unsigned swdio_set_freq(unsigned freq_khz) { 28 uint clk_sys_freq_khz = clock_get_hz(clk_sys) / 1000; 29 // Worked out with saleae 30 uint32_t divider = clk_sys_freq_khz / freq_khz / 2; 31 pio_sm_set_clkdiv_int_frac(pio0, SWDIO_SM, divider, 0); 32 return clk_sys_freq_khz / divider / 2; 33 } 34 35 static inline void swdio_write_bits(uint32_t data, unsigned bit_count) { 36 pio_sm_put_blocking(pio0, SWDIO_SM, bit_count - 1); 37 pio_sm_put_blocking(pio0, SWDIO_SM, data); 38 // Wait for pio to push garbage to rx fifo so we know it has finished sending 39 pio_sm_get_blocking(pio0, SWDIO_SM); 40 } 41 42 static inline uint32_t swdio_read_bits(unsigned bit_count) { 43 pio_sm_put_blocking(pio0, SWDIO_SM, bit_count - 1); 44 uint32_t data = pio_sm_get_blocking(pio0, SWDIO_SM); 45 if (bit_count < 32) { 46 data >>= (32 - bit_count); 47 } 48 return data; 49 } 50 51 static void swdio_read_mode(void) { 52 pio_sm_exec(pio0, SWDIO_SM, pio_encode_jmp(swdio_offset + swdio_offset_in_posedge)); 53 while(pio0->dbg_padoe & (1 << PIN_SWDIO)); 54 } 55 56 static void swdio_write_mode(void) { 57 pio_sm_exec(pio0, SWDIO_SM, pio_encode_jmp(swdio_offset + swdio_offset_out_negedge)); 58 while(!(pio0->dbg_padoe & (1 << PIN_SWDIO))); 59 } 60 61 void swdio_init() { 62 // Funcsel pins 63 pio_gpio_init(pio0, PIN_SWCLK); 64 pio_gpio_init(pio0, PIN_SWDIO); 65 66 // Make sure SWDIO has a pullup on it. Idle state is high 67 gpio_pull_up(PIN_SWDIO); 68 69 swdio_offset = pio_add_program(pio0, &swdio_program); 70 71 pio_sm_config sm_config = swdio_program_get_default_config(swdio_offset); 72 73 // Set SWCLK as a sideset pin 74 sm_config_set_sideset_pins(&sm_config, PIN_SWCLK); 75 76 // Set SWDIO offset 77 sm_config_set_out_pins(&sm_config, PIN_SWDIO, 1); 78 sm_config_set_set_pins(&sm_config, PIN_SWDIO, 1); 79 sm_config_set_in_pins(&sm_config, PIN_SWDIO); 80 81 // Set SWD and SWDIO pins as output to start. This will be set in the sm 82 pio_sm_set_consecutive_pindirs(pio0, SWDIO_SM, PIN_OFFSET, 2, true); 83 84 // shift output right, autopull off, autopull threshold 85 sm_config_set_out_shift(&sm_config, true, false, 0); 86 // shift input right as swd data is lsb first, autopush off 87 sm_config_set_in_shift(&sm_config, true, false, 0); 88 89 // Init SM with config 90 pio_sm_init(pio0, SWDIO_SM, swdio_offset, &sm_config); 91 92 // Set up divisor 93 swdio_set_freq(4000); 94 95 // Enable SM 96 pio_sm_set_enabled(pio0, SWDIO_SM, 1); 97 98 // Jump to write program 99 swdio_write_mode(); 100 }