From 4a0c462ec33b10177baa03a40f3be1e258b9623b Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 17 Mar 2023 14:34:44 +0100 Subject: [PATCH 1/2] cpu/stm32: Implement gpio_ll for STM32F1 This provides basic GPIO LL support. IRQ support will be added as follow up. --- cpu/stm32/Makefile.features | 2 +- cpu/stm32/include/gpio_ll_arch.h | 7 + cpu/stm32/include/periph/cpu_gpio_ll.h | 20 +- cpu/stm32/include/periph/f1/periph_cpu.h | 44 +++ cpu/stm32/kconfigs/f1/Kconfig | 1 + cpu/stm32/periph/gpio_ll.c | 325 +++++++++++++++++------ cpu/stm32/periph/gpio_ll_irq.c | 62 +++-- 7 files changed, 359 insertions(+), 102 deletions(-) diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index 3f96dc100a..9926be2af5 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -11,9 +11,9 @@ FEATURES_PROVIDED += periph_timer_periodic FEATURES_PROVIDED += periph_rtt_overflow FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_uart_nonblocking +FEATURES_PROVIDED += periph_gpio_ll ifneq ($(CPU_FAM),f1) - FEATURES_PROVIDED += periph_gpio_ll FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low diff --git a/cpu/stm32/include/gpio_ll_arch.h b/cpu/stm32/include/gpio_ll_arch.h index 96b6d1f68b..87e0c9d753 100644 --- a/cpu/stm32/include/gpio_ll_arch.h +++ b/cpu/stm32/include/gpio_ll_arch.h @@ -71,7 +71,14 @@ static inline void gpio_ll_set(gpio_port_t port, uword_t mask) static inline void gpio_ll_clear(gpio_port_t port, uword_t mask) { GPIO_TypeDef *p = (GPIO_TypeDef *)port; + /* The STM32F4 vendor header files do include defines for accessing the + * BRR register, but do not have a BRR register. + * See https://github.com/STMicroelectronics/cmsis_device_f4/pull/7 */ +#if defined(GPIO_BRR_BR0) && !defined(CPU_FAM_STM32F4) + p->BRR = mask; +#else p->BSRR = mask << 16; +#endif } static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask) diff --git a/cpu/stm32/include/periph/cpu_gpio_ll.h b/cpu/stm32/include/periph/cpu_gpio_ll.h index e3cd0e78e6..5ae238ab24 100644 --- a/cpu/stm32/include/periph/cpu_gpio_ll.h +++ b/cpu/stm32/include/periph/cpu_gpio_ll.h @@ -20,7 +20,7 @@ #define PERIPH_CPU_GPIO_LL_H #include -#include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { @@ -46,6 +46,24 @@ typedef enum { GPIO_DRIVE_STRONGEST = 0 } gpio_drive_strength_t; +#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \ + || defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0) +/* Modern STM32 GPIO config registers with the OSPEEDR register support full + * 4 slew rates, legacy STM32F1 style only have three slew rates. We define + * slow and fast to the same value, so that we have three options: + * 1. SLOWEST: 2 MHZ + * 2. SLOW: 10 MHZ + * 3. FAST/FASTEST: 50 MHz + */ +#define HAVE_GPIO_SLEW_T +typedef enum { + GPIO_SLEW_SLOWEST = 0, + GPIO_SLEW_SLOW = 1, + GPIO_SLEW_FAST = 2, + GPIO_SLEW_FASTEST = 2, +} gpio_slew_t; +#endif + #define HAVE_GPIO_IRQ_TRIG_T /* * Layout: diff --git a/cpu/stm32/include/periph/f1/periph_cpu.h b/cpu/stm32/include/periph/f1/periph_cpu.h index e8e0654837..3225c29030 100644 --- a/cpu/stm32/include/periph/f1/periph_cpu.h +++ b/cpu/stm32/include/periph/f1/periph_cpu.h @@ -19,6 +19,8 @@ #ifndef PERIPH_F1_PERIPH_CPU_H #define PERIPH_F1_PERIPH_CPU_H +#include "cpu_conf.h" + #ifdef __cplusplus extern "C" { #endif @@ -63,6 +65,48 @@ extern "C" { */ #define ADC_DEVS (2U) +/** + * @name GPIO Definitions Missing in Vendor Files + * @{ + */ +/** + * @brief Possible values of the MODE0 field in the GPIO CRL register + * + * The MODE1 to MODE7 fields have the same values. Don't forget to shift the + * constants to the field position for MODE1 to MODE7 by 4 times n bits, where + * n is the pin number. + * + * In addition the MODE8 to MODE15 fields in the CRH register have the same + * layout and semantics as the MODE0 to MODE 7 fields in the CRL register. + */ +enum { + GPIO_CRL_MODE0_INPUT = (0x0 << GPIO_CRL_MODE0_Pos), + GPIO_CRL_MODE0_OUTPUT_10MHZ = (0x1 << GPIO_CRL_MODE0_Pos), + GPIO_CRL_MODE0_OUTPUT_2MHZ = (0x2 << GPIO_CRL_MODE0_Pos), + GPIO_CRL_MODE0_OUTPUT_50MHZ = (0x3 << GPIO_CRL_MODE0_Pos), +}; + +/** + * @brief Possible values of the CNF0 field in the GPIO CRL register + * + * The CNF1 to CNF7 fields have the same values. Don't forget to shift the + * constants to the field position for CNF1 to CNF7 by 4 times n bits, where + * n is the pin number. + * + * In addition the CNF8 to CNF15 fields in the CRH register have the same + * layout and semantics as the CNF0 to CNF 7 fields in the CRL register. + */ +enum { + GPIO_CRL_CNF0_INPUT_ANALOG = (0x0 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_INPUT_FLOATING = (0x1 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_INPUT_PULL = (0x2 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_OUTPUT_PUSH_PULL = (0x0 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_OUTPUT_OPEN_DRAIN = (0x1 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_AF_PUSH_PULL = (0x2 << GPIO_CRL_CNF0_Pos), + GPIO_CRL_CNF0_AF_OPEN_DRAIN = (0x3 << GPIO_CRL_CNF0_Pos), +}; +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/stm32/kconfigs/f1/Kconfig b/cpu/stm32/kconfigs/f1/Kconfig index 37cf169c1b..5028b2bc02 100644 --- a/cpu/stm32/kconfigs/f1/Kconfig +++ b/cpu/stm32/kconfigs/f1/Kconfig @@ -16,6 +16,7 @@ config CPU_FAM_F1 select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_FLASHPAGE_RAW + select HAS_PERIPH_GPIO_LL select HAS_PERIPH_RTT_SET_COUNTER select HAS_PERIPH_WDT select HAVE_SHARED_PERIPH_RTT_PERIPH_RTC diff --git a/cpu/stm32/periph/gpio_ll.c b/cpu/stm32/periph/gpio_ll.c index 25543ef10c..ae0358e6bb 100644 --- a/cpu/stm32/periph/gpio_ll.c +++ b/cpu/stm32/periph/gpio_ll.c @@ -35,32 +35,42 @@ #include "bitarithm.h" #include "periph/gpio_ll.h" -#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1) +#ifdef RCC_AHBENR_GPIOAEN # define GPIO_BUS AHB # define GPIOAEN RCC_AHBENR_GPIOAEN -#elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32G0) -# define GPIO_BUS IOP -# define GPIOAEN RCC_IOPENR_GPIOAEN -#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) || \ - defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32WL) -#define GPIO_BUS AHB2 -# if defined(CPU_FAM_STM32U5) -# define GPIOAEN RCC_AHB2ENR1_GPIOAEN -# else -# define GPIOAEN RCC_AHB2ENR_GPIOAEN -# endif -# ifdef PWR_CR2_IOSV -# define PORTG_REQUIRES_EXTERNAL_POWER -# endif -#elif defined(CPU_FAM_STM32MP1) -# define GPIO_BUS AHB4 -# define GPIOAEN RCC_MC_AHB4ENSETR_GPIOAEN -#else +#endif + +#ifdef RCC_AHB1ENR_GPIOAEN # define GPIO_BUS AHB1 # define GPIOAEN RCC_AHB1ENR_GPIOAEN #endif +#ifdef RCC_AHB2ENR1_GPIOAEN +# define GPIO_BUS AHB2 +# define GPIOAEN RCC_AHB2ENR1_GPIOAEN +#endif + +#ifdef RCC_AHB2ENR_GPIOAEN +# define GPIO_BUS AHB2 +# define GPIOAEN RCC_AHB2ENR_GPIOAEN +#endif + +#ifdef RCC_MC_AHB4ENSETR_GPIOAEN +# define GPIO_BUS AHB4 +# define GPIOAEN RCC_MC_AHB4ENSETR_GPIOAEN +#endif + +#ifdef RCC_IOPENR_GPIOAEN +# define GPIO_BUS IOP +# define GPIOAEN RCC_IOPENR_GPIOAEN +#endif + +#ifdef RCC_APB2ENR_IOPAEN +# define GPIO_BUS APB2 +# define GPIOAEN RCC_APB2ENR_IOPAEN +#endif + + static void _init_clock(gpio_port_t port) { periph_clk_en(GPIO_BUS, (GPIOAEN << GPIO_PORT_NUM(port))); @@ -73,6 +83,7 @@ static void _init_clock(gpio_port_t port) #endif } +#if defined(GPIO_MODER_MODER0) || defined(GPIO_MODER_MODE0) static void _set_dir(gpio_port_t port, uint8_t pin, bool output) { GPIO_TypeDef *p = (void *)port; @@ -83,63 +94,10 @@ static void _set_dir(gpio_port_t port, uint8_t pin, bool output) } p->MODER = tmp; } +#endif -static void _set_output_type(gpio_port_t port, uint8_t pin, bool open_drain) -{ - GPIO_TypeDef *p = (void *)port; - if (open_drain) { - p->OTYPER |= 1UL << pin; - } - else { - p->OTYPER &= ~(1UL << pin); - } -} - -static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull) -{ - GPIO_TypeDef *p = (void *)port; - /* being more verbose here so that compiler doesn't generate two loads and stores when accessing - * volatile variable */ - uint32_t pupdr = p->PUPDR; - pupdr &= ~(0x3UL << (2 * pin)); - pupdr |= (uint32_t)pull << (2 * pin); - p->PUPDR = pupdr; -} - -static void _set_slew_rate(gpio_port_t port, uint8_t pin, gpio_slew_t slew_rate) -{ - GPIO_TypeDef *p = (void *)port; - /* being more verbose here so that compiler doesn't generate two loads and - * stores when accessing volatile variable */ - uint32_t ospeedr = p->OSPEEDR; - ospeedr &= ~(3UL << (2 * pin)); - ospeedr |= (uint32_t)slew_rate << (2 * pin); - p->OSPEEDR = ospeedr; -} - -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) -{ - if ((conf->pull == GPIO_PULL_KEEP) || (conf->state == GPIO_OUTPUT_OPEN_SOURCE)) { - return -ENOTSUP; - } - - unsigned state = irq_disable(); - _init_clock(port); - if (conf->initial_value) { - gpio_ll_set(port, 1UL << pin); - } - else { - gpio_ll_clear(port, 1UL << pin); - } - _set_output_type(port, pin, conf->state == GPIO_OUTPUT_OPEN_DRAIN); - _set_pull_config(port, pin, conf->pull); - _set_slew_rate(port, pin, conf->slew_rate); - _set_dir(port, pin, conf->state < GPIO_INPUT); - irq_restore(state); - - return 0; -} - +#if (defined(GPIO_MODER_MODER0) || defined(GPIO_MODER_MODE0)) \ + && (defined(GPIO_OTYPER_OT0) || defined(GPIO_OTYPER_OT_0)) static gpio_state_t _get_state(gpio_port_t port, uint8_t pin) { GPIO_TypeDef *p = (void *)port; @@ -153,6 +111,32 @@ static gpio_state_t _get_state(gpio_port_t port, uint8_t pin) } return GPIO_USED_BY_PERIPHERAL; } +#endif + +#if defined(GPIO_OTYPER_OT0) || defined(GPIO_OTYPER_OT_0) +static void _set_output_type(gpio_port_t port, uint8_t pin, bool open_drain) +{ + GPIO_TypeDef *p = (void *)port; + if (open_drain) { + p->OTYPER |= 1UL << pin; + } + else { + p->OTYPER &= ~(1UL << pin); + } +} +#endif + +#if defined(GPIO_PUPDR_PUPDR0) || defined(GPIO_PUPDR_PUPD0) +static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull) +{ + GPIO_TypeDef *p = (void *)port; + /* being more verbose here so that compiler doesn't generate two loads and stores when accessing + * volatile variable */ + uint32_t pupdr = p->PUPDR; + pupdr &= ~(0x3UL << (2 * pin)); + pupdr |= (uint32_t)pull << (2 * pin); + p->PUPDR = pupdr; +} static gpio_pull_t _get_pull_config(gpio_port_t port, uint8_t pin) { @@ -160,6 +144,20 @@ static gpio_pull_t _get_pull_config(gpio_port_t port, uint8_t pin) uint32_t pupdr = (p->PUPDR >> (2 * pin)) & 0x3UL; return (gpio_pull_t)pupdr; } +#endif + +#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \ + || defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0) +static void _set_slew_rate(gpio_port_t port, uint8_t pin, gpio_slew_t slew_rate) +{ + GPIO_TypeDef *p = (void *)port; + /* being more verbose here so that compiler doesn't generate two loads and + * stores when accessing volatile variable */ + uint32_t ospeedr = p->OSPEEDR; + ospeedr &= ~(3UL << (2 * pin)); + ospeedr |= (uint32_t)slew_rate << (2 * pin); + p->OSPEEDR = ospeedr; +} static gpio_slew_t _get_slew_rate(gpio_port_t port, uint8_t pin) { @@ -167,15 +165,190 @@ static gpio_slew_t _get_slew_rate(gpio_port_t port, uint8_t pin) uint32_t ospeedr = (p->OSPEEDR >> (2 * pin)) & 0x3UL; return (gpio_slew_t)ospeedr; } +#endif + +#ifdef GPIO_CRL_MODE +static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, + const gpio_conf_t *conf) +{ + /* STM32F1 style config register mix output mode and slew rate into the + * same field. This look up table can be used to look up the correct + * output mode by slew rate */ + static const uint8_t output_mode_by_slew_rate[] = { + [GPIO_SLEW_SLOWEST] = GPIO_CRL_MODE0_OUTPUT_2MHZ, + [GPIO_SLEW_FAST] = GPIO_CRL_MODE0_OUTPUT_10MHZ, + [GPIO_SLEW_FASTEST] = GPIO_CRL_MODE0_OUTPUT_50MHZ, + }; + + GPIO_TypeDef *p = (void *)port; + /* There is low control register (CRL) for pins 0-7, and a high control + * register (CRH) for pins 8-15. `offset` is the offset within the + * registers, `high_reg` is true if CRH is to be used */ + unsigned offset = (pin & 0x7U) << 2; + bool high_reg = pin > 7; + uint32_t control = high_reg ? p->CRH : p -> CRL; + + assert((unsigned)conf->slew_rate < ARRAY_SIZE(output_mode_by_slew_rate)); + + /* prepare bis in cnf and mode fields for given pin */ + uint32_t cnf_mode = 0; + switch (conf->state) { + default: + case GPIO_DISCONNECT: + /* Keeping GPIO in analog mode is said to reduce power consumption. + * This is plausible, as the Schmitt trigger and the input buffer could + * be disabled. */ + cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_ANALOG; + break; + case GPIO_INPUT: + switch (conf->pull) { + default: + case GPIO_FLOATING: + cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_FLOATING; + break; + case GPIO_PULL_UP: + cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_PULL; + /* ODR controls pull resistor in input mode. We access ODR via + * BSRR to atomically set the bit (mostly to safe ROM and CPU + * cycles, IRQs are disabled anyway) */ + p->BSRR = 1U << pin; + break; + case GPIO_PULL_DOWN: + cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_PULL; + /* ODR controls pull resistor in input mode. We access ODR via + * BSRR to atomically clear the bit (mostly to safe ROM and CPU + * cycles, IRQs are disabled anyway) */ + p->BSRR = 1U << (pin | 0x10); + } + break; + case GPIO_OUTPUT_PUSH_PULL: + cnf_mode = GPIO_CRL_CNF0_OUTPUT_PUSH_PULL + | output_mode_by_slew_rate[conf->slew_rate]; + break; + case GPIO_OUTPUT_OPEN_DRAIN: + cnf_mode = GPIO_CRL_CNF0_OUTPUT_OPEN_DRAIN + | output_mode_by_slew_rate[conf->slew_rate]; + } + + /* clear old values of cnf and mode fields in config reg */ + control &= ~(0xFU << offset); + /* apply new values of cnf and mode fields in config reg */ + control |= cnf_mode << offset; + + if (high_reg) { + p->CRH = control; + } + else { + p->CRL = control; + } +} +static void _get_legacy_f1_config(gpio_conf_t *dest, gpio_port_t port, + uint8_t pin) +{ + GPIO_TypeDef *p = (void *)port; + unsigned offset = (pin & 0x7U) << 2; + bool high_reg = pin > 7; + uint32_t control = high_reg ? p->CRH : p ->CRL; + uint32_t cnf_mode = control >> offset; + uint32_t cnf = cnf_mode & GPIO_CRL_CNF0_Msk; + uint32_t mode = cnf_mode & GPIO_CRL_MODE0_Msk; + + switch (mode) { + default: + case GPIO_CRL_MODE0_INPUT: + switch (cnf) { + default: + case GPIO_CRL_CNF0_INPUT_ANALOG: + dest->state = GPIO_DISCONNECT; + break; + case GPIO_CRL_CNF0_INPUT_FLOATING: + dest->state = GPIO_INPUT; + break; + case GPIO_CRL_CNF0_INPUT_PULL: + dest->state = GPIO_INPUT; + dest->pull = GPIO_PULL_DOWN; + if (p->ODR & (1U << pin)) { + dest->pull = GPIO_PULL_UP; + } + } + return; + case GPIO_CRL_MODE0_OUTPUT_2MHZ: + dest->slew_rate = GPIO_SLEW_SLOWEST; + break; + case GPIO_CRL_MODE0_OUTPUT_10MHZ: + dest->slew_rate = GPIO_SLEW_FAST; + break; + case GPIO_CRL_MODE0_OUTPUT_50MHZ: + dest->slew_rate = GPIO_SLEW_FASTEST; + break; + } + + switch (cnf) { + case GPIO_CRL_CNF0_OUTPUT_PUSH_PULL: + dest->state = GPIO_OUTPUT_PUSH_PULL; + break; + case GPIO_CRL_CNF0_OUTPUT_OPEN_DRAIN: + dest->state = GPIO_OUTPUT_OPEN_DRAIN; + break; + default: + case GPIO_CRL_CNF0_AF_PUSH_PULL: + case GPIO_CRL_CNF0_AF_OPEN_DRAIN: + dest->state = GPIO_USED_BY_PERIPHERAL; + } +} +#endif + +int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +{ + if ((conf->pull == GPIO_PULL_KEEP) || (conf->state == GPIO_OUTPUT_OPEN_SOURCE)) { + return -ENOTSUP; + } + +#ifndef GPIO_PUPDR_PUPDR0 + /* without dedicated pull up / pull down register, pull resistors can only + * be used with input pins */ + if ((conf->state == GPIO_OUTPUT_OPEN_DRAIN) && (conf->pull != GPIO_FLOATING)) { + return -ENOTSUP; + } +#endif + + unsigned state = irq_disable(); + _init_clock(port); + if (conf->initial_value) { + gpio_ll_set(port, 1UL << pin); + } + else { + gpio_ll_clear(port, 1UL << pin); + } +#ifdef GPIO_CRL_MODE + /* old STM32F1 style GPIO configuration register layout */ + _set_legacy_f1_config(port, pin, conf); +#else + /* modern STM32 style GPIO configuration register layout */ + _set_output_type(port, pin, conf->state == GPIO_OUTPUT_OPEN_DRAIN); + _set_pull_config(port, pin, conf->pull); + _set_slew_rate(port, pin, conf->slew_rate); + _set_dir(port, pin, conf->state < GPIO_INPUT); +#endif + irq_restore(state); + + return 0; +} void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) { assert(dest); unsigned state = irq_disable(); memset(dest, 0, sizeof(*dest)); +#ifdef GPIO_CRL_MODE + /* old STM32F1 style GPIO configuration register layout */ + _get_legacy_f1_config(dest, port, pin); +#else + /* modern STM32 style GPIO configuration register layout */ dest->state = _get_state(port, pin); dest->pull = _get_pull_config(port, pin); dest->slew_rate = _get_slew_rate(port, pin); +#endif if (dest->state == GPIO_INPUT) { dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL; } diff --git a/cpu/stm32/periph/gpio_ll_irq.c b/cpu/stm32/periph/gpio_ll_irq.c index c9eb11129f..39c5eb45e7 100644 --- a/cpu/stm32/periph/gpio_ll_irq.c +++ b/cpu/stm32/periph/gpio_ll_irq.c @@ -40,30 +40,44 @@ #define EXTI_NUMOF (16U) #define EXTI_MASK (0xFFFF) -#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \ - defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32G0) || \ - defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5) || \ - defined(CPU_FAM_STM32WL) -# define EXTI_REG_RTSR (EXTI->RTSR1) -# define EXTI_REG_FTSR (EXTI->FTSR1) -# define EXTI_REG_SWIER (EXTI->SWIER1) -# define EXTI_REG_IMR (EXTI->IMR1) -# if !defined(CPU_FAM_STM32G0) && !defined(CPU_FAM_STM32L5) && \ - !defined(CPU_FAM_STM32U5) && !defined(CPU_FAM_STM32MP1) -# define EXTI_REG_PR (EXTI->PR1) -# endif -#elif defined(CPU_FAM_STM32MP1) -# define EXTI_REG_RTSR (EXTI->RTSR1) -# define EXTI_REG_FTSR (EXTI->FTSR1) -# define EXTI_REG_PR (EXTI->PR1) -# define EXTI_REG_SWIER (EXTI->SWIER1) -# define EXTI_REG_IMR (EXTI_C2->IMR1) -#else -# define EXTI_REG_RTSR (EXTI->RTSR) -# define EXTI_REG_FTSR (EXTI->FTSR) -# define EXTI_REG_PR (EXTI->PR) -# define EXTI_REG_SWIER (EXTI->SWIER) -# define EXTI_REG_IMR (EXTI->IMR) +#if defined(EXTI_SWIER_SWI0) || defined(EXTI_SWIER_SWIER0) +#define EXTI_REG_SWIER (EXTI->SWIER) +#endif + +#if defined(EXTI_SWIER1_SWI0) || defined(EXTI_SWIER1_SWIER0) +#define EXTI_REG_SWIER (EXTI->SWIER1) +#endif + +#if defined(EXTI_RTSR_RT0) || defined(EXTI_RTSR_TR0) +#define EXTI_REG_RTSR (EXTI->RTSR) +#endif + +#if defined(EXTI_RTSR1_RT0) || defined(EXTI_RTSR1_TR0) +#define EXTI_REG_RTSR (EXTI->RTSR1) +#endif + +#if defined(EXTI_FTSR_FT0) || defined(EXTI_FTSR_TR0) +#define EXTI_REG_FTSR (EXTI->FTSR) +#endif + +#if defined(EXTI_FTSR1_FT0) || defined (EXTI_FTSR1_TR0) +#define EXTI_REG_FTSR (EXTI->FTSR1) +#endif + +#ifdef EXTI_PR_PR0 +#define EXTI_REG_PR (EXTI->PR) +#endif + +#ifdef EXTI_PR1_PIF0 +#define EXTI_REG_PR (EXTI->PR1) +#endif + +#if defined(EXTI_C2_BASE) +# define EXTI_REG_IMR (EXTI_C2->IMR1) +#elif defined(EXTI_IMR_IM0) +# define EXTI_REG_IMR (EXTI->IMR) +#elif defined(EXTI_IMR1_IM0) +# define EXTI_REG_IMR (EXTI->IMR1) #endif void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin) From ff727f8f90c1765b0bb77031afce4e1b2113b5a8 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 17 Mar 2023 18:57:25 +0100 Subject: [PATCH 2/2] tests/periph_gpio_ll: Minor improvement Use a custom expect() that just spins in an endless loop instead of panicking. The test isn't run automatically anyway, as it requires connecting two GPIOs with jumper wires; but when run manually it is helpful to not kill RIOT to also get the stdio output of the exact point where the test fails (e.g. USB CDC ACM doesn't like panic()). --- tests/periph_gpio_ll/main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/periph_gpio_ll/main.c b/tests/periph_gpio_ll/main.c index 006b77fe96..dbdfcf904d 100644 --- a/tests/periph_gpio_ll/main.c +++ b/tests/periph_gpio_ll/main.c @@ -27,7 +27,6 @@ #include "mutex.h" #include "periph/gpio_ll.h" #include "periph/gpio_ll_irq.h" -#include "test_utils/expect.h" #include "timex.h" #include "ztimer.h" @@ -54,6 +53,19 @@ static void puts_optional(const char *str) #define printf_optional(...) printf(__VA_ARGS__) #endif +/* a custom expect that keeps the CPU alive makes debugging easier with + * stdio that requires RIOT to remain alive, e.g. USB CDC ACM */ +static void expect_impl(int val, unsigned line) +{ + if (!val) { + printf("expect failed at line %u\n", line); + fflush(stdout); + while(1) {} + } +} + +#define expect(x) expect_impl((int)(x), __LINE__) + static void print_cabling(unsigned port1, unsigned pin1, unsigned port2, unsigned pin2) { @@ -66,7 +78,8 @@ static void print_details(void) { puts_optional("Test / Hardware Details:\n" "========================\n" - "Cabling:"); + "Cabling:\n" + "(INPUT -- OUTPUT)"); print_cabling(PORT_IN, PIN_IN_0, PORT_OUT, PIN_OUT_0); print_cabling(PORT_IN, PIN_IN_1, PORT_OUT, PIN_OUT_1); printf("Number of pull resistor values supported: %u\n", GPIO_PULL_NUMOF);