GPIO in C/C++ on the Beaglebone Black?

16,891 views
Skip to first unread message

MH

unread,
Jun 12, 2013, 12:46:04 AM6/12/13
to beagl...@googlegroups.com
Just want to start a discussion.  Who all is working or maybe even found a means of controlling the GPIO in C for Beaglebone Black?  I have been hunting for a while and haven't found anything reliable.

Jacek Radzikowski

unread,
Jun 12, 2013, 12:53:38 AM6/12/13
to beagl...@googlegroups.com
I have an almost ready library that interfaces user's application to
the IO pins. It provides mapping mechanism between the user-level
block of bits to an arbitrary set of IO pins, allowing the scattered
IOs to be accessed as a continuous and ordered set of bits.
The last (I hope) issue that prevents me from posting it on github is
denial of access to memory blocks controlling GPIOs 0, 2 and 3.

j.
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to the Google Groups
> "BeagleBoard" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to beagleboard...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Given a choice between two theories, take the one which is funnier

MH

unread,
Jun 12, 2013, 1:48:46 AM6/12/13
to beagl...@googlegroups.com
Jacek,

Great to hear some work is underway.  Please post an update as you make more progress.  I have been able to access some of the GPIO port 1 pins through dev/mem.  I have also had issues with the other GPIO ports as well.  I have been trying to use a device tree overlay to set pin modes for the GPIO yet haven't had any success yet.  Such as GPIO0_5, everything I have done to change its pin mode and be able to toggle it on and off hasn't worked.  It would be really great to get access to the large group of GPIO2 pins that are initially configured for the HDMI.

MH

MH

unread,
Jun 13, 2013, 10:25:45 AM6/13/13
to beagl...@googlegroups.com

This is a fantastic solution.  http://www.youtube.com/watch?v=wui_wU1AeQc

Jacek Radzikowski

