User avatar
Redrobes
Posts: 80
Joined: Mon Dec 26, 2011 9:19 pm
Location: S.W. UK
Contact: Website

RaspiUtils GPIO using a device driver

Sun Feb 03, 2013 1:22 am

I have written a device driver for manipulating the GPIO lines directly without going via the memory mapping device. The module decodes some ioctl commands and writes some values to registers of which values have been set up in the parameters to the ioctl.

In order to run this code you will need to be able to compile and install a kernel module so you will need to get kernel sources and the associated files for that. The makefile for the driver has an install target for which you need to be root to install but once installed you can run it in normal user mode.

The interface which sets up the ioctl commands is made into two files. The C file has a small test main function in it to drive the first 6 GPIO lines in sequence.

You can get a small demo video (XviD) of it running here.

The zip of the driver and the interface code is here.

The driver code includes a prebuilt .ko module and prebuilt gpio.exe file assuming that you have a raspian wheezy 3.2.27+ kernel. Otherwise you will need to compile it.

I have released this code as dual BSD / GPL for maximum freedom so you can use this one commercially under the BSD license if you require. I will probably expand on this for my own nefarious reasons and may or may not update it. I'm posting it because I see a lot of people wanting to use GPIO stuff and if you find that any other method is not fast enough then this one is about as fast as it could get - if you stay in the driver. I will be needing to send out batches of IO patterns as fast as possible to drive an IO expander which I will be building or driving IO signals into PICs so id like to run groups of maybe 256 IO writes in one go and I dont want to make 256 kernel transitions with 512 memory barriers in the way.

On the subject of memory barriers. Since I am not an ARM expert I have a general question to which I have seen some replies to it on this forum but they are not really answers. So I think the question is still open...

The BCM spec says that we need to insert a read or a write memory barrier around the use of GPIO lines. The ARM TRM spec ( 3-83 and 3-84) says that there are two type of memory barrier related calls. One is a DATA SYNC and one is a DATA MEM barrier. Both seem to be similar in nature. Which of them would be considered the read or write memory barrier. The driver code at the moment is using the DATA SYNC one. The BCM spec and the ARM specs dont quite align here so its a bit confusing.

Otherwise, enjoy and hope this may help some people.

Just some notes about the video. Its not very clear so I am in the Driver dir. Then I type "make" then "sudo make install" then it installs the driver and shows the kernel message pop up showing the driver has been installed. Then I "cd .." then "make" for the interface test. Then "./gpio.exe" to run it and the LEDs flash.

The red LED is power only. The yellow ones are the first 6 GPIO lines. I used a hacked up PATA old hard drive cable, sawn off 2x10 pins worth of header. Stripped back some of the cable lines and exposed the 3V3, 5V, GND and the GPIO0 to 5 lines.

They go into my breadboard which has them into a 1K ohm resistor each then into the LEDs which are 2mA low current types.

RPIUser
Posts: 14
Joined: Thu Aug 30, 2012 8:08 pm

Re: RaspiUtils GPIO using a device driver

Tue Feb 12, 2013 6:32 pm

Hi
I've been studying your kernel driver approach for GPIO. My Config is R Pi, Model B Rev1.( so one GPIO is different on your newer build example).
I'am attempting to crosscompile/rebuild on a fedora17 platform.
I have located sources using elinux.org/RPi_Kernel_Compilation for 3.2.27.Please can you explain how to patch to 3.2.27+.
Thanks
RPIUser

User avatar
Redrobes
Posts: 80
Joined: Mon Dec 26, 2011 9:19 pm
Location: S.W. UK
Contact: Website

Re: RaspiUtils GPIO using a device driver

Wed Feb 13, 2013 12:24 am

I am not exactly sure but I got the sources for the 3.2.27 because that was the kernel version I am currently on and got the config from my current build as a starting config to generate the kernel build files. I don't think that its absolutely necessary to do the full build if you have the correct Module.symvers. The Makefile has the kernel version that you are trying to build and it had the + as part of the version number (versionextra) to generate. Maybe it requires patching to be absolutely correct for the + sign but I did not patch these sources prior to compiling.

I had build issues every time I tried to cross compile compiler errors from ubuntu however. Presumably it can be done with enough know how but I found that I had no errors building the kernel on the Pi itself. It took at least 10hrs tho.

If you do need a Module symvers and maybe avoid the kernel compile then I have one you can download for the 3.2.27+ build that I made.
Module Symvers Link

For general info, I followed these instructions (http://www.elinux.org/RPi_Kernel_Compilation) in several different variants. I could not get the git files correctly - it seems that the git URL has changed. I used the tar downloads. I compiled on the Pi itself and I didn't install the built kernel because of the firmware boot issues but just used it as a means to get the symvers file. I used the "zcat /proc/config.gz > .config" to generate a config file for it.

User avatar
Redrobes
Posts: 80
Joined: Mon Dec 26, 2011 9:19 pm
Location: S.W. UK
Contact: Website

Re: RaspiUtils GPIO using a device driver

Wed Feb 13, 2013 1:02 am

Just booted the pi to check my files and both the download sources and Makefile I used did not have the + in the extraversion but it worked ok without. Presumably whatever the patch has been applied to does not affect the module installation proc addresses.

User avatar
Redrobes
Posts: 80
Joined: Mon Dec 26, 2011 9:19 pm
Location: S.W. UK
Contact: Website

Re: RaspiUtils GPIO using a device driver

Tue Feb 19, 2013 9:05 pm

It was pointed out to me that the PI has a free running hardware timer counter register which is pretty useful to have. Also some other people were asking about making IR transmitters and universal remotes out of a PI. I thought of this as well and realized that I could grab the TV listings, parse them, send some instructions over the LAN and get a PI to program the TV or PVR box. I have now wondered whether we could get the new camera module to look at the TV broadcast from the telly and mute the ads automatically but thats for another day.

Anyway - I have modified the GPIO code and downloadable zip file to include the timer register and also added a demo infra red 38KHz LED pulse generator to the sample main() func. You can see a vid of this in action here.

I changed the first GPIO led for an infra red type. Its still being driven with the same 2mA even tho its a high power type so it will not emit a lot of IR in this setup. I am using a normal 38KHz IR detector module and these are very sensitive however so we can go a few feet with this setup. I have this little box that I made a few years back that detects any IR and beeps.

I set it to pulse the IR led on for 5uS and off for the remaining ~21uS to set up the frequency. So with the addition of some power transistors you could run this up with a lot more current. Just be careful tho that because were switching this using software and linux is a preemptive OS then it could thread switch and leave that LED on for longer than 5us. I.e. its probably a good idea not to over drive that LED too much.

I tested the max frequency that I could get out of my GPIO driver using calls from user space and it was just over 500KHz which is not bad. Switching in the kernel space should be much faster tho if required. So there is plenty of headroom yet.

In the video you can see the LEDs on the detector briefly flicker with the initial binary count. These IR detector modules have a high pass filter in them with AGC so it will detect single pulses and rapid changes in IR level. But when the 38KHz kicks in you get a solid detection.

The text at the end says:
Clocked 38000 pulses in 1.000001 secs -> 37999.96484 Hz.

So assuming that the PI's timer is accurate then you can generate very accurate frequencies over a non trivial time span.

Return to “C/C++”