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

Christian MAUDERER christian.mauderer at embedded-brains.de
Mon Jun 27 11:33:56 UTC 2022


Hello Duc,

Am 27.06.22 um 12:39 schrieb Duc Doan:
> Hello Christian and Karel,
> 
> On Mon, 2022-06-27 at 08:29 +0200, Christian MAUDERER wrote:
>> Please think about whether you want to start at 0 or at 1!
>>
> 
> I want it to start at 0.
> 
>>
>> Be really careful with that syntax. If you use increasing numbers
>> like
>> you suggested, every controller would have to know it's own offest.
>> On
>> the other hand, if there is a unique number to each pin, you don't
>> necessarily need the "ctrl" pointer at all. You can just use
>> something like
>>
>>      rtems_gpio_write(60, RTEMS_GPIO_PIN_SET);
>>
>> That's an advantage from the usage perspective because you don't have
>> to
>> fetch the GPIO controller and can work with a single pin number.
>>
>> Disadvantage is a overhead in the API: You have to create some global
>> table with GPIO controllers and their first and last pins. That table
>> has to be searched for every operation. In the worst case it adds a
>> loop
>> over the table with one comparison for each entry. Most systems
>> should
>> only have a hand full of GPIO controller so it's not too much but
>> it's a
>> lot more than just one pointer de-referencing. There could be methods
>> to
>> optimize the search so the loop might isn't the best solution. But
>> every
>> search is slower than if you already have the pointer.
>>
>> It's more or less a trade-off. There are good arguments for both
>> directions. I think I have seen both directions implemented in
>> different
>> situations.
>>
> 
> You are right; having both ctrl and virtual pin number is abundant.
> Karel's email gave me some inspiration to (hopefully) improve this:
> 
> On Mon, 2022-06-27 at 10:25 +0200, Karel Gardas wrote:
>> In fact I guess ctrl structure would contain some BSP specific data
>> and
>> since bsp_gpio_get_ctrl is BSP specific function for f4 that means in
>> ctrl you will save your GPIOx and pin number -- e.g. hardware
>> specific
>> pin representation.
>>
>> This means on write/read you do not need to map virtual pin ->
>> physical
>> pin again, but in fact use physical pin from ctrl and be as fast as
>> possible.
>>
> 
> Actually as of now, my ctrl structure only has pointers to handlers and
> GPIOx (F4 only). Pin number was not in there, but I am thinking
> including pin number inside that structure might work. The changes I
> want to make would be:
> 
> - ctrl structure will now include both pointers to handlers and BSP-
> specific physical port/pin
> 
> struct rtems_gpio_ctrl {
>      rtems_gpio_handlers_t *handlers;
> }
> 
> struct stm32f4_gpio_ctrl {
>      rtems_gpio_ctrl base;
>      GPIO_TypeDef *GPIOx;
>      uint32_t pin; //physical
> }
> 
> - I will create 2 internal tables (based on Christian's suggestion) to
> store the last pins of each controller and pointers to the get_ctrl()
> functions. For example, if STM32 has 16 pins per port and 4 ports in
> total, my table would be:
> 
> uint32_t table[MAX_CONTROLLERS] = {16, 32, 48, 64};
> 
> These numbers and the controller pointers are added to the tables by
> calling a register() function for each controller. BSPs need to
> implement an initialize() function. The prototype of initialize() is
> provided by the GPIO API. initialize() needs to be called before any
> GPIO operation in the application.
> 
> If GPIO expanders exist, their drivers need to have similar initialize
> functions that call the register().
> 
> Currently I can only think of binary search as a faster method than a
> for loop. rtems_gpio_get_ctrl(virtual_pin) will search for the correct
> controller, call the BSP/driver-specific get_ctrl(), and return the
> result.
> 
> - Because pin number is now in ctrl, functions only need to provide
> pointer to ctrl object.
> 
> Below is an example program with a fake STM32 with 4 GPIOs/16 pins
> each. Two GPIO expanders (exA, exB) are used.
> 
> /********** API header *******/
> void register(void (*get_ctrl) (uint32_t pin), uint32_t num_pins); //
> shared, already implemented
> void initialize(void); // to be implemented by BSP
> 
> /********** stm32f4 gpio.c **********/
> void rtems_gpio_initialize(void) {
>      register(stm32f4_get_ctrl, 16); // port A
>      register(stm32f4_get_ctrl, 16); // port B
>      register(stm32f4_get_ctrl, 16); // port C
>      register(stm32f4_get_ctrl, 16); // port D
> }
> 
> /********* application blink.c *******/
> 
> // initialization
> rtems_gpio_initialize();
> exA_initialize(); // registers pins to the table
> exB_initialize(); // registers pins to the table
> 
> uint32_t led_pin = 60; // just a random number
> rtems_gpio_ctrl_t *led_ctrl = rtems_gpio_get_ctrl(60);
> 
> rtems_gpio_write(led_ctrl, RTEMS_GPIO_PIN_SET);

I think I misinterpreted the rtems_gpio_ctrl_t in my earlier mail. With 
this example it's now much clearer that the rtems_gpio_ctrl_t now 
represents a pin (or maybe a pin group) and not a controller any more. I 
would suggest to rename it to rtems_gpio_t or rtems_gpio_pin_t to make 
that more clear. Otherwise: OK for me.

> 
> /********* END OF EXAMPLE **************/
> 
> The only place where the search must be done is now in get_ctrl(), so
> read/write operations are still fast. One drawback of this approach
> might be the support for pin groups, but currently I have quite little
> clue about that.

To have the search only in the get_... function sounds good.

Regarding pin groups: I think it's worth to think a bit about how the 
structure could be extended. You don't have to implement it right now 
but you should have a plan what could be possible.

 From my point of view, there are two directions how that could be 
implemented: Masks or lists.

If you have a mask (like 0x00108 for pin 3 and pin 8) it has the 
advantage that it works fast for most controllers. Difficult is that it 
adds a limit to the maximum pin number depending on the size of the 
mask. With that it works only for a few hardware models.

The other option is to add a list of pins instead of a mask. That makes 
it inefficient because most controllers will have to collect pins into 
masks and work with that.

Hm. Difficult. Maybe someone else has a good idea for that in the next 
few days.

Best regards

Christian

> 
> What do you think about these changes?
> 
> Thank you,
> 
> Duc Doan
> 
>>>
>>> This, however, only returns integrated GPIO from a BSP. In order to
>>> use
>>> a GPIO expansion, a separate function must be used. Each GPIO
>>> expander
>>> driver will have its own get_ctrl function. For example, when using
>>> 2
>>> different expanders exA and exB:
>>>
>>> rtems_gpio_ctrl_t *exA_ctrl = exA_get_ctrl(pin);
>>> rtems_gpio_ctrl_t *exB_ctrl = exB_get_ctrl(pin);
>>
>> What would be the pin numbers in that case? You mentioned that the
>> STM32F4 has 16 pins per GPIO. Let's assume it's 4 GPIOs so the last
>> internal GPIO would be 16*4-1=63. Would the first registered expander
>> have pin numbers starting at 64 or again at 0?
>>
>> I would strongly suggest to use the same method for internal and
>> external GPIOs. If you start with 0 for an expander, start with 0 for
>> each internal GPIO controller too (in the STM example: You should
>> have 4
>> internal pins with the number 0). If you plan to have an increasing
>> number, use that for the external GPIO controllers too.
>>
>> Best regards
>>
>> Christian
>>
>>>
>>> I think this method will assure that it compiles and works on all
>>> BSPs
>>> but needs an additional function to get the controller of an
>>> expander.
>>> A drawback might be added computation because of translating
>>> abstract
>>> pin number to physical pin/port.
>>>
>>> What do you think about this?
>>>
>>> Best,
>>>
>>> Duc Doan
>>>
>>> On Sun, 2022-06-26 at 20:48 +0200, Karel Gardas wrote:
>>>> On 6/26/22 10:49, Duc Doan wrote:
>>>>>>> #define rtems_gpio_get_ctrl(_driver, _arg, _out) \
>>>>>>>         _driver##_gpio_get_ctrl( _arg , _out )
>>>>>>>
>>>>>>> In the application code:
>>>>>>>
>>>>>>> rtems_gpio_get_ctrl(stm32f4, GPIOD, &led_ctrl);
>>>>>>> rtems_gpio_get_ctrl(stm32f4, GPIOA, &button_ctrl);
>>>>>>
>>>>>> It's only a different method of writing the same. It won't
>>>>>> solve
>>>>>> Karels
>>>>>> problem because it still wouldn't compile on another BSP.
>>>>>>
>>>>>
>>>>> Do you mean this application code should compile on other BSPs
>>>>> without
>>>>> changing the source?
>>>>
>>>> Yes, that's exactly what portability means and that's exactly
>>>> what is
>>>> desired outcome of the API here -- if I'm not mistaken in your
>>>> project
>>>> outcome specification. :-)
>>>>
>>>> I'm not expert here, so please bear with me, but as I see it, you
>>>> will
>>>> need to come with some abstraction for groups and pins and write
>>>> API
>>>> around it. Then in BSP you will perform/provide a mapping between
>>>> your
>>>> abstracted group/pins construct and between actual hardware. This
>>>> way,
>>>> if I take example from stm32f4 and try to compile on rpi4, it
>>>> will
>>>> compile well -- but it will not run well (probably!) of course.
>>>> But
>>>> API
>>>> wise, it will compile. Now, to make it run, I'll need to connect
>>>> LED
>>>> example following BSP specific mapping and for that I need to
>>>> consult
>>>> BSP docs.
>>>>
>>>>> I am a bit confused about that because I thought
>>>>> at least we still need to specify the pin/port. And if we have
>>>>> multiple
>>>>> GPIO controllers, we still need to select one right?
>>>>
>>>> Yes, and this needs to be done in abstract manner mapped down
>>>> into
>>>> actual BSP implementation code. Abstract mapping here ensure
>>>> portability
>>>> between BSPs/boards.
>>>>
>>>> E.g. for stm32f4 you do not select GPIOA group and pin1, but you
>>>> select
>>>> group 0 and pin 1 and in f4 BSP this group 0 is mapped to GPIOA
>>>> and
>>>> pin
>>>> 1 is mapped to its pin 1. -- something like that.
>>>>
>>>> Karel
>>>
>>> _______________________________________________
>>> devel mailing list
>>> devel at rtems.org
>>> http://lists.rtems.org/mailman/listinfo/devel
>>

-- 
--------------------------------------------
embedded brains GmbH
Herr Christian MAUDERER
Dornierstr. 4
82178 Puchheim
Germany
email:  christian.mauderer at embedded-brains.de
phone:  +49-89-18 94 741 - 18
mobile: +49-176-152 206 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/


More information about the devel mailing list