unread,
Jun 13, 2013, 10:36:17 AM6/13/13
to beagl...@googlegroups.com
Nice video. The problem is that the overlay itself does not enable
GPIO modules. They start working after exporting through sysfs (as
Derek did). It's a good workaround, but not a solution to the problem
:(

j.


On Thu, Jun 13, 2013 at 10:25 AM, MH <haynes...@gmail.com> wrote:
>
> This is a fantastic solution. http://www.youtube.com/watch?v=wui_wU1AeQc
>

joseph yarborough

unread,
Jun 13, 2013, 11:28:25 AM6/13/13
to beagl...@googlegroups.com
It's a fine solution if your program or library simply uses sysfs to enable them.

Are you pin muxing without device trees? Then the library won't work with recent kernels?

CEB

unread,
Jun 13, 2013, 4:31:51 PM6/13/13
to beagl...@googlegroups.com

Jacek Radzikowski

unread,
Jun 13, 2013, 8:46:18 PM6/13/13
to beagl...@googlegroups.com
I'm not addressing pinmuxing, as it is platform specific. The library
is designed to be platform independent, with beaglebone being only the
first implementation of the interface.
In 3.8 kernels pinmuxing is supposed to be done with device tree and
this is my preferred method of setting the pin modes.

j.

MH

unread,
Jun 18, 2013, 2:21:18 AM6/18/13
to beagl...@googlegroups.com
Jacek,

so after some experimenting with the libraries and using sysfs to control the GPIO pins.  I have found that this method of toggling gpio pins is extremely slow.  It is great for simple applications, yet is really limiting.  I think the best case on-off time toggling the pins is about .1 milliseconds on the BBB.  How is your library progressing?  Is there anything you are particularly stuck with?

Thanks,

Mark

Jacek Radzikowski

unread,
Jun 18, 2013, 2:58:17 AM6/18/13
to beagl...@googlegroups.com
I'm pretty close to having some code ready for release. All what is
left is to get rid of the most obvious bugs, clean up the code a bit,
add simple makefile and I think I will be ready to post it. My current
biggest headache is the crosscompiler. I've been using pre-compiled
g++ from Angstrom, but it adds some memory leaks to the compiled
programs. Running valgrind on a trivial cross-compiled "Hello world"
shows big allocation and memory corruption problems localized
somewhere around main(). The same code compiled natively on beaglebone
passes all the checks. I'm building right now new cross-toolchain with
angstrom and I hope it will work better and will fix most of the
memory-related problems I was observing.
I will definitely need testers, so I'll post information to the list
as soon as the library will be ready for download.

j.

Brandon I

unread,
Jun 19, 2013, 12:47:54 AM6/19/13
to beagl...@googlegroups.com
You'll want to use a library that uses mmap. This should get you around 5MHz.


Most of the libraries from that search will be for the 3.2 kernel, but since arbitrary pin muxing on the fly isn't really supported anymore, you could pull the mux routines out and use them for basic toggling and reading.

Jacek Radzikowski

unread,
Jul 11, 2013, 1:05:09 AM7/11/13
to beagl...@googlegroups.com
I wrapped the code up and posted the library on github. It is more of
a framework, which allows to write applications that can be easily
ported between different platforms. The GPIO access is just a small
part of the library.
Currently I have only implementation for Beaglebone, but RPI port
should be trivial to make. I'm also thinking about a version for
Cortex MCUs.
Please check out, clone and comment at https://github.com/piranha32/IOoo

j.

ky...@cranehome.info

unread,
Jul 18, 2013, 12:23:39 PM7/18/13
to beagl...@googlegroups.com
Very nice.   I'll have to give this a test on my BBB soon.   I knew that if I just went back to the milling machine and lathe for a while to make more robot parts the GPIO situation would start sorting itself out.   I started my own library project but honestly, I'm sure I'm going to be beat to the punch on this.  Thanks for the effort and keeping the project rolling.  If there are things we need to contribute please let us know!

Scott Rush

unread,
Jul 25, 2013, 9:38:48 PM7/25/13
to beagl...@googlegroups.com
All,

I asked Jacek about problems on the pinmuxing, but didn't post my question to everyone (sorry).  Thanks Jacek so much for your explanation.  Really helps noobs like myself. 

Here's his response to my question as to how to workaround the overlay with pinmuxing issue:

For GPIOs 0,2 and 3 clocks are not enabled when you load an overlay
with pinmuxing and every access to the registers of these modules
results in a bus error. The workaround for this problem is to export
one pin from each module through sysfs. There was last month a
discussion on the group about this problem:
https://groups.google.com/d/msg/beagleboard/OYFp4EXawiI/61Zwn2Z5REgJ
I included with the library a script which enables all modules. Just
run tools/bbb_enable_gpio.sh and the bus error will be gone until next
reboot. There is no need to run this script before each run of your
program.

j.


On Wed, Jul 24, 2013 at 10:55 PM, Scott Rush wrote:
> Hello Jacek,
>
> Looks like a great solution, but I don't understand the problem I'm seeing.
> Everything looks like it works until the first memory write to a GPIO
> register. I have a BeagleBone Black rev A5 running latest Angstrom demo
> build (June 17th 2013 build from website).  When I run the gpio_leds example
> in the IOoo package, I get a "non-linefetch" fault (output highlighted in
> RED below) that happens on the mmap call for GPIO[0].  However, the other 3
> mappings succeed and I see that the BeagleGoo says it is successfully
> activated.
>
> The program then runs through the rest of the initialization and then
> terminates with a "Bus Error" which I traced to line 140 of BeagleGooP.cpp
> when the first GPIO[0] port OE register is written:
>
> 140:   parent->gpios[ports[i]][GPIO_
OE_REG / 4] &= ~masks[i];
>
> I built the code with the 4.7.3 release of the stock Angstrom gnu tools
> (except for pasm which isn't in distro, but I didn't have any problems
> with).
> I
> 'll admit I'm still be a noob to embedded linux, but I would greatly
> appreciate it if you can give me a hint as to what I'm doing wrong here.
>
> Thanks
> Scott Rush
>
> Here's the dump from the command line:
>
> root@beaglebone:~/IOoo/bin# ./gpio_leds
> BeagleGoo.cpp:129[  328.372017] Unhandled fault: external abort on
> non-linefetch (0x1018) at 0xb6f6b134
> 9:"BeagleGoo::BeagleGoo() gpio[0] at address 0x44e07000 mapped at
> 0xb6f6e000\n"
> BeagleGoo.cpp:129:"BeagleGoo::BeagleGoo() gpio[1] at address 0x4804c000
> mapped at 0xb6f6c000\n"
> BeagleGoo.cpp:129:"BeagleGoo::BeagleGoo() gpio[2] at address 0x481ac000
> mapped at 0xb6f6b000\n"
> BeagleGoo.cpp:129:"BeagleGoo::BeagleGoo() gpio[3] at address 0x481ae000
> mapped at 0xb6f4b000\n"
> BeagleGoo.cpp:131:"BeagleGoo successfully activated\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 0: name: \"P8_7\", port=2,
> bit=2\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 1: name: \"P8_8\", port=2,
> bit=3\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 2: name: \"P8_9\", port=2,
> bit=5\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 3: name: \"P8_10\", port=2,
> bit=4\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 4: name: \"P8_11\", port=1,
> bit=13\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 5: name: \"P8_12\", port=1,
> bit=12\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 6: name: \"P8_13\", port=0,
> bit=23\n"
> BeagleGoo.cpp:180:"BeagleGoo::claim(): found pin 7: name: \"P8_14\", port=0,
> bit=26\n"
> BeagleGoo.cpp:183:"Creating BeagleGooP\n"
> BeagleGooP.cpp:39:"BeagleGooP::BeagleGooP(): done\n"
> BeagleGoo.cpp:186:"Adding pins\n"
> BeagleGoo.cpp:189:"Adding pin 0\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=0, pin->gpioNum=2,
> pin->bitNum=2, masks=00000004, localNames=\"P8_7\"\n"
> BeagleGoo.cpp:189:"Adding pin 1\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=1, pin->gpioNum=2,
> pin->bitNum=3, masks=00000008, localNames=\"P8_8\"\n"
> BeagleGoo.cpp:189:"Adding pin 2\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=2, pin->gpioNum=2,
> pin->bitNum=5, masks=00000020, localNames=\"P8_9\"\n"
> BeagleGoo.cpp:189:"Adding pin 3\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=3, pin->gpioNum=2,
> pin->bitNum=4, masks=00000010, localNames=\"P8_10\"\n"
> BeagleGoo.cpp:189:"Adding pin 4\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=4, pin->gpioNum=1,
> pin->bitNum=13, masks=00002000, localNames=\"P8_11\"\n"
> BeagleGoo.cpp:189:"Adding pin 5\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=5, pin->gpioNum=1,
> pin->bitNum=12, masks=00001000, localNames=\"P8_12\"\n"
> BeagleGoo.cpp:189:"Adding pin 6\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=6, pin->gpioNum=0,
> pin->bitNum=23, masks=00800000, localNames=\"P8_13\"\n"
> BeagleGoo.cpp:189:"Adding pin 7\n"
> BeagleGooP.cpp:85:"BeagleGooP::addPin(): current=7, pin->gpioNum=0,
> pin->bitNum=26, masks=04000000, localNames=\"P8_14\"\n"
> BeagleGoo.cpp:197:"BeagleGoo::claim: finish\n"
> BeagleGooP.cpp:149:"BeagleGooP::enableOutput(arr): enabling 8 pins\n"
> BeagleGooP.cpp:129:"BeagleGooP::enableOutput(): i=0, enable=1\n"
> Bus error
>
>

Jacek Radzikowski

unread,
Jul 25, 2013, 10:00:19 PM7/25/13
to beagl...@googlegroups.com
I hope it solved the problem :)

