diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h index 4a9910a5353e..bf6627072fda 100644 --- a/cpu/atmega_common/include/periph_cpu_common.h +++ b/cpu/atmega_common/include/periph_cpu_common.h @@ -231,14 +231,6 @@ typedef enum { GPIO_TRIGGER_LEVEL_HIGH = 0xff, /**< not supported */ } gpio_irq_trig_t; -#define HAVE_GPIO_PULL_T -typedef enum { - GPIO_FLOATING = 0, - GPIO_PULL_UP = 1, - GPIO_PULL_DOWN = 0xfe, /*< not supported */ - GPIO_PULL_KEEP = 0xff, /*< not supported */ -} gpio_pull_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 405a3589a6c7..3bd5eec65318 100644 --- a/cpu/atmega_common/periph/gpio_ll.c +++ b/cpu/atmega_common/periph/gpio_ll.c @@ -56,45 +56,42 @@ static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull) p->port |= pull << pin; } -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +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)) { + if ((conf.pull > GPIO_PULL_UP) + || (conf.state == GPIO_OUTPUT_OPEN_DRAIN) + || (conf.state == GPIO_OUTPUT_OPEN_SOURCE)) { return -ENOTSUP; } unsigned state = irq_disable(); - if (conf->initial_value) { + if (conf.initial_value) { gpio_ll_set(port, 1UL << pin); } else { gpio_ll_clear(port, 1UL << pin); } - _set_dir(port, pin, conf->state == GPIO_OUTPUT_PUSH_PULL); - if (conf->state == GPIO_INPUT) { - _set_pull_config(port, pin, conf->pull); + _set_dir(port, pin, conf.state == GPIO_OUTPUT_PUSH_PULL); + if (conf.state == GPIO_INPUT) { + _set_pull_config(port, pin, conf.pull); } irq_restore(state); return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - assert(dest); - memset(dest, 0, sizeof(*dest)); - /* E.g. the schematics in figure 14-5 in the ATmega328P datasheet shows that - * a Schmitt Trigger is always connected before the digital input signal. - * Let's assume this is also true for all other ATmegas */ - dest->schmitt_trigger = true; + gpio_conf_t result = { 0 }; if (_is_output(port, pin)) { - dest->state = GPIO_OUTPUT_PUSH_PULL; - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1U; + result.state = GPIO_OUTPUT_PUSH_PULL; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1U; } else { - dest->state = GPIO_INPUT; - dest->pull = (gpio_ll_read_output(port) >> pin) & 1U; - dest->initial_value = (gpio_ll_read(port) >> pin) & 1U; + result.state = GPIO_INPUT; + result.pull = (gpio_ll_read_output(port) >> pin) & 1U; + result.initial_value = (gpio_ll_read(port) >> pin) & 1U; } + + return result; } diff --git a/cpu/efm32/periph/gpio_ll.c b/cpu/efm32/periph/gpio_ll.c index f076bc770a50..a771b871c05b 100644 --- a/cpu/efm32/periph/gpio_ll.c +++ b/cpu/efm32/periph/gpio_ll.c @@ -19,28 +19,26 @@ * @} */ -#include #include -#include #include "cpu.h" #include "periph/gpio_ll.h" #include "periph_cpu.h" #include "periph_conf.h" -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) { GPIO_Mode_TypeDef mode; - bool initial = conf->initial_value; + bool initial = conf.initial_value; - switch (conf->state) { + switch (conf.state) { case GPIO_DISCONNECT: /* ignoring pull */ mode = gpioModeDisabled; break; case GPIO_INPUT: - switch (conf->pull) { + switch (conf.pull) { case GPIO_FLOATING: mode = gpioModeInput; break; @@ -61,7 +59,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) mode = gpioModePushPull; break; case GPIO_OUTPUT_OPEN_DRAIN: - switch (conf->pull) { + switch (conf.pull) { case GPIO_FLOATING: mode = gpioModeWiredAnd; break; @@ -73,7 +71,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) } break; case GPIO_OUTPUT_OPEN_SOURCE: - switch (conf->pull) { + switch (conf.pull) { case GPIO_FLOATING: mode = gpioModeWiredOr; break; @@ -99,58 +97,48 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - memset(dest, 0, sizeof(*dest)); - + gpio_conf_t result = { 0 }; GPIO_Mode_TypeDef mode = GPIO_PinModeGet(port, pin); - dest->pull = GPIO_FLOATING; + result.pull = GPIO_FLOATING; switch (mode) { case gpioModePushPull: - dest->state = GPIO_OUTPUT_PUSH_PULL; + result.state = GPIO_OUTPUT_PUSH_PULL; break; case gpioModeWiredOr: - dest->state = GPIO_OUTPUT_OPEN_SOURCE; + result.state = GPIO_OUTPUT_OPEN_SOURCE; break; case gpioModeWiredOrPullDown: - dest->state = GPIO_OUTPUT_OPEN_SOURCE; - dest->pull = GPIO_PULL_DOWN; + result.state = GPIO_OUTPUT_OPEN_SOURCE; + result.pull = GPIO_PULL_DOWN; break; case gpioModeWiredAnd: - dest->state = GPIO_OUTPUT_OPEN_DRAIN; + result.state = GPIO_OUTPUT_OPEN_DRAIN; break; case gpioModeWiredAndPullUp: - dest->state = GPIO_OUTPUT_OPEN_DRAIN; - dest->pull = GPIO_PULL_UP; + result.state = GPIO_OUTPUT_OPEN_DRAIN; + result.pull = GPIO_PULL_UP; break; case gpioModeInput: - dest->state = GPIO_INPUT; + result.state = GPIO_INPUT; break; case gpioModeInputPull: - dest->state = GPIO_INPUT; - dest->pull = GPIO_PinOutGet(port, pin) ? + result.state = GPIO_INPUT; + result.pull = GPIO_PinOutGet(port, pin) ? GPIO_PULL_UP : GPIO_PULL_DOWN; break; case gpioModeDisabled: /* Fall-through: There is no error reporting here */ default: - dest->state = GPIO_DISCONNECT; + result.state = GPIO_DISCONNECT; break; } - /* as good as any */ - dest->slew_rate = GPIO_SLEW_FAST; - - /* It's always on as long as they're in a mode in which it matters, judging - * from https://www.silabs.com/documents/public/application-notes/an0027.pdf */ - dest->schmitt_trigger = true; - - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1; - /* Using 'strong' her already as that fits with what the hardware has - * (lowest, low, standard, high) */ - dest->drive_strength = GPIO_DRIVE_STRONG; + return result; } diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 6e0623533fe5..b00f0ee6d1a0 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -190,7 +190,7 @@ typedef enum { GPIO_FLOATING = 0, GPIO_PULL_UP = 1, GPIO_PULL_DOWN = 2, - GPIO_PULL_KEEP = 0xff /*< not supported */ + GPIO_PULL_KEEP = 3 /*< not supported */ } gpio_pull_t; /** @@ -212,9 +212,64 @@ typedef enum { #define GPIO_DRIVE_20 GPIO_DRIVE_STRONG /**< 20 mA (default) */ #define GPIO_DRIVE_30 GPIO_DRIVE_STRONGEST /**< 30 mA */ -/* END: GPIO LL overwrites */ +#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_state_t; + +#define HAVE_GPIO_CONF_T +typedef union gpio_conf_esp32 gpio_conf_t; #endif /* ndef DOXYGEN */ + +/** + * @brief GPIO pin configuration for ESP32/ESP32Cx/ESP32Sx MCUs + * @ingroup drivers_periph_gpio_ll + */ +union gpio_conf_esp32 { + uint8_t bits; /**< the raw bits */ + struct { + /** + * @brief State of the pin + */ + gpio_state_t state : 3; + /** + * @brief Pull resistor configuration + */ + gpio_pull_t pull : 2; + /** + * @brief Drive strength of the GPIO + * + * @warning If the requested drive strength is not available, the closest + * fit supported will be configured instead. + * + * This value is ignored when @ref gpio_conf_esp32::state is configured + * to @ref GPIO_INPUT or @ref GPIO_DISCONNECT. + */ + gpio_drive_strength_t drive_strength : 2; + /** + * @brief Initial value of the output + * + * Ignored if @ref gpio_conf_esp32::state is set to @ref GPIO_INPUT or + * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance + * state, it is guaranteed to directly transition to the given initial + * value. + * + * @ref gpio_ll_query_conf will write the current value of the specified + * pin here, which is read from the input register when the state is + * @ref GPIO_INPUT, otherwise the state from the output register is + * consulted. + */ + bool initial_value : 1; + }; +}; + +/* END: GPIO LL overwrites */ /** @} */ /** diff --git a/cpu/esp32/periph/gpio_ll.c b/cpu/esp32/periph/gpio_ll.c index af02263d3088..7faadb5f9b14 100644 --- a/cpu/esp32/periph/gpio_ll.c +++ b/cpu/esp32/periph/gpio_ll.c @@ -38,6 +38,15 @@ #include "esp_idf_api/gpio.h" +#ifdef MODULE_FMT +#include "fmt.h" +#else +static inline void print_str(const char *str) +{ + fputs(str, stdout); +} +#endif + /* variables that have to be used together with periph/gpio */ #ifdef ESP_PM_WUP_PINS extern bool _gpio_pin_pu[GPIO_PIN_NUMOF]; @@ -71,10 +80,9 @@ const _esp32_port_t _esp32_ports[GPIO_PORT_NUMOF] = { #endif }; -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) { assert(port); - assert(conf); assert(GPIO_PORT_NUM(port) < GPIO_PORT_NUMOF); assert(pin < GPIO_PORT_PIN_NUMOF(port)); @@ -87,7 +95,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) .pull_down_en = false, }; - switch (conf->state) { + switch (conf.state) { case GPIO_OUTPUT_PUSH_PULL: cfg.mode = GPIO_MODE_DEF_OUTPUT; break; @@ -104,7 +112,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return -ENOTSUP; } - switch (conf->pull) { + switch (conf.pull) { case GPIO_FLOATING: break; case GPIO_PULL_UP: @@ -134,15 +142,14 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) _gpio_pin_pd[pin] = cfg.pull_down_en; #endif - if (conf->state == GPIO_DISCONNECT) { + if (conf.state == GPIO_DISCONNECT) { /* reset the pin to disconnects any other peripheral output configured via GPIO Matrix, the pin is reconfigured according to given conf */ esp_idf_gpio_reset_pin(gpio); } /* since we can't read back the configuration, we have to save it */ - _gpio_conf[gpio] = *conf; - _gpio_conf[gpio].schmitt_trigger = false; + _gpio_conf[gpio] = conf; if (esp_idf_gpio_config(&cfg) != ESP_OK) { return -ENOTSUP; @@ -150,7 +157,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) /* if output pin, try to set drive strength */ gpio_drive_cap_t strength; - switch (conf->drive_strength) { + switch (conf.drive_strength) { case GPIO_DRIVE_WEAKEST: strength = GPIO_DRIVE_CAP_0; break; @@ -171,7 +178,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return -ENOTSUP; } - if (conf->initial_value) { + if (conf.initial_value) { gpio_ll_set(port, 1UL << pin); } else { @@ -181,18 +188,34 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - assert(dest); + gpio_conf_t result; unsigned state = irq_disable(); - *dest = _gpio_conf[GPIO_PIN(GPIO_PORT_NUM(port), pin)]; - if (dest->state == GPIO_INPUT) { - dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL; + result = _gpio_conf[GPIO_PIN(GPIO_PORT_NUM(port), pin)]; + if (result.state == GPIO_INPUT) { + result.initial_value = (gpio_ll_read(port) >> pin) & 1UL; } else { - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; } irq_restore(state); + + return result; +} + +void gpio_ll_print_conf(gpio_conf_t conf) +{ + static const char *drive_strs[] = { + [GPIO_DRIVE_WEAKEST] = "weakest", + [GPIO_DRIVE_WEAK] = "weak", + [GPIO_DRIVE_STRONG] = "strong", + [GPIO_DRIVE_STRONGEST] = "strongest", + }; + + gpio_ll_print_conf_common(conf); + print_str(", drive: "); + print_str(drive_strs[conf.drive_strength]); } diff --git a/cpu/gd32v/include/periph_cpu.h b/cpu/gd32v/include/periph_cpu.h index 17431ea19968..ec6e437610b7 100644 --- a/cpu/gd32v/include/periph_cpu.h +++ b/cpu/gd32v/include/periph_cpu.h @@ -187,6 +187,24 @@ void gpio_init_analog(gpio_t pin); * public view on type */ #ifndef DOXYGEN +#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_state_t; + +#define HAVE_GPIO_PULL_T +typedef enum { + GPIO_FLOATING, + GPIO_PULL_UP, + GPIO_PULL_DOWN, + GPIO_PULL_KEEP, +} gpio_pull_t; + #define HAVE_GPIO_PULL_STRENGTH_T typedef enum { GPIO_PULL_WEAKEST = 0, @@ -211,8 +229,66 @@ typedef enum { GPIO_SLEW_FASTEST = 2, } gpio_slew_t; +#define HAVE_GPIO_CONF_T +typedef union gpio_conf_gd32v gpio_conf_t; + #endif /* !DOXYGEN */ +/** + * @brief GPIO pin configuration for GD32V MCUs. + * @ingroup drivers_periph_gpio_ll + */ +union gpio_conf_gd32v { + uint16_t bits; /**< the raw bits */ + struct { + /** + * @brief State of the pin + */ + gpio_state_t state : 3; + /** + * @brief Pull resistor configuration + */ + gpio_pull_t pull : 2; + /** + * @brief Configure the slew rate of outputs + * + * @warning If the requested slew rate is not available, the closest fit + * supported will be configured instead. + * + * This value is ignored *unless* @ref gpio_conf_stm32::state is + * 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 + * + * Ignored if @ref gpio_conf_stm32::state is set to @ref GPIO_INPUT or + * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance + * state, it is guaranteed to directly transition to the given initial + * value. + * + * @ref gpio_ll_query_conf will write the current value of the specified + * pin here, which is read from the input register when the state is + * @ref GPIO_INPUT, otherwise the state from the output register is + * consulted. + */ + bool initial_value : 1; + uint8_t : 7; /*< padding */ + }; +}; + /** * @brief Available number of ADC devices */ diff --git a/cpu/gd32v/periph/gpio_ll.c b/cpu/gd32v/periph/gpio_ll.c index 03ec181fa538..375c010863fc 100644 --- a/cpu/gd32v/periph/gpio_ll.c +++ b/cpu/gd32v/periph/gpio_ll.c @@ -19,7 +19,6 @@ */ #include -#include #include "cpu.h" #include "bitarithm.h" @@ -28,13 +27,22 @@ #define ENABLE_DEBUG 0 #include "debug.h" +#ifdef MODULE_FMT +#include "fmt.h" +#else +static inline void print_str(const char *str) +{ + fputs(str, stdout); +} +#endif + uint16_t pin_used[GPIO_PORT_NUMOF] = {}; -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) { - if ((conf->pull == GPIO_PULL_KEEP) || - (conf->state == GPIO_OUTPUT_OPEN_SOURCE) || - ((conf->state != GPIO_INPUT) && (conf->pull != GPIO_FLOATING))) { + if ((conf.pull == GPIO_PULL_KEEP) || + (conf.state == GPIO_OUTPUT_OPEN_SOURCE) || + ((conf.state != GPIO_INPUT) && (conf.pull != GPIO_FLOATING))) { return -ENOTSUP; } @@ -50,7 +58,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) /* reset configuration CTLx[1:0], MDx[1:0] (analogue, input mode) */ *ctrl &= ~(0xf << pos); - switch (conf->state) { + switch (conf.state) { case GPIO_DISCONNECT: *ctrl |= 0x1 << (pos + 2); pin_used[GPIO_PORT_NUM(port)] &= ~(1 << pin); @@ -60,12 +68,12 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) break; case GPIO_INPUT: pin_used[GPIO_PORT_NUM(port)] |= 1 << pin; - if (conf->pull == GPIO_FLOATING) { + if (conf.pull == GPIO_FLOATING) { *ctrl |= 0x1 << (pos + 2); } else { *ctrl |= 0x2 << (pos + 2); - if (conf->pull == GPIO_PULL_UP) { + if (conf.pull == GPIO_PULL_UP) { *octl |= 1 << pin; } else { @@ -76,9 +84,9 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) case GPIO_OUTPUT_PUSH_PULL: case GPIO_OUTPUT_OPEN_DRAIN: pin_used[GPIO_PORT_NUM(port)] |= 1 << pin; - *ctrl |= (conf->slew_rate + 1) << pos; - *ctrl |= (conf->state == GPIO_OUTPUT_OPEN_DRAIN ? 0x1 : 0x0) << (pos + 2); - if (conf->initial_value) { + *ctrl |= (conf.slew_rate + 1) << pos; + *ctrl |= (conf.state == GPIO_OUTPUT_OPEN_DRAIN ? 0x1 : 0x0) << (pos + 2); + if (conf.initial_value) { gpio_ll_set(port, 1UL << pin); } else { @@ -95,14 +103,12 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - assert(dest); + gpio_conf_t result = { 0 }; unsigned state = irq_disable(); - memset(dest, 0, sizeof(*dest)); - volatile uint32_t *ctrl_reg = (pin < 8) ? &((GPIO_Type *)port)->CTL0 : &((GPIO_Type *)port)->CTL1; @@ -112,16 +118,16 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) uint32_t ctrl = (*ctrl_reg >> (pos + 2)) & 0x3; if (mode == 0) { - dest->state = GPIO_INPUT; + result.state = GPIO_INPUT; switch (ctrl) { case 0: - dest->state = GPIO_USED_BY_PERIPHERAL; + result.state = GPIO_USED_BY_PERIPHERAL; break; case 1: - dest->pull = GPIO_FLOATING; + result.pull = GPIO_FLOATING; break; case 2: - dest->pull = (((GPIO_Type *)port)->OCTL & (1UL << pin)) ? GPIO_PULL_UP + result.pull = (((GPIO_Type *)port)->OCTL & (1UL << pin)) ? GPIO_PULL_UP : GPIO_PULL_DOWN; break; default: @@ -129,26 +135,46 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) } } else { - dest->slew_rate = mode - 1; - dest->pull = GPIO_FLOATING; + result.slew_rate = mode - 1; + result.pull = GPIO_FLOATING; switch (ctrl) { case 0: - dest->state = GPIO_OUTPUT_PUSH_PULL; + result.state = GPIO_OUTPUT_PUSH_PULL; break; case 1: - dest->state = GPIO_OUTPUT_OPEN_DRAIN; + result.state = GPIO_OUTPUT_OPEN_DRAIN; break; default: - dest->state = GPIO_USED_BY_PERIPHERAL; + result.state = GPIO_USED_BY_PERIPHERAL; break; } } - if (dest->state == GPIO_INPUT) { - dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL; + if (result.state == GPIO_INPUT) { + result.initial_value = (gpio_ll_read(port) >> pin) & 1UL; } else { - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; } irq_restore(state); + + return result; +} + +void gpio_ll_print_conf(gpio_conf_t conf) +{ + static const char *slew_strs[] = { + [GPIO_SLEW_SLOWEST] = "slowest", + [GPIO_SLEW_SLOW] = "medium", + [GPIO_SLEW_FASTEST] = "fastest", + "invalid" + }; + + 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/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h index c6ab6d51ccae..b37a4a8b1da2 100644 --- a/cpu/nrf5x_common/include/periph_cpu_common.h +++ b/cpu/nrf5x_common/include/periph_cpu_common.h @@ -138,12 +138,69 @@ typedef enum { #define HAVE_GPIO_PULL_T typedef enum { GPIO_FLOATING = 0, - GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos, - GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos, - /* GPIO_PULL_KEEP is not supported by, gpio_ll_init() returns -ENOTSUP */ - GPIO_PULL_KEEP = 0xff + GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup, + GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown, + GPIO_PULL_KEEP = 2, } gpio_pull_t; -#endif /* END: GPIO LL overwrites */ + +#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_state_t; + +#define HAVE_GPIO_CONF_T +typedef union gpio_conf_nrf5x gpio_conf_t; + +#endif + +/** + * @brief GPIO pin configuration for nRF5x MCUs + * @ingroup drivers_periph_gpio_ll + */ +union gpio_conf_nrf5x { + uint8_t bits; /**< the raw bits */ + struct { + /** + * @brief State of the pin + */ + gpio_state_t state : 3; + /** + * @brief Pull resistor configuration + */ + gpio_pull_t pull : 2; + /** + * @brief Drive strength of the GPIO + * + * @warning If the requested drive strength is not available, the + * closest fit supported will be configured instead. + * + * This value is ignored when @ref gpio_conf_nrf5x::state is configured + * to @ref GPIO_INPUT or @ref GPIO_DISCONNECT. + */ + gpio_drive_strength_t drive_strength : 1; + /** + * @brief Initial value of the output + * + * Ignored if @ref gpio_conf_nrf5x::state is set to @ref GPIO_INPUT or + * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance + * state, it is guaranteed to directly transition to the given initial + * value. + * + * @ref gpio_ll_query_conf will write the current value of the specified + * pin here, which is read from the input register when the state is + * @ref GPIO_INPUT, otherwise the state from the output register is + * consulted. + */ + bool initial_value : 1; + uint8_t : 1; /*< padding */ + }; +}; +/* END: GPIO LL overwrites */ #if !defined(DOXYGEN) && (defined(CPU_NRF53) || defined(CPU_NRF9160)) /** diff --git a/cpu/nrf5x_common/periph/gpio_ll.c b/cpu/nrf5x_common/periph/gpio_ll.c index c03e19437c93..c556f8ac921b 100644 --- a/cpu/nrf5x_common/periph/gpio_ll.c +++ b/cpu/nrf5x_common/periph/gpio_ll.c @@ -36,24 +36,33 @@ #include "periph_cpu.h" #include "periph_conf.h" -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +#ifdef MODULE_FMT +#include "fmt.h" +#else +static inline void print_str(const char *str) { - if (conf->pull == GPIO_PULL_KEEP) { + fputs(str, stdout); +} +#endif + +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) +{ + if (conf.pull == GPIO_PULL_KEEP) { return -ENOTSUP; } - uint32_t pin_cnf = conf->pull; - switch (conf->state) { + uint32_t pin_cnf = (unsigned)conf.pull << GPIO_PIN_CNF_PULL_Pos; + switch (conf.state) { case GPIO_OUTPUT_PUSH_PULL: /* INPUT bit needs to be *CLEARED* in input mode, so set to disconnect input buffer */ pin_cnf |= GPIO_PIN_CNF_DIR_Msk | GPIO_PIN_CNF_INPUT_Msk; - if (conf->drive_strength) { + if (conf.drive_strength) { pin_cnf |= GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos; } break; case GPIO_OUTPUT_OPEN_DRAIN: pin_cnf |= GPIO_PIN_CNF_DIR_Msk; - if (conf->drive_strength) { + if (conf.drive_strength) { pin_cnf |= GPIO_PIN_CNF_DRIVE_H0D1 << GPIO_PIN_CNF_DRIVE_Pos; } else { @@ -62,7 +71,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) break; case GPIO_OUTPUT_OPEN_SOURCE: pin_cnf |= GPIO_PIN_CNF_DIR_Msk; - if (conf->drive_strength) { + if (conf.drive_strength) { pin_cnf |= GPIO_PIN_CNF_DRIVE_D0H1 << GPIO_PIN_CNF_DRIVE_Pos; } else { @@ -78,8 +87,8 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) break; } - if (conf->state != GPIO_OUTPUT_PUSH_PULL) { - switch (conf->pull) { + if (conf.state != GPIO_OUTPUT_PUSH_PULL) { + switch (conf.pull) { default: case GPIO_FLOATING: break; @@ -93,7 +102,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) } NRF_GPIO_Type *p = (NRF_GPIO_Type *)port; - if (conf->initial_value) { + if (conf.initial_value) { p->OUTSET = 1UL << pin; } else { @@ -104,19 +113,11 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - assert((dest != NULL) - && (NULL == gpio_port_unpack_addr(port)) - && (pin < 32)); - memset(dest, 0, sizeof(*dest)); - /* Searching "Schmitt" in - * https://infocenter.nordicsemi.com/pdf/nRF52840_OPS_v0.5.pdf yields - * no matches. Assuming Schmitt trigger cannot be disabled for the - * nRF5x MCU. - */ - dest->schmitt_trigger = true; - dest->state = GPIO_INPUT; + gpio_conf_t result = { 0 }; + assert((NULL == gpio_port_unpack_addr(port)) && (pin < 32)); + result.state = GPIO_INPUT; NRF_GPIO_Type *p = (NRF_GPIO_Type *)port; uint32_t cnf = p->PIN_CNF[pin]; @@ -134,38 +135,38 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) case GPIO_PIN_CNF_DRIVE_S0S1: /* standard drive 0, standard drive 1 * --> push pull with weak drive */ - dest->state = GPIO_OUTPUT_PUSH_PULL; - dest->drive_strength = GPIO_DRIVE_WEAK; + result.state = GPIO_OUTPUT_PUSH_PULL; + result.drive_strength = GPIO_DRIVE_WEAK; break; case GPIO_PIN_CNF_DRIVE_H0H1: /* high drive 0, high drive 1 * --> push pull with high drive */ - dest->state = GPIO_OUTPUT_PUSH_PULL; - dest->drive_strength = GPIO_DRIVE_STRONG; + result.state = GPIO_OUTPUT_PUSH_PULL; + result.drive_strength = GPIO_DRIVE_STRONG; break; case GPIO_PIN_CNF_DRIVE_S0D1: /* standard drive 0, disconnect at 1 * --> open drain with weak drive */ - dest->state = GPIO_OUTPUT_OPEN_DRAIN; - dest->drive_strength = GPIO_DRIVE_WEAK; + result.state = GPIO_OUTPUT_OPEN_DRAIN; + result.drive_strength = GPIO_DRIVE_WEAK; break; case GPIO_PIN_CNF_DRIVE_H0D1: /* high drive 0, disconnect at 1 * --> open drain with strong drive */ - dest->state = GPIO_OUTPUT_OPEN_DRAIN; - dest->drive_strength = GPIO_DRIVE_STRONG; + result.state = GPIO_OUTPUT_OPEN_DRAIN; + result.drive_strength = GPIO_DRIVE_STRONG; break; case GPIO_PIN_CNF_DRIVE_D0S1: /* disconnect at 0, standard drive 1 * --> open emitter with weak drive */ - dest->state = GPIO_OUTPUT_OPEN_SOURCE; - dest->drive_strength = GPIO_DRIVE_WEAK; + result.state = GPIO_OUTPUT_OPEN_SOURCE; + result.drive_strength = GPIO_DRIVE_WEAK; break; case GPIO_PIN_CNF_DRIVE_D0H1: /* disconnect at 0, high drive 1 * --> open emitter with strong drive */ - dest->state = GPIO_OUTPUT_OPEN_SOURCE; - dest->drive_strength = GPIO_DRIVE_STRONG; + result.state = GPIO_OUTPUT_OPEN_SOURCE; + result.drive_strength = GPIO_DRIVE_STRONG; break; } } @@ -174,26 +175,40 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) /* input buffer is disconnected and pin is not in output mode * --> GPIO pin is off */ - dest->state = GPIO_DISCONNECT; + result.state = GPIO_DISCONNECT; } } switch ((cnf & GPIO_PIN_CNF_PULL_Msk) >> GPIO_PIN_CNF_PULL_Pos) { case GPIO_PIN_CNF_PULL_Pullup: - dest->pull = GPIO_PULL_UP; + result.pull = GPIO_PULL_UP; break; case GPIO_PIN_CNF_PULL_Pulldown: - dest->pull = GPIO_PULL_DOWN; + result.pull = GPIO_PULL_DOWN; break; default: - dest->pull = GPIO_FLOATING; + result.pull = GPIO_FLOATING; break; } - if (dest->state == GPIO_INPUT) { - dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL; + if (result.state == GPIO_INPUT) { + result.initial_value = (gpio_ll_read(port) >> pin) & 1UL; } else { - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; } + + return result; +} + +void gpio_ll_print_conf(gpio_conf_t conf) +{ + static const char *drive_strs[] = { + [GPIO_DRIVE_WEAK] = "weak", + [GPIO_DRIVE_STRONG] = "strong", + }; + + gpio_ll_print_conf_common(conf); + print_str(", drive: "); + print_str(drive_strs[conf.drive_strength]); } diff --git a/cpu/stm32/include/periph/cpu_gpio_ll.h b/cpu/stm32/include/periph/cpu_gpio_ll.h index 5ae238ab2473..741604048ee9 100644 --- a/cpu/stm32/include/periph/cpu_gpio_ll.h +++ b/cpu/stm32/include/periph/cpu_gpio_ll.h @@ -19,6 +19,7 @@ #ifndef PERIPH_CPU_GPIO_LL_H #define PERIPH_CPU_GPIO_LL_H +#include #include #include "periph_cpu.h" @@ -46,8 +47,6 @@ typedef enum { GPIO_DRIVE_STRONGEST = 0 } gpio_drive_strength_t; -#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \ - || defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0) /* Modern STM32 GPIO config registers with the OSPEEDR register support full * 4 slew rates, legacy STM32F1 style only have three slew rates. We define * slow and fast to the same value, so that we have three options: @@ -55,11 +54,26 @@ typedef enum { * 2. SLOW: 10 MHZ * 3. FAST/FASTEST: 50 MHz */ +#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \ + || defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0) +# define STM32_HAS_OSPEED 1 +#else +# define STM32_HAS_OSPEED 0 +#endif + #define HAVE_GPIO_SLEW_T +#if STM32_HAS_OSPEED typedef enum { GPIO_SLEW_SLOWEST = 0, GPIO_SLEW_SLOW = 1, GPIO_SLEW_FAST = 2, + GPIO_SLEW_FASTEST = 3, +} gpio_slew_t; +#else +typedef enum { + GPIO_SLEW_SLOWEST = 0, + GPIO_SLEW_SLOW = 0, + GPIO_SLEW_FAST = 1, GPIO_SLEW_FASTEST = 2, } gpio_slew_t; #endif @@ -88,8 +102,84 @@ typedef enum { GPIO_TRIGGER_LEVEL_LOW = GPIO_TRIGGER_LEVEL | GPIO_TRIGGER_EDGE_FALLING, } gpio_irq_trig_t; +#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_state_t; + +#define HAVE_GPIO_PULL_T +typedef enum { + GPIO_FLOATING, + GPIO_PULL_UP, + GPIO_PULL_DOWN, + GPIO_PULL_KEEP, +} gpio_pull_t; + +#define HAVE_GPIO_CONF_T +typedef union gpio_conf_stm32 gpio_conf_t; + #endif /* ndef Doxygen */ +/** + * @brief GPIO pin configuration for STM32 MCUs. + * @ingroup drivers_periph_gpio_ll + */ +union gpio_conf_stm32 { + uint16_t bits; /**< the raw bits */ + struct { + /** + * @brief State of the pin + */ + gpio_state_t state : 3; + /** + * @brief Pull resistor configuration + */ + gpio_pull_t pull : 2; + /** + * @brief Configure the slew rate of outputs + * + * @warning If the requested slew rate is not available, the closest fit + * supported will be configured instead. + * + * This value is ignored *unless* @ref gpio_conf_stm32::state is + * 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 + * + * Ignored if @ref gpio_conf_stm32::state is set to @ref GPIO_INPUT or + * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance + * state, it is guaranteed to directly transition to the given initial + * value. + * + * @ref gpio_ll_query_conf will write the current value of the specified + * pin here, which is read from the input register when the state is + * @ref GPIO_INPUT, otherwise the state from the output register is + * consulted. + */ + bool initial_value : 1; + uint8_t : 7; /*< padding */ + }; +}; + #ifdef __cplusplus } #endif diff --git a/cpu/stm32/periph/eth.c b/cpu/stm32/periph/eth.c index c42a2076a2ff..eeb18a8f935c 100644 --- a/cpu/stm32/periph/eth.c +++ b/cpu/stm32/periph/eth.c @@ -24,7 +24,6 @@ #include #include -#include "bitarithm.h" #include "board.h" #include "iolist.h" #include "macros/utils.h" @@ -33,7 +32,6 @@ #include "net/ethernet.h" #include "net/eui_provider.h" #include "net/netdev/eth.h" -#include "periph/gpio.h" #include "periph/gpio_ll.h" #include "time_units.h" @@ -487,10 +485,10 @@ static int stm32_eth_init(netdev_t *netdev) if (IS_USED(MODULE_STM32_ETH_TRACING)) { gpio_ll_init(GPIO_PORT(STM32_ETH_TRACING_TX_PORT_NUM), STM32_ETH_TRACING_TX_PIN_NUM, - &gpio_ll_out); + gpio_ll_out); gpio_ll_init(GPIO_PORT(STM32_ETH_TRACING_RX_PORT_NUM), STM32_ETH_TRACING_RX_PIN_NUM, - &gpio_ll_out); + gpio_ll_out); } if (IS_USED(MODULE_STM32_ETH_LINK_UP)) { _link_status_timer.callback = _timer_cb; diff --git a/cpu/stm32/periph/eth_common.c b/cpu/stm32/periph/eth_common.c index 07242727d253..db9fa528f16e 100644 --- a/cpu/stm32/periph/eth_common.c +++ b/cpu/stm32/periph/eth_common.c @@ -95,7 +95,7 @@ void stm32_eth_common_init(void) if (IS_USED(MODULE_STM32_ETH_TRACING)) { gpio_ll_init(GPIO_PORT(STM32_ETH_TRACING_IRQ_PORT_NUM), STM32_ETH_TRACING_IRQ_PIN_NUM, - &gpio_ll_out); + gpio_ll_out); } if (IS_USED(MODULE_PERIPH_ETH) || IS_USED(MODULE_PERIPH_PTP_TIMER)) { diff --git a/cpu/stm32/periph/gpio_ll.c b/cpu/stm32/periph/gpio_ll.c index 439b77e56434..ec8d7d7f4b48 100644 --- a/cpu/stm32/periph/gpio_ll.c +++ b/cpu/stm32/periph/gpio_ll.c @@ -29,12 +29,19 @@ */ #include -#include #include "cpu.h" -#include "bitarithm.h" #include "periph/gpio_ll.h" +#ifdef MODULE_FMT +#include "fmt.h" +#else +static inline void print_str(const char *str) +{ + fputs(str, stdout); +} +#endif + #ifdef RCC_AHBENR_GPIOAEN # define GPIO_BUS AHB # define GPIOAEN RCC_AHBENR_GPIOAEN @@ -168,7 +175,7 @@ static gpio_slew_t _get_slew_rate(gpio_port_t port, uint8_t pin) #ifdef GPIO_CRL_MODE static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, - const gpio_conf_t *conf) + gpio_conf_t conf) { /* STM32F1 style config register mix output mode and slew rate into the * same field. This look up table can be used to look up the correct @@ -187,11 +194,11 @@ static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, bool high_reg = pin > 7; uint32_t control = high_reg ? p->CRH : p -> CRL; - assert((unsigned)conf->slew_rate < ARRAY_SIZE(output_mode_by_slew_rate)); + assert((unsigned)conf.slew_rate < ARRAY_SIZE(output_mode_by_slew_rate)); /* prepare bis in cnf and mode fields for given pin */ uint32_t cnf_mode = 0; - switch (conf->state) { + switch (conf.state) { default: case GPIO_DISCONNECT: /* Keeping GPIO in analog mode is said to reduce power consumption. @@ -200,7 +207,7 @@ static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_ANALOG; break; case GPIO_INPUT: - switch (conf->pull) { + switch (conf.pull) { default: case GPIO_FLOATING: cnf_mode = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_INPUT_FLOATING; @@ -222,11 +229,11 @@ static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, break; case GPIO_OUTPUT_PUSH_PULL: cnf_mode = GPIO_CRL_CNF0_OUTPUT_PUSH_PULL - | output_mode_by_slew_rate[conf->slew_rate]; + | output_mode_by_slew_rate[conf.slew_rate]; break; case GPIO_OUTPUT_OPEN_DRAIN: cnf_mode = GPIO_CRL_CNF0_OUTPUT_OPEN_DRAIN - | output_mode_by_slew_rate[conf->slew_rate]; + | output_mode_by_slew_rate[conf.slew_rate]; } /* clear old values of cnf and mode fields in config reg */ @@ -241,9 +248,9 @@ static void _set_legacy_f1_config(gpio_port_t port, uint8_t pin, p->CRL = control; } } -static void _get_legacy_f1_config(gpio_conf_t *dest, gpio_port_t port, - uint8_t pin) +static gpio_conf_t _get_legacy_f1_config(gpio_port_t port, uint8_t pin) { + gpio_conf_t result = { 0 }; GPIO_TypeDef *p = (void *)port; unsigned offset = (pin & 0x7U) << 2; bool high_reg = pin > 7; @@ -258,62 +265,64 @@ static void _get_legacy_f1_config(gpio_conf_t *dest, gpio_port_t port, switch (cnf) { default: case GPIO_CRL_CNF0_INPUT_ANALOG: - dest->state = GPIO_DISCONNECT; + result.state = GPIO_DISCONNECT; break; case GPIO_CRL_CNF0_INPUT_FLOATING: - dest->state = GPIO_INPUT; + result.state = GPIO_INPUT; break; case GPIO_CRL_CNF0_INPUT_PULL: - dest->state = GPIO_INPUT; - dest->pull = GPIO_PULL_DOWN; + result.state = GPIO_INPUT; + result.pull = GPIO_PULL_DOWN; if (p->ODR & (1U << pin)) { - dest->pull = GPIO_PULL_UP; + result.pull = GPIO_PULL_UP; } } - return; + return result; case GPIO_CRL_MODE0_OUTPUT_2MHZ: - dest->slew_rate = GPIO_SLEW_SLOWEST; + result.slew_rate = GPIO_SLEW_SLOWEST; break; case GPIO_CRL_MODE0_OUTPUT_10MHZ: - dest->slew_rate = GPIO_SLEW_FAST; + result.slew_rate = GPIO_SLEW_FAST; break; case GPIO_CRL_MODE0_OUTPUT_50MHZ: - dest->slew_rate = GPIO_SLEW_FASTEST; + result.slew_rate = GPIO_SLEW_FASTEST; break; } switch (cnf) { case GPIO_CRL_CNF0_OUTPUT_PUSH_PULL: - dest->state = GPIO_OUTPUT_PUSH_PULL; + result.state = GPIO_OUTPUT_PUSH_PULL; break; case GPIO_CRL_CNF0_OUTPUT_OPEN_DRAIN: - dest->state = GPIO_OUTPUT_OPEN_DRAIN; + result.state = GPIO_OUTPUT_OPEN_DRAIN; break; default: case GPIO_CRL_CNF0_AF_PUSH_PULL: case GPIO_CRL_CNF0_AF_OPEN_DRAIN: - dest->state = GPIO_USED_BY_PERIPHERAL; + result.state = GPIO_USED_BY_PERIPHERAL; } + + return result; } #endif -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf) +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf) { - if ((conf->pull == GPIO_PULL_KEEP) || (conf->state == GPIO_OUTPUT_OPEN_SOURCE)) { + if ((conf.pull == GPIO_PULL_KEEP) || (conf.state == GPIO_OUTPUT_OPEN_SOURCE)) { return -ENOTSUP; } #ifndef GPIO_PUPDR_PUPDR0 /* without dedicated pull up / pull down register, pull resistors can only * be used with input pins */ - if ((conf->state == GPIO_OUTPUT_OPEN_DRAIN) && (conf->pull != GPIO_FLOATING)) { + if ((conf.state == GPIO_OUTPUT_OPEN_DRAIN) && (conf.pull != GPIO_FLOATING)) { return -ENOTSUP; } #endif unsigned state = irq_disable(); _init_clock(port); - if (conf->initial_value) { + if (conf.initial_value) { gpio_ll_set(port, 1UL << pin); } else { @@ -324,35 +333,61 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const 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_pull_config(port, pin, conf->pull); - _set_slew_rate(port, pin, conf->slew_rate); - _set_dir(port, pin, conf->state < GPIO_INPUT); + _set_output_type(port, pin, conf.state == GPIO_OUTPUT_OPEN_DRAIN); + _set_pull_config(port, pin, conf.pull); + _set_slew_rate(port, pin, conf.slew_rate); + _set_dir(port, pin, conf.state < GPIO_INPUT); #endif irq_restore(state); return 0; } -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin) +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin) { - assert(dest); + gpio_conf_t result = { 0 }; unsigned state = irq_disable(); - memset(dest, 0, sizeof(*dest)); #ifdef GPIO_CRL_MODE /* old STM32F1 style GPIO configuration register layout */ - _get_legacy_f1_config(dest, port, pin); + result = _get_legacy_f1_config(port, pin); #else /* modern STM32 style GPIO configuration register layout */ - dest->state = _get_state(port, pin); - dest->pull = _get_pull_config(port, pin); - dest->slew_rate = _get_slew_rate(port, pin); + result.state = _get_state(port, pin); + result.pull = _get_pull_config(port, pin); + result.slew_rate = _get_slew_rate(port, pin); #endif - if (dest->state == GPIO_INPUT) { - dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL; + if (result.state == GPIO_INPUT) { + result.initial_value = (gpio_ll_read(port) >> pin) & 1UL; } else { - dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; + result.initial_value = (gpio_ll_read_output(port) >> pin) & 1UL; } irq_restore(state); + + return result; +} + +void gpio_ll_print_conf(gpio_conf_t conf) +{ + static const char *slew_strs[] = { + [GPIO_SLEW_SLOWEST] = "slowest", +#if STM32_HAS_OSPEED + [GPIO_SLEW_SLOW] = "slow", +#endif + [GPIO_SLEW_FAST] = "fast", + [GPIO_SLEW_FASTEST] = "fastest", +/* If only three slew rates are supported, a fourth value would be + * representable with the two-bit field. Let's be rather safe than sorry */ +#if !STM32_HAS_OSPEED + "invalid" +#endif + }; + + 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 f436a7792625..e8690f002f53 100644 --- a/drivers/include/periph/gpio_ll.h +++ b/drivers/include/periph/gpio_ll.h @@ -299,7 +299,57 @@ typedef enum { + (GPIO_SLEW_SLOW != GPIO_SLEW_FAST) \ + (GPIO_SLEW_FAST != GPIO_SLEW_FASTEST)) -#if !defined(HAVE_GPIO_CONF_T) || defined(DOXYGEN) +/** + * @brief Public members of `gpio_conf_t` + * + * The type `gpio_conf_t` is implementation specific, but will in any case + * be a union of an unsigned integer of implementation defined width named + * `bits` (to access all bits of the configuration in one read/write), and + * an anonymous `struct` to access the actual configuration via its members. + * + * The members given here have to be present in every implementation. Make sure + * to use the `enum` names to assign them, as the actual numeric representation + * again is implementation specific. + * + * It is explicitly intended that code makes use of implementation specific + * extensions to `gpio_conf_t`. However, portable code should be restricted + * to only use the members detailed here and make sure that all other bits + * are initialized with zero. + */ +union gpio_conf_minimal { + uint8_t bits; /**< The raw bits of the configuration */ + struct { + /** + * @brief State of the pin + */ + gpio_state_t state : 3; + /** + * @brief Pull resistor configuration + */ + gpio_pull_t pull : 2; + /** + * @brief Initial value of the output + * + * Ignored if @ref gpio_conf_minimal::state is set to @ref GPIO_INPUT or + * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance + * state, it is guaranteed to directly transition to the given initial + * value. + * + * @ref gpio_ll_query_conf will write the current value of the specified + * pin here, which is read from the input register when the state is + * @ref GPIO_INPUT, otherwise the state from the output register is + * consulted. + */ + bool initial_value : 1; + uint8_t : 2; /*< padding */ + }; +}; + +#if !defined(HAVE_GPIO_CONF_T) && !defined(DOXYGEN) +typedef union gpio_conf_minimal gpio_conf_t; +#endif + +#ifdef DOXYGEN /** * @brief GPIO pin configuration * @@ -309,93 +359,56 @@ typedef enum { * initializers or zeroing out the whole contents using `memset() * before initializing the individual fields. * - * It is fully valid that an implementation extends this structure with - * additional implementation specific fields. For example, it could be useful - * to also include fields to configure routing of a GPIO pin to other - * peripherals (e.g. for us as an TXD pin of an UART). These implementation - * specific fields **MUST** however have reasonable defaults when initialized - * with zero (e.g. pin is not routed to another peripheral but to be used as - * regular GPIO). For obvious reasons, portable code cannot rely on the - * presence and semantic of any implementation specific fields. Additionally, - * out-of-tree users should not use these fields, as the implementation - * specific fields cannot be considered a stable API. - */ -typedef struct { - gpio_state_t state; /**< State of the pin */ - gpio_pull_t pull; /**< Pull resistor configuration */ - /** - * @brief Configure the slew rate of outputs - * - * @warning If the requested slew rate is not available, the closest fit - * supported will be configured instead. - * - * This value is ignored *unless* @ref gpio_conf_t::state is configured - * to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN. - */ - gpio_slew_t slew_rate; - /** - * @brief Whether to enable the input Schmitt trigger - * - * @warning If the requested Schmitt trigger setting is not available, it - * will be ignored. - * - * This value is ignored *unless* @ref gpio_conf_t::state is configured - * to @ref GPIO_INPUT. - */ - bool schmitt_trigger; - /** - * @brief Initial value of the output - * - * Ignored if @ref gpio_conf_t::state is set to @ref GPIO_INPUT or - * @ref GPIO_DISCONNECT. If the pin was previously in a high impedance - * state, it is guaranteed to directly transition to the given initial - * value. - * - * @ref gpio_ll_query_conf will write the current value of the specified - * pin here, which is read from the input register when the state is - * @ref GPIO_INPUT, otherwise the state from the output register is - * consulted. - */ - bool initial_value; - /** - * @brief Strength of the pull up/down resistor - * - * @warning If the requested pull strength is not available, the closest fit - * supported will be configured instead. - * - * This value is ignored when @ref gpio_conf_t::pull is configured to - * @ref GPIO_FLOATING. - */ - gpio_pull_strength_t pull_strength; - /** - * @brief Drive strength of the GPIO - * - * @warning If the requested drive strength is not available, the closest - * fit supported will be configured instead. - * - * This value is ignored when @ref gpio_conf_t::state is configured to - * @ref GPIO_INPUT or @ref GPIO_DISCONNECT. - */ - gpio_drive_strength_t drive_strength; -} gpio_conf_t; + * See @ref gpio_conf_minimal for the minimal structure fields to expect. + */ +typedef /* implementation specific */ gpio_conf_t; #endif +#ifndef __cplusplus +/** + * @name Commonly used GPIO LL configuration presets + * + * @warning These are not available in C++ + * + * C++ requires initializers to be provided in declaration order and contain + * explicit initialization for each and every field. However, the actual + * layout and the number of members of `gpio_conf_t` depends on the + * implementation, so that implementations can expose advanced features such + * as pull strength, driver strength, skew rate, mux settings, etc. The + * API mandates that those extra fields will have a sane default value when + * implicitly initialized with 0, as done here in C. + * + * This doesn't work in C++, unless multiplying the maintenance burden by + * the number of implementations by having each implementation provide this + * by hand. This is not acceptable. + * + * @{ + */ /** * @brief A standard configuration for a generic floating input pin */ -extern const gpio_conf_t gpio_ll_in; +static const gpio_conf_t gpio_ll_in = { + .state = GPIO_INPUT, + .pull = GPIO_FLOATING, +}; /** * @brief A standard configuration for a generic input pin with pull down * resistor */ -extern const gpio_conf_t gpio_ll_in_pd; +static const gpio_conf_t gpio_ll_in_pd = { + .state = GPIO_INPUT, + .pull = GPIO_PULL_DOWN, +}; /** * @brief A standard configuration for a generic input pin with pull up * resistor */ -extern const gpio_conf_t gpio_ll_in_pu; +static const gpio_conf_t gpio_ll_in_pu = { + .state = GPIO_INPUT, + .pull = GPIO_PULL_UP, +}; /** * @brief A standard configuration for a generic input pin with pull @@ -403,15 +416,24 @@ extern const gpio_conf_t gpio_ll_in_pu; * * This means, when the input reaches a 0, a pull down resistor is applied. If * input reaches 1, a pull up is applied instead. + * + * @note This is a rather uncommon feature. MCUs that support this are + * RP2040. */ -extern const gpio_conf_t gpio_ll_in_pk; +static const gpio_conf_t gpio_ll_in_pk = { + .state = GPIO_INPUT, + .pull = GPIO_PULL_KEEP, +}; /** * @brief A standard configuration for a generic push-pull output pin * * @note The pin will have an initial value of 0. */ -extern const gpio_conf_t gpio_ll_out; +static const gpio_conf_t gpio_ll_out = { + .state = GPIO_OUTPUT_PUSH_PULL, + .initial_value = false, +}; /** * @brief A standard configuration for a generic floating open drain output @@ -419,7 +441,11 @@ extern const gpio_conf_t gpio_ll_out; * @note The pin will have an initial value of 1 (which in absence of an * external pull up resistor will be high impedance). */ -extern const gpio_conf_t gpio_ll_od; +static const gpio_conf_t gpio_ll_od = { + .state = GPIO_OUTPUT_OPEN_DRAIN, + .pull = GPIO_FLOATING, + .initial_value = true, +}; /** * @brief A standard configuration for a generic open drain output with pull @@ -428,7 +454,13 @@ extern const gpio_conf_t gpio_ll_od; * @note The pin will have an initial value of 1 (so that the pull up will * pill the line high). */ -extern const gpio_conf_t gpio_ll_od_pu; +static const gpio_conf_t gpio_ll_od_pu = { + .state = GPIO_OUTPUT_OPEN_DRAIN, + .pull = GPIO_PULL_UP, + .initial_value = true, +}; +/** @} */ +#endif /** * @brief Check if the given number is a valid argument for @ref GPIO_PORT @@ -476,23 +508,23 @@ static inline bool is_gpio_port_num_valid(uint_fast8_t num); * different pins on the same port is supported. The underlying * implementation might perform locking where needed. */ -int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf); +int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf); /** * @brief Retrieve the current configuration of a GPIO pin * - * @param[out] dest Write the current config of the given GPIO here * @param[in] port GPIO port the pin to query is located at * @param[in] pin Number of the pin to query within @p port + * @return The current config of the given GPIO here * * @pre @p port and @p pin refer to an existing GPIO pin and @p dest can * be written to. Expect blowing assertions otherwise. * - * @note @ref gpio_conf_t::initial_value should be set to the current value - * of the pin, so that no shadow log of the initial value is needed to - * consult. + * @note @ref gpio_conf_minimal::initial_value should be set to the current + * value of the pin, so that no shadow log of the initial value is + * needed to consult. */ -void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin); +gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin); /** * @brief INTERNAL, use @ref gpio_ll_print_conf instead @@ -502,13 +534,13 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin); * more members overwrite @ref gpio_ll_print_conf and call this function to * print the common members */ -void gpio_ll_print_conf_common(const gpio_conf_t *conf); +void gpio_ll_print_conf_common(const gpio_conf_t conf); /** * @brief Utility function to print a given GPIO configuration to stdio * @param[in] conf Configuration to print */ -void gpio_ll_print_conf(const gpio_conf_t *conf); +void gpio_ll_print_conf(const gpio_conf_t conf); /** * @brief Get the current input value of all GPIO pins of the given port as diff --git a/drivers/periph_common/gpio_ll.c b/drivers/periph_common/gpio_ll.c index a90a6695c023..392354515c76 100644 --- a/drivers/periph_common/gpio_ll.c +++ b/drivers/periph_common/gpio_ll.c @@ -6,8 +6,6 @@ * directory for more details. */ -#include -#include #include #include "periph/gpio_ll.h" @@ -29,60 +27,12 @@ static inline void print_str(const char *str) } #endif -const gpio_conf_t gpio_ll_in = { - .state = GPIO_INPUT, - .pull = GPIO_FLOATING, - .schmitt_trigger = true, -}; - -const gpio_conf_t gpio_ll_in_pd = { - .state = GPIO_INPUT, - .pull = GPIO_PULL_DOWN, - .schmitt_trigger = true, -}; - -const gpio_conf_t gpio_ll_in_pu = { - .state = GPIO_INPUT, - .pull = GPIO_PULL_UP, - .schmitt_trigger = true, -}; - -const gpio_conf_t gpio_ll_in_pk = { - .state = GPIO_INPUT, - .pull = GPIO_PULL_KEEP, - .schmitt_trigger = true, -}; - -const gpio_conf_t gpio_ll_out = { - .state = GPIO_OUTPUT_PUSH_PULL, - .drive_strength = GPIO_DRIVE_STRONGEST, - .slew_rate = GPIO_SLEW_FASTEST, - .initial_value = false, -}; - -const gpio_conf_t gpio_ll_pd = { - .state = GPIO_OUTPUT_OPEN_DRAIN, - .pull = GPIO_FLOATING, - .drive_strength = GPIO_DRIVE_STRONGEST, - .slew_rate = GPIO_SLEW_FASTEST, - .initial_value = true, -}; - -const gpio_conf_t gpio_ll_pd_pu = { - .state = GPIO_OUTPUT_OPEN_DRAIN, - .pull = GPIO_PULL_UP, - .drive_strength = GPIO_DRIVE_STRONGEST, - .slew_rate = GPIO_SLEW_FASTEST, - .initial_value = true, -}; - -void gpio_ll_print_conf_common(const gpio_conf_t *conf) +void gpio_ll_print_conf_common(const gpio_conf_t conf) { - assert(conf); const char *off_on[] = { "off", "on" }; print_str("state: "); - switch (conf->state) { + switch (conf.state) { case GPIO_OUTPUT_PUSH_PULL: print_str("out-pp"); break; @@ -103,42 +53,9 @@ void gpio_ll_print_conf_common(const gpio_conf_t *conf) break; } - if (conf->state != GPIO_INPUT) { - if (GPIO_DRIVE_NUMOF > 1) { - print_str(", drive: "); - if (conf->drive_strength == GPIO_DRIVE_WEAK) { - print_str("weak"); - } - else if (conf->drive_strength == GPIO_DRIVE_WEAKEST) { - print_str("weakest"); - } - else if (conf->drive_strength == GPIO_DRIVE_STRONG) { - print_str("strong"); - } - else { - print_str("strongest"); - } - } - if (GPIO_SLEW_NUMOF > 1) { - print_str(", slew: "); - if (conf->slew_rate == GPIO_SLEW_SLOW) { - print_str("slow"); - } - else if (conf->slew_rate == GPIO_SLEW_SLOWEST) { - print_str("slowest"); - } - else if (conf->slew_rate == GPIO_SLEW_FAST) { - print_str("fast"); - } - else { - print_str("fastest"); - } - } - } - - if (conf->state != GPIO_OUTPUT_PUSH_PULL) { + if (conf.state != GPIO_OUTPUT_PUSH_PULL) { print_str(", pull: "); - switch (conf->pull) { + switch (conf.pull) { default: case GPIO_FLOATING: print_str("none"); @@ -153,30 +70,10 @@ void gpio_ll_print_conf_common(const gpio_conf_t *conf) print_str("keep"); break; } - - if ((conf->pull != GPIO_FLOATING) && (GPIO_PULL_NUMOF > 1)) { - print_str(" ("); - if (conf->pull_strength == GPIO_PULL_WEAK) { - print_str("weak"); - } - else if (conf->pull_strength == GPIO_PULL_WEAKEST) { - print_str("weakest"); - } - else if (conf->pull_strength == GPIO_PULL_STRONG) { - print_str("strong"); - } - else { - print_str("strongest"); - } - print_str(")"); - } - - print_str(", schmitt trigger: "); - print_str(off_on[conf->schmitt_trigger]); } print_str(", value: "); - print_str(off_on[conf->initial_value]); + print_str(off_on[conf.initial_value]); } /* implement gpio_ll_print_conf as weak alias symbol for @@ -184,4 +81,4 @@ void gpio_ll_print_conf_common(const gpio_conf_t *conf) * override gpio_ll_print_conf while reusing gpio_ll_print_conf_common() */ __attribute__((weak, alias("gpio_ll_print_conf_common"))) -void gpio_ll_print_conf(const gpio_conf_t *conf); +void gpio_ll_print_conf(gpio_conf_t conf); diff --git a/drivers/ws281x/timer_gpio_ll.c b/drivers/ws281x/timer_gpio_ll.c index 652f5af0ae4f..204a00284e40 100644 --- a/drivers/ws281x/timer_gpio_ll.c +++ b/drivers/ws281x/timer_gpio_ll.c @@ -143,7 +143,7 @@ int ws281x_init(ws281x_t *dev, const ws281x_params_t *params) gpio_port_t port = gpio_get_port(dev->params.pin); uint8_t pin = gpio_get_pin_num(dev->params.pin); - err = gpio_ll_init(port, pin, &gpio_ll_out); + err = gpio_ll_init(port, pin, gpio_ll_out); DEBUG("Initializing port %x pin %d (originally %x): %d\n", port, pin, params->pin, err); if (err != 0) { diff --git a/tests/bench/periph_gpio_ll/main.c b/tests/bench/periph_gpio_ll/main.c index 17c399985868..baf5496f734c 100644 --- a/tests/bench/periph_gpio_ll/main.c +++ b/tests/bench/periph_gpio_ll/main.c @@ -18,17 +18,13 @@ * @} */ -#include #include -#include -#include -#include "mutex.h" #include "periph/gpio.h" #include "periph/gpio_ll.h" #include "test_utils/expect.h" +#include "time_units.h" #include "ztimer.h" -#include "timex.h" #ifndef COMPENSATE_OVERHEAD #define COMPENSATE_OVERHEAD 1 @@ -157,10 +153,9 @@ int main(void) "-------------------------------------------------------"); 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)); + 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--) { @@ -211,10 +206,9 @@ int main(void) "-----------------------------------------"); 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)); + 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--) { @@ -265,10 +259,9 @@ int main(void) "----------------------------------------"); 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)); + 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); diff --git a/tests/periph/gpio_ll/Makefile b/tests/periph/gpio_ll/Makefile index 3ef4275489f5..eec61d6f1bb3 100644 --- a/tests/periph/gpio_ll/Makefile +++ b/tests/periph/gpio_ll/Makefile @@ -10,11 +10,11 @@ BOARD ?= nucleo-f767zi # first output pin and the second input pin to the second output pin, e.g. using # jumper wires. PORT_IN ?= 1 -PORT_OUT ?= 0 +PORT_OUT ?= 1 PIN_IN_0 ?= 0 PIN_IN_1 ?= 1 -PIN_OUT_0 ?= 0 -PIN_OUT_1 ?= 1 +PIN_OUT_0 ?= 2 +PIN_OUT_1 ?= 3 # Boards that require tweaking for low ROM LOW_ROM_BOARDS := \ diff --git a/tests/periph/gpio_ll/main.c b/tests/periph/gpio_ll/main.c index dbdfcf904d2a..03a8423011b3 100644 --- a/tests/periph/gpio_ll/main.c +++ b/tests/periph/gpio_ll/main.c @@ -29,6 +29,7 @@ #include "periph/gpio_ll_irq.h" #include "timex.h" #include "ztimer.h" +#include "flash_utils.h" #ifndef LOW_ROM #define LOW_ROM 0 @@ -40,12 +41,16 @@ static gpio_port_t port_in = GPIO_PORT(PORT_IN); static const uint64_t mutex_timeout = US_PER_MS; +#if LOW_ROM static void puts_optional(const char *str) { - if (!LOW_ROM) { - puts(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 @@ -114,6 +119,12 @@ static void test_gpio_port_pack(void) puts_optional("All OK"); } +static void print_conf(gpio_conf_t conf) +{ + gpio_ll_print_conf(conf); + puts(""); +} + static void test_gpio_ll_init(void) { bool is_supported; @@ -127,47 +138,39 @@ static void test_gpio_ll_init(void) 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)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); + 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(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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 */ @@ -179,31 +182,28 @@ static void test_gpio_ll_init(void) .state = GPIO_OUTPUT_PUSH_PULL, .initial_value = false, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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); - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); + conf = gpio_ll_query_conf(port_out, PIN_OUT_0); expect((conf.state == GPIO_OUTPUT_PUSH_PULL) && conf.initial_value); } @@ -212,17 +212,15 @@ static void test_gpio_ll_init(void) .state = GPIO_OUTPUT_PUSH_PULL, .initial_value = true, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); @@ -236,17 +234,15 @@ static void test_gpio_ll_init(void) .initial_value = false, .pull = GPIO_PULL_UP }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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); @@ -261,17 +257,15 @@ static void test_gpio_ll_init(void) .initial_value = true, .pull = GPIO_PULL_UP }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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); @@ -286,17 +280,15 @@ static void test_gpio_ll_init(void) .initial_value = false, .pull = GPIO_FLOATING, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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); @@ -311,25 +303,21 @@ static void test_gpio_ll_init(void) .initial_value = true, .pull = GPIO_FLOATING, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); + 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(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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", @@ -340,12 +328,10 @@ static void test_gpio_ll_init(void) 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)); + 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(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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", @@ -364,25 +350,21 @@ static void test_gpio_ll_init(void) .initial_value = false, .pull = GPIO_FLOATING, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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)); + 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(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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", @@ -393,12 +375,10 @@ static void test_gpio_ll_init(void) 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)); + 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(&conf, port_in, PIN_IN_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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", @@ -411,7 +391,7 @@ static void test_gpio_ll_init(void) } } - expect(0 == gpio_ll_init(port_in, PIN_IN_0, &gpio_ll_in)); + expect(0 == gpio_ll_init(port_in, PIN_IN_0, gpio_ll_in)); { gpio_conf_t conf = { @@ -419,17 +399,15 @@ static void test_gpio_ll_init(void) .initial_value = true, .pull = GPIO_FLOATING, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + 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]); if (is_supported) { - gpio_conf_t conf; - gpio_ll_query_conf(&conf, port_out, PIN_OUT_0); - gpio_ll_print_conf(&conf); - puts_optional(""); + 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); @@ -444,7 +422,7 @@ static void test_gpio_ll_init(void) .initial_value = true, .pull = GPIO_PULL_DOWN, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf)); } printf_optional("Support for output (open source with pull up) with initial " "value of HIGH: %s\n", @@ -463,7 +441,7 @@ static void test_gpio_ll_init(void) .initial_value = false, .pull = GPIO_PULL_DOWN, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf)); } printf_optional("Support for output (open source with pull up) with initial " "value of LOW: %s\n", @@ -480,13 +458,13 @@ static void test_gpio_ll_init(void) gpio_conf_t conf = { .state = GPIO_DISCONNECT, }; - is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, &conf)); + is_supported = (0 == gpio_ll_init(port_out, PIN_OUT_0, conf)); } printf_optional("Support for disconnecting GPIO: %s\n", noyes[is_supported]); /* This is mandatory */ expect(is_supported); - is_supported = (0 == gpio_ll_init(port_in, PIN_IN_0, &gpio_ll_in_pd)); + 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)); @@ -498,7 +476,7 @@ static void test_gpio_ll_init(void) 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)); + 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)); @@ -518,10 +496,10 @@ static void test_input_output(void) "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)); + 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); @@ -799,8 +777,8 @@ static void test_irq(void) "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();