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

drivers/periph_timer: add timer_get_closest_freq() #20581

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

maribu
Copy link
Member

@maribu maribu commented Apr 15, 2024

Contribution description

This provides a helper function that builds upon the periph_timer_query_freqs feature to find the frequency supported by a given timer that is closest to a given target frequency.

This functionality isn't as straight forward to implement, as a naive implementation iterating over all supported pre-scalers will be prohibitively expensive when the pre-scaler register is 16 bit or even 32 bit wide.

Instead, a binary search is performed plus some corner case handling in case the target frequency cannot exactly be met, in which it is checked if the highest frequency below the target or the smallest above the target is closer.

Testing procedure

The test app was extended:

git:(timer_get_closest_freq) ~/Repos/software/RIOT/master/tests/periph/timer ➜ make BOARD=nucleo-f429zi flash test
Building application "tests_timer" for "nucleo-f429zi" with CPU "stm32".

"make" -C /home/maribu/Repos/software/RIOT/master/pkg/cmsis/ 
"make" -C /home/maribu/Repos/software/RIOT/master/boards/common/init
"make" -C /home/maribu/Repos/software/RIOT/master/boards/nucleo-f429zi
"make" -C /home/maribu/Repos/software/RIOT/master/boards/common/nucleo
"make" -C /home/maribu/Repos/software/RIOT/master/core
"make" -C /home/maribu/Repos/software/RIOT/master/core/lib
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/stm32
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/cortexm_common
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/cortexm_common/periph
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/stm32/periph
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/stm32/stmclk
"make" -C /home/maribu/Repos/software/RIOT/master/cpu/stm32/vectors
"make" -C /home/maribu/Repos/software/RIOT/master/drivers
"make" -C /home/maribu/Repos/software/RIOT/master/drivers/periph_common
"make" -C /home/maribu/Repos/software/RIOT/master/sys
"make" -C /home/maribu/Repos/software/RIOT/master/sys/auto_init
"make" -C /home/maribu/Repos/software/RIOT/master/sys/div
"make" -C /home/maribu/Repos/software/RIOT/master/sys/isrpipe
"make" -C /home/maribu/Repos/software/RIOT/master/sys/libc
"make" -C /home/maribu/Repos/software/RIOT/master/sys/malloc_thread_safe
"make" -C /home/maribu/Repos/software/RIOT/master/sys/newlib_syscalls_default
"make" -C /home/maribu/Repos/software/RIOT/master/sys/pm_layered
"make" -C /home/maribu/Repos/software/RIOT/master/sys/preprocessor
"make" -C /home/maribu/Repos/software/RIOT/master/sys/stdio
"make" -C /home/maribu/Repos/software/RIOT/master/sys/stdio_uart
"make" -C /home/maribu/Repos/software/RIOT/master/sys/test_utils/interactive_sync
"make" -C /home/maribu/Repos/software/RIOT/master/sys/test_utils/print_stack_usage
"make" -C /home/maribu/Repos/software/RIOT/master/sys/tsrb
   text	  data	   bss	   dec	   hex	filename
  13972	   128	  2752	 16852	  41d4	/home/maribu/Repos/software/RIOT/master/tests/periph/timer/bin/nucleo-f429zi/tests_timer.elf
/home/maribu/Repos/software/RIOT/master/dist/tools/openocd/openocd.sh flash /home/maribu/Repos/software/RIOT/master/tests/periph/timer/bin/nucleo-f429zi/tests_timer.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 2000 kHz
Info : STLINK V2J29M18 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.260526
Info : [stm32f4x.cpu] Cortex-M4 r0p1 processor detected
Info : [stm32f4x.cpu] target has 6 breakpoints, 4 watchpoints
Info : [stm32f4x.cpu] Examination succeed
Info : starting gdb server for stm32f4x.cpu on 0
Info : Listening on port 33673 for gdb connections
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* stm32f4x.cpu       hla_target little stm32f4x.cpu       unknown
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
[stm32f4x.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000cc8 msp: 0x20000200
Info : device id = 0x20016419
Info : flash size = 2048 KiB
Info : Dual Bank 2048 kiB STM32F42x/43x/469/479 found
auto erase enabled
wrote 16384 bytes from file /home/maribu/Repos/software/RIOT/master/tests/periph/timer/bin/nucleo-f429zi/tests_timer.elf in 0.659411s (24.264 KiB/s)
verified 14100 bytes in 0.161758s (85.124 KiB/s)
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
shutdown command invoked
Done flashing
r
/home/maribu/Repos/software/RIOT/master/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "115200" --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.07-devel-12-ga63d0-timer_get_closest_freq)

Test for peripheral TIMERs

Available timers: 2

TIMER 0
=======

  - supported frequencies:
    0: 90000000
    1: 45000000
    2: 30000000
    ....
    65535: 1373
