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@rtems.org
http://lists.rtems.org/mailman/listinfo/devel


--
--------------------------------------------
embedded brains GmbH
Herr Christian MAUDERER
Dornierstr. 4
82178 Puchheim
Germany
email:  christian.maude...@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/
_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to