Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/stm32: implement periph_gpio_ll_switch_dir #20805

Conversation

maribu
Copy link
Member

@maribu maribu commented Aug 2, 2024

Contribution description

This changes the API of the periph_gpio_ll_switch_dir feature, so that gpio_ll_switch_dir_output() and gpio_ll_switch_dir_input() no longer directly take a bitmask indicating with GPIO pins to switch, but the output of gpio_ll_prepare_switch_dir() that takes this bitmask.

The reason for this change is that on STM32 (except for F1) the GPIO periphal has no direction register (with one bit per pin), but a mode register (with two bits per pin). This required some non-trivial bit operation to prepare the bitmask to write to the mode register from the bitmask specifying the pins to change. Splitting out the preparation allows to cache the result and switch directions fast anyway.

An implementation for STM32F1 is not provided yet.

A default implementation for gpio_ll_prepare_switch_dir() is provided that returns the argument unmodified, so that no overhead is introduced on the platforms already supporting periph_gpio_ll_switch_dir.

Testing procedure

git:(cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir) ~/Repos/software/RIOT/stm32_gpio_ll/tests/periph/gpio_ll ➜ make BOARD=nucleo-f303re flash test-with-config 
Building application "tests_gpio_ll" for "nucleo-f303re" with CPU "stm32".

"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/pkg/cmsis/ 
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/boards/common/init
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/boards/nucleo-f303re
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/boards/common/nucleo
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/core
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/core/lib
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/stm32
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/cortexm_common
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/cortexm_common/periph
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/stm32/periph
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/stm32/stmclk
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/cpu/stm32/vectors
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/drivers
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/drivers/periph_common
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/auto_init
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/div
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/frac
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/isrpipe
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/libc
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/malloc_thread_safe
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/newlib_syscalls_default
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/pm_layered
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/preprocessor
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/stdio
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/stdio_uart
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/test_utils/interactive_sync
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/test_utils/print_stack_usage
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/tsrb
"make" -C /home/maribu/Repos/software/RIOT/stm32_gpio_ll/sys/ztimer
   text	  data	   bss	   dec	   hex	filename
  21880	   176	  2736	 24792	  60d8	/home/maribu/Repos/software/RIOT/stm32_gpio_ll/tests/periph/gpio_ll/bin/nucleo-f303re/tests_gpio_ll.elf
/home/maribu/Repos/software/RIOT/stm32_gpio_ll/dist/tools/openocd/openocd.sh flash /home/maribu/Repos/software/RIOT/stm32_gpio_ll/tests/periph/gpio_ll/bin/nucleo-f303re/tests_gpio_ll.elf
### Flashing Target ###
Open On-Chip Debugger 0.12.0+dev-snapshot (2024-01-17-08:38)
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 V2J28M17 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.246873
Info : [stm32f3x.cpu] Cortex-M4 r0p1 processor detected
Info : [stm32f3x.cpu] target has 6 breakpoints, 4 watchpoints
Info : [stm32f3x.cpu] Examination succeed
Info : starting gdb server for stm32f3x.cpu on 0
Info : Listening on port 44059 for gdb connections
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* stm32f3x.cpu       hla_target little stm32f3x.cpu       unknown
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
[stm32f3x.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08001d70 msp: 0x20000200
Info : device id = 0x10036446
Info : flash size = 512 KiB
Warn : Adding extra erase range, 0x08005628 .. 0x080057ff
auto erase enabled
wrote 22056 bytes from file /home/maribu/Repos/software/RIOT/stm32_gpio_ll/tests/periph/gpio_ll/bin/nucleo-f303re/tests_gpio_ll.elf in 1.199477s (17.957 KiB/s)
verified 22056 bytes in 0.376511s (57.207 KiB/s)
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
shutdown command invoked
Done flashing
r
/home/maribu/Repos/software/RIOT/stm32_gpio_ll/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "115200" -ln "/tmp/pyterm-maribu" -rn "2024-08-02_20.05.02-tests_gpio_ll-nucleo-f303re" --no-reconnect --noprefix --no-repeat-command-on-empty-line 
Twisted not available, please install it if you want to use pyterm's JSON capabilities
Connect to serial port /dev/ttyACM0
Welcome to pyterm!
Type '/exit' to exit.
READY
s
START
main(): This is RIOT! (Version: 2024.10-devel-43-g746981-cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir)
Test / Hardware Details:
========================
Cabling:
(INPUT -- OUTPUT)
  PC0 -- PC8
  PC1 -- PC9
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)
- PORT 5 (PORT F)
- PORT 6 (PORT G)
- PORT 7 (PORT H)

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, value: on, slew: slowest
Support for input with pull down: yes
state: in, pull: down, value: off, slew: slowest
Support for input with pull to bus level: no
Support for floating input (no pull resistors): yes
state: in, pull: none, value: off, slew: slowest

