encoding GPIO ports

Discussions and support about ChibiOS/RT, the free embedded RTOS.
Thargon
Posts: 113
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 11 times
Been thanked: 20 times

encoding GPIO ports

Postby Thargon » Thu Nov 14, 2019 11:44 am

tl:dr: I would like to encode GPIO ports as integer values [0, 1, 2, ...]. Is there an existing macro/function for this or can it be introduced?

In my project, I use a central event source to inform the whole system about GPIO events. In order to distinguish individual sources (i.e. pins) that triggered the event, I so far only encode the GPIO pad in the propagated eventflags_t value like this:

Code: Select all

static void isrCallback(void* args) {
    chSysLockFromISR();
    // args is known to point to an ioline_t value
    chEvtBroadcastFlagsI(&gpioEvtSource,  (eventflags_t)1 << PAL_PAD(*((ioline_t*)args)));
    chSysUnlockFromISR();
}
This approach works quite well for me, especially since I can take advantage of the event flag filtering by the listeners to reduce computational overhead.
However, a major drawback of this solution is that I can only use a single port per pad, thus limiting the number of distinguishable GPIO events to 16 on STM32 MCUs.

So what came to my mind is to encode the port as well. Since there is no MCU that features more than 24 EXTI lines (I think), there would be 8 bits left in the eventflags_t value to encode a port. Using the PAL_PORT() macro in a similar manner is not feasible, though, as it returns a pointer to the according GPIO port memory address.
What I am rather looking for is an integer representation of ports, like

Code: Select all

uint8_t porta = ENCODE_PORT(GPIOA); // 0
uint8_t portb = ENCODE_PORT(GPIOB); // 1
uint8_t portc = ENCODE_PORT(GPIOC); // 2
...
so I could extend the encoding above to something like

Code: Select all

static void isrCallback(void* args) {
    chSysLockFromISR();
    // args is known to point to an ioline_t value
    chEvtBroadcastFlagsI(&gpioEvtSource, ((eventflags_t)1 <<              PAL_PAD( *((ioline_t*)args))       ) |
                                         ((eventflags_t)1 << (ENCODE_PORT(PAL_PORT(*((ioline_t*)args))) + 24)));
    chSysUnlockFromISR();
}

Is there something like that already in place? If not, can it be introdoced at all, since this whole encoding is quite platform dependent?

User avatar
wurstnase
Posts: 121
Joined: Tue Oct 17, 2017 2:24 pm
Has thanked: 43 times
Been thanked: 30 times
Contact:

Re: encoding GPIO ports

Postby wurstnase » Thu Nov 14, 2019 11:50 am

For something similar I'm using the PORT_LINE PAL_LINE macro. Probably this is what are you searching for.
\o/ Nico

User avatar
Giovanni
Site Admin
Posts: 13008
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 742 times
Been thanked: 620 times
Contact:

Re: encoding GPIO ports

Postby Giovanni » Thu Nov 14, 2019 12:34 pm

The PAL line encodes a port and a pin into a same 32 bits value.

Giovanni

Thargon
Posts: 113
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 11 times
Been thanked: 20 times

Re: encoding GPIO ports

Postby Thargon » Thu Nov 14, 2019 1:52 pm

Unfortunately, PAL_LINE() does not help me here, as it does not fulfill my flag-like encoding requirement.

In my current solution, each pad is represented by an individual bit in the eventflags_t value. This is easy, since pads are numbered from 0 to 15, which can be used as-is for shifting.
GPIO ports on the other hand, are not enumerated by 'IDs' but by pointers that direct to the according registers (e.g. 0x4002000 for GPIOA on STM32F405). What I am looking for is something similar as with the pads, so that I can transform GPIOx (e.g. 0x4002000) to 'IDs' as well (i.e. 0 for GPIOA).

For instance, pad 3 is encoded as (1 << 3) = 0x000008 (24 bit) and port A would be encoded as (1 << 0) = 0x01 (8 bit). Both masks can be combined to a single 32 bit value: 0x01000008. With this mask, I can then identify, which pad on which port triggered the event. Of course there could be ambiguities like 0x03000028 (pads 3 and 4; ports A and B), but in combination with the flag filtering mechanism of listeners, those cases should be quite rare.

The challenges are now:
  1. How can ports be enumerated as described above?
  2. Which width is required for pads to support as many platforms as possible?
  3. Which width is required for ports to support as many platforms as possible?
  4. Does this ultimately fit into eventflags_t (32 bit)? If not, the whole idea should be rejected anyway.
1) Could be achieved by modification of the GPIOx macros from the form

Code: Select all

 BASE + offset
to something similar to

Code: Select all

 BASE + (i * WIDTH)
