diff --git a/drivers/include/periph/gpio_ll.h b/drivers/include/periph/gpio_ll.h index 6dec66d5cc..f7494f49c5 100644 --- a/drivers/include/periph/gpio_ll.h +++ b/drivers/include/periph/gpio_ll.h @@ -731,29 +731,39 @@ static inline uword_t gpio_ll_prepare_write(gpio_port_t port, uword_t mask, } #endif +#if defined(DOXYGEN) || !defined(HAVE_GPIO_LL_PREPARE_SWITCH_DIR) /** - * @brief Turn GPIO pins specified by the bitmask @p outputs to outputs + * @brief Prepare bitmask for use with @ref gpio_ll_switch_dir_output + * and @ref gpio_ll_switch_dir_input + * @param[in] mask bitmask specifying the pins to switch the direction of + * + * @return Value to use in @ref gpio_ll_switch_dir_output or + * @ref gpio_ll_switch_dir_input + */ +static inline uword_t gpio_ll_prepare_switch_dir(uword_t mask) +{ + return mask; +} +#endif + +/** + * @brief Turn GPIO pins specified by @p pins (obtained from + * @ref gpio_ll_prepare_switch_dir) to outputs * * @param[in] port GPIO port to modify - * @param[in] outputs Bitmask specifying the GPIO pins to set in output - * mode + * @param[in] pins Output of @ref gpio_ll_prepare_switch_dir * @pre The feature `gpio_ll_switch_dir` is available * @pre Each affected GPIO pin is either configured as input or as * push-pull output. - * - * @note This is a makeshift solution to implement bit-banging of - * bidirectional protocols on less sophisticated GPIO peripherals - * that do not support open drain mode. - * @warning Use open drain mode instead, if supported. */ -static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t outputs); +static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t pins); /** - * @brief Turn GPIO pins specified by the bitmask @p inputs to inputs + * @brief Turn GPIO pins specified by @p pins (obtained from + * @ref gpio_ll_prepare_switch_dir) to inputs * * @param[in] port GPIO port to modify - * @param[in] inputs Bitmask specifying the GPIO pins to set in input - * mode + * @param[in] pins Output of @ref gpio_ll_prepare_switch_dir * @pre The feature `gpio_ll_switch_dir` is available * @pre Each affected GPIO pin is either configured as input or as * push-pull output. @@ -765,12 +775,8 @@ static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t outputs); * resistor is enabled). Hence, the bits in the output * register of the pins switched to input should be restored * just after this call. - * @note This is a makeshift solution to implement bit-banging of - * bidirectional protocols on less sophisticated GPIO peripherals - * that do not support open drain mode. - * @warning Use open drain mode instead, if supported. */ -static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t inputs); +static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t pins); /** * @brief Perform a masked write operation on the I/O register of the port diff --git a/features.yaml b/features.yaml index 6821cad0a8..4620882675 100644 --- a/features.yaml +++ b/features.yaml @@ -567,9 +567,9 @@ groups: help: The GPIO LL driver allows switching the direction between input and (push-pull) output in an efficient manner. The main use case is bit-banging bidirectional protocols when open-drain / open-source - mode is not supported. GPIO LL drivers for peripherals that do - support open drain mode typically do not bother implementing this, - even if the hardware would allow it. + mode is not supported. Another use case is controlling GPIOs + at high speed with three output states (high, low, high impedance), + as e.g. needed for Charlieplexing - title: Serial Interfaces help: Features related to serial interfaces diff --git a/tests/periph/gpio_ll/main.c b/tests/periph/gpio_ll/main.c index 2c1011c78e..71c47c2920 100644 --- a/tests/periph/gpio_ll/main.c +++ b/tests/periph/gpio_ll/main.c @@ -905,6 +905,7 @@ static void test_switch_dir(void) "===========================\n"); uword_t mask_out = 1U << PIN_OUT_0; + uword_t pins_out = gpio_ll_prepare_switch_dir(mask_out); uword_t mask_in = 1U << PIN_IN_0; /* floating input must be supported by every MCU */ @@ -924,7 +925,7 @@ static void test_switch_dir(void) uword_t out_state = gpio_ll_read_output(port_out); /* now, switch to output mode and verify the switch */ - gpio_ll_switch_dir_output(port_out, mask_out); + gpio_ll_switch_dir_output(port_out, pins_out); conf = gpio_ll_query_conf(port_out, PIN_OUT_0); test_passed = (conf.state == GPIO_OUTPUT_PUSH_PULL); printf_optional("Input pin can be switched to output (push-pull) mode: %s\n", @@ -940,7 +941,7 @@ static void test_switch_dir(void) expect(test_passed); /* switch back to input mode */ - gpio_ll_switch_dir_input(port_out, mask_out); + gpio_ll_switch_dir_input(port_out, pins_out); /* restore out state from before the switch */ gpio_ll_write(port_out, out_state); /* verify we are back at the old config */