C++ FSGPIO_Pin wrapper class for using GPIO through SYSFS

I have mashed together a simple class for accessing GPIO on the Bone Black using SYSFS. Given all the file operations needed I wanted to create a library of some kind to abstract that and found a good starting example here:

http://hertaville.com/2012/11/18/introduction-to-accessing-the-raspberry-pis-gpio-in-c/

I modified from that to get it working with the BeagleBone and to eliminate the need to work in strings when interfacing to the class. It’s at least workable right now and lets me do some basic LED flashing and button pushing experiments. Plans for the future include creating a FSGPIO_PinMgr class that will read the pinmux files and create FSGPIO_Pins for each kernel pin that is actually muxed to be a GPIO. This would also checkout pins to you based on the header pin numbering vs the kernel notion of GPIO number. As far as I can tell Linux will export anything you ask for so best to make sure you can only ask for something that is valid.

I made two examples of main.cpp. The default is just a simple test of the raw toggle rate. The scope says that’s about 62KHz but of course that is anything but a jitter-free rate. Still seems like doing something like creating a 20uSec pulse should be doable and it’s faster than I thought it might be. I opted to keep the files open instead of closing and re-opening on each operation. I hoped that might improve the speed since I would think opening is more costly than rewinding to the top of the file.

The second example has the .disable label so just rename it back to main.cpp to activate it. This is a more interactive demo. Press a button to light an LED. I connected to P8_12 for the LED and P8_26 for the button but of course you can connect as you like. Button would need to be a normally high type.

`

enum FSGPIO_CONSTANTS
{
MAX_GPIO = 125,
HIGH = 1,
LOW = 0,
INPUT = 0,
OUTPUT = 1
};

enum FSGPIO_ERRORS
{
FSGPIO_GENERR = -1,
FSGPIO_FILEERR = -2,
FSGPIO_RDYERR = -3
};

class FSGPIO_Pin
{

/*
FSGPIO_Pin
*/
private:
string m_sGPIONum; // GPIO number associated with the instance of an object
int m_GPIONum; // The GPIO pin number this object controls
int m_active; // String representing the GPIO pin number this oject controls

ofstream m_GPIODirOutFile; // The direction file for this GPIO pin.
ifstream m_GPIODirInFile;
ofstream m_GPIOValOutFile; // The value file fot this GPIO pin.
ifstream m_GPIOValInFile;

public:
FSGPIO_Pin(); // create a GPIO object that controls GPIO45 default
FSGPIO_Pin(int num); // create a GPIO object that controls GPIO(name)
int connectGPIO(int num); // connect object to a GPIO pin.
int activate(); // exports GPIO
int deactivate(); // unexport GPIO
int setdir(int dir); // Set GPIO Direction
int setval(int val); // Set GPIO Value (putput pins)
int getval(); // Get GPIO Value (input/ output pins)
int get_GPIONum(); // Return the GPIO number associated with this object
};

`

sysfs-gpio-20130516.zip (7.27 KB)

Looks good, may convert my version of stuff over to this or some version like this.

Still wish there was a more direct approach not involving the file system…

Some things that I am curious about is how much overhead is there per things like file(stream) objects, as I believe you are holding on to 4 file stream objects per pin (Direction Int, Direction out, Input, Output). My C++ is a bit rusty as I retired several years ago. Also back then, we avoided many features of C++ to minimize overhead… Questions for my self include, is it more or less overhead to to use 2 streams for the same thing (ifstream, ofstream) versus using a fstream and changing the open mode?

Also back then we avoided using things like string objects as to minimize garbage collection… But they do make it easier to work with.

Again looking good
Kurt

Thanks! Just a first stab at making it work so there are definately areas to improve. WiringPi over on the RaspberryPi world can get up to 200KHz from SYSFS and I have a feeling that fstreams are definitely the weak link here. I started out just ripping off the demo to have something known to work and modifying in steps from there. I will be going to C type functions to read/write instead of streams. stay. I absolutely abhor working with string data in C/C++ and makes that less painful. Hopefully I can at least double this toggle rate with less overhead.

I THINK it will still be possible to create a hybrid SYSFS/MMAP version. That assumes that Linux wont barf if I just try to use MMAP to touch the value registers for the pins. We can still export them to access the direction/interrupt settings via the file system but if we can direct map to the value registers the speed up would be huge! That is my ultimate goal but I have never played with MMAP before so for now I prefer to stick with what I know.

For my robot I plan to off-load a lot of real-time electronics to sub-controllers on a bus of some kind vs trying to connect it all to the bone. I have a nice little board in a 32 pin dip format for a Parallax Propeller chip and that will give me 8 80MHz cores to dedicate to stuff that needs to be services ‘just-so’. I can then simply connect via serial to query the Propeller for data I need at the higher level. So what I have now is probably sufficient but I always get wrapped up in ‘but can’t I make it a little faster?’

Totally understand. Will be interesting to see if we can use some version of MMAP.

I am still also trying to decide how I will be using my BBB and as you mentioned it will be sufficient if the main things I end up using the GPIO pins for (other than the UARTS, and a few other things like that) are for a few Leds and buttons. But I am not sure how well it would work if I tried to port the code for a PS2 game controller over, which uses 4 IO pins, with a modified SPI interface. May try for the heck of it.

