golemparts / rppal

A Rust library that provides access to the Raspberry Pi's GPIO, I2C, PWM, SPI and UART peripherals.
MIT License
1.23k stars 96 forks source link

Why Raspberry Pi specific? #23

Closed romainreignier closed 5 years ago

romainreignier commented 5 years ago

Hi, First of all, thank you for this very nice crate, with a lot of features and a nicely documented. But I wonder why did you make it Raspberry Pi specific? The strength of an OS like Linux is to provide common abstraction layers to different hardware. So using i2cdev, spidev, gpiochip interfaces should allow to use any Linux board like all the fruitPi boards based on different chips from Allwinner, Rockchip, Amlogic and so on. From what I understand of your crate, mainly the GPIO interface through direct memory access and maybe the software PWM are using BCM specific interfaces. Would it be possible to use gpiochip character device to interact with the GPIO and make this crate hardware agnostic or it would result in slower operations making the software PWM too slow?

golemparts commented 5 years ago

Thanks for your question! You're correct in your assessment that directly accessing the GPIO registers is what mainly makes RPPAL Pi-specific. The other peripherals also implement Pi-specific code, but that's mostly to make the interface easier to use by automatically opening the correct device files and limiting features based on the Pi's capabilities.

I've looked into using gpiochip exclusively before. Besides potential performance problems, the main issues I encountered are gpiochip's interface preventing me from using it to read the mode of an unconfigured Pin or configure an IoPin when any of the Pi-specific alternative functions are involved, and not being able to configure the built-in pull-ups/pull-downs.

Requesting a handle requires providing a pin mode (if flags is kept 0, the pin mode will still be changed to Input). Since gpiochip's ioctl interface doesn't yet provide a way to set (or read) any of the ALT function modes, that means requesting a handle will always overwrite those modes unless I subsequently reset them through the registers, which ends up requiring a messy workaround that briefly changes the pin mode (which could cause issues), and would still require direct register access.

However, supporting other SBCs has been on my mind for a while, and I think it's something to consider after I'm done adding UART support, which is the last peripheral on my list. I don't have a clear solution for the above-mentioned issues, but other platforms might offer similar direct access to the registers (although that would still tie RPPAL to specific platforms), or gpiochip might receive Pi-specific changes in the future. I could leave the current implementation as is for the Pi, and add a generic gpiochip interface for other boards, provided those won't have the same issues with gpiochip as I ran into on the Pi.

romainreignier commented 5 years ago

Ok, tank you for your detailed answer. I see your pitfalls and like your aim to open your crates to other boards.

Out of curiosity, why do you need to read the current config of a pin? To check that it is not already in use before using it? In that case, the kernel should know that the pin is used by a certain module and gpiochip should report it. But from what I remember while trying it, it was not always the case.

I am not sure of the actual code path of a gpiochip call within the kernel but do you know if the overhead is still high compared to direct memory access?

golemparts commented 5 years ago

A nice example where reading the current pin mode is useful is the gpio_status example in the examples directory, which displays the mode and logic level of all pins on the GPIO header. It behaves similarly to the gpio command line tool that's included in one of the Pi's packages (I think it's in wiringPi?). That would be impossible to do with gpiochip, because it would change any pin that's configured for one of the ALT functions (for instance, when you enable pins for I2C or SPI) and set those to Input. It wouldn't even be able to just skip those pins, because gpiochip has no way to indicate which pin is configured for something other than Input or Output.

I've also run into some issues when different applications try to open a pin through gpiochip simultaneously (see this comment). I could probably fix that with a workaround, but I stopped looking into it after I discovered the other issues.

I never got around to actually benchmarking gpiochip versus direct access. I know it'll be slower simply because of the additional calls, but it might still be an acceptable speed. If you come across any data, or end up doing a comparison yourself, I'd love to hear about the results.

romainreignier commented 5 years ago

Ok, thank you again for the details.

Indeed a benchmark would be nice to do.

romainreignier commented 5 years ago

Ok so for now I think that the best thing to do would be to create a new crate (I am not aware of an existing one) to replace rust-sysfs-gpio to use gpiochip interface.

And use it with rust-spidev and rust-i2cdev instead of your crate on other board while gpiochip do not provide the interfaces you need.

Did you ever try to reach out the libgpiod developer to expose your feature requests?

golemparts commented 5 years ago

There are two gpiochip crates available on crates.io although I haven't tried them myself, so I don't know how well they work. Either way, replacing sysfs gpio is definitely a good idea, since that interface was deprecated a while ago and will disappear at some point.

Other than that, I think what you suggest is probably the best solution for now.

RPPAL doesn't use libgpiod. Instead, it directly interfaces with gpiochip through ioctl calls, which is where any changes would need to be made. I do know some people have already brought up missing support for configuring pull-ups/pull-downs after moving from sysfs gpio to gpiochip, and it's being worked on.

I'm not sure if anything is planned regarding Pi-specific ALT function mode support, but https://github.com/raspberrypi/linux/issues is probably the best place to bring that up as a platform-specific patch (for instance by adding additional flags) unless other platforms require similar support. For now, my current solution works fine for the Pi, so I haven't brought it up, but I'll look into it again once I start working on supporting other platforms.

Out of curiosity, is there a specific board you're working with, or are you just interested in platform-agnostic support in general?

romainreignier commented 5 years ago

Oh nice, I have never seen these crates before (but never really look for it). For my use case, the sysfs was sufficient.

Out of curiosity, is there a specific board you're working with, or are you just interested in platform-agnostic support in general?

I don't have any use case in mind right now and I use boards using different SoC that's why is it more the plaform-agnostic support in general.

I do not use Rust a lot yet but I have been following the rust-embedded progress and found your crate. It was well documented and seemed to provide a lot of features so I have checked if it was supporting other boards.

Anyway, it was a very instructive discussion. Thanks a lot for all the explanations and once again, congratulations for this crate.