j.

Scott Rush

unread,
Jul 25, 2013, 11:22:09 PM7/25/13
to beagl...@googlegroups.com

Jacek,

That did the trick.  Just played for an hour characterizing the response latency in the write function on an oscilloscope.  Very cool.  Thanks again for your help.

Regards,

Scott Rush

You received this message because you are subscribed to a topic in the Google Groups "BeagleBoard" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/beagleboard/yflrTE39KhQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to beagleboard...@googlegroups.com.

Sempe...@live.com

unread,
Aug 5, 2013, 2:56:04 PM8/5/13
to beagl...@googlegroups.com
After reading Bad to the Bone, I have toask why is it that in BoneScript (Node.js) you can access the pins by:

Var pins = (typeof bone != 'undefined') ? bone : b.bone.pins;
var ledPin = pins.P8_13;
var ledPin2 = pins.USR3;
b.pinMode(ledPin, b.OUTPUT);
b.pinMode(ledPin2, b.OUTPUT);

ETC

b.diitalWrite(ledPin, b.LOW)

ETC

And in C/C++ one has to open two files for each pin nested down several levels from root?????

Makes no sense!!!

Jacek Radzikowski

unread,
Aug 5, 2013, 3:08:11 PM8/5/13
to beagl...@googlegroups.com
Because in your JS program you're taking advantage of a library which
abstracts access to GPIO, while in C/C++ you want to implement it from
scratch. You can also use one of the existing libraries for C/C++,
<autopromo> for example this one: https://github.com/piranha32/IOoo
</autopromo>

j.

Sempe...@live.com

unread,
Aug 5, 2013, 6:23:31 PM8/5/13
to beagl...@googlegroups.com
Jacek,