Testing output configurations for PIN_OUT_0:
Support for output (push-pull) with initial value of LOW: yes
state: out-pp, value: off, slew: slowest
Output is indeed LOW: yes
state: out-pp, value: on, slew: slowest
Output can be pushed HIGH: yes
Support for output (push-pull) with initial value of HIGH: yes
state: out-pp, value: on, slew: slowest
Output is indeed HIGH: yes
Support for output (open drain with pull up) with initial value of LOW: yes
state: out-od, pull: up, value: off, slew: slowest
Output is indeed LOW: yes
Support for output (open drain with pull up) with initial value of HIGH: yes
state: out-od, pull: up, value: on, slew: slowest
Output is indeed HIGH: yes
Support for output (open drain) with initial value of LOW: yes
state: out-od, pull: none, value: off, slew: slowest
Output is indeed LOW: yes
Support for output (open drain) with initial value of HIGH: yes
state: out-od, pull: none, value: on, slew: slowest
state: in, pull: down, value: off, slew: slowest
Output can indeed be pulled LOW: yes
state: in, pull: up, value: on, slew: slowest
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 down) with initial value of HIGH: no
Support for output (open source with pull down) with initial value of LOW: no

Support for disconnecting GPIO: yes
state: off, pull: none, value: off, slew: slowest
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

Testing Switching Direction
===========================

Input pin can be switched to output (push-pull) mode: yes
Pin behaves as output after switched to output mode: yes
Returning back to input had no side effects on config: yes
Pin behaves as input after switched back to input mode: yes


TEST SUCCEEDED

Issues/PRs references

None

@maribu maribu added Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care. Area: drivers Area: Device drivers CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Area: cpu Area: CPU/MCU ports labels Aug 2, 2024
@github-actions github-actions bot added Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: tests Area: tests and testing framework labels Aug 2, 2024
@riot-ci
Copy link

riot-ci commented Aug 2, 2024

Murdock results

✔️ PASSED

8839ccb cpu/stm32: implement periph_gpio_ll_switch_dir

Success Failures Total Runtime
10195 0 10197 16m:59s

Artifacts

@maribu maribu force-pushed the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch from 7469811 to d42aa66 Compare August 2, 2024 18:59
@maribu maribu force-pushed the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch 2 times, most recently from 0a23efb to e7def57 Compare August 5, 2024 19:05
maribu added 2 commits August 8, 2024 16:22
It turns out that the feature to switch the GPIO direction quickly
is not only a way to emulate open drain / open source mode for less
sophisticated GPIO peripherals that do not natively support it.
It also enables tri-state output (push-pull high, push-pull low,
high impedance), which is useful e.g. for driven charlieplexed LEDs
quickly.

This changes the API by introducing a `gpio_ll_prepare_switch_dir()`
function that prepares the value used to identify which pins should
be switched to input or to output mode. This is useful for GPIO
peripherals in which the GPIO mode register does not allocate one bit
per pin (so that only the direction is given there), such as the one
for STM32. This allows an STM32 implementation in which preparing the
bitmask needed to modify the direction of pins is not trivial.
In all other tests we added a delay after writing to the output buffer
of GPIO A before expected the input buffer of GPIO B (connected to A)
to reflect the change, but not in test_switch_dir().

This adds the delay here as well to make the test more robust in regard
to GPIO peripherals that react not as fast as the CPU can query them.
@maribu maribu force-pushed the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch from 909f536 to 994d05c Compare August 8, 2024 14:22
@benpicco benpicco enabled auto-merge August 8, 2024 17:19
@benpicco benpicco added this pull request to the merge queue Aug 8, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Aug 8, 2024
@maribu maribu force-pushed the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch 2 times, most recently from 5f39c0b to 00e12c9 Compare August 8, 2024 18:08
@maribu
Copy link
Member Author

maribu commented Aug 8, 2024

I forgot about the legacy STM32F1 GPIO peripheral. It is not trivial to provide the feature there, as the configuration is spread over multiple registers.

For now, the feature is provided only by STM32 families other than F1.

@maribu maribu enabled auto-merge August 8, 2024 18:21
@maribu maribu added this pull request to the merge queue Aug 8, 2024
github-merge-queue bot pushed a commit that referenced this pull request Aug 8, 2024
…_gpio_ll_switch_dir

cpu/stm32: implement `periph_gpio_ll_switch_dir`
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Aug 8, 2024
This implements periph_gpio_ll_switch_dir for STM32 except for STM32F1,
which has a different register layout.
@maribu maribu force-pushed the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch from 00e12c9 to 8839ccb Compare August 8, 2024 20:17
@maribu maribu enabled auto-merge August 8, 2024 20:17
@maribu maribu added this pull request to the merge queue Aug 8, 2024
Merged via the queue into RIOT-OS:master with commit 4c55f92 Aug 9, 2024
25 checks passed
@maribu maribu deleted the cpu/stm32/periph_gpio_ll_periph_gpio_ll_switch_dir branch August 9, 2024 04:30
@maribu
Copy link
Member Author

maribu commented Aug 9, 2024

Thx!

@benpicco benpicco added this to the Release 2024.10 milestone Nov 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: cpu Area: CPU/MCU ports Area: drivers Area: Device drivers Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants