[PATCH] Proposal for new GPIO API and example implementation for STM32F4 BSP

oss at c-mauderer.de oss at c-mauderer.de
Sun Jun 19 15:16:31 UTC 2022


Hello Duc,

Am 14.06.22 um 16:46 schrieb Duc Doan:
> Dear all,
> 
> I am proposing a new GPIO API for RTEMS. The current API is kind of tailored to some specific hardware and therefore may require some overhead to make it fit for others. The one I am proposing is not finished but it is aimed to be simple and generic. It has some opaque type structures that need to be implemented by BSP. The functions include initialization, configuration, reading, writing, and toggle. I took inspiration from the Wiring framework. I also have an example implementation for the STM32F4 BSP.

Using examples of working APIs is a good idea. But be careful not to 
copy any code from that framework because the license (GPL) wouldn't be 
compatible.

> 
> I would love to get feedback from all of you.
> 
> Thank you,
> 
> Duc Doan
> 
> ---
>   bsps/arm/stm32f4/gpio/gpio.c |  39 +++++++++++
>   bsps/include/bsp/gpio2.h     | 129 +++++++++++++++++++++++++++++++++++
>   2 files changed, 168 insertions(+)
>   create mode 100644 bsps/arm/stm32f4/gpio/gpio.c
>   create mode 100644 bsps/include/bsp/gpio2.h
> 
> diff --git a/bsps/arm/stm32f4/gpio/gpio.c b/bsps/arm/stm32f4/gpio/gpio.c
> new file mode 100644
> index 0000000000..40aea3febd
> --- /dev/null
> +++ b/bsps/arm/stm32f4/gpio/gpio.c
> @@ -0,0 +1,39 @@
> +#include <bsp.h>
> +#include <rtems.h>
> +#include <bsp/gpio2.h>
> +#include <stm32f4xx_hal.h>
> +
> +struct rtems_gpio_t {
> +    GPIO_TypeDef *port;
> +};
> +
> +struct rtems_gpio_pin_t {
> +    uint16_t pin_mask;
> +};
> +
> +struct rtems_gpio_config_t {
> +    GPIO_InitTypeDef *config;
> +}
> +
> +__weak rtems_status_code rtems_gpio_initialize(void) {
> +    return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_configure(rtems_gpio_t *gpiox, rtems_gpio_config_t *config) {
> +    HAL_GPIO_Init(gpiox->port, config->config);
> +    return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_write_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin, rtems_gpio_pin_state value) {
> +    HAL_GPIO_WritePin(gpiox->port, pin->pin_mask, value);
> +    return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_gpio_pin_state rtems_gpio_read_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin) {
> +    return HAL_GPIO_ReadPin(gpiox->port, pin->pin_mask);
> +}
> +
> +rtems_status_code rtems_gpio_toggle_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin) {
> +    HAL_GPIO_TogglePin(gpiox->port, pin->pin_mask);
> +    return RTEMS_SUCCESSFUL;
> +}
> diff --git a/bsps/include/bsp/gpio2.h b/bsps/include/bsp/gpio2.h
> new file mode 100644
> index 0000000000..ef10d1729a
> --- /dev/null
> +++ b/bsps/include/bsp/gpio2.h
> @@ -0,0 +1,129 @@
> +/**
> +  * @file
> +  *
> +  * @ingroup rtems_gpio2
> +  *
> +  * @brief RTEMS GPIO new API definition.
> +  */
> +
> + /*
> +  *  Copyright (c) 2022 Duc Doan <dtbpkmte at gmail.com>
> +  *
> +  *  The license and distribution terms for this file may be
> +  *  found in the file LICENSE in this distribution or at
> +  *  http://www.rtems.org/license/LICENSE.
> +  */
> +
> +#ifndef LIBBSP_SHARED_GPIO2_H
> +#define LIBBSP_SHARED_GPIO2_H
> +
> +#include <bsp.h>
> +#include <rtems.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +/**
> + * @name GPIO data structures
> + *
> + * @{
> + */
> +
> +/**
> +  * @brief GPIO bit set and reset enumeration.
> +  */
> +typedef enum {
> +    RTEMS_GPIO_PIN_SET = 0,
> +    RTEMS_GPIO_PIN_RESET
> +} rtems_gpio_pin_state;

Is set and reset the only state a pin can have? Or is that field thought 
to be extended with (for example) open drain or similar states if a 
device supports that?

Beneath that: Not a fan of SET == 0. I think RESET == 0 would be better 
because than you can use it as a boolean without conversion.

> +
> +/**
> +  * @brief Opaque type for a GPIO object.
> +  *        To be implemented by BSP.
> +  *
> +  * @details This could represent the unit that owns GPIO pins.
> +  *          For example, it would be a port for ARM Cortex-M.
> +  */
> +typedef struct rtems_gpio_t rtems_gpio_t;

Does that mean it is (for example) a GPIO controller? In that case maybe 
call it "rtems_gpio_ctrl_t". My first guess from the name would have 
been that it is already a pin.

I assume that you don't plan to publish the definition of the struct 
rtems_gpio_t, right? With that the application can only use pointers. 
Where does the application get the pointer from?

Same is true for the structures below: How would I initialize one of 
these objects in the application?

> +
> +/**
> +  * @brief Opaque type for a GPIO pin object.
> +  *        To be implemented by BSP.
> +  */
> +typedef struct rtems_gpio_pin_t rtems_gpio_pin_t;
> +
> +/**
> +  * @brief Opaque type for configuration of a GPIO object.
> +  *        To be implemented by BSP.
> +  */
> +typedef struct rtems_gpio_config_t;
> +
> +/** @} */
> +
> +/**
> +  * @name GPIO Functions
> +  *
> +  * @{
> +  */
> +
> +/**
> +  * @brief Initialization for GPIO. To be implemented by User Application.
> +  *
> +  * @retval RTEMS_SUCCESSFUL GPIO successfully initialized.
> +  * @retval RTEMS_UNSATISFIED Could not initialize GPIO object.
> +  */
> +extern rtems_status_code rtems_gpio_initialize(void);
> +

What would be done in that function?

Why does the application has to implement it?

Where would it be called?

> +/**
> +  * @brief Configures a GPIO object.
> +  *        To be implemented by BSP.
> +  *
> +  * @param[in] gpiox The GPIO object to be configured.
> +  * @param[in] config The GPIO configuration object.
> +  *
> +  * @retval RTEMS_SUCCESSFUL GPIO configured successfully.
> +  * @retval RTEMS_UNSATISFIED Could not configure GPIO object.
> +  */
> +extern rtems_status_code rtems_gpio_configure(rtems_gpio_t *gpiox, rtems_gpio_config_t *config);
> +
> +/**
> +  * @brief Writes a digital value to a pin/pins.
> +  *
> +  * @param[in] gpiox The GPIO object that owns the pin(s).
> +  * @param[in] pin The GPIO pin number or pin mask to be written.
> +  * @param[in] value The state to be written to the pin(s).
> +  *
> +  * @retval RTEMS_SUCCESSFUL Pin successfully written.
> +  * @retval RTEMS_UNSATISFIED Could not write to pin(s).
> +  */
> +extern rtems_status_code rtems_gpio_write_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin, rtems_gpio_pin_state value);

