1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
19412: cpu/stm32/periph: Add GPIO LL IRQ support for STM32F1 r=gschorcht a=maribu

### Contribution description

As the title says

### Testing procedure

<details><summary><code>make BOARD=nucleo-f103rb flash test-with-config -C tests/periph_gpio_ll</code></summary>

```
make: Entering directory '/home/maribu/Repos/software/RIOT/tests/periph_gpio_ll'
Building application "tests_periph_gpio_ll" for "nucleo-f103rb" with MCU "stm32".

"make" -C /home/maribu/Repos/software/RIOT/boards/common/init
"make" -C /home/maribu/Repos/software/RIOT/boards/nucleo-f103rb
"make" -C /home/maribu/Repos/software/RIOT/boards/common/nucleo
"make" -C /home/maribu/Repos/software/RIOT/core
"make" -C /home/maribu/Repos/software/RIOT/core/lib
"make" -C /home/maribu/Repos/software/RIOT/cpu/stm32
"make" -C /home/maribu/Repos/software/RIOT/cpu/cortexm_common
"make" -C /home/maribu/Repos/software/RIOT/cpu/cortexm_common/periph
"make" -C /home/maribu/Repos/software/RIOT/cpu/stm32/periph
"make" -C /home/maribu/Repos/software/RIOT/cpu/stm32/stmclk
"make" -C /home/maribu/Repos/software/RIOT/cpu/stm32/vectors
"make" -C /home/maribu/Repos/software/RIOT/drivers
"make" -C /home/maribu/Repos/software/RIOT/drivers/periph_common
"make" -C /home/maribu/Repos/software/RIOT/sys
"make" -C /home/maribu/Repos/software/RIOT/sys/auto_init
"make" -C /home/maribu/Repos/software/RIOT/sys/div
"make" -C /home/maribu/Repos/software/RIOT/sys/frac
"make" -C /home/maribu/Repos/software/RIOT/sys/isrpipe
"make" -C /home/maribu/Repos/software/RIOT/sys/libc
"make" -C /home/maribu/Repos/software/RIOT/sys/malloc_thread_safe
"make" -C /home/maribu/Repos/software/RIOT/sys/newlib_syscalls_default
"make" -C /home/maribu/Repos/software/RIOT/sys/pm_layered
"make" -C /home/maribu/Repos/software/RIOT/sys/preprocessor
"make" -C /home/maribu/Repos/software/RIOT/sys/stdio_uart
"make" -C /home/maribu/Repos/software/RIOT/sys/test_utils/interactive_sync
"make" -C /home/maribu/Repos/software/RIOT/sys/test_utils/print_stack_usage
"make" -C /home/maribu/Repos/software/RIOT/sys/tsrb
"make" -C /home/maribu/Repos/software/RIOT/sys/ztimer
   text	  data	   bss	   dec	   hex	filename
  20760	   176	  2728	 23664	  5c70	/home/maribu/Repos/software/RIOT/tests/periph_gpio_ll/bin/nucleo-f103rb/tests_periph_gpio_ll.elf
/home/maribu/Repos/software/RIOT/dist/tools/openocd/openocd.sh flash /home/maribu/Repos/software/RIOT/tests/periph_gpio_ll/bin/nucleo-f103rb/tests_periph_gpio_ll.elf
### Flashing Target ###
Open On-Chip Debugger 0.12.0+dev-snapshot (2023-03-13-08:56)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
DEPRECATED! use 'adapter serial' not 'hla_serial'
hla_swd
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
srst_only separate srst_nogate srst_open_drain connect_assert_srst
Info : clock speed 1000 kHz
Info : STLINK V2J29M18 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.252984
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 0
Info : Listening on port 32843 for gdb connections
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* stm32f1x.cpu       hla_target little stm32f1x.cpu       unknown
[stm32f1x.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08001ae4 msp: 0x20000200
Info : device id = 0x20036410
Info : flash size = 128 KiB
Warn : Adding extra erase range, 0x080051c8 .. 0x080053ff
auto erase enabled
wrote 20936 bytes from file /home/maribu/Repos/software/RIOT/tests/periph_gpio_ll/bin/nucleo-f103rb/tests_periph_gpio_ll.elf in 1.192543s (17.144 KiB/s)
verified 20936 bytes in 0.333379s (61.328 KiB/s)
shutdown command invoked
Done flashing
r
/home/maribu/Repos/software/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM1" -b "115200" --no-reconnect --noprefix --no-repeat-command-on-empty-line 
Connect to serial port /dev/ttyACM1
Welcome to pyterm!
Type '/exit' to exit.
READY
s
START
main(): This is RIOT! (Version: 2023.04-devel-685-gd0d5d-cpu/stm32/periph/gpio_ll_irq)
Test / Hardware Details:
========================
Cabling:
(INPUT -- OUTPUT)
  P2.10 (PC10) -- P1.8 (PB8)
  P2.12 (PC12) -- P1.9 (PB9)
Number of pull resistor values supported: 1
Number of drive strengths supported: 1
Number of slew rates supported: 4
Valid GPIO ports:
- PORT 0 (PORT A)
- PORT 1 (PORT B)
- PORT 2 (PORT C)
- PORT 3 (PORT D)
- PORT 4 (PORT E)

Testing gpio_port_pack_addr()
=============================

All OK

Testing gpip_ng_init()
======================

Testing is_gpio_port_num_valid() is true for PORT_OUT and PORT_IN:

Testing input configurations for PIN_IN_0:
Support for input with pull up: yes
state: in, pull: up, schmitt trigger: off, value: on
Support for input with pull down: yes
state: in, pull: down, schmitt trigger: off, value: off
Support for input with pull to bus level: no
Support for floating input (no pull resistors): yes
state: in, pull: none, schmitt trigger: off, value: off

Testing output configurations for PIN_OUT_0:
Support for output (push-pull) with initial value of LOW: yes
state: out-pp, slew: slowest, value: off
Output is indeed LOW: yes
state: out-pp, slew: slowest, value: on
Output can be pushed HIGH: yes
Support for output (push-pull) with initial value of HIGH: yes
state: out-pp, slew: slowest, value: on
Output is indeed HIGH: yes
Support for output (open drain with pull up) with initial value of LOW: no
Support for output (open drain with pull up) with initial value of HIGH: no
Support for output (open drain) with initial value of LOW: yes
state: out-od, slew: slowest, pull: none, schmitt trigger: off, value: off
Output is indeed LOW: yes
Support for output (open drain) with initial value of HIGH: yes
state: out-od, slew: slowest, pull: none, schmitt trigger: off, value: on
state: in, pull: down, schmitt trigger: off, value: off
Output can indeed be pulled LOW: yes
state: in, pull: up, schmitt trigger: off, value: on
Output can indeed be pulled HIGH: yes
Support for output (open source) with initial value of LOW: no
Support for output (open source) with initial value of HIGH: no
Support for output (open source with pull up) with initial value of HIGH: no
Support for output (open source with pull up) with initial value of LOW: no
Support for disconnecting GPIO: yes
Output can indeed be pulled LOW: yes
Output can indeed be pulled HIGH: yes

Testing Reading/Writing GPIO Ports
==================================

testing initial value of 0 after init
...OK
testing setting both outputs_optional simultaneously
...OK
testing clearing both outputs_optional simultaneously
...OK
testing toggling first output (0 --> 1)
...OK
testing toggling first output (1 --> 0)
...OK
testing toggling second output (0 --> 1)
...OK
testing toggling second output (1 --> 0)
...OK
testing setting first output and clearing second with write
...OK
testing setting second output and clearing first with write
...OK
All input/output operations worked as expected

Testing External IRQs
=====================

Testing rising edge on PIN_IN_0
... OK
Testing falling edge on PIN_IN_0
... OK
Testing both edges on PIN_IN_0
... OK
Testing masking of IRQs (still both edges on PIN_IN_0)
... OK
Testing level-triggered on HIGH on PIN_IN_0 (when input is LOW when setting up IRQ)
... OK
Testing level-triggered on HIGH on PIN_IN_0 (when input is HIGH when setting up IRQ)
... OK
Testing level-triggered on LOW on PIN_IN_0 (when input is HIGH when setting up IRQ)
... OK
Testing level-triggered on LOW on PIN_IN_0 (when input is LOW when setting up IRQ)
... OK


TEST SUCCEEDED
```

