Git Product home page Git Product logo

cppgpio's Introduction

CppGPIO

C++14 GPIO library for Raspberry Pi and other embedded systems

What is CppGPIO

CppGPIO is a C++ library for the GPIOs of embedded systems like the Raspberry Pi written entirely in the modern C++ dialect C++14.

It provides a fallback to C++11 however. Please read below.

With the current source CppGPIO only works on the Pi, but it has enough abstraction to be ported to other boards.

It implements a high speed low level access on the GPIO pins of the embedded CPU, much like the C libraries like wiringPi or the bcm2835 library.

It also supports I2C communication via the Linux I2C abstraction.

Inspired by the implementation in wiringPi, it supports Soft PWM and tone outputs on all GPIO ports. Hardware PWM is supported when run as root, by addressing the registers in the bcm2835.

In addition it implements a number of hardware abstractions based on the low level model, such as PushButtons, RotaryDials, LCD displays, and other inputs and outputs.

It performs proper software debouncing on input ports. If you want to, you can modify the default parameters for the debouncing. You can also set the pullup/pulldown mode for all inputs.

The library works event based for input objects. This means that you do not have to poll for state changes of e.g. a switch, but can simply register a function from your own class that will be called from the object when the state changes. This sounds complicated but is actually quite simple with C++11/14 features like lambda expressions. The demo.cpp file has samples for this.

The speed of the library is at the upper limit of the hardware capabilities of the Raspberry Pi (2). Only 12 nanoseconds are needed to switch an output pin on or off. This results in a 44.67 Mhz square wave output just by soft control.

C++11 fallback

CppGPIO compiles with any C++11 compiler, as the only (but important) feature used from C++14 is std::make_unique<>(), and the library provides a local copy of the standard implementation of that feature. The main reason for this is that this provides support for the previous Raspian version, based on debian wheezy, once you install g++-4.8 with sudo apt-get install g++-4.8 (which is available on wheezy). On wheezy, you then need however specify the newer compiler explicitly, e.g. by changing the Makefiles supplied with this project to explicitly call g++-4.8 instead of g++ .

In result, CppGPIO is a pure C++11 library. You cannot use it from C nor from non-C++11 capable compilers.

How to install

Just clone a revision from here, and get into the source directory and type

make -j4
sudo make install
make demo

How to use

After you have installed the library and the include headers, you can simply include it into your own projects by adding

#include <cppgpio.hpp>

to the files in which you want to use the functionality. For proper linking, you have to add

-lcppgpio

to your linker arguments. It will normally be added as a shared library, but if you want to force static linking, it provides a static version as well.

Documentation

All header files have fully commented public and protected methods. When using IDEs like Eclipse or XCode, you get the methods "intellisensed", with documentation. If in doubt, just look at the header files in include/cppgpio/. In the following days I may be adding doxygen generated documentation from the source files.

Supported operating environments

The only GPIO model is currently the BCM2835 as used in the Raspberry Pi boards. It adapts automatically to the various versions (I have it only tested though on a B, A+, and 2 B). The code itself should compile fine on any OS with a C++14 compiler. I typically develop and test build my projects on OSX with XCode, and then copy them to the Pi. This works because the GPIO automatically switches to simulation mode when not on Linux (or can be forced to do with Linux, too).

License

CppGPIO is open source. The terms of the BSD license apply. Copyright (c) 2016 Joachim Schurig.

Some examples

The following examples are taken from demo.cpp in this project.

Writing to a digital output

#include <chrono>
#include <cppgpio.hpp>

using namespace GPIO;

int main()
{
  // use gpio #18

  DigitalOut out(18);
  
  // switch output to logical 1 (3.3V)

  out.on();
  
  // wait some time
  
  std::this_thread::sleep_for(std::chrono::milliseconds(1));
  
  // switch it off again
  
  out.off();

  return 0;
}

When DigitalOut goes out of scope, the port is automatically reset to input mode and any resource associated with it is freed

Example with a PWM output

In the following example we output a PWM signal to a port, not regarding if it will be generated by a hardware PWM circuit or by the software emulation, which is a function of the port number and the initialisation mode.

It could e.g. dim a LED on and off.

#include <chrono>
#include <cppgpio.hpp>

using namespace GPIO;