What would be possible error cases? Is one "UNSATISFIED" enough or 
should it be able to return other errors too (like the return value from 
an I2C transfer because the pin is connected to some SPI-GPIO extender).

> +
> +/**
> +  * @brief Reads the digital value of a pin/pins.
> +  *
> +  * @param[in] gpiox The GPIO object that owns the pin(s).
> +  * @param[in] pin The GPIO pin(s) to be read.
> +  *
> +  * @retval The state of the pin(s).
> +  */
> +extern rtems_gpio_pin_state rtems_gpio_read_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin);
> +

If the write can fail, the read can also fail. Do we need an error 
return value too?

Best regards

Christian

> +/**
> +  * @brief Toggles the state of a GPIO pin/pins.
> +  *
> +  * @param[in] gpiox The GPIO object that owns the pin(s).
> +  * @param[in] pin The GPIO pin(s) to be toggled.
> +  *
> +  * @retval RTEMS_SUCCESSFUL Pin(s) successfully toggled.
> +  * @retval RTEMS_UNSATISFIED Could not toggle pin(s).
> +  */
> +extern rtems_status_code rtems_gpio_toggle_pin(rtems_gpio_t *gpiox, rtems_gpio_pin_t *pin);
> +
> +/** @} */
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* LIBBSP_SHARED_GPIO2_H */


More information about the devel mailing list