swd: provide function to set SWCLK/SWDIO pin

This commit is contained in:
King Kévin 2021-03-10 18:26:13 +01:00
parent 6b3b55839e
commit 0010c5e046
2 changed files with 101 additions and 13 deletions

106
lib/swd.c
View File

@ -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)

View File

@ -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 */