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