where i is the 'ID' I am looking for. This requires WIDTH to be identical for all ports, though.
Regarding 2) I found that no platform supported by ChibiOS has more than 24 EXTI lines, but GPIO lines are typically even less (e.g. 16 for STM32).
A quick search also revealed, that no MCU in ChibiOS goes beyond port GPIOK yet, so 11 bit would suffice for 3).
So I would draw the conclusion, that the 32 bits of the eventflags_t type could be be divided into something from 16 + 16 to 11 + 21 to encode a <port, pad> pair. I might be mistaken, though, and there might be other arguments against my idea.

steved
Posts: 730
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 105 times

Re: encoding GPIO ports

Postby steved » Thu Nov 14, 2019 2:34 pm

You can derive the port number (and thence a bit position) from selected bits of the pointer address. It looks as if each port has a block of 0x400 addresses assigned (RM0410 table 1).
It also looks as if this is how Chibi does it - have a look at the PAL_LINE and PAL_PORT macros in hal_pal_lld.h

Thargon
Posts: 113
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 11 times
Been thanked: 20 times

Re: encoding GPIO ports

Postby Thargon » Thu Nov 14, 2019 3:14 pm

Such a solution would not be portable, as it highly depends on the memory layout of each platform.

The mentioned hal_pal_lld.h is defined on a per-port basis, while the PAL_PORT(), PAL_PAD() and PAL_LINE() macros are part of HAL (even though they are implemented for each port specifically). Moreover, the eventflags_t type is part of ChibiOS/RT and /NIL respectively, but is defined on a per-compiler basis for each architecture. The latter could actually turn out to be a hard blocker, since I assume eventflags_t to be at least 32 bit wide to start with.

Because the issue involves multiple layers or abstraction and specialization, a more generic solution is required here. My particular project aims to be portable to any hardware that is supported by ChibiOS, so a specific solution for a single use case won't cut it for me.

User avatar
Giovanni
Site Admin
Posts: 13008
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 742 times
Been thanked: 620 times
Contact:

Re: encoding GPIO ports

Postby Giovanni » Thu Nov 14, 2019 3:23 pm

Correct, so far it has been always the same but there is no guarantee it wont change in future devices.

BTW, why don't use one EventSource for each port? you could mask port bits 1:1 with event flags.

Giovanni

Thargon
Posts: 113
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 11 times
Been thanked: 20 times

Re: encoding GPIO ports

Postby Thargon » Thu Nov 14, 2019 7:08 pm

Giovanni wrote: [...] there is no guarantee it wont change in future devices.
I read this as "might break portability and will thus not be implemented in ChibiOS". I would be absolutely fine with that argument ;)

Giovanni wrote: BTW, why don't use one EventSource for each port? you could mask port bits 1:1 with event flags.
This was my though as well, but there are two arguments against this solution:
  1. Listening to multiple ports would require multiple bits in the eventmask_t to be utilized. Imo bits in the eventmask_t are a much more precious resource than those in the eventflags_t.
  2. Memory footprint would increase significantly, because there would be up to 11 event sources instead of 1 and the number of listeners needs to scale similarly.
Anyway, I just encountered the first situation where I would like to use the same pad on another port and in this particular case I can easily afford polling, since it is not time critical at all. It would just been nice to have ;)

I still have the vision of enhanced event filtering in my mind, and maybe there is one solution to realize both ideas. But this would be a feature for a major update of ChibiOS in any case.

User avatar
Giovanni
Site Admin
Posts: 13008
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 742 times
Been thanked: 620 times
Contact:

Re: encoding GPIO ports

Postby Giovanni » Thu Nov 14, 2019 7:14 pm

Thargon wrote:
  1. Listening to multiple ports would require multiple bits in the eventmask_t to be utilized. Imo bits in the eventmask_t are a much more precious resource than those in the eventflags_t.


Just a detail, you can map multiple event sources to the same eventmask_t bit. Your handler can then poll the various listeners for available flags. RAM usage is true.

The reliable and slow way to convert from port to bit mask is creating an association table but I really dislike such a crude solution.

Another option is to use a mailbox, ports would send encoded messages to the listening thread with the added bonus that messages are not ORed in the same variable, flags remain "grouped" in separate msg_t.

Giovanni

Thargon
Posts: 113
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 11 times
Been thanked: 20 times

Re: encoding GPIO ports

Postby Thargon » Thu Nov 14, 2019 9:38 pm

Giovanni wrote:The reliable and slow way to convert from port to bit mask is creating an association table but I really dislike such a crude solution.
I absolutely support this statement! A cumbersome LUT cannot be called a "good solution".

Giovanni wrote: Just a detail, you can map multiple event sources to the same eventmask_t bit. Your handler can then poll the various listeners for available flags
[...]
Another option is to use a mailbox, ports would send encoded messages to the listening thread with the added bonus that messages are not ORed in the same variable, flags remain "grouped" in separate msg_t.
Thank you for the advice. Especially the latter hint sounds very appropriate for my design.

Thank you all for the discussion!
I would close this thread now if I could ;)


Return to “ChibiOS/RT”

Who is online

Users browsing this forum: Google [Bot] and 1 guest