</details>

### Issues/PRs references

Depends on https://github.com/RIOT-OS/RIOT/pull/19407

Co-authored-by: Marian Buschsieweke <marian.buschsieweke@ovgu.de>
This commit is contained in:
bors[bot] 2023-03-22 13:15:19 +00:00 committed by GitHub
commit 9405bf7a26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 78 deletions

View File

@ -12,12 +12,9 @@ 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_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
endif
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
ifneq (,$(filter $(CPU_FAM),f0 f1 f3 g0 g4 l0 l1 l4 l5 u5 wb wl))
FEATURES_PROVIDED += periph_flashpage

View File

@ -17,6 +17,9 @@ config CPU_FAM_F1
select HAS_PERIPH_FLASHPAGE_PAGEWISE
select HAS_PERIPH_FLASHPAGE_RAW
select HAS_PERIPH_GPIO_LL
select HAS_PERIPH_GPIO_LL_IRQ
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW
select HAS_PERIPH_RTT_SET_COUNTER
select HAS_PERIPH_WDT
select HAVE_SHARED_PERIPH_RTT_PERIPH_RTC

View File

@ -41,43 +41,87 @@
#define EXTI_MASK (0xFFFF)
#if defined(EXTI_SWIER_SWI0) || defined(EXTI_SWIER_SWIER0)
#define EXTI_REG_SWIER (EXTI->SWIER)
# define EXTI_REG_SWIER (EXTI->SWIER)
#endif
#if defined(EXTI_SWIER1_SWI0) || defined(EXTI_SWIER1_SWIER0)
#define EXTI_REG_SWIER (EXTI->SWIER1)
# define EXTI_REG_SWIER (EXTI->SWIER1)
#endif
#if defined(EXTI_RTSR_RT0) || defined(EXTI_RTSR_TR0)
#define EXTI_REG_RTSR (EXTI->RTSR)
# define EXTI_REG_RTSR (EXTI->RTSR)
#endif
#if defined(EXTI_RTSR1_RT0) || defined(EXTI_RTSR1_TR0)
#define EXTI_REG_RTSR (EXTI->RTSR1)
# define EXTI_REG_RTSR (EXTI->RTSR1)
#endif
#if defined(EXTI_FTSR_FT0) || defined(EXTI_FTSR_TR0)
#define EXTI_REG_FTSR (EXTI->FTSR)
# define EXTI_REG_FTSR (EXTI->FTSR)
#endif
#if defined(EXTI_FTSR1_FT0) || defined (EXTI_FTSR1_TR0)
#define EXTI_REG_FTSR (EXTI->FTSR1)
# 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)
#if defined(EXTI_PR_PR0)
# define EXTI_REG_PR (EXTI->PR)
#elif defined(EXTI_PR1_PIF0)
# define EXTI_REG_PR (EXTI->PR1)
#else
# define EXTI_REG_FPR (EXTI->FPR1)
# define EXTI_REG_RPR (EXTI->RPR1)
#endif
#if defined(EXTI_C2_BASE)
# define EXTI_REG_IMR (EXTI_C2->IMR1)
# define EXTI_REG_IMR (EXTI_C2->IMR1)
#elif defined(EXTI_IMR_IM0)
# define EXTI_REG_IMR (EXTI->IMR)
# define EXTI_REG_IMR (EXTI->IMR)
#elif defined(EXTI_IMR1_IM0)
# define EXTI_REG_IMR (EXTI->IMR1)
# define EXTI_REG_IMR (EXTI->IMR1)
#endif
#ifdef RCC_APB2ENR_SYSCFGCOMPEN
# define SYSFG_CLOCK APB2
# define SYSFG_ENABLE_MASK RCC_APB2ENR_SYSCFGCOMPEN
#endif
#ifdef RCC_APBENR2_SYSCFGEN
# define SYSFG_ENABLE_MASK RCC_APBENR2_SYSCFGEN
# ifdef APB12
# define SYSFG_CLOCK APB12
# else
# define SYSFG_CLOCK APB2
# endif
#endif
#ifdef RCC_APB3ENR_SYSCFGEN
# define SYSFG_CLOCK APB3
# define SYSFG_ENABLE_MASK RCC_APB3ENR_SYSCFGEN
#endif
#ifdef EXTI_EXTICR1_EXTI0
# define EXTICR_REG(num) (EXTI->EXTICR[(num) >> 2])
#endif
#ifdef SYSCFG_EXTICR1_EXTI0
# define EXTICR_REG(num) (SYSCFG->EXTICR[(num) >> 2])
#endif
#ifdef AFIO_EXTICR1_EXTI0
# define EXTICR_REG(num) (AFIO->EXTICR[(num) >> 2])
#endif
#ifdef SYSCFG_EXTICR1_EXTI1_Pos
# define EXTICR_FIELD_SIZE SYSCFG_EXTICR1_EXTI1_Pos
#endif
#ifdef EXTI_EXTICR1_EXTI1_Pos
# define EXTICR_FIELD_SIZE EXTI_EXTICR1_EXTI1_Pos
#endif
#ifdef AFIO_EXTICR1_EXTI1_Pos
# define EXTICR_FIELD_SIZE AFIO_EXTICR1_EXTI1_Pos
#endif
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
@ -102,6 +146,8 @@ static uint16_t level_triggered;
static IRQn_Type get_irqn(uint8_t pin)
{
/* TODO: Come up with a way that this doesn't need updates whenever a new
* MCU family gets added */
#if defined(CPU_FAM_STM32L5) || defined(CPU_FAM_STM32U5)
return EXTI0_IRQn + pin;
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
@ -155,48 +201,29 @@ static IRQn_Type get_irqn(uint8_t pin)
static void clear_pending_irqs(uint8_t pin)
{
#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \
defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32MP1)
/* clear any pending requests */
EXTI->RPR1 = (1 << pin);
EXTI->FPR1 = (1 << pin);
#ifdef EXTI_REG_PR
/* same IRQ flag no matter if falling or rising edge detected */
EXTI_REG_PR = (1U << pin);
#else
/* clear any pending requests */
EXTI_REG_PR = (1 << pin);
/* distinct IRQ flags for falling and rising edge, clearing both */
EXTI_REG_FPR = (1U << pin);
EXTI_REG_RPR = (1U << pin);
#endif
}
static void set_exti_port(uint8_t exti_num, uint8_t port_num)
{
#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \
defined(CPU_FAM_STM32U5)
/* enable specific pin as exti sources */
EXTI->EXTICR[exti_num >> 2] &= ~(0xf << ((exti_num & 0x03) * 8));
EXTI->EXTICR[exti_num >> 2] |= (port_num << ((exti_num & 0x03) * 8));
#elif defined(CPU_FAM_STM32MP1)
/* enable specific pin as exti sources */
EXTI->EXTICR[exti_num >> 2] &= ~(0xf << ((exti_num & 0x03) * 4));
EXTI->EXTICR[exti_num >> 2] |= (port_num << ((exti_num & 0x03) * 4));
#else
/* enable specific pin as exti sources */
SYSCFG->EXTICR[exti_num >> 2] &= ~(0xf << ((exti_num & 0x03) * 4));
SYSCFG->EXTICR[exti_num >> 2] |= (port_num << ((exti_num & 0x03) * 4));
#endif
uint32_t tmp = EXTICR_REG(exti_num);
tmp &= ~(0xf << ((exti_num & 0x03) * EXTICR_FIELD_SIZE));
tmp |= (port_num << ((exti_num & 0x03) * EXTICR_FIELD_SIZE));
EXTICR_REG(exti_num) = tmp;
}
static uint8_t get_exti_port(uint8_t exti_num)
{
#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \
defined(CPU_FAM_STM32U5)
/* enable specific pin as exti sources */
return 0xf & (EXTI->EXTICR[exti_num >> 2] >> ((exti_num & 0x03) * 8));
#elif defined(CPU_FAM_STM32MP1)
/* enable specific pin as exti sources */
return 0xf & (EXTI->EXTICR[exti_num >> 2] >> ((exti_num & 0x03) * 4));
#else
/* enable specific pin as exti sources */
return 0xf & (SYSCFG->EXTICR[exti_num >> 2] >> ((exti_num & 0x03) * 4));
#endif
uint32_t reg = EXTICR_REG(exti_num);
reg >>= (exti_num & 0x03) * EXTICR_FIELD_SIZE;
return reg & 0xf;
}
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, gpio_ll_cb_t cb, void *arg)
@ -209,17 +236,8 @@ int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, gpio_ll_cb_
isr_ctx[pin].arg = arg;
/* enable clock of the SYSCFG module for EXTI configuration */
#if !defined(CPU_FAM_STM32WB) && !defined(CPU_FAM_STM32MP1) && \
!defined(CPU_FAM_STM32WL)
#ifdef CPU_FAM_STM32F0
periph_clk_en(APB2, RCC_APB2ENR_SYSCFGCOMPEN);
#elif defined(CPU_FAM_STM32G0)
periph_clk_en(APB12, RCC_APBENR2_SYSCFGEN);
#elif defined(CPU_FAM_STM32U5)
periph_clk_en(APB3, RCC_APB3ENR_SYSCFGEN);
#else
periph_clk_en(APB2, RCC_APB2ENR_SYSCFGEN);
#endif
#ifdef SYSFG_CLOCK
periph_clk_en(SYSFG_CLOCK, SYSFG_ENABLE_MASK);
#endif
/* enable global pin interrupt */
@ -262,30 +280,35 @@ int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, gpio_ll_cb_
return 0;
}
void isr_exti(void)
static uint32_t get_and_clear_pending_irqs(void)
{
#if defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32L5) || \
defined(CPU_FAM_STM32U5) || defined(CPU_FAM_STM32MP1)
/* get all interrupts handled by this ISR */
uint32_t pending_rising_isr = (EXTI->RPR1 & EXTI_MASK);
uint32_t pending_falling_isr = (EXTI->FPR1 & EXTI_MASK);
#ifdef EXTI_REG_PR
/* only one pending IRQ flag register for both falling and rising flanks */
uint32_t pending_isr = (EXTI_REG_PR & EXTI_MASK);
/* clear by writing a 1 */
EXTI_REG_PR = pending_isr;
return pending_isr;
#else
/* distinct registers for pending IRQ flags depending on rising or falling
* flank */
uint32_t pending_rising_isr = (EXTI_REG_RPR & EXTI_MASK);
uint32_t pending_falling_isr = (EXTI_REG_FPR & EXTI_MASK);
/* clear by writing a 1 */
EXTI->RPR1 = pending_rising_isr;
EXTI->FPR1 = pending_falling_isr;
/* only generate interrupts against lines which have their IMR set */
uint32_t pending_isr = (pending_rising_isr | pending_falling_isr) & EXTI_REG_IMR;
#else
/* read all pending interrupts wired to isr_exti */
uint32_t pending_isr = (EXTI_REG_PR & EXTI_MASK);
return pending_rising_isr | pending_falling_isr;
#endif
}
/* clear by writing a 1 */
EXTI_REG_PR = pending_isr;
void isr_exti(void)
{
uint32_t pending_isr = get_and_clear_pending_irqs();
/* only generate soft interrupts against lines which have their IMR set */
pending_isr &= EXTI_REG_IMR;
#endif
/* iterate over all set bits */
uint8_t pin = 0;