pico-mdebug

mdebug firmware for pico / rp2040
git clone http://frotz.net/git/pico-mdebug.git
Log | Files | Refs | README

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 }