I appreciate your response. However, I've never had to open files to write to the pins of a controller or computer. This is a first for me; and may I say, I find it a very inefficient method which leaves room for many errors. Furthermore, if you have to interact with the OS to read or write to a file system, it slows the system down by several orders of magnitude. I never had to work with a file to write to an output pin on a PC, PIC Microcontroller, AVR, Arduino, (old Sinclar 1000) etc... If TI wants this development board (computer) to be a viable development platform, they need to provide a more efficient manner in addressing GPIO pins directly from within the processor. Whether that is via inline assembly, a standard library, C++ data structures that facilitate '.' access to the elements and methods, etc. I stress, this needs to work within the embedded ARM processor and not through the OS file system. How many machine instructions/cycles are wasted telling the ARM to:

Open a file;
fseek...
analyze the data
fwrite...
fflush...
fclose...

And then, the processor has to go to the file system to open the file, read the data the programmer just set, and then set/write/read to/from the pin...

All the while, the ARM processor has to have assembler code that directly: 1. Reads/Sets the pin mode--to include data direction, pull-up/down resistor, etc., 2. Reads the pin value, 3. Writes a value to the pin.

Jacek Radzikowski

unread,
Aug 5, 2013, 7:24:34 PM8/5/13
to beagl...@googlegroups.com
The file interface has been initially provided in the kernel for
debugging. IIRC in 3.2 kernels it even resided in debug subdirectory.
Accessing GPIO via file interface is very simple from user's point of
view and makes experimenting much easier, so it quickly become very
popular. There are many GPIO libraries which are just wrappers for the
file I/O. I think that the JS library also uses the file interface.
GPIOs are also accessible through memory interface, however it is not
as simple and intuitive as writing 1 or 0 to a file. If you take a
look at the link, you will see that there are no fopens, fseeks,
freads and fwrites, but pure black magic of mmap, memory offsets and
bit shifts.

j.

Brandon I

unread,
Aug 5, 2013, 7:48:16 PM8/5/13
to beagleboard
You don't have to use the sysfs interface. It's a simple user friendly, low performance, way to sparingly interact with the gpio. Absolutely great for clicking a relay or turning on an led. I think it's silly to use it in a program as it was meant more for command line operations like "cat" and "echo".

You can use the linux gpio interface: https://www.kernel.org/doc/Documentation/gpio.txt

Or, you can get near bare metal with direct memory manipulation for highest performance (> 4MHz, compared to the few hundred kHz of the sysfs interface), where you can twiddle bits of the gpio registers: http://stackoverflow.com/questions/13124271/driving-beaglebone-gpio-through-dev-mem 

Or, you can use one of the many performance minded gpio libraries that makes gpio manipulation as simple as calling an existing function.

Or, write an asm program and load it on one of the PRU co-processors for your deterministic GPIO needs.

This is Linux, a seemingly random and uncoordinated mixture of interfaces and libraries (many duplicated several times over), so there's are always many ways to do any one thing. :D

cwrse...@gmail.com

unread,
Aug 6, 2013, 8:35:58 AM8/6/13
to beagl...@googlegroups.com, Sempe...@live.com


On Monday, August 5, 2013 11:23:31 PM UTC+1, Sempe...@live.com wrote:
Jacek,

I appreciate your response. However, I've never had to open files to write to the pins of a controller or computer. This is a first for me; and may I say, I find it a very inefficient method which leaves room for many errors. Furthermore, if you have to interact with the OS to read or write to a file system, it slows the system down by several orders of magnitude. I never had to work with a file to write to an output pin on a PC, PIC Microcontroller, AVR, Arduino, (old Sinclar 1000) etc... If TI wants this development board (computer) to be a viable development platform, they need to provide a more efficient manner in addressing GPIO pins directly from within the processor. Whether that is via inline assembly, a standard library, C++ data structures that facilitate '.' access to the elements and methods, etc. I stress, this needs to work within the embedded ARM processor and not through the OS file system. How many machine instructions/cycles are wasted telling the ARM to:

Open a file;
fseek...
analyze the data
fwrite...
fflush...
fclose...

And then, the processor has to go to the file system to open the file, read the data the programmer just set, and then set/write/read to/from the pin...

All the while, the ARM processor has to have assembler code that directly: 1. Reads/Sets the pin mode--to include data direction, pull-up/down resistor, etc., 2. Reads the pin value, 3. Writes a value to the pin.

 
You need to read "kernels - their care, feeding and cure".  On all the processors you mention you were working on the bare metal, which as you say has advantages for simplicity and speed.  However, kernels are useful (among other things) for allocating resources such as memory and disk space, and  to do that they have to restrict memory access - to write to a port, you need to go through the kernel.  (As a general rule - CP/M was a perfectly good 8-bit OS, but it had no memory management, so if you were sufficiently irritated you could hit the controller registers directly.)