int main()
{
  // create PWM on GPIO 23, set range to 100, inital value to 0
  
  PWMOut pwm(23, 100, 0);
  
  // now dim a LED 20 times from off to on to off
  
  for (int l = 0; l < 20; ++l) {
  
    for (int p = 0; p < 100; ++p) {
      pwm.set_ratio(p);
      std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
    
    for (int p = 100; p > 0; --p) {
      pwm.set_ratio(p);
      std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
    
  }
  
  return 0;
}

Example with an LCD display, a rotary dial and a push button

In the following example we use the event driven approach with a rotary dial with integrated push button. We connect callables (in this case member functions of the Rotary1 class) to the rotary and button classes, and have them called whenever an event occurs. Remark there is no polling, and no control loop.

#include <string>
#include <chrono>
#include <stdlib.h>
#include <cppgpio.hpp>

using namespace GPIO;


class Rotary1 {
public:
    Rotary1()
    : lcd(4, 20, "/dev/i2c-1", 0x27)
    , dial(6, 12, GPIO_PULL::UP)
    , push(5, GPIO_PULL::UP)
    {
        lcd.fill();
        lcd.write(0, 0, "Please dial me!");
        lcd.write(1, 0, "Will exit at #42");

        // register a lambda function at the dial to connect it to this class

        dial.f_dialed = [&](bool up, long value) { dialed(up, value); };

        // could also use std::bind():
        // dial.f_dialed = std::bind(&Rotary1::dialed, this, std::placeholders::_1, std::placeholders::_2);

        push.f_pushed = [&]() { pushed(); };

        push.f_released = [&](std::chrono::nanoseconds nano) { released(nano); };

        // after finishing the initialization of the event driven input objects
        // start the event threads of the input objects

        dial.start();
        push.start();
    }

private:
    HitachiLCD lcd;
    RotaryDial dial;
    PushButton push;
    
    void dialed(bool up, long value)
    {
        std::string out = "Value: ";
        out += std::to_string(value);
        lcd.write(0, 0, out);

        if (value == 42) {
            lcd.write(0, 0, "Goodbye");
            lcd.write(1, 0, "");
            std::this_thread::sleep_for(std::chrono::seconds(2));
            lcd.backlight(false);
            exit(0);
        }
    }
    
    void pushed()
    {
        lcd.write(1, 0, "Button: pushed");
    }
    
    void released(std::chrono::nanoseconds nano)
    {
        lcd.write(1, 0, "Button: released");
    }
    
};



int main()
{

  Rotary1 rotary;

  // the rotary object will function properly on any
  // event alltough the main thread will now sleep for an hour
  
  std::this_thread::sleep_for(std::chrono::hours(1));
  
  return 0;
}

When Rotary1 goes out of scope, all GPIO objects used inside are properly reset and freed.

cppgpio's People

Contributors

joachimschurig avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cppgpio's Issues

Undefined Refrence to any "Keywords" like Digitalout

I folowed the instalation steps exactly and when i compile without any executable code it works but as soon as i useanything from the LIB it gives me the Undefined refrence to "....". But for example when i do something like

DigitalOut out()

it douesnt givew me an error but when i input an int like

DigitalOut out(29)

it gives the error.

Btw im using the pi 3b

Hardware PWM

Board: RPi 3
OS: Raspbian Stretch

How to run hardware generated PWM? I tried all pins, but is_software_emulation() always returns '1'.

licens? and my changes to this library

Hi,
I found your library useful but I also found many bugs that I needed to target.
I would make PR if you merge it to the main but if you are not able to do so I keep My version.
I couldn't see any Licens. Kindly would you choose one?
Let me know if you wish to get the RP.
Thanks for the library
Mariwan

Raspberry Pi 4 freezes on Ubuntu when controlling digital output

I used the example provided here to try out the library. I can see the LED turning on for the requested time but the Pi mostly freezes afterwards. Sometimes the LED stays on longer. An SSH session wouldn't survive but I could get more output using a serial UART consule:

$ g++ onoff.cpp -o onoff -lcppgpio
$ ./onoff
[  161.254299] mmc1: Timeout waiting for hardware interrupt.
[  161.259919] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  169.098267] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
[  169.104480] rcu:     0-...!: (1 ticks this GP) idle=1a7/0/0x7 softirq=8657/8657 fqs=0
[  169.112361] rcu: rcu_preempt kthread timer wakeup didn't happen for 5251 jiffies! g9873 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402
[  169.123844] rcu:     Possible timer handling issue on cpu=0 timer-softirq=2351
[  169.130910] rcu: rcu_preempt kthread starved for 5252 jiffies! g9873 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0
[  169.141421] rcu:     Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
[  169.150691] rcu: RCU grace-period kthread stack dump:
[  169.155936] rcu: Stack dump where RCU GP kthread last ran:
[  171.494266] mmc1: Timeout waiting for hardware interrupt.
[  171.499872] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  176.006255] watchdog: BUG: soft lockup - CPU#0 stuck for 26s! [swapper/0:0]
[  181.730253] mmc1: Timeout waiting for hardware interrupt.
[  181.735866] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  191.970244] mmc1: Timeout waiting for hardware interrupt.
[  191.975847] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  202.210242] mmc1: Timeout waiting for hardware interrupt.
[  202.215841] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  204.006227] watchdog: BUG: soft lockup - CPU#0 stuck for 52s! [swapper/0:0]
[  212.450238] mmc1: Timeout waiting for hardware interrupt.
[  212.455859] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  222.690236] mmc1: Timeout waiting for hardware interrupt.
[  222.695849] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110
[  232.006223] watchdog: BUG: soft lockup - CPU#0 stuck for 79s! [swapper/0:0]
[  232.118228] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
[  232.124436] rcu:     0-....: (1 ticks this GP) idle=1a7/0/0x5 softirq=8657/8657 fqs=5681
[  232.930242] mmc1: Timeout waiting for hardware interrupt.
[  232.935832] brcmfmac: brcmf_sdio_htclk: HT Avail request error: -110

