BeagleBone kernel module for fast GPIO access

I’m working on a BeagleBone project that needs to drive a few GPIO pretty fast (driving a 110-bit shift register, chip selects, etc. with a full SR update occurring every 4 ms). I’ve got my add-on hardware proven out using sys/class/gpio but it’s way too slow. My next thought before going off and changing the hardware design is to write a kernel module to do the heavy lifting of driving the GPIO pins.

My initial attempts at building just a “Hello, World!” type module ultimately lead to a dead end with a missing header file that doesn’t exist. I’m sure I’m missing something pretty simple (like a define somewhere that needs to be adjusted) but I would be eternally grateful to anyone who can know down the learning curve a bit.

Does anyone have a working example of how to build a kernel module that flashes, say, the USR3 LED without using sys/class/gpio. Source code and Makefile would be great. Thanks in advance for any assistance, links, etc.

Jerrill

I’d be interested in seeing some source code for this too.
it’d make a great “beginners guide to using GPIO”.

Does anyone have a working example of how to build a kernel module that
flashes, say, the USR3 LED without using sys/class/gpio. Source code and
Makefile would be great. Thanks in advance for any assistance, links, etc.

You can take a look at the following source for the example how to
control PWM's on the BeagleBoard xM using direct memory writes:
https://www.gitorious.org/veter/vehicle/blobs/master/src/xenopwm.c
Actual GPIO toggling is in pwm_func() and all the required
initialization is in the initpwm() function.

You can also take a look at the following article for some more
details and context:
http://veter-project.blogspot.co.uk/2011/09/real-time-enough-about-pwms-and-shaky.html

Since many months I want to re-write the code as a kernel module
(xenomai RTDM driver) but did not get to it yet (it is just a hobby
project). Stars will come to the right position :slight_smile: maybe I would be
able to do it on this weekend. Anyway I will post results as soon as
they will be available.

Andrey.

Would you not be better off writing some PRUSS code, and doing the GPIO
from there?

David

I'm working on a BeagleBone project that needs to drive a few GPIO
pretty
fast (driving a 110-bit shift register, chip selects, etc. with a full
SR
update occurring every 4 ms). I've got my add-on hardware proven out
using
sys/class/gpio but it's way too slow. My next thought before going off
and
changing the hardware design is to write a kernel module to do the heavy
lifting of driving the GPIO pins.

My initial attempts at building just a "Hello, World!" type module
ultimately lead to a dead end with a missing header file that doesn't
exist. I'm sure I'm missing something pretty simple (like a define
somewhere that needs to be adjusted) but I would be eternally grateful
to
anyone who can know down the learning curve a bit.

Does anyone have a working example of how to build a kernel module that
flashes, say, the USR3 LED without using sys/class/gpio. Source code and
Makefile would be great. Thanks in advance for any assistance, links,
etc.

Jerrill

Would you not be better off writing some PRUSS code, and doing the GPIO
from there?

If just driving a shift register, using one of the synchronous serial
ports (such as McASP or SPI) would also make sense rather than using GPIO.

I looked at the PRU module information in the Sitara Technical Reference Manual here:

http://www.ti.com/product/am3358

Yes, it looks like this peripheral is intended for exactly what I want to do, though I’ve never used the peripheral before and would have some studying to do.

My background is firmware development (in C and assembly) on microcontrollers like the MSP430, 8050, PIC, etc. So I’m comfortable digesting this sort of documentation. However I’m new to ARM and new to Embedded Linux. What I’m missing is the experience with Linux to know how to even begin to interface to a GPIO (much less a PRU) from the higher level abstraction layers of the OS. Right now there is this big wall between me and all the horsepower the micro offers and it’s called Linux and I’m just don’t know enough (yet) to get around it.

Right now, my understanding is that unless I want to compile a custom kernel, then I need to build a custom kernel module. I don’t know how to do either off the top of my head, but I imagine that the learning curve on the kernel module is less steep. I’ve done both in the past with some of the more commercial Linux versions following dirt simple tutorials, but haven’t had much success doing the same for the BeagleBone yet.

Any direction is welcome. Thanks.
Jerrill

Yes, I designed the hardware so that I can use a SPI port as well but I do have some other chip select type IO I need to do. Again I still have the same problem with how to build a kernel module to run the SPI peripheral and the GPIO in for a close-to-realtime sort of application. Any tutorials are welcome.

Thanks.
Jerrill

Hi Jerill,

