1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/tests/bench/periph_gpio_ll
Marian Buschsieweke 36e8526046
drivers/periph_gpio_ll: change API to access GPIO ports
The API was based on the assumption that GPIO ports are mapped in memory
sanely, so that a `GPIO_PORT(num)` macro would work allow for constant
folding when `num` is known and still be efficient when it is not.

Some MCUs, however, will need a look up tables to efficiently translate
GPIO port numbers to the port's base address. This will prevent the use
of such a `GPIO_PORT(num)` macro in constant initializers.

As a result, we rather provide `GPIO_PORT_0`, `GPIO_PORT_1`, etc. macros
for each GPIO port present (regardless of MCU naming scheme), as well as
`GPIO_PORT_A`, `GPIO_PORT_B`, etc. macros if (and only if) the MCU port
naming scheme uses letters rather than numbers.

These can be defined as macros to the peripheral base address even when
those are randomly mapped into the address space. In addition, a C
function `gpio_port()` replaces the role of the `GPIO_PORT()` and
`gpio_port_num()` the `GPIO_PORT_NUM()` macro. Those functions will
still be implemented as efficient as possible and will allow constant
folding where it was formerly possible. Hence, there is no downside for
MCUs with sane peripheral memory mapping, but it is highly beneficial
for the crazy ones.

There are also two benefits for the non-crazy MCUs:
1. We can now test for valid port numbers with `#ifdef GPIO_PORT_<NUM>`
    - This directly benefits the test in `tests/periph/gpio_ll`, which
      can now provide a valid GPIO port for each and every board
    - Writing to invalid memory mapped I/O addresses was treated as
      triggering undefined behavior by the compiler and used as a
      optimization opportunity
2. We can now detect at compile time if the naming scheme of the MCU
   uses letters or numbers, and produce more user friendly output.
    - This is directly applied in the test app
2024-08-02 09:55:24 +02:00
..
tests-with-config tests: move bench_ applications to bench/ subdirectory 2023-05-10 09:49:56 +02:00
.gitignore tests: move bench_ applications to bench/ subdirectory 2023-05-10 09:49:56 +02:00
main.c drivers/periph_gpio_ll: change API to access GPIO ports 2024-08-02 09:55:24 +02:00
Makefile drivers/periph_gpio_ll: change API to access GPIO ports 2024-08-02 09:55:24 +02:00
Makefile.ci examples and tests: add atmega8 to relevent Makefile.ci 2023-07-11 21:22:02 +02:00
README.md tests: move bench_ applications to bench/ subdirectory 2023-05-10 09:49:56 +02:00

Benchmark for periph/gpio_ll

This application will generate a square wave on two output pins with a phase difference of zero between them using both the periph/gpio API (as reference) and the periph/gpio_ll API. You can use a logic analyzer or scope to verify that the square waves are indeed simultaneous (no phase difference) and their frequency. Note that with the pin based periph/gpio API a phase difference is expected, but not for the port based periph/gpio_ll API.

In addition, a timer is used to measure the average frequency over 50,000 square wave periods. The overhead of the loop is estimated and a compensated frequency (that would be achievable only by unrolling the loop) is calculated. Both frequencies are printed, in addition to the number of CPU cycles per wave period. The optimal value is 2 CPU cycles (signal is 1 cycle high and 1 cycle low).

Configuration

Configure in the Makefile or set via environment variables the number of the GPIO port to use via the PORT_OUT variable. The PIN_OUT_0 and PIN_OUT_1 variables select the pins to use within that GPIO port. If possible, choose a GPIO port that is fully broken out to pins of your board but left unconnected. That way you can connect a scope or a logic analyzer to verify the output.

Note that the test using gpio_ll_write() might cause changes to unrelated pins on the PORT_OUT GPIO port, by restoring their value to what it was at the beginning of the benchmark.

FAQ

Why are 4 functions calls used for periph/gpio, but only 2 for periph/gpio_ll? This isn't fair!

Since in a port based APIs multiple pins can be accessed at once, only two accesses are needed (one for the high and one for the low part of each square wave period). In the pin based periph/gpio API, two accesses are needed per pin. This unfair advantage in speed is one of the reasons we want a low level port based API in RIOT - in addition to a more convenient to use and high level pin based API.