Testing timer_get_closest_freq()...
[OK]
Testing timer_query_freqs() for out of bound index...
[OK]
  - Calling timer_init(0, 90000000)
    initialization successful
  - timer_stop(0): stopped
  - timer_set(0, 0, 450000)
    Successfully set timeout 450000 for channel 0
  - timer_set(0, 1, 900000)
    Successfully set timeout 900000 for channel 1
  - timer_set(0, 2, 1350000)
    Successfully set timeout 1350000 for channel 2
  - timer_set(0, 3, 1800000)
    Successfully set timeout 1800000 for channel 3
  - timer_start(0)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105867      - diff:    52926
    - channel 2 fired at SW count   158798      - diff:    52931
    - channel 3 fired at SW count   211728      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)
  - Calling timer_init(0, 45000000)
    initialization successful
  - timer_stop(0): stopped
  - timer_set(0, 0, 225000)
    Successfully set timeout 225000 for channel 0
  - timer_set(0, 1, 450000)
    Successfully set timeout 450000 for channel 1
  - timer_set(0, 2, 675000)
    Successfully set timeout 675000 for channel 2
  - timer_set(0, 3, 900000)
    Successfully set timeout 900000 for channel 3
  - timer_start(0)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105867      - diff:    52926
    - channel 2 fired at SW count   158798      - diff:    52931
    - channel 3 fired at SW count   211728      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)
  - Calling timer_init(0, 30000000)
    initialization successful
  - timer_stop(0): stopped
  - timer_set(0, 0, 150000)
    Successfully set timeout 150000 for channel 0
  - timer_set(0, 1, 300000)
    Successfully set timeout 300000 for channel 1
  - timer_set(0, 2, 450000)
    Successfully set timeout 450000 for channel 2
  - timer_set(0, 3, 600000)
    Successfully set timeout 600000 for channel 3
  - timer_start(0)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105868      - diff:    52927
    - channel 2 fired at SW count   158798      - diff:    52930
    - channel 3 fired at SW count   211728      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)

TIMER 1
=======

  - supported frequencies:
    0: 90000000
    1: 45000000
    2: 30000000
    ....
    65535: 1373
Testing timer_get_closest_freq()...
[OK]
Testing timer_query_freqs() for out of bound index...
[OK]
  - Calling timer_init(1, 90000000)
    initialization successful
  - timer_stop(1): stopped
  - timer_set(1, 0, 450000)
    Successfully set timeout 450000 for channel 0
  - timer_set(1, 1, 900000)
    Successfully set timeout 900000 for channel 1
  - timer_set(1, 2, 1350000)
    Successfully set timeout 1350000 for channel 2
  - timer_set(1, 3, 1800000)
    Successfully set timeout 1800000 for channel 3
  - timer_start(1)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105868      - diff:    52927
    - channel 2 fired at SW count   158799      - diff:    52931
    - channel 3 fired at SW count   211729      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)
  - Calling timer_init(1, 45000000)
    initialization successful
  - timer_stop(1): stopped
  - timer_set(1, 0, 225000)
    Successfully set timeout 225000 for channel 0
  - timer_set(1, 1, 450000)
    Successfully set timeout 450000 for channel 1
  - timer_set(1, 2, 675000)
    Successfully set timeout 675000 for channel 2
  - timer_set(1, 3, 900000)
    Successfully set timeout 900000 for channel 3
  - timer_start(1)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105868      - diff:    52927
    - channel 2 fired at SW count   158799      - diff:    52931
    - channel 3 fired at SW count   211729      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)
  - Calling timer_init(1, 30000000)
    initialization successful
  - timer_stop(1): stopped
  - timer_set(1, 0, 150000)
    Successfully set timeout 150000 for channel 0
  - timer_set(1, 1, 300000)
    Successfully set timeout 300000 for channel 1
  - timer_set(1, 2, 450000)
    Successfully set timeout 450000 for channel 2
  - timer_set(1, 3, 600000)
    Successfully set timeout 600000 for channel 3
  - timer_start(1)
  - Results:
    - channel 0 fired at SW count    52941      - init:    52941
    - channel 1 fired at SW count   105868      - diff:    52927
    - channel 2 fired at SW count   158799      - diff:    52931
    - channel 3 fired at SW count   211729      - diff:    52930
  - Validating no spurious IRQs are triggered:
    [OK] (no spurious IRQs)

TEST SUCCEEDED

Issues/PRs references

None

Add an API to search for the frequency supported by a timer that
is closest to the given target frequency.

This is in fact non-trivial to get right, as pre-scaler registers can
be 16 bit or even 32 bit in size, making a naive loop over all possible
pre-scalers too expensive (computationally).
@maribu maribu added Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Apr 15, 2024
@github-actions github-actions bot added Area: tests Area: tests and testing framework Area: drivers Area: Device drivers labels Apr 15, 2024
@riot-ci
Copy link

riot-ci commented Apr 15, 2024

Murdock results

✔️ PASSED

555ab6a tests/periph/timer: test timer_get_closest_freq()

Success Failures Total Runtime
10040 0 10043 14m:00s

Artifacts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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 Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants