mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
af61cf40e3
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.
999 lines
38 KiB
C
999 lines
38 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 "flash_utils.h"
|
|
#include "irq.h"
|
|
#include "modules.h"
|
|
#include "mutex.h"
|
|
#include "periph/gpio_ll.h"
|
|
#include "periph/gpio_ll_irq.h"
|
|
#include "time_units.h"
|
|
#include "ztimer.h"
|
|
|
|
#ifndef LOW_ROM
|
|
#define LOW_ROM 0
|
|
#endif
|
|
|
|
/* On e.g. ATmega328P the smallest available GPIO Port is GPIO_PORT_1 (GPIOB),
|
|
* on others (e.g. nRF51) the highest available GPIO PORT is GPIO_PORT_0.
|
|
* So we need the following dance to find a valid GPIO port to allow compile
|
|
* testing. Extend the dance as needed, when new MCUs are added */
|
|
#if !defined(PORT_OUT)
|
|
# if defined(GPIO_PORT_0)
|
|
# define PORT_OUT GPIO_PORT_0
|
|
# define PORT_OUT_NUM 0
|
|
# elif defined(GPIO_PORT_1)
|
|
# define PORT_OUT GPIO_PORT_1
|
|
# define PORT_OUT_NUM 1
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined(PORT_IN)
|
|
# if defined(GPIO_PORT_0)
|
|
# define PORT_IN GPIO_PORT_0
|
|
# define PORT_IN_NUM 0
|
|
# elif defined(GPIO_PORT_1)
|
|
# define PORT_IN GPIO_PORT_1
|
|
# define PORT_IN_NUM 1
|
|
# endif
|
|
#endif
|
|
|
|
static const char *noyes[] = { "no", "yes" };
|
|
static gpio_port_t port_out = PORT_OUT;
|
|
static gpio_port_t port_in = PORT_IN;
|
|
|
|
static const uint64_t mutex_timeout = US_PER_MS;
|
|
|
|
#if LOW_ROM
|
|
static void puts_optional(const char *str)
|
|
{
|
|
(void)str;
|
|
}
|
|
#else
|
|
/* this is like puts() on most platforms, but e.g. on AVR safes lots of RAM by
|
|
* placing the string literal to puts in flash. */
|
|
#define puts_optional(str_literal) flash_puts(TO_FLASH(str_literal))
|
|
#endif
|
|
|
|
#if LOW_ROM
|
|
#define printf_optional(...) (void)0
|
|
#else
|
|
#define printf_optional(...) printf(__VA_ARGS__)
|
|
#endif
|
|
|
|
/* a custom expect that keeps the CPU alive makes debugging easier with
|
|
* stdio that requires RIOT to remain alive, e.g. USB CDC ACM */
|
|
static void expect_impl(int val, unsigned line)
|
|
{
|
|
if (!val) {
|
|
printf("expect failed at line %u\n", line);
|
|
fflush(stdout);
|
|
while(1) {}
|
|
}
|
|
}
|
|
|
|
#define expect(x) expect_impl((int)(x), __LINE__)
|
|
|
|
static void print_cabling(unsigned port1, unsigned pin1,
|
|
unsigned port2, unsigned pin2)
|
|
{
|
|
if (GPIO_PORT_NUMBERING_ALPHABETIC) {
|
|
/* alphabetic naming scheme */
|
|
printf(" P%c%u -- P%c%u\n", 'A' + (char)port1, pin1,
|
|
'A' + (char)port2, pin2);
|
|
}
|
|
else {
|
|
/* numeric naming scheme */
|
|
printf(" P%u.%u -- P%u.%u\n", port1, pin1, port2, pin2);
|
|
}
|
|
}
|
|
|
|
static void print_details(void)
|
|
{
|
|
puts_optional("Test / Hardware Details:\n"
|
|
"========================\n"
|
|
"Cabling:\n"
|
|
"(INPUT -- OUTPUT)");
|
|
print_cabling(PORT_IN_NUM, PIN_IN_0, PORT_OUT_NUM, PIN_OUT_0);
|
|
print_cabling(PORT_IN_NUM, PIN_IN_1, PORT_OUT_NUM, PIN_OUT_1);
|
|
printf("Number of pull resistor values supported: %u\n", GPIO_PULL_NUMOF);
|
|
printf("Number of drive strengths supported: %u\n", GPIO_DRIVE_NUMOF);
|
|
printf("Number of slew rates supported: %u\n", GPIO_SLEW_NUMOF);
|
|
puts("Valid GPIO ports:");
|
|
|
|
/* 64 GPIO ports ought to be enough for anybody */
|
|
for (uint_fast8_t i = 0; i < 64; i++) {
|
|
if (is_gpio_port_num_valid(i)) {
|
|
printf("- PORT %" PRIuFAST8 " (PORT %c)\n", i, 'A' + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_gpio_port_pack(void)
|
|
{
|
|
char stacked;
|
|
|
|
puts_optional("\n"
|
|
"Testing gpio_port_pack_addr()\n"
|
|
"=============================\n");
|
|
|
|
expect(gpio_port_unpack_addr(gpio_port_pack_addr(&stacked)) == &stacked);
|
|
expect(gpio_port_unpack_addr(gpio_port_pack_addr(noyes)) == noyes);
|
|
void *tmp = malloc(1);
|
|
expect(tmp);
|
|
expect(gpio_port_unpack_addr(gpio_port_pack_addr(tmp)) == tmp);
|
|
free(tmp);
|
|
expect(gpio_port_unpack_addr(port_in) == NULL);
|
|
expect(gpio_port_unpack_addr(port_out) == NULL);
|
|
puts_optional("All OK");
|
|
}
|
|
|
|
static void print_conf(gpio_conf_t conf)
|
|
{
|
|
gpio_ll_print_conf(conf);
|
|
puts("");
|
|
}
|
|
|
|
static void test_gpio_ll_init_input_configs(void)
|
|
{
|
|
bool is_supported;
|
|
puts_optional("\nTesting input configurations for PIN_IN_0:");
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pu));
|
|
printf_optional("Support for input with pull up: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_INPUT_PULL_UP));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_INPUT) && (conf.pull == GPIO_PULL_UP));
|
|
}
|
|
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pd));
|
|
printf_optional("Support for input with pull down: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_INPUT_PULL_DOWN));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_INPUT) && (conf.pull == GPIO_PULL_DOWN));
|
|
}
|
|
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pk));
|
|
printf_optional("Support for input with pull to bus level: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_INPUT_PULL_KEEP));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_INPUT) && (conf.pull == GPIO_PULL_KEEP));
|
|
}
|
|
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in));
|
|
printf_optional("Support for floating input (no pull resistors): %s\n",
|
|
noyes[is_supported]);
|
|
{
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_INPUT) && (conf.pull == GPIO_FLOATING));
|
|
}
|
|
/* Support for floating inputs is mandatory */
|
|
expect(is_supported);
|
|
}
|
|
|
|
static void test_gpio_ll_init_output_configs(void)
|
|
{
|
|
bool is_supported;
|
|
puts_optional("\nTesting output configurations for PIN_OUT_0:");
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_PUSH_PULL,
|
|
.initial_value = false,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (push-pull) with initial value of "
|
|
"LOW: %s\n",
|
|
noyes[is_supported]);
|
|
|
|
/* this is mandatory */
|
|
expect(is_supported);
|
|
{
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_PUSH_PULL) && !conf.initial_value);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed LOW: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
gpio_ll_set(port_out, (1ULL<< PIN_OUT_0));
|
|
conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can be pushed HIGH: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
expect((conf.state == GPIO_OUTPUT_PUSH_PULL) && conf.initial_value);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_PUSH_PULL,
|
|
.initial_value = true,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (push-pull) with initial value of "
|
|
"HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
|
|
/* this is mandatory */
|
|
expect(is_supported);
|
|
{
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_PUSH_PULL) && conf.initial_value);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed HIGH: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_DRAIN,
|
|
.initial_value = false,
|
|
.pull = GPIO_PULL_UP
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open drain with pull up) with initial "
|
|
"value of LOW: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_DRAIN_PULL_UP));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_DRAIN) && !conf.initial_value
|
|
&& (conf.pull == GPIO_PULL_UP));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed LOW: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_DRAIN,
|
|
.initial_value = true,
|
|
.pull = GPIO_PULL_UP
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open drain with pull up) with initial "
|
|
"value of HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_DRAIN_PULL_UP));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_DRAIN) && conf.initial_value
|
|
&& (conf.pull == GPIO_PULL_UP));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !!(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed HIGH: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_DRAIN,
|
|
.initial_value = false,
|
|
.pull = GPIO_FLOATING,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open drain) with initial value of "
|
|
"LOW: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_DRAIN));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_DRAIN) && !conf.initial_value
|
|
&& (conf.pull == GPIO_FLOATING));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed LOW: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_DRAIN,
|
|
.initial_value = true,
|
|
.pull = GPIO_FLOATING,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open drain) with initial value of "
|
|
"HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_DRAIN));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_DRAIN) && conf.initial_value
|
|
&& (conf.pull == GPIO_FLOATING));
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pd));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled LOW: %s\n",
|
|
noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull down of PIN_IN_0 to verify "
|
|
"correct Open Drain behavior");
|
|
}
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pu));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull up of PIN_IN_0 to verify "
|
|
"correct Open Drain behavior");
|
|
}
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_SOURCE,
|
|
.initial_value = false,
|
|
.pull = GPIO_FLOATING,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open source) with initial value of "
|
|
"LOW: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_SOURCE));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_SOURCE) && !conf.initial_value
|
|
&& (conf.pull == GPIO_FLOATING));
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pd));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled LOW: %s\n",
|
|
noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull down of PIN_IN_0 to verify "
|
|
"correct Open Source behavior");
|
|
}
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pu));
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_in, PIN_IN_0);
|
|
print_conf(conf);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull up of PIN_IN_0 to verify "
|
|
"correct Open Source behavior");
|
|
}
|
|
}
|
|
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in));
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_SOURCE,
|
|
.initial_value = true,
|
|
.pull = GPIO_FLOATING,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open source) with initial value of "
|
|
"HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_SOURCE));
|
|
|
|
if (is_supported) {
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
print_conf(conf);
|
|
expect((conf.state == GPIO_OUTPUT_OPEN_SOURCE) && conf.initial_value
|
|
&& (conf.pull == GPIO_FLOATING));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed HIGH: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_SOURCE,
|
|
.initial_value = true,
|
|
.pull = GPIO_PULL_DOWN,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open source with pull down) with initial "
|
|
"value of HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_SOURCE_PULL_DOWN));
|
|
|
|
if (is_supported) {
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed HIGH: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_OUTPUT_OPEN_SOURCE,
|
|
.initial_value = false,
|
|
.pull = GPIO_PULL_DOWN,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("Support for output (open source with pull down) with initial "
|
|
"value of LOW: %s\n",
|
|
noyes[is_supported]);
|
|
/* check if this matches compile time checks */
|
|
expect(is_supported == IS_USED(MODULE_PERIPH_GPIO_LL_OPEN_SOURCE_PULL_DOWN));
|
|
|
|
if (is_supported) {
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output is indeed LOW: %s\n", noyes[is_supported]);
|
|
expect(is_supported);
|
|
}
|
|
}
|
|
|
|
static void test_gpio_ll_init(void)
|
|
{
|
|
bool is_supported;
|
|
puts_optional("\n"
|
|
"Testing gpip_ng_init()\n"
|
|
"======================\n"
|
|
"\n"
|
|
"Testing is_gpio_port_num_valid() is true for PORT_OUT and "
|
|
"PORT_IN:");
|
|
expect(is_gpio_port_num_valid(PORT_IN_NUM));
|
|
expect(is_gpio_port_num_valid(PORT_OUT_NUM));
|
|
|
|
/* first, iterate through input configurations and test them one by one */
|
|
test_gpio_ll_init_input_configs();
|
|
|
|
/* second, iterate through output configurations and test them */
|
|
test_gpio_ll_init_output_configs();
|
|
|
|
/* finally, test disconnecting pins */
|
|
{
|
|
gpio_conf_t conf = {
|
|
.state = GPIO_DISCONNECT,
|
|
};
|
|
is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf));
|
|
}
|
|
printf_optional("\nSupport for disconnecting GPIO: %s\n", noyes[is_supported]);
|
|
/* This is mandatory */
|
|
expect(is_supported);
|
|
|
|
/* Ensure that gpio_ll_query_conf() correctly detects the state as
|
|
* disconnected. On MCUs that don't support this (e.g. ATmega),
|
|
* GPIO_DISCONNECT must be an alias of GPIO_INPUT. */
|
|
{
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
gpio_ll_print_conf(conf);
|
|
puts("");
|
|
expect(conf.state == GPIO_DISCONNECT);
|
|
}
|
|
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pd));
|
|
if (is_supported) {
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = !(gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled LOW: %s\n",
|
|
noyes[is_supported]);
|
|
/* If this expects fails, try with a different pin. Often pins intended
|
|
* for use as UART, I2C, or hardware /CS on SPI cannot be configured
|
|
* as high impedance and will instead remain HIGH. An implementation
|
|
* is free to work around this e.g. by configuring these pins as
|
|
* input with the input buffer disabled or as analog input without
|
|
* routing them to the ADC, or just to restore the reset configuration
|
|
* and have them high.
|
|
*
|
|
* Even though this can fail on some pins, the `expect()` here should
|
|
* remain. Just test with a different pin that can be configured as
|
|
* high impedance to confirm that this functionality does work where
|
|
* supported. */
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull down of PIN_IN_0 to verify "
|
|
"correct disabled behavior");
|
|
}
|
|
is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in_pu));
|
|
if (is_supported) {
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
is_supported = (gpio_ll_read(port_in) & (1ULL << PIN_IN_0));
|
|
printf_optional("Output can indeed be pulled HIGH: %s\n",
|
|
noyes[is_supported]);
|
|
/* May also fail for some pins, if the reset configuration of the
|
|
* pin results in LOW output. Do not comment this out, but rather
|
|
* try with a different pin to confirm that this functionality does
|
|
* work where supported */
|
|
expect(is_supported);
|
|
}
|
|
else {
|
|
puts_optional("WARN: Cannot enable pull up of PIN_IN_0 to verify "
|
|
"correct disabled behavior");
|
|
}
|
|
}
|
|
|
|
static void test_input_output(void)
|
|
{
|
|
puts_optional("\n"
|
|
"Testing Reading/Writing GPIO Ports\n"
|
|
"==================================\n");
|
|
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in));
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_1, gpio_ll_in));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, gpio_ll_out));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, gpio_ll_out));
|
|
|
|
uword_t mask_in_0 = (1UL << PIN_IN_0);
|
|
uword_t mask_in_1 = (1UL << PIN_IN_1);
|
|
uword_t mask_in_both = mask_in_0 | mask_in_1;
|
|
uword_t mask_out_both = (1UL << PIN_OUT_0) | (1UL << PIN_OUT_1);
|
|
|
|
puts_optional("testing initial value of 0 after init");
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(0x00 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing setting both outputs_optional simultaneously");
|
|
gpio_ll_set(port_out, (1UL << PIN_OUT_0) | (1UL << PIN_OUT_1));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(mask_in_both == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing clearing both outputs_optional simultaneously");
|
|
gpio_ll_clear(port_out, (1UL << PIN_OUT_0) | (1UL << PIN_OUT_1));
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(0x00 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing toggling first output (0 --> 1)");
|
|
gpio_ll_toggle(port_out, 1UL << PIN_OUT_0);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(mask_in_0 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing toggling first output (1 --> 0)");
|
|
gpio_ll_toggle(port_out, 1UL << PIN_OUT_0);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(0x00 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing toggling second output (0 --> 1)");
|
|
gpio_ll_toggle(port_out, 1UL << PIN_OUT_1);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(mask_in_1 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing toggling second output (1 --> 0)");
|
|
gpio_ll_toggle(port_out, 1UL << PIN_OUT_1);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(0x00 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("testing setting first output and clearing second with "
|
|
"write");
|
|
/* Preventing side-effects on output GPIO port due to changes on unrelated
|
|
* pins between the calls to gpio_ll_prepare_write() and gpio_ll_write()
|
|
* by disabling IRQs. Better safe than sorry. */
|
|
unsigned irq_state = irq_disable();
|
|
gpio_ll_write(port_out, gpio_ll_prepare_write(port_out, mask_out_both,
|
|
1UL << PIN_OUT_0));
|
|
irq_restore(irq_state);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
expect(mask_in_0 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
irq_state = irq_disable();
|
|
gpio_ll_write(port_out, gpio_ll_prepare_write(port_out, mask_out_both,
|
|
1UL << PIN_OUT_1));
|
|
irq_restore(irq_state);
|
|
puts_optional("testing setting second output and clearing first with "
|
|
"write");
|
|
expect(mask_in_1 == (gpio_ll_read(port_in) & mask_in_both));
|
|
puts_optional("...OK");
|
|
|
|
puts_optional("All input/output operations worked as expected");
|
|
}
|
|
|
|
static void irq_edge_cb(void *mut)
|
|
{
|
|
mutex_unlock(mut);
|
|
}
|
|
|
|
static void test_irq_edge(void)
|
|
{
|
|
mutex_t irq_mut = MUTEX_INIT_LOCKED;
|
|
|
|
puts_optional("Testing rising edge on PIN_IN_0");
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_EDGE_RISING,
|
|
irq_edge_cb, &irq_mut));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
/* test for IRQ on rising edge */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
/* test for no IRQ on falling edge */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
puts_optional("... OK");
|
|
|
|
puts_optional("Testing falling edge on PIN_IN_0");
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_EDGE_FALLING,
|
|
irq_edge_cb, &irq_mut));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
/* test for no IRQ on rising edge */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
/* test for IRQ on falling edge */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
puts_optional("... OK");
|
|
|
|
puts_optional("Testing both edges on PIN_IN_0");
|
|
if (IS_USED(MODULE_PERIPH_GPIO_LL_IRQ_EDGE_TRIGGERED_BOTH)) {
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_EDGE_BOTH,
|
|
irq_edge_cb, &irq_mut));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
/* test for IRQ on rising edge */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
/* test for IRQ on falling edge */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
puts_optional("... OK");
|
|
}
|
|
else {
|
|
puts_optional("... SKIPPED (not supported)");
|
|
}
|
|
|
|
puts_optional("Testing masking of IRQs (still both edges on PIN_IN_0)");
|
|
gpio_ll_irq_mask(port_in, PIN_IN_0);
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
/* test for no IRQ while masked */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_irq_unmask_and_clear(port_in, PIN_IN_0);
|
|
/* test for IRQ of past event is cleared */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* testing for normal behavior after unmasked */
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
#if MODULE_PERIPH_GPIO_LL_IRQ_UNMASK
|
|
gpio_ll_irq_mask(port_in, PIN_IN_0);
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
/* test for no IRQ while masked */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
gpio_ll_irq_unmask(port_in, PIN_IN_0);
|
|
/* test for IRQ of past event */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &irq_mut,
|
|
mutex_timeout));
|
|
#endif
|
|
puts_optional("... OK");
|
|
gpio_ll_irq_off(port_in, PIN_IN_0);
|
|
}
|
|
|
|
struct irq_level_cb_arg {
|
|
mutex_t mutex;
|
|
unsigned counter;
|
|
enum {
|
|
LOW,
|
|
HIGH
|
|
} trigger_level;
|
|
};
|
|
|
|
__attribute__((unused))
|
|
static void irq_level_cb(void *_arg)
|
|
{
|
|
struct irq_level_cb_arg *arg = _arg;
|
|
|
|
if (!arg->counter) {
|
|
if (arg->trigger_level == HIGH) {
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
}
|
|
else {
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
}
|
|
mutex_unlock(&arg->mutex);
|
|
}
|
|
else {
|
|
arg->counter--;
|
|
}
|
|
}
|
|
|
|
static void test_irq_level(void)
|
|
{
|
|
struct irq_level_cb_arg arg = { .mutex = MUTEX_INIT_LOCKED, .counter = 10 };
|
|
|
|
if (IS_USED(MODULE_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH)) {
|
|
arg.trigger_level = HIGH;
|
|
puts_optional("Testing level-triggered on HIGH on PIN_IN_0 (when input "
|
|
"is LOW when setting up IRQ)");
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_LEVEL_HIGH,
|
|
irq_level_cb, &arg));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for 10 level triggered IRQs on high */
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
gpio_ll_irq_off(port_in, PIN_IN_0);
|
|
puts_optional("... OK");
|
|
|
|
puts_optional("Testing level-triggered on HIGH on PIN_IN_0 (when input "
|
|
"is HIGH when setting up IRQ)");
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_LEVEL_HIGH,
|
|
irq_level_cb, &arg));
|
|
/* test for 10 level triggered IRQs */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
gpio_ll_irq_off(port_in, PIN_IN_0);
|
|
puts_optional("... OK");
|
|
}
|
|
|
|
if (IS_USED(MODULE_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW)) {
|
|
arg.trigger_level = LOW;
|
|
puts_optional("Testing level-triggered on LOW on PIN_IN_0 (when input "
|
|
"is HIGH when setting up IRQ)");
|
|
gpio_ll_set(port_out, 1UL << PIN_OUT_0);
|
|
arg.counter = 10;
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_LEVEL_LOW,
|
|
irq_level_cb, &arg));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for 10 level triggered IRQs on low */
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
gpio_ll_irq_off(port_in, PIN_IN_0);
|
|
puts_optional("... OK");
|
|
|
|
puts_optional("Testing level-triggered on LOW on PIN_IN_0 (when input "
|
|
"is LOW when setting up IRQ)");
|
|
gpio_ll_clear(port_out, 1UL << PIN_OUT_0);
|
|
arg.counter = 10;
|
|
expect(0 == gpio_ll_irq(port_in, PIN_IN_0, GPIO_TRIGGER_LEVEL_LOW,
|
|
irq_level_cb, &arg));
|
|
/* test for 10 level triggered IRQs */
|
|
expect(0 == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
/* test for spurious IRQ */
|
|
expect(-ECANCELED == ztimer_mutex_lock_timeout(ZTIMER_USEC, &arg.mutex,
|
|
mutex_timeout));
|
|
gpio_ll_irq_off(port_in, PIN_IN_0);
|
|
puts_optional("... OK");
|
|
}
|
|
}
|
|
|
|
static void test_irq(void)
|
|
{
|
|
puts_optional("\n"
|
|
"Testing External IRQs\n"
|
|
"=====================\n");
|
|
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, gpio_ll_out));
|
|
|
|
test_irq_edge();
|
|
test_irq_level();
|
|
}
|
|
|
|
static void test_switch_dir(void)
|
|
{
|
|
bool test_passed;
|
|
puts_optional("\n"
|
|
"Testing Switching Direction\n"
|
|
"===========================\n");
|
|
|
|
uword_t mask_out = 1U << PIN_OUT_0;
|
|
uword_t pins_out = gpio_ll_prepare_switch_dir(mask_out);
|
|
uword_t mask_in = 1U << PIN_IN_0;
|
|
|
|
/* floating input must be supported by every MCU */
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in));
|
|
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, gpio_ll_in));
|
|
gpio_conf_t conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
expect(conf.state == GPIO_INPUT);
|
|
gpio_conf_t conf_orig = conf;
|
|
|
|
/* conf_orig.initial_value contains the current value in query_conf.
|
|
* Since this is a floating input connected to a floating input, it is
|
|
* random here. ==> Clear it. */
|
|
conf_orig.initial_value = false;
|
|
|
|
/* capture output state before switching from input mode to output mode, so
|
|
* that it can be restored when switching back to input mode */
|
|
uword_t out_state = gpio_ll_read_output(port_out);
|
|
|
|
/* now, switch to output mode and verify the switch */
|
|
gpio_ll_switch_dir_output(port_out, pins_out);
|
|
conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
test_passed = (conf.state == GPIO_OUTPUT_PUSH_PULL);
|
|
printf_optional("Input pin can be switched to output (push-pull) mode: %s\n",
|
|
noyes[test_passed]);
|
|
expect(test_passed);
|
|
|
|
gpio_ll_clear(port_out, mask_out);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
test_passed = (0 == (gpio_ll_read(port_in) & mask_in));
|
|
gpio_ll_set(port_out, mask_out);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
test_passed = test_passed && (gpio_ll_read(port_in) & mask_in);
|
|
printf_optional("Pin behaves as output after switched to output mode: %s\n",
|
|
noyes[test_passed]);
|
|
expect(test_passed);
|
|
|
|
/* switch back to input mode */
|
|
gpio_ll_switch_dir_input(port_out, pins_out);
|
|
/* restore out state from before the switch */
|
|
gpio_ll_write(port_out, out_state);
|
|
/* verify we are back at the old config */
|
|
conf = gpio_ll_query_conf(port_out, PIN_OUT_0);
|
|
/* again, initial_value is random due to floating input ==> clear it */
|
|
conf.initial_value = false;
|
|
test_passed = (conf.bits == conf_orig.bits);
|
|
printf_optional("Returning back to input had no side effects on config: %s\n",
|
|
noyes[test_passed]);
|
|
if (!test_passed) {
|
|
puts_optional("Before:");
|
|
print_conf(conf_orig);
|
|
puts_optional("After:");
|
|
print_conf(conf);
|
|
expect(0);
|
|
}
|
|
|
|
/* Finally: check if input behaves like a proper input. For that, we
|
|
* configure the pin it is connected to (PORT_IN.PIN_IN_0) as output and
|
|
* see if we can read that from the pin used to switch back and force */
|
|
expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_out));
|
|
|
|
gpio_ll_clear(port_in, mask_in);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
test_passed = (0 == (gpio_ll_read(port_out) & mask_out));
|
|
gpio_ll_set(port_in, mask_in);
|
|
ztimer_sleep(ZTIMER_USEC, US_PER_MS);
|
|
test_passed = test_passed && (gpio_ll_read(port_out) & mask_out);
|
|
printf_optional("Pin behaves as input after switched back to input mode: %s\n",
|
|
noyes[test_passed]);
|
|
expect(test_passed);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
print_details();
|
|
test_gpio_port_pack();
|
|
test_gpio_ll_init();
|
|
test_input_output();
|
|
if (IS_USED(MODULE_PERIPH_GPIO_LL_IRQ)) {
|
|
test_irq();
|
|
}
|
|
|
|
if (IS_USED(MODULE_PERIPH_GPIO_LL_SWITCH_DIR)) {
|
|
test_switch_dir();
|
|
}
|
|
|
|
/* if no expect() didn't blow up until now, the test is passed */
|
|
|
|
puts("\n\nTEST SUCCEEDED");
|
|
return 0;
|
|
}
|