C GPIO library for Raspberry Pi

Lightweight GPL'd #include for your C programs

Similar projects worth following
I've been developping and using this tiny file for a few years now and it has been already published in 2014 in the french Linux Magazine and Open Silicium, but here you should find a sort of "repository" with the freshest version.

Optimised for size/speed/latency/real-time, then only for convenience. USE AT YOUR OWN RISKS.

Tested on RPI A, B, B+, RPi2 and RPi3. Contributions are welcome.

Based on informations I gathered around the 'net at the time, in particular from (which borrowed from )

I use this file for all my RPi projects that interface to the outside world. In no special order and not exhaustively:

This file is also used as a basis for my compact #C SPI library for Raspberry Pi (and others, later)

It's pretty well tested now, it was published in 2014 ( but the limits are understood as well.

Actually I publish it here to motivate me to support the newer chips, and eventually port it to other architectures. Help welcome !

In 2014 I added the "parachutes" (atexit() calls) which is mostly OK for development but if you need real reliability, use the #Discrete watchdog system.

In 2017 I finally added support for RPi2 and RPi3.

Bonus: 2 dumb example programs and 3 tiny bash scripts that will save your @$$

Note: Direct access to the GPIO pins requires the program to run with root rights, or as setuid root. Compilation usually uses this kind of script:

gcc $GPIO_BASE -Wall -o program program.c &&\
 sudo chown root program &&\
 sudo chmod +s program

I know there are new ways to use GPIOs without root (through /dev/gpiomem) but I'm so used to it that I don't bother, since I run hard real-time SW that need other root goodies...

1. How to support the Raspberry Pi 2
2. Damned RPi3 !



The file to include.

x-chdr - 4.51 kB - 11/01/2016 at 20:49


Run this to set the proper compiler option (v2, OK for Pi3)

application/x-shellscript - 197.00 bytes - 02/16/2017 at 18:46



A tiny example that polls pin#7

text/x-chdr - 607.00 bytes - 11/01/2016 at 22:01



Copies a GPIO input to a GPIO output.

x-chdr - 764.00 bytes - 11/01/2016 at 20:48


Bash script that turns a given GPIO pin to 3.3V

x-shellscript - 199.00 bytes - 11/01/2016 at 14:30


Bash script that reads the state of a given GPIO pin (not always accurate)

x-shellscript - 193.00 bytes - 11/01/2016 at 14:30


Bash script that turns a given GPIO pin to 0V

x-shellscript - 200.00 bytes - 11/01/2016 at 14:30


View all 7 files

  • Damned RPi3 !

    Yann Guidon / YGDES02/16/2017 at 17:34 0 comments

    Trying to turn a LED on with the lib on a RPi3 using the slim image. and work but not the C code.

    The culprit is found easily because doesn't return anything (despite being on RPi3).

    pi@raspberrypi:~/ $ cat /proc/iomem 
    00000000-3affffff : System RAM
      00008000-007ea673 : Kernel code
      00862000-009901eb : Kernel data
    3f007000-3f007eff : /soc/dma@7e007000
    3f200000-3f2000b3 : /soc/gpio@7e200000
    3f201000-3f201fff : /soc/uart@7e201000
      3f201000-3f201fff : /soc/uart@7e201000
    3f300000-3f3000ff : /soc/mmc@7e300000
    The expected keyword is not found ! Instead of bcm2708_gpio, I get /soc/gpio

    Another thing is that I forgot to enable the device tree... But a keyword can be added:

    grep -E '/soc/gpio|bcm2708_gpio' /proc/iomem


    pi@raspberrypi:~/projets/files $ . 
    3f200000-3f2000b3 : /soc/gpio@7e200000
    pi@raspberrypi:~/projets/files $ echo $GPIO_BASE 
    Seems legit... But I still have to test with the device tree.

  • How to support the Raspberry Pi 2

    Yann Guidon / YGDES11/01/2016 at 17:39 2 comments

    The RPi2 swapped the venerable BCM2835 for a BCM2836. The Peripheral block is pretty much the same (or so we hope !) but the BCM2835 changed its base address. So that's the only thing that seems to matter for now.

    Note: For Raspberry Pi 2, change BCM2708_PERI_BASE to 0x3F000000 for the code to work. 

    My current approach is to provide the base pointer as a compile-time parameter because I write mostly "bare-metal" code for a specific board, which is then embedded somewhere for an indefinite while. I don't do "portable binary code" that gets distributed and executed here and there on all kinds of boards.

    Actually, "simple is best" because the situation is pretty complicated with the current software environment. A pile of legacy code is accumulating... Some distribution provide features that allow detection of the board type and revisions, some other don't. And this depends on the kernel compile flags, as well as the distribution's bells and whistles.

    Another argument in favor of a compile-time parameter is: the pointer is constant and can be optimised, which saves a bit of time and space. Nothing really important but in some cases it can do a little welcome difference.

    More food for thoughts:

    The following is a shameful copy-paste from

    Physical Addresses

    The functions bcm2835_peri_read(), bcm2835_peri_write() and bcm2835_peri_set_bits() are low level peripheral register access functions. They are designed to use physical addresses as described in section 1.2.3 ARM physical addresses of the BCM2835 ARM Peripherals manual. Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals. The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000. Thus a peripheral advertised in the manual at bus address 0x7Ennnnnn is available at physical address 0x20nnnnnn.

    On RPI 2, the peripheral addresses are different and the bcm2835 library gets them from reading /proc/device-tree/soc/ranges. This is only availble with recent versions of the kernel on RPI 2.


    Raspberry Pi 2 (RPI2)

    For this library to work correctly on RPI2, you MUST have the device tree support enabled in the kernel. You should also ensure you are using the latest version of Linux. The library has been tested on RPI2 with 2015-02-16-raspbian-wheezy and ArchLinuxARM-rpi-2 as of 2015-03-29.

    When device tree suport is enabled, the file /proc/device-tree/soc/ranges will appear in the file system, and the bcm2835 module relies on its presence to correctly run on RPI2 (it is optional for RPI1). Without device tree support enabled and the presence of this file, it will not work on RPI2.

    To enable device tree support:

    sudo raspi-config
    under Advanced Options - enable Device Tree

    Since I don't distribute binaries, I don't care about supporting all the HW&SW combinations under the sun. I can relegate the detection to a bash script :-)

    Oh and in an older Raspbian running on a B+, I get the necessary info from a different /proc/ file:

    pi@pi ~/GPIO $ cat /proc/iomem 
    00000000-17ffffff : System RAM
      00008000-005bca23 : Kernel code
    20007000-20007fff : bcm2708_dma.0
      20007000-20007fff : bcm2708_dma
    20100000-201000ff : bcm2708_powerman.0
    20101098-2010109a : bcm2708-i2s.0
      20101098-2010109a : bcm2708-i2s.0
    20200000-20200fff : bcm2708_gpio
    20201000-20201fff : dev:f1
      20201000-20201fff : uart-pl011

    The base address is obtained with the following command:

    $ echo "(0x"$(grep bcm2708_gpio /proc/iomem|sed -s 's/-.*//')")"
    Turning this into a compile-time define is straight-forward:
    $ GPIO_BASE="-DGPIO_BASE=(0x"$(grep bcm2708_gpio /proc/iomem|sed -s 's/-.*//')")"
    $ echo $GPIO_BASE 
    $ gcc $GPIO_BASE -Wall -o test_in_out test_in_out.c && sudo chown root test...
    Read more »

View all 2 project logs

Enjoy this project?



Does this project spark your interest?

Become a member to follow this project and never miss any updates