You don’t need to build a custom kernel module to use the PRUSS. You only need the uio_pruss module and a user space application to load and start a PRU.
I don’t know if the uio_pruss module is enabled and built by default nowadays. If not, then you’ll need to compile a kernel, or obtain the module from someone else.
It will be a steep learning curve, but all information is available if you search the newsgroup or otherwise ask around. And it’s fun to do. You’ll also find that the PRU is a fine design with plenty of debugging capabilities. Myself, I’m controlling 4 stepper motors with one PRU and each runs up to 60 kHz steprate (a limitation of the motor drivers, much headroom available). Acceleration is also done in the PRU. Linux is only used for the not hard-realtime code.

Success,
Bas

I looked at the PRU module information in the Sitara Technical Reference Manual here:

Yes, it looks like this peripheral is intended for exactly what I want to do, though I’ve never used the peripheral before and would have some studying to do. My background is firmware development (in C and assembly) on microcontrollers like the MSP430, 8050, PIC, etc. So I’m comfortable digesting this sort of documentation. However I’m new to ARM and new to Embedded Linux. What I’m missing is the experience with Linux to know how to even begin to interface to a GPIO (much less a PRU) from the higher level abstraction layers of the OS. Right now there is this big wall between me and all the horsepower the micro offers and it’s called Linux and I’m just don’t know enough (yet) to get around it. Right now, my understanding is that unless I want to compile a custom kernel, then I need to build a custom kernel module. I don’t know how to do either off the top of my head, but I imagine that the learning curve on the kernel module is less steep. I’ve done both in the past with some of the more commercial Linux versions following dirt simple tutorials, but haven’t had much success doing the same for the BeagleBone yet. Any direction is welcome. Thanks. Jerrill

Hi Jerill,

Oops, sorry for the typo in your name!

I have a working kernel module for toggling GPIO which was working on posting a guide to recreating. I don’t know if it will be fast enough as the GPIO kernel module only toggles at a little greater than 2 MHz and is not as regular in period as a good pwm output or something of the like.

I would also be interested in seeing an example of something like this. If not a guide, then just some example code would be nice to get me started!

Regards,
Jack.

Bas,

The uio_pruss module sounds like it’s the way I would like to go with my project. I did a locate for uio_pruss and pruss and pru and didn’t find anything on the current Angstrom/Cloud9 SD card image, so I’m assuming that that means that it’s not loaded by default.

I’m in the process of Googling to see what I need to do to find the source code and build the module (unless someone already has it built for 3.2.5+). If you have any information on where to get started (Linux newbie here… sorry…) I would greatly appreciate it.

Thank you in advance for any information you can provide.
Jerrill

Hi Jerrill,

I recently saw a commit by Koen enabling the PRU on the BeagleBone for the 3.2 kernel. Have you build the latest and greatest Angstrom image recently?

Regards,
Jack.

Hi,

I made an example how to access the GPIO directly through mmap which is here:
https://groups.google.com/forum/?fromgroups#!searchin/beagleboard/GPIO$20(LED)$20access$20using$20mmap/beagleboard/pouZDig10Mw/MY7UkBoOy9MJ

In the same way, I tested the toggle rate, and each pulse was 228ns wide, means 4MHz. Straight forward code, set and reset in a simple sequence.

Cheers, Günter

hi dogisfat,

please let me know when you post the guide

thanks

My understanding is that using mmap you are already accessing the GPIO hardware at the lowest level. The trick they use to reduce power and
maybe complexity is to multiplex the GPIO by banks. On the original Beagle Board it is about 240 ns, apparently the bone cuts it to ~225 ns
with a faster clock, or maybe because it has fewer GPIO banks. So, I don’t think you can go faster via GPIO accesses. When I started with this
I tried to figure out how to turn up the clock on the GPIO system, but I never got that to work.

At least what I’ve seen so far, there is no way to get 25 MHz out of the GPIO. Now, the MMC peripherals can go faster, but they are serial, so
that may not increase speed much over a byte-wide GPIO port.

Jon

Userspace, just write a kernel driver, much better performance

Would anyone have any example of how to write a kernel driver for gpio ?

See LDD [1]. There's examples.

[1]: https://lwn.net/Kernel/LDD3/

-Andrew

Would anyone have any example of how to write a kernel driver for
gpio ?

See LDD [1]. There’s examples.

It would be really helpful if there was a beagle-specific example. I assume
there are include files that perform the same thing as mmap in the kernel
environment, but are probably different.

Thanks,

Jon