System info:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
Codename:       jammy

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/aarch64-linux-gnu/11/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.3.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++
,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=aarch64-linux-gnu- --enable-shared --enable-linker-build-
id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debu
g --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-de
fault-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --enable-fix-cortex-a53-843419 -
-disable-werror --enable-checking=release --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-l
ink-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04) 

Undefined reference when compiling example code

When compiling the example code

#include <chrono>
#include <cppgpio.hpp>
int main()
{
	// use gpio #18

	GPIO::DigitalOut out(18);

	 //switch output to logical 1 (3.3V)

	out.on();

	// wait some time

	std::this_thread::sleep_for(std::chrono::milliseconds(1));

	// switch it off again

	out.off();

	return 0;
}

the following error appear

Error		undefined reference to `GPIO::DigitalOut::DigitalOut(unsigned int)'	

How can I solve it?

Unable to switch GPIO pin to high (1) in simulation mode

Should this even work? Or am I missing something?

Consider the following code:

GPIO::GPIOBase::simulation(true);
GPIO::DigitalOut out(11);
out.on();
std::this_thread::sleep_for(std::chrono::milliseconds(1));

I did expect the value of gpio_addr turn to 1 but this does not happen.

Raspberry pi4, pullup seems to be not effective.

Hi, foremost thank you for awesome work!

I have slight issue with button class.

#include <cppgpio.hpp>
#include <thread>
int main(int argc, char **argv) {
    health_server::setStatusHandler(mandeye::produceReport);
    std::thread http_thread1(health_server::server_worker);
    GPIO::DigitalOut out(21);
    GPIO::PushButton in(20, GPIO::GPIO_PULL::UP);

    in.f_pushed  = [&](){
        out.on();
        std::this_thread::sleep_for(std::chrono::milliseconds (500));
        out.off();
    };
    in.start();
    // blink once to test GPIO21
    in.f_pushed();
    for (;;) {
    }
    return 0;
}

It is basic code that is to trigger blink of led on output GPIO21 when GPIO20 is connected to GND.
However, it is not working, raspi-gpio says it is still pulldown mode:

pi@raspberrypi:~ $ raspi-gpio get 20
GPIO 20: level=0 fsel=0 func=INPUT pull=DOWN

When I connect to GPIO21 3.3V the GPIO20 blinks.

From my initial debbugging GPIOBase::pullupdown is not called.
I am opening issue since I do not know if I am experiencing a bug, or done smth wrong.
Kindly ask for assistance.

Repository state : 017564088be26b36cdfaa418becc62a7ed52da94
Static linking
Raspberry pi 4 
Raspbian GNU/Linux 10 (buster)

how to write a string

Hi, I'm new to GPIO and I want to use your code to send strings to and read strings from to the slave computer. I am using LattePanda with ubuntu OS x86 architecture. Could you please give me an example?

Thanks!

This isn't an issue, just a thank you as Github doesn't offer a super easy way to say thanks besides stars.

I just wrapped up CppGPIO for openFrameworks with great success. Looking forward to using it. There are a few other options available for openFrameworks (https://github.com/joshuajnoble/ofxWiringPi and https://github.com/kashimAstro/ofxGPIO), but they use wiring pi and sysfs. I was very happy to find your implementation!

Anyway, thanks!

cross-compile demo

Hello,

I modify Makefile with :
'''
/opt/crosstool-ng/armv7-rpi2-linux-gnueabihf/bin/armv7-rpi2-linux-gnueabihf-g++ -I./include -Wall -O2 -std=c++11 -pthread -c -o demo.o demo.cpp
/opt/crosstool-ng/armv7-rpi2-linux-gnueabihf/bin/armv7-rpi2-linux-gnueabihf-g++ -I./include -L./ -L./libcppgpio.so.1.0.0 -lpthread -lcppgpio -o demo demo.o
'''
but :
'''
demo.o: In function lcdtest()': demo.cpp:(.text+0x3c): undefined reference toGPIO::HitachiLCD::HitachiLCD(unsigned int, unsigned int, std::string const&, unsigned int, bool, bool)'
demo.cpp:(.text+0xd8): undefined reference to GPIO::HitachiLCD::write(unsigned int, unsigned int, std::string const&, unsigned int)' demo.cpp:(.text+0x21c): undefined reference toGPIO::HitachiLCD::scroll(bool)'
demo.cpp:(.text+0x250): undefined reference to GPIO::HitachiLCD::home()' demo.cpp:(.text+0x288): undefined reference toGPIO::HitachiLCD::write(std::string const&)'
......
''''
THX

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.