mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
295 lines
9.0 KiB
C
295 lines
9.0 KiB
C
/*
|
|
* Copyright (C) 2021 Otto-von-Guericke-Universität Magdeburg
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup tests
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Test application for the Peripheral GPIO Low-Level API
|
|
*
|
|
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "mutex.h"
|
|
#include "periph/gpio.h"
|
|
#include "periph/gpio_ll.h"
|
|
#include "test_utils/expect.h"
|
|
#include "ztimer.h"
|
|
#include "timex.h"
|
|
|
|
#ifndef COMPENSATE_OVERHEAD
|
|
#define COMPENSATE_OVERHEAD 1
|
|
#endif
|
|
|
|
static gpio_port_t port_out = GPIO_PORT(PORT_OUT);
|
|
|
|
static void print_summary_compensated(uint_fast16_t loops, uint32_t duration,
|
|
uint32_t duration_uncompensated)
|
|
{
|
|
printf("%" PRIuFAST16 " iterations took %" PRIu32 " us "
|
|
"(%" PRIu32 " us uncompensated)\n",
|
|
loops, duration, duration_uncompensated);
|
|
printf("Two square waves pins at %12" PRIu32 " Hz "
|
|
"(%12" PRIu32 " Hz uncompensated)\n",
|
|
(uint32_t)((uint64_t)US_PER_SEC * loops / duration),
|
|
(uint32_t)((uint64_t)US_PER_SEC * loops / duration_uncompensated));
|
|
#ifdef CLOCK_CORECLOCK
|
|
uint64_t divisor = (uint64_t)US_PER_SEC * loops / CLOCK_CORECLOCK;
|
|
uint32_t cycles = (duration + divisor / 2) / divisor;
|
|
uint32_t cycles_uncompensated = (duration_uncompensated + divisor / 2)
|
|
/ divisor;
|
|
printf("~%" PRIu32 " CPU cycles per square wave period "
|
|
"(~%" PRIu32 " cycles uncompensated)\n",
|
|
cycles, cycles_uncompensated);
|
|
if (cycles <= 2) {
|
|
puts(":-D");
|
|
}
|
|
else if (cycles <= 4) {
|
|
puts(":-)");
|
|
}
|
|
else if (cycles <= 8) {
|
|
puts(":-|");
|
|
}
|
|
else if (cycles <= 16) {
|
|
puts(":-(");
|
|
}
|
|
else {
|
|
puts(":'-(");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void print_summary_uncompensated(uint_fast16_t loops, uint32_t duration)
|
|
{
|
|
printf("%" PRIuFAST16 " iterations took %" PRIu32 " us\n",
|
|
loops, duration);
|
|
printf("Two square waves pins at %12" PRIu32 " Hz\n",
|
|
(uint32_t)((uint64_t)US_PER_SEC * loops / duration));
|
|
#ifdef CLOCK_CORECLOCK
|
|
uint64_t divisor = (uint64_t)US_PER_SEC * loops / CLOCK_CORECLOCK;
|
|
uint32_t cycles = (duration + divisor / 2) / divisor;
|
|
printf("~%" PRIu32 " CPU cycles per square wave period\n", cycles);
|
|
if (cycles <= 2) {
|
|
puts(":-D");
|
|
}
|
|
else if (cycles <= 4) {
|
|
puts(":-)");
|
|
}
|
|
else if (cycles <= 8) {
|
|
puts(":-|");
|
|
}
|
|
else if (cycles <= 16) {
|
|
puts(":-(");
|
|
}
|
|
else {
|
|
puts(":'-(");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
static const uint_fast16_t loops = 50000;
|
|
uint32_t loop_overhead = 0;
|
|
|
|
uword_t mask_both = (1U << PIN_OUT_0) | (1U << PIN_OUT_1);
|
|
|
|
puts("\n"
|
|
"Benchmarking GPIO APIs\n"
|
|
"======================");
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
puts("\n"
|
|
"estimating loop overhead for compensation\n"
|
|
"-----------------------------------------");
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
__asm__ volatile ("" : : : );
|
|
}
|
|
loop_overhead = ztimer_now(ZTIMER_USEC) - start;
|
|
printf("%" PRIu32 " us for %" PRIuFAST16 " iterations\n",
|
|
loop_overhead, loops);
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio: Using 2x gpio_set() and 2x gpio_clear()\n"
|
|
"---------------------------------------------------");
|
|
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
|
|
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
|
|
gpio_init(p0, GPIO_OUT);
|
|
gpio_init(p1, GPIO_OUT);
|
|
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_set(p0);
|
|
gpio_set(p1);
|
|
gpio_clear(p0);
|
|
gpio_clear(p1);
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio_ll: Using gpio_ll_set() and gpio_ll_clear()\n"
|
|
"-------------------------------------------------------");
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_PUSH_PULL,
|
|
.slew_rate = GPIO_SLEW_FASTEST
|
|
};
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));
|
|
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_ll_set(port_out, (1UL << PIN_OUT_0) | (1UL << PIN_OUT_1));
|
|
gpio_ll_clear(port_out, (1UL << PIN_OUT_0) | (1UL << PIN_OUT_1));
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio: Using 4x gpio_toggle()\n"
|
|
"-----------------------------------");
|
|
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
|
|
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
|
|
gpio_init(p0, GPIO_OUT);
|
|
gpio_init(p1, GPIO_OUT);
|
|
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_toggle(p0);
|
|
gpio_toggle(p1);
|
|
gpio_toggle(p0);
|
|
gpio_toggle(p1);
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio_ll: Using 2x gpio_ll_toggle()\n"
|
|
"-----------------------------------------");
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_PUSH_PULL,
|
|
.slew_rate = GPIO_SLEW_FASTEST
|
|
};
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));
|
|
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_ll_toggle(port_out, mask_both);
|
|
gpio_ll_toggle(port_out, mask_both);
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio: Using 4x gpio_write()\n"
|
|
"----------------------------------");
|
|
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
|
|
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
|
|
gpio_init(p0, GPIO_OUT);
|
|
gpio_init(p1, GPIO_OUT);
|
|
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_write(p0, 1);
|
|
gpio_write(p1, 1);
|
|
gpio_write(p0, 0);
|
|
gpio_write(p1, 0);
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
{
|
|
puts("\n"
|
|
"periph/gpio_ll: Using 2x gpio_ll_write()\n"
|
|
"----------------------------------------");
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_PUSH_PULL,
|
|
.slew_rate = GPIO_SLEW_FASTEST
|
|
};
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));
|
|
|
|
uword_t both_high = gpio_ll_prepare_write(port_out, mask_both,
|
|
mask_both);
|
|
uword_t both_low = gpio_ll_prepare_write(port_out, mask_both, 0);
|
|
uint32_t start = ztimer_now(ZTIMER_USEC);
|
|
for (uint_fast16_t i = loops; i > 0; i--) {
|
|
gpio_ll_write(port_out, both_high);
|
|
gpio_ll_write(port_out, both_low);
|
|
}
|
|
uint32_t duration = ztimer_now(ZTIMER_USEC) - start;
|
|
|
|
if (COMPENSATE_OVERHEAD) {
|
|
print_summary_compensated(loops, duration - loop_overhead,
|
|
duration);
|
|
}
|
|
else {
|
|
print_summary_uncompensated(loops, duration);
|
|
}
|
|
}
|
|
|
|
puts("\n\nTEST SUCCEEDED");
|
|
return 0;
|
|
}
|