raspberrypi / utils

A collection of scripts and simple applications
BSD 3-Clause "New" or "Revised" License
134 stars 41 forks source link

[gpiolib] Why Pi 5 needs gpio_set_fsel() for setting direction, and Pi 4 just gpio_set_dir() #63

Closed rafael2k closed 5 months ago

rafael2k commented 5 months ago

I just wrote some software using gpiolib (thanks a lot!!), but I noticed a small behavior difference, of when gpio_set_fsel() is needed (Pi 5 seems needed), and when not - just gpio_set_dir() (as in Pi 4).

For eg., to support the Pi 5, I added a call to gpio_set_fsel(): https://github.com/Rhizomatica/sbitx-core/commit/df0d8fed1410ec2fc76d53c08795be742ae55772

pelwell commented 5 months ago

It's about efficiency, and a difference in the way the GPIO controllers work.

BCM2835 integrates the pinmux and GPIO hardware, so that GPIO_INPUT and GPIO_OUTPUT are two of the pinmux options. On Pi 5 (both for RP1 GPIOs and BCM2712 GPIOs) the GPIO is effectively separated from pinmux, with GPIO only occupying one of the available FSELs.

gpiolib was written to support both schemes, which is why the API has GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT and GPIO_FSEL_GPIO (which means reactivate the GPIO function, using whatever direction is currently set).

For applications where one is repeatedly changing the GPIO direction, not being forced to also set the pinmux is an optimisation. The same is also true for only wanting to change the FSEL, but applications for that are harder to imagine.

For your application initialisation I suggest you use gpio_set_fsel to set the pinmux and direction. Setting the drive for outputs before the FSEL change will minimise glitches on the wire.

rafael2k commented 5 months ago

Thanks a lot @pelwell ! Perfect. Should I also "gpio_set_pull" before "gpio_set_fsel" in case of inputs?

With regards to thread safety - should I enforce all calls to gpiolib "gpioset*" are protected by mutual exclusion logic?

One last question: do you have a link to the datasheet of the Pi 5 chips?

pelwell commented 5 months ago

Should I also "gpio_set_pull" before "gpio_set_fsel" in case of inputs?

Yes, I guess so, just in case you are adding a pull to maintain a level that was previously achieved by it being an output (or some other FSEL that drives the level).

should I enforce all calls to gpiolib "gpioset*" are protected by mutual exclusion logic?

I'm afraid so - as you'll have noticed there are no mutual exclusion or synchronisation calls or hooks in the library itself.

do you have a link to the datasheet of the Pi 5 chips?

Only the (incomplete) RP1 datasheet has been published: https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf I'd like a more complete one myself, rather than having to search our servers for IP documentation...

rafael2k commented 5 months ago

The use case is really for "startup" procedure, when I don't know the state. Better I check the state of each GPIO before setting it to INPUT or OUTPUT? The state does not change anymore during execution.

Thanks for the pdf link! Anyway, any problem I hit I let you know. Up to now - all good, thanks!

pelwell commented 5 months ago

Better I check the state of each GPIO before setting it to INPUT or OUTPUT?

No, just choose what you want the configuration to be and set it in the order described above. If you don't care about glitching, don't worry about the order. If you don't care about the state of a pin, don't set it.

rafael2k commented 5 months ago

Thanks a lot @pewell. For the record, I left the initialization gpio code of the software I'm writing like this: https://github.com/Rhizomatica/sbitx-core/commit/8758f4e684d8c143ddf52940b9f89c655cc1fd4d

rafael2k commented 5 months ago

Btw, may be you already got used to the pdf. I found this (page 17):

"If any level-based interrupts are required, then the interrupt-to-message translation block (see PCIE MSIn_CFG section) must enable the IACK mechanism to properly sequence software through the Pending, Active, and EOI states. Interrupts may be missed by the host processor if this feature is not used."

So in theory we could use interrupts to get know level changes without "polling" the GPIO, right? Polling is fine, just to know if there could be some more optimized way in the future.

pelwell commented 5 months ago

You can't get an interrupt to user-level - it would be a huge security problem - so you then need some kernel code to intercept the interrupt and wake the user thread, presumably telling it on which GPIO a change was detected. Before you know it you've re-invented libgpiod. And you've certainly reduced the maximum sampling rate, given the overheads of interrupt handling, calling into the kernel, context switches etc.

rafael2k commented 5 months ago

Got it. : )

So with regards to GPIOLIB, I'm totally happy! I'll close this one, ok?

pelwell commented 5 months ago

No objections here.