From ce5710c041d3ee078f48cfb9626aa1c973897b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Wed, 10 Mar 2021 18:26:13 +0100 Subject: [PATCH] swd: provide function to set SWCLK/SWDIO pin --- lib/swd.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++------- lib/swd.h | 8 +++++ 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/lib/swd.c b/lib/swd.c index da78f74..8d4ac63 100644 --- a/lib/swd.c +++ b/lib/swd.c @@ -52,16 +52,9 @@ static volatile uint8_t swd_bits_i = 0; /** transaction bit index */ void swd_setup(uint32_t freq) { - // setup GPIO for clock and data signals - rcc_periph_clock_enable(swd_swclk_rcc); // enable clock for GPIO peripheral for clock signal - gpio_set(swd_swclk_port, swd_swclk_pin); // inactive clock is high - gpio_mode_setup(swd_swclk_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, swd_swclk_pin); // the host controls the clock - gpio_set_output_options(swd_swclk_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, swd_swclk_pin); // set SWCLK pin output as push-pull - rcc_periph_clock_enable(swd_swdio_rcc); // enable clock for GPIO peripheral for data signal - gpio_set(swd_swdio_port, swd_swdio_pin); // inactive data is high (resetting the target when clock is active) - gpio_mode_setup(swd_swdio_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, swd_swdio_pin); // the data signal is half duplex, with the host controlling who is driving the data signal when - gpio_set_output_options(swd_swdio_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, swd_swdio_pin); // set SWDIO pin output as push-pull - + // setup GPIO + swd_set_pins(swd_swclk_port, swd_swclk_pin, swd_swdio_port, swd_swdio_pin); + // setup timer to generate periodic clock rcc_periph_clock_enable(RCC_TIM(SWD_TIMER)); // enable clock for timer peripheral rcc_periph_reset_pulse(RST_TIM(SWD_TIMER)); // reset timer state @@ -84,6 +77,14 @@ void swd_setup(uint32_t freq) swd_bits_count = 0; } +/** release used pins */ +static void swd_release_pins(void) +{ + // release GPIO + gpio_mode_setup(swd_swclk_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, swd_swclk_pin); // put clock signal pin back to input floating + gpio_mode_setup(swd_swdio_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, swd_swdio_pin); // put data signal pin back to input floating +} + void swd_release(void) { // release timer @@ -91,9 +92,88 @@ void swd_release(void) rcc_periph_reset_pulse(RST_TIM(SWD_TIMER)); // reset timer state rcc_periph_clock_disable(RCC_TIM(SWD_TIMER)); // disable clock for timer peripheral - // release GPIO - gpio_mode_setup(swd_swclk_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, swd_swclk_pin); // put clock signal pin back to input floating - gpio_mode_setup(swd_swdio_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, swd_swdio_pin); // put data signal pin back to input floating + swd_release_pins(); // release GPIO +} + +bool swd_set_pins(uint32_t swclk_port, uint32_t swclk_pin, uint32_t swdio_port, uint32_t swdio_pin) +{ + if (swclk_pin > (1 << 15) || swdio_pin > (1 << 15) || __builtin_popcount(swclk_pin) != 1 || __builtin_popcount(swdio_pin) != 1) { // check if pin exists and is unique + return false; + } + uint32_t swclk_rcc = 0; + switch (swclk_port) { + case GPIOA: + swclk_rcc = RCC_GPIOA; + break; + case GPIOB: + swclk_rcc = RCC_GPIOB; + break; + case GPIOC: + swclk_rcc = RCC_GPIOC; + break; + case GPIOD: + swclk_rcc = RCC_GPIOD; + break; + case GPIOE: + swclk_rcc = RCC_GPIOE; + break; + case GPIOF: + swclk_rcc = RCC_GPIOF; + break; + case GPIOG: + swclk_rcc = RCC_GPIOG; + break; + default: // unknown port + return false; + } + uint32_t swdio_rcc = 0; + switch (swdio_port) { + case GPIOA: + swdio_rcc = RCC_GPIOA; + break; + case GPIOB: + swdio_rcc = RCC_GPIOB; + break; + case GPIOC: + swdio_rcc = RCC_GPIOC; + break; + case GPIOD: + swdio_rcc = RCC_GPIOD; + break; + case GPIOE: + swdio_rcc = RCC_GPIOE; + break; + case GPIOF: + swdio_rcc = RCC_GPIOF; + break; + case GPIOG: + swdio_rcc = RCC_GPIOG; + break; + default: // unknown port + return false; + } + + swd_release_pins(); // release already set pins (not a problem even if not already used + + // remember pins + swd_swclk_rcc = swclk_rcc; + swd_swclk_port = swclk_port; + swd_swclk_pin = swclk_pin; + swd_swdio_rcc = swdio_rcc; + swd_swdio_port = swdio_port; + swd_swdio_pin = swdio_pin; + + // setup GPIO for clock and data signals + rcc_periph_clock_enable(swd_swclk_rcc); // enable clock for GPIO peripheral for clock signal + gpio_set(swd_swclk_port, swd_swclk_pin); // inactive clock is high + gpio_mode_setup(swd_swclk_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, swd_swclk_pin); // the host controls the clock + gpio_set_output_options(swd_swclk_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, swd_swclk_pin); // set SWCLK pin output as push-pull + rcc_periph_clock_enable(swd_swdio_rcc); // enable clock for GPIO peripheral for data signal + gpio_set(swd_swdio_port, swd_swdio_pin); // inactive data is high (resetting the target when clock is active) + gpio_mode_setup(swd_swdio_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, swd_swdio_pin); // the data signal is half duplex, with the host controlling who is driving the data signal when + gpio_set_output_options(swd_swdio_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, swd_swdio_pin); // set SWDIO pin output as push-pull + + return true; } /** perform SWD transaction (one sequence of bits read or write) diff --git a/lib/swd.h b/lib/swd.h index c08eada..57bae6b 100644 --- a/lib/swd.h +++ b/lib/swd.h @@ -90,6 +90,14 @@ void swd_setup(uint32_t freq); /** release 1-wire peripheral */ void swd_release(void); +/** set SWCLK and SWDIO pins + * @param[in] swclk_port port for SWCLK pin + * @param[in] swclk_pin pin for SWCLK pin + * @param[in] swclk_port port for SWDIO pin + * @param[in] swclk_pin pin for SWDIO pin + * @return true if operation succeeded, false if pin is unknown + */ +bool swd_set_pins(uint32_t swclk_port, uint32_t swclk_pin, uint32_t swdio_port, uint32_t swdio_pin); /* DPv1/SWDv1 operations */