My first BBB, I think I will try first in a Rover (http://www.orionrobotics.com/Razor-4WD_p_249.html). I will be starting off hooking up an XBee (Could be USB like I have done for RPI with my Lynxmotion T-Hex robot). I will be using one of Orion (Basic Micro) Roboclaw motor controllers to control the 4 motors using another of the Uarts. Will hook up webcam. Preferably with some Pan/Tilt hookup. Not sure yet what I will use to control the servos. Not sure yet which servos I will use. May use standard hitec servos (or maybe) ones from Basic Micro that have feedback or may use Robotis ax12 servos using a uart through something like: (http://www.robotshop.com/productinfo.aspx?pc=RB-Dfr-142&lang=en-US) Will probably also use a TTL voltage converter on this as it may output 5v? …

But it may also be fun to build a Remote control using one of these. Several of us built some using RC and later XBees (http://www.lynxmotion.net/viewtopic.php?f=21&t=5447), but it might be fun to try one using Wifi… That project may requires lots of IO pins…

Again this is fun stuff, can not wait to see what you come up with.
Kurt

For the BB classic I use this C++ class someone made to access the GPIOs: https://github.com/majestik666/Beagle_GPIO
It uses mmap. As the BBB has, as far as I know, the same processor, this may be a good starting point. In best case you may only have to change the mmap offsets, but I haven't gone to deep into it (I am happy that it works).

This is one I think I already tried, but it spattered all over the windshield when it tried to initialize. They say the addresses are the same but I think the error happens when it tries to set the pin mode and directly write to the configuration registers. The code will still be useful I think but I’m not going to be able to directly write to config registers to make a pin Mode 7, just have to use what’s already configured as GPIO.

Yes, I think I read somewhere that you can't really change the mux settings using mmap (don't know enough to say that is really the case).
That's why the library fails if you want to use custom muxed pins.
There is also this project here: https://github.com/ehayon/BeagleBone-GPIO
It also offers to set the mux accordingly, but if it is a general problem with mmap than this one won't work either (I haven't tried it though).

Options would be to mux your pins using the sysfs in a script before starting your program or directly in the kernel settings (that's what I am doing). I am using the 3.2.x branch of the kernel. I don't know how that works in the 3.8-version. Apparently there were huge changes introducing device tree.

Alright, now we’re on to something. Changing to the open/read/write instead of C++ streams and It’s able to toggle at about 160KHz. Much more respectable given the interface. I’ll clean it and the examples up a bit this weekend and post the new version. I’ll create a super-class of just GPIO_Pin that will define the interface and that will allow me to use the pins in other code without needing to know if they are FSGPIO_Pins or MMGPIO_Pins I’m using once I get around to creating the memory-mapped version.

So this is my first foray into the world of github. Published the code out through there:

https://github.com/photomankc/bbblack-gpio-library

I now have the base-class defined and common code is pushed up to it.

Attached is the GPIO Map spreadsheet I made. I have not figured out the base address yet for memory map access to pin value registers but I will someday.

BB-Black Header Map.xlsx (33.8 KB)

Thank you very much for your hard work

I will second that. Just having a printed version around has kept me from having to constantly search through 3 different PDFs to find information about each pin I am interested in!

Thanks again
Kurt

Thanks for these files.

I have tried before Python class of GPIO given by M. Richardson on Make Magazine, but they
do not work on the BBB (No such file or directory: ‘/sys/kernel/debug/omap_mux/gpmc_ad12’)

Until there is a decent Python file for the GPIO, I will stick to the C++.

Jacques

Sorry to drag this thread up from the dead, but is there any reason why photomankc’s GPIO library would not work with the DHT11 temperature/humidity sensor?

https://github.com/photomankc/bbblack-gpio-library

http://www.micro4you.com/files/sensor/DHT11.pdf

The GPIO library’s readme states the following:

“FSGPIO_Pin With the current implementation, is able to toggle to output a full squarewave in approx 6.25 uSec for a maximum rate of about 160KHz.”

Since the DHT11’s communication protocol involves switching for a minimum period of 20-40us and reading a pulse of 26-28us at the shortest, does this mean it’s possible to communicate with the sensor using FSGPIO? Or is there additional delay when reading?

If so, I’ll adapt lhuet’s DHT22 code to produce a driver for this thing (https://github.com/lhuet/beaglebone-project/tree/master/DHT22)

Warmly,
Daniel

I have not in fact tested what the maximum rate is that it can read pulses without missing, but the DHT11’s protocol seems to involve discerning the difference between a pulse that is around 30 microseconds long for a zero and 70 microseconds long for a one. That might be easier once I get as far as setting up interrupts using a GPIO pin but I doubt you could count on the kernel not to misread a bit given that 40 microseconds is all you have to tell the difference from a 1 or a 0. I have not worked on this much as I have been traveling in Europe for a couple weeks. I do plan to expand it to include interrupt capability, but I need to understand threading better to really implement that well. I hope to release some improvements in July.

Sorry, but I think this would be marginal for the DHT11 protocol at best as it stands since you would have to be very tightly polling the pin to detect a 0 or 1. Might work though, I just have not worked up a test yet to see what limits are in pulse detection vs production.

PRU could handle it, easy! :smiley: