1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/periph/gpio_ll: change gpio_ll_switch_dir API

It turns out that the feature to switch the GPIO direction quickly
is not only a way to emulate open drain / open source mode for less
sophisticated GPIO peripherals that do not natively support it.
It also enables tri-state output (push-pull high, push-pull low,
high impedance), which is useful e.g. for driven charlieplexed LEDs
quickly.

This changes the API by introducing a `gpio_ll_prepare_switch_dir()`
function that prepares the value used to identify which pins should
be switched to input or to output mode. This is useful for GPIO
peripherals in which the GPIO mode register does not allocate one bit
per pin (so that only the direction is given there), such as the one
for STM32. This allows an STM32 implementation in which preparing the
bitmask needed to modify the direction of pins is not trivial.
This commit is contained in:
Marian Buschsieweke 2024-08-02 17:48:21 +02:00
parent a1efa07c07
commit a6b459eff3
No known key found for this signature in database
GPG Key ID: 77AA882EC78084E6
3 changed files with 29 additions and 22 deletions

View File

@ -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

View File

@ -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

View File

@ -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 */