diff --git a/cpu/atmega_common/Makefile.features b/cpu/atmega_common/Makefile.features index 607d875bed..a7255a0110 100644 --- a/cpu/atmega_common/Makefile.features +++ b/cpu/atmega_common/Makefile.features @@ -8,6 +8,7 @@ FEATURES_PROVIDED += atmega_pcint0 FEATURES_PROVIDED += periph_eeprom FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low FEATURES_PROVIDED += periph_gpio_ll_irq_unmask diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h index bf6627072f..3b5a5756b9 100644 --- a/cpu/atmega_common/include/periph_cpu_common.h +++ b/cpu/atmega_common/include/periph_cpu_common.h @@ -231,6 +231,16 @@ typedef enum { GPIO_TRIGGER_LEVEL_HIGH = 0xff, /**< not supported */ } gpio_irq_trig_t; +#define HAVE_GPIO_STATE_T +typedef enum { + GPIO_INPUT, + GPIO_OUTPUT_PUSH_PULL, + GPIO_OUTPUT_OPEN_DRAIN, /**< not supported */ + GPIO_OUTPUT_OPEN_SOURCE, /**< not supported */ + GPIO_USED_BY_PERIPHERAL, /**< not supported */ + GPIO_DISCONNECT = GPIO_INPUT, +} gpio_state_t; + #define HAVE_GPIO_LL_PREPARE_WRITE_ALL_PINS #define HAVE_GPIO_LL_PREPARE_WRITE diff --git a/cpu/atmega_common/periph/gpio_ll.c b/cpu/atmega_common/periph/gpio_ll.c index 3bd5eec653..f47beb5a60 100644 --- a/cpu/atmega_common/periph/gpio_ll.c +++ b/cpu/atmega_common/periph/gpio_ll.c @@ -40,7 +40,7 @@ static void _set_dir(gpio_port_t port, uint8_t pin, bool output) p->ddr |= 1U << pin; } else { - p-> ddr &= ~(1U << pin); + p->ddr &= ~(1U << pin); } } @@ -59,8 +59,7 @@ static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull) int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) { if ((conf.pull > GPIO_PULL_UP) - || (conf.state == GPIO_OUTPUT_OPEN_DRAIN) - || (conf.state == GPIO_OUTPUT_OPEN_SOURCE)) { + || (conf.state > GPIO_OUTPUT_PUSH_PULL)) { return -ENOTSUP; } diff --git a/cpu/efm32/Makefile.features b/cpu/efm32/Makefile.features index 9b3a77314a..536dd070c9 100644 --- a/cpu/efm32/Makefile.features +++ b/cpu/efm32/Makefile.features @@ -18,6 +18,13 @@ FEATURES_PROVIDED += periph_flashpage_in_address_space FEATURES_PROVIDED += periph_flashpage_pagewise FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_disconnect +FEATURES_PROVIDED += periph_gpio_ll_input_pull_down +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up +FEATURES_PROVIDED += periph_gpio_ll_open_drain +FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up +FEATURES_PROVIDED += periph_gpio_ll_open_source +FEATURES_PROVIDED += periph_gpio_ll_open_source_pull_down FEATURES_PROVIDED += periph_rtt_set_counter FEATURES_PROVIDED += periph_rtt_overflow FEATURES_PROVIDED += periph_uart_modecfg diff --git a/cpu/efm32/periph/gpio_ll.c b/cpu/efm32/periph/gpio_ll.c index a771b871c0..4cb2a5b0e8 100644 --- a/cpu/efm32/periph/gpio_ll.c +++ b/cpu/efm32/periph/gpio_ll.c @@ -34,8 +34,8 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) switch (conf.state) { case GPIO_DISCONNECT: - /* ignoring pull */ mode = gpioModeDisabled; + initial = (conf.pull == GPIO_PULL_UP); break; case GPIO_INPUT: switch (conf.pull) { @@ -135,6 +135,9 @@ gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) /* Fall-through: There is no error reporting here */ default: result.state = GPIO_DISCONNECT; + if (GPIO_PinOutGet(port, pin)) { + result.pull = GPIO_PULL_UP; + } break; } diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index dcc8dba6be..dfd91e25b0 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -22,9 +22,14 @@ FEATURES_PROVIDED += periph_flashpage FEATURES_PROVIDED += periph_flashpage_in_address_space FEATURES_PROVIDED += periph_flashpage_pagewise FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_disconnect +FEATURES_PROVIDED += periph_gpio_ll_input_pull_down +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low +FEATURES_PROVIDED += periph_gpio_ll_open_drain +FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up FEATURES_PROVIDED += periph_spi_reconfigure FEATURES_PROVIDED += puf_sram diff --git a/cpu/gd32v/Makefile.features b/cpu/gd32v/Makefile.features index 00c8d4c87b..0d630145b3 100644 --- a/cpu/gd32v/Makefile.features +++ b/cpu/gd32v/Makefile.features @@ -5,9 +5,13 @@ FEATURES_PROVIDED += periph_clic FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_gpio_irq FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_disconnect +FEATURES_PROVIDED += periph_gpio_ll_input_pull_down +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low +FEATURES_PROVIDED += periph_gpio_ll_open_drain FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtc_mem FEATURES_PROVIDED += periph_rtt diff --git a/cpu/gd32v/include/periph_cpu.h b/cpu/gd32v/include/periph_cpu.h index ec6e437610..bec2001cb0 100644 --- a/cpu/gd32v/include/periph_cpu.h +++ b/cpu/gd32v/include/periph_cpu.h @@ -239,7 +239,7 @@ typedef union gpio_conf_gd32v gpio_conf_t; * @ingroup drivers_periph_gpio_ll */ union gpio_conf_gd32v { - uint16_t bits; /**< the raw bits */ + uint8_t bits; /**< the raw bits */ struct { /** * @brief State of the pin @@ -259,18 +259,6 @@ union gpio_conf_gd32v { * configured to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN. */ gpio_slew_t slew_rate : 2; - /** - * @brief Whether to disable the input Schmitt trigger - * - * @details This could be called `schmitt_trigger` with inverse - * meaning, but the API contract says that additional - * members in the structure should have a sane - * default when zero. - * - * This value is ignored *unless* @ref gpio_conf_stm32::state is - * configured to @ref GPIO_INPUT. - */ - bool schmitt_trigger_disabled : 1; /** * @brief Initial value of the output * @@ -285,7 +273,6 @@ union gpio_conf_gd32v { * consulted. */ bool initial_value : 1; - uint8_t : 7; /*< padding */ }; }; diff --git a/cpu/gd32v/periph/gpio_ll.c b/cpu/gd32v/periph/gpio_ll.c index 375c010863..72de29352b 100644 --- a/cpu/gd32v/periph/gpio_ll.c +++ b/cpu/gd32v/periph/gpio_ll.c @@ -60,7 +60,6 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) switch (conf.state) { case GPIO_DISCONNECT: - *ctrl |= 0x1 << (pos + 2); pin_used[GPIO_PORT_NUM(port)] &= ~(1 << pin); if (pin_used[GPIO_PORT_NUM(port)] == 0) { periph_clk_dis(APB2, (RCU_APB2EN_PAEN_Msk << GPIO_PORT_NUM(port))); @@ -121,14 +120,14 @@ gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) result.state = GPIO_INPUT; switch (ctrl) { case 0: - result.state = GPIO_USED_BY_PERIPHERAL; + result.state = GPIO_DISCONNECT; break; case 1: result.pull = GPIO_FLOATING; break; case 2: result.pull = (((GPIO_Type *)port)->OCTL & (1UL << pin)) ? GPIO_PULL_UP - : GPIO_PULL_DOWN; + : GPIO_PULL_DOWN; break; default: break; @@ -173,8 +172,4 @@ void gpio_ll_print_conf(gpio_conf_t conf) gpio_ll_print_conf_common(conf); print_str(", slew: "); print_str(slew_strs[conf.slew_rate]); - - if (conf.schmitt_trigger_disabled) { - print_str(", Schmitt trigger disabled"); - } } diff --git a/cpu/nrf5x_common/Makefile.features b/cpu/nrf5x_common/Makefile.features index 7f6fdfdd07..2779a60656 100644 --- a/cpu/nrf5x_common/Makefile.features +++ b/cpu/nrf5x_common/Makefile.features @@ -11,7 +11,16 @@ FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_wdt periph_wdt_cb ifeq (,$(filter nrf5340_app,$(CPU_MODEL))) -FEATURES_PROVIDED += periph_gpio_ll periph_gpio_ll_irq periph_gpio_ll_irq_unmask + FEATURES_PROVIDED += periph_gpio_ll + FEATURES_PROVIDED += periph_gpio_ll_disconnect + FEATURES_PROVIDED += periph_gpio_ll_input_pull_down + FEATURES_PROVIDED += periph_gpio_ll_input_pull_up + FEATURES_PROVIDED += periph_gpio_ll_irq + FEATURES_PROVIDED += periph_gpio_ll_irq_unmask + FEATURES_PROVIDED += periph_gpio_ll_open_drain + FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up + FEATURES_PROVIDED += periph_gpio_ll_open_source + FEATURES_PROVIDED += periph_gpio_ll_open_source_pull_down endif # nRF9160/nRF5340 don't support these drivers right now diff --git a/cpu/sam0_common/Makefile.features b/cpu/sam0_common/Makefile.features index 43d620c6f9..8915115c6b 100644 --- a/cpu/sam0_common/Makefile.features +++ b/cpu/sam0_common/Makefile.features @@ -14,6 +14,9 @@ FEATURES_PROVIDED += periph_flashpage_pagewise FEATURES_PROVIDED += periph_flashpage_rwee FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_disconnect +FEATURES_PROVIDED += periph_gpio_ll_input_pull_down +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index 1ff35af515..314e36380a 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -13,9 +13,17 @@ FEATURES_PROVIDED += periph_rtt_overflow FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_uart_nonblocking FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_disconnect +FEATURES_PROVIDED += periph_gpio_ll_input_pull_down +FEATURES_PROVIDED += periph_gpio_ll_input_pull_up FEATURES_PROVIDED += periph_gpio_ll_irq FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low +FEATURES_PROVIDED += periph_gpio_ll_open_drain + +ifneq (f1,$(CPU_FAM)) + FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up +endif ifneq (,$(filter $(CPU_FAM),c0 f0 f1 f3 g0 g4 l0 l1 l4 l5 u5 wb wl)) FEATURES_PROVIDED += periph_flashpage diff --git a/cpu/stm32/include/periph/cpu_gpio_ll.h b/cpu/stm32/include/periph/cpu_gpio_ll.h index 741604048e..454bfc2123 100644 --- a/cpu/stm32/include/periph/cpu_gpio_ll.h +++ b/cpu/stm32/include/periph/cpu_gpio_ll.h @@ -102,14 +102,33 @@ typedef enum { GPIO_TRIGGER_LEVEL_LOW = GPIO_TRIGGER_LEVEL | GPIO_TRIGGER_EDGE_FALLING, } gpio_irq_trig_t; +/** + * @brief Possible modes to write to the STM32 GPIOx MODER register + */ +typedef enum { + GPIOX_MODER_INPUT = 0x0, /**< Pin is used as input (reset value) */ + GPIOX_MODER_OUTPUT = 0x1, /**< Pin is used as output */ + GPIOX_MODER_AF = 0x2, /**< Pin is routed to peripheral (alternate function) */ + GPIOX_MODER_ANALOG = 0x3, /**< Pin is in analog mode (least current leakage) */ +} gpiox_moder_t; + +/** + * @brief Check if gpio_state_t requires open drain mode + */ +#define GPIO_STATE_T_OPEN_DRAIN_FLAG 0x4 +/** + * @brief Bitmask to extract moder config + */ +#define GPIO_STATE_T_MODER_Msk 0x3 + #define HAVE_GPIO_STATE_T typedef enum { - GPIO_OUTPUT_PUSH_PULL, - GPIO_OUTPUT_OPEN_DRAIN, - GPIO_OUTPUT_OPEN_SOURCE, - GPIO_INPUT, - GPIO_USED_BY_PERIPHERAL, - GPIO_DISCONNECT, + GPIO_INPUT = GPIOX_MODER_INPUT, + GPIO_OUTPUT_PUSH_PULL = GPIOX_MODER_OUTPUT, + GPIO_OUTPUT_OPEN_DRAIN = GPIOX_MODER_OUTPUT | GPIO_STATE_T_OPEN_DRAIN_FLAG, + GPIO_USED_BY_PERIPHERAL = GPIOX_MODER_AF, + GPIO_DISCONNECT = GPIOX_MODER_ANALOG, + GPIO_OUTPUT_OPEN_SOURCE = 0x7, /**< not supported */ } gpio_state_t; #define HAVE_GPIO_PULL_T @@ -130,7 +149,7 @@ typedef union gpio_conf_stm32 gpio_conf_t; * @ingroup drivers_periph_gpio_ll */ union gpio_conf_stm32 { - uint16_t bits; /**< the raw bits */ + uint8_t bits; /**< the raw bits */ struct { /** * @brief State of the pin @@ -150,18 +169,6 @@ union gpio_conf_stm32 { * configured to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN. */ gpio_slew_t slew_rate : 2; - /** - * @brief Whether to disable the input Schmitt trigger - * - * @details This could be called `schmitt_trigger` with inverse - * meaning, but the API contract says that additional - * members in the structure should have a sane - * default when zero. - * - * This value is ignored *unless* @ref gpio_conf_stm32::state is - * configured to @ref GPIO_INPUT. - */ - bool schmitt_trigger_disabled : 1; /** * @brief Initial value of the output * @@ -176,7 +183,6 @@ union gpio_conf_stm32 { * consulted. */ bool initial_value : 1; - uint8_t : 7; /*< padding */ }; }; diff --git a/cpu/stm32/periph/gpio_ll.c b/cpu/stm32/periph/gpio_ll.c index ec8d7d7f4b..35e1a3597a 100644 --- a/cpu/stm32/periph/gpio_ll.c +++ b/cpu/stm32/periph/gpio_ll.c @@ -77,6 +77,22 @@ static inline void print_str(const char *str) # define GPIOAEN RCC_APB2ENR_IOPAEN #endif +/* Bitmask to extract a mode field of the mode register "MODER". + * Note: Some families provide both, hence #elif */ +#ifdef GPIO_MODER_MODER0_Msk +# define MODE_Msk GPIO_MODER_MODER0_Msk +#elif GPIO_MODER_MODE0_Msk +# define MODE_Msk GPIO_MODER_MODE0_Msk +#endif + +/* Number of bits a mode field in the mode register "MODER" is wide. + * Note: Some families provide both, hence #elif */ +#ifdef GPIO_MODER_MODER1_Pos +# define MODE_BITS GPIO_MODER_MODER1_Pos +#elif GPIO_MODER_MODE1_Pos +# define MODE_BITS GPIO_MODER_MODE1_Pos +#endif + static void _init_clock(gpio_port_t port) { periph_clk_en(GPIO_BUS, (GPIOAEN << GPIO_PORT_NUM(port))); @@ -90,14 +106,12 @@ static void _init_clock(gpio_port_t port) } #if defined(GPIO_MODER_MODER0) || defined(GPIO_MODER_MODE0) -static void _set_dir(gpio_port_t port, uint8_t pin, bool output) +static void _set_mode(gpio_port_t port, uint8_t pin, gpiox_moder_t mode) { GPIO_TypeDef *p = (void *)port; uint32_t tmp = p->MODER; - tmp &= ~(0x3 << (2 * pin)); - if (output) { - tmp |= 1UL << (2 * pin); - } + tmp &= ~(MODE_Msk << (MODE_BITS * pin)); + tmp |= (unsigned)mode << (MODE_BITS * pin); p->MODER = tmp; } #endif @@ -107,15 +121,19 @@ static void _set_dir(gpio_port_t port, uint8_t pin, bool output) static gpio_state_t _get_state(gpio_port_t port, uint8_t pin) { GPIO_TypeDef *p = (void *)port; - uint32_t moder = (p->MODER >> (2 * pin)) & 0x3UL; + gpiox_moder_t moder = (p->MODER >> (MODE_BITS * pin)) & MODE_Msk; switch (moder) { - case 0: + case GPIOX_MODER_INPUT: return GPIO_INPUT; - case 1: + case GPIOX_MODER_OUTPUT: return ((p->OTYPER >> pin) & 0x1UL) ? GPIO_OUTPUT_OPEN_DRAIN : GPIO_OUTPUT_PUSH_PULL; + case GPIOX_MODER_ANALOG: + return GPIO_DISCONNECT; + default: + case GPIOX_MODER_AF: + return GPIO_USED_BY_PERIPHERAL; } - return GPIO_USED_BY_PERIPHERAL; } #endif @@ -333,10 +351,10 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) _set_legacy_f1_config(port, pin, conf); #else /* modern STM32 style GPIO configuration register layout */ - _set_output_type(port, pin, conf.state == GPIO_OUTPUT_OPEN_DRAIN); + _set_output_type(port, pin, conf.state & GPIO_STATE_T_OPEN_DRAIN_FLAG); _set_pull_config(port, pin, conf.pull); _set_slew_rate(port, pin, conf.slew_rate); - _set_dir(port, pin, conf.state < GPIO_INPUT); + _set_mode(port, pin, conf.state & GPIO_STATE_T_MODER_Msk); #endif irq_restore(state); @@ -386,8 +404,4 @@ void gpio_ll_print_conf(gpio_conf_t conf) gpio_ll_print_conf_common(conf); print_str(", slew: "); print_str(slew_strs[conf.slew_rate]); - - if (conf.schmitt_trigger_disabled) { - print_str(", Schmitt trigger disabled"); - } } diff --git a/drivers/include/periph/gpio_ll.h b/drivers/include/periph/gpio_ll.h index 280b6f3cc2..cd7c21f918 100644 --- a/drivers/include/periph/gpio_ll.h +++ b/drivers/include/periph/gpio_ll.h @@ -134,6 +134,8 @@ typedef enum { /** * @brief Use pin as output in push-pull configuration * + * @note This is supported and implemented on all MCUs. + * * | Logical Value | Electrical Behavior | * |:-------------- |:--------------------------------- | * | `0` | Low | @@ -143,6 +145,10 @@ typedef enum { /** * @brief Use pin as output in open collector configuration * + * @note The feature `periph_gpio_ll_open_drain` is used to indicate + * support for this GPIO mode. However, it may not be available on + * all pins. + * * | Logical Value | Electrical Behavior | * |:-------------- |:--------------------------------- | * | `0` | Low | @@ -152,13 +158,22 @@ typedef enum { /** * @brief Use pin as output in open emitter configuration * + * @note The feature `periph_gpio_ll_open_source` is used to indicate + * support for this GPIO mode. However, it may not be available on + * all pins. + * * | Logical Value | Electrical Behavior | * |:-------------- |:--------------------------------- | * | `0` | High Impedance (Disconnected) | * | `1` | High | */ GPIO_OUTPUT_OPEN_SOURCE, - GPIO_INPUT, /**< Use pin as input */ + /** + * @brief Use pin as input + * + * @note This is supported and implemented on all MCUs. + */ + GPIO_INPUT, /** * @brief The GPIO pin is used by a peripheral * @@ -175,6 +190,12 @@ typedef enum { /** * @brief Disconnect pin from all peripherals * + * @note This may be an alias for GPIO_INPUT when the MCU does not + * support support disconnecting GPIO pins from the GPIO + * peripheral. The feature `periph_gpio_ll_disconnect` indicates + * that disconnecting pins from all peripherals (including the + * GPIO peripheral) is supported. + * * The implementation should aim to reduce power consumption of the pin * when this state is entered, if this is feasible. For pins where it is * possible and sensible, this should electrically disconnect them diff --git a/drivers/periph_common/Makefile.dep b/drivers/periph_common/Makefile.dep index 5a08a3c0e4..cf0a84f9ff 100644 --- a/drivers/periph_common/Makefile.dep +++ b/drivers/periph_common/Makefile.dep @@ -1,4 +1,14 @@ -# Always use periph_gpio_irq_unmask, if available +# Always use hardware features, if available ifneq (,$(filter periph_gpio_ll%,$(USEMODULE))) + FEATURES_OPTIONAL += periph_gpio_ll_disconnect + FEATURES_OPTIONAL += periph_gpio_ll_irq_level_triggered_high + FEATURES_OPTIONAL += periph_gpio_ll_input_pull_down + FEATURES_OPTIONAL += periph_gpio_ll_input_pull_keep + FEATURES_OPTIONAL += periph_gpio_ll_input_pull_up + FEATURES_OPTIONAL += periph_gpio_ll_irq_level_triggered_low FEATURES_OPTIONAL += periph_gpio_ll_irq_unmask + FEATURES_OPTIONAL += periph_gpio_ll_open_drain + FEATURES_OPTIONAL += periph_gpio_ll_open_drain_pull_up + FEATURES_OPTIONAL += periph_gpio_ll_open_source + FEATURES_OPTIONAL += periph_gpio_ll_open_source_pull_down endif diff --git a/drivers/periph_common/gpio_ll.c b/drivers/periph_common/gpio_ll.c index 392354515c..30f3209bf0 100644 --- a/drivers/periph_common/gpio_ll.c +++ b/drivers/periph_common/gpio_ll.c @@ -33,24 +33,33 @@ void gpio_ll_print_conf_common(const gpio_conf_t conf) print_str("state: "); switch (conf.state) { - case GPIO_OUTPUT_PUSH_PULL: - print_str("out-pp"); - break; - case GPIO_OUTPUT_OPEN_DRAIN: - print_str("out-od"); - break; - case GPIO_OUTPUT_OPEN_SOURCE: - print_str("out-os"); - break; case GPIO_INPUT: print_str("in"); break; + case GPIO_OUTPUT_PUSH_PULL: + print_str("out-pp"); + break; +#if MODULE_PERIPH_GPIO_LL_OPEN_DRAIN + case GPIO_OUTPUT_OPEN_DRAIN: + print_str("out-od"); + break; +#endif +#if MODULE_PERIPH_GPIO_LL_OPEN_SOURCE + case GPIO_OUTPUT_OPEN_SOURCE: + print_str("out-os"); + break; +#endif case GPIO_USED_BY_PERIPHERAL: print_str("periph"); break; +#if MODULE_PERIPH_GPIO_LL_DISCONNECT case GPIO_DISCONNECT: print_str("off"); break; +#endif + default: + print_str("?"); + break; } if (conf.state != GPIO_OUTPUT_PUSH_PULL) { diff --git a/tests/periph/gpio_ll/README.md b/tests/periph/gpio_ll/README.md index 28ec025f54..4c4953bfba 100644 --- a/tests/periph/gpio_ll/README.md +++ b/tests/periph/gpio_ll/README.md @@ -27,3 +27,8 @@ Implementations are allowed to not electrically disconnect GPIO pins in state disconnected. For every MCU supported by GPIO LL so far at least some pins can be electrically disconnected. You might need to change the GPIO pins tested if the test for disconnected GPIOs being also electrically disconnected. + +When features such as `periph_gpio_ll_pull_up` or `periph_gpio_ll_open_drain` +are provided, this test expect those to be available on the tested pins. If +those features are not available on all pins, suitable pins need to be +selected for the test to pass. diff --git a/tests/periph/gpio_ll/main.c b/tests/periph/gpio_ll/main.c index 4505989ed8..36d05cd2fc 100644 --- a/tests/periph/gpio_ll/main.c +++ b/tests/periph/gpio_ll/main.c @@ -23,13 +23,14 @@ #include #include +#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 "timex.h" +#include "time_units.h" #include "ztimer.h" -#include "flash_utils.h" #ifndef LOW_ROM #define LOW_ROM 0 @@ -125,22 +126,15 @@ static void print_conf(gpio_conf_t conf) puts(""); } -static void test_gpio_ll_init(void) +static void test_gpio_ll_init_input_configs(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)); - expect(is_gpio_port_num_valid(PORT_OUT)); - 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); @@ -150,6 +144,8 @@ static void test_gpio_ll_init(void) 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); @@ -159,6 +155,8 @@ static void test_gpio_ll_init(void) 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); @@ -175,7 +173,11 @@ static void test_gpio_ll_init(void) } /* 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 = { @@ -188,7 +190,9 @@ static void test_gpio_ll_init(void) "LOW: %s\n", noyes[is_supported]); - if (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); @@ -218,7 +222,9 @@ static void test_gpio_ll_init(void) "HIGH: %s\n", noyes[is_supported]); - if (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); @@ -239,6 +245,8 @@ static void test_gpio_ll_init(void) 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); @@ -262,6 +270,8 @@ static void test_gpio_ll_init(void) 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); @@ -285,6 +295,8 @@ static void test_gpio_ll_init(void) 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); @@ -308,6 +320,8 @@ static void test_gpio_ll_init(void) 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); @@ -355,6 +369,8 @@ static void test_gpio_ll_init(void) 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); @@ -404,6 +420,8 @@ static void test_gpio_ll_init(void) 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); @@ -424,9 +442,11 @@ static void test_gpio_ll_init(void) }; is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf)); } - printf_optional("Support for output (open source with pull up) with initial " + 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); @@ -443,9 +463,11 @@ static void test_gpio_ll_init(void) }; is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf)); } - printf_optional("Support for output (open source with pull up) with initial " + 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); @@ -453,19 +475,40 @@ static void test_gpio_ll_init(void) 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)); + expect(is_gpio_port_num_valid(PORT_OUT)); + + /* 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("Support for disconnecting GPIO: %s\n", noyes[is_supported]); + 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. */ + * 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); @@ -808,17 +851,15 @@ static void test_irq_level(void) static void test_irq(void) { - if (IS_USED(MODULE_PERIPH_GPIO_LL_IRQ)) { - puts_optional("\n" - "Testing External IRQs\n" - "=====================\n"); + 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)); + 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(); - } + test_irq_edge(); + test_irq_level(); } int main(void)