You could program the BBB without using an OS, but it would be pretty painful; better to use the PRUSS cores if you want speed, or the Xenomai near-realtime Linux kernel patches.   The Linux used on the BBB has a wide variety of approaches to I/O, some slow and convenient, some  fast and tricky.  You should be able to find one  that suits your project.

Good luck - Will

Bill Lewis

unread,
Aug 6, 2013, 12:40:00 PM8/6/13
to beagl...@googlegroups.com
The mmap example at stackoverflow works on the BBB with 3.8 Angstrom kernel?

Brandon I

unread,
Aug 6, 2013, 4:17:17 PM8/6/13
to beagleboard
The only way to modify the physical gpio hardware is through the gpio registers, some of them pointed to by that mmap example. There's nothing in the 3.8 Kernel that prevents you from getting an mmap to that memory space.

The pad control/pin mux stuffs changed in 3.8, but that's completely separate from the gpio. You tell the pad control registers to connect the physical pin to the internal gpio circuitry (though the pin mux mode bits), but the gpio blocks exist separately. Pad control registers have never been controllable through mmap since it requires privileged (kernel) access.

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to a topic in the Google Groups "BeagleBoard" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/beagleboard/yflrTE39KhQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to beagleboard...@googlegroups.com.

Julian Gold

unread,
Feb 4, 2015, 6:27:33 AM2/4/15
to beagl...@googlegroups.com
This - like several solutions - tries to open /dev/mem for read and write. On my Rev C debian BBB, this operation fails, I suspect due to access rights as it seems like it may need root access privilege? (Similarly for the sysfs method, you can't write to sys/class/gpio/export unless you're root, making it easy from a shell using sudo, and a PITA from C++). Is that correct?

Jacek Radzikowski

unread,
Feb 4, 2015, 9:28:15 AM2/4/15
to beagleboard
As /dev/mem gives you uncontrolled access to the entire memory, you
need administrative rights to open the device. If you are concerned
about security, it should possible to drop privileges after opening
the device; However, the program has to be started as root, either
from root account, or as suid root.

j.
> For more options, visit https://groups.google.com/d/optout.

Raul Piper

unread,
Jun 13, 2016, 12:11:34 AM6/13/16
to BeagleBoard, bred...@gmail.com
CEB,
On which platform you tested this?Did you get any issue?Set/Reset of any GPIO works fine on any kernel?4.x+?
Rp

Raul Piper

unread,
Jun 13, 2016, 2:37:48 AM6/13/16
to BeagleBoard, bred...@gmail.com
I modified the app a bit and  tried running this code on the BBB  under sudo mode :

        gpio_export(gpio);
//      gpio_set_dir(gpio, 0);
        gpio_set_dir(gpio, 1);
        gpio_set_edge(gpio, "rising");
        gpio_fd = gpio_fd_open(gpio);
        printf("debug_1 \n");
        gpio_set_value(gpio,1);
        sleep(1000);
        gpio_set_value(gpio,0);
        printf("debug_2 \n");

but I see App stuck @debug_1 and getting this error :
gpio-49(sysfs):_gpiod_direction_output_raw:tried to set a  GPIO tied to an IRQ as output.

I even tried this :

     gpio_set_dir(gpio, 0);
  //      gpio_set_dir(gpio, 1);

in this I don't get the error but again the App hangs at the same point.

What I am doign wrong here?My intent is to Set -reset the GPIO1_17 ( that is p9 header pin P9_23) that  is GPIO 17 of 32 (0–31) on the second GPIO chip of four (0–3).
Am I choosing the wrong GPIO.?

John Syne

unread,
Jun 13, 2016, 5:13:31 AM6/13/16
to beagl...@googlegroups.com
Read the Kernel docs to learn how to do this correctly. If you have the kernel source, the docs are under /Documentation/gpio. The board.txt file will explain how to access the DTS definitions for the GPIO. In the DTS, you will define which GPIO are allocated to your driver. The driver.txt file will explain how to use the generic gpio library to set gpio direction and how to read/write from/to the gpio defined in the DTS.

Look at /driver/gpio/gpiolib to learn about the generic gpio interface. Also look at /driver/gpio/gpio-omap to see how the generic interface is implemented on the AM335x. Specifically, the gpio_bank and gpio_chip are the two structures that do everything you need. 

Regards,
John




-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages