-
Notifications
You must be signed in to change notification settings - Fork 7
Home
Arduino on Pi boards, the best of both worlds.
PiDuino was born from a question from one of my students who asked me why programming input-output on NanoPi was not as simple as on Arduino.
PiDuino therefore aims to respond to this need:
An Application Programming Interface (API) on Pi boards as close as possible to that of Arduino.
This API must allow to use GPIO, Serial port, I2C bus and SPI... on Raspberry Pi, Nano Pi,Orange Pi, Banana Pi, Beagle Board... boards as on an Arduino board.
What PiDuino offers:
-
A programming interface API same as Arduino except adding
#include <Piduino.h>
at the beginning of the program. It does not prohibit offering extensions of the API but provided that stay as independent as possible from the platform and not to make the code incompatible with Arduino. It makes sense to think that users who want to stay in the Arduino world use C ++, PiDuino is intended for this use case. Nevertheless some functions can be used in C (pinMode ()
,digitalWrite ()
, ...). -
The description of Pi boards that is based on an "Object" model stored in a database (SQLite by default), allowing a simple user to add a new Pi board "variant" WITHOUT programming.
-
An object design in C++ with a clear separation of the part specific to the platform. Support for new SoCs is summarizes to add a part "driver" in the directory
src/gpio/arch
-
Utilities for manipulating GPIO signals:
pido
, retrieve information from the board:pinfo
or manage the Pi boards database:pidbman
PiDuino is in development, version 0.3 currently but the completed parts are functional on Broadcom SoC BCM283X and AllWinner Hx.
The list of models present in the database is as follows:
- NanoPi Core
- NanoPi Core with Mini Shield
- NanoPi Core2
- NanoPi Core2 with Mini Shield
- NanoPi M1
- NanoPi M1+
- NanoPi Neo
- NanoPi Neo 2
- NanoPi Neo Air
- NanoPi Neo+ 2
- RaspberryPi 2
- RaspberryPi 3
- RaspberryPi A
- RaspberryPi A+
- RaspberryPi B
- RaspberryPi B+
- RaspberryPi Compute Module
- RaspberryPi Compute Module 3
- RaspberryPi Zero
- RaspberryPi Zero Wifi
The examples folder contains examples from the Arduino world that are can be used directly with PiDuino. The only thing to add is the line:
#include <Piduino.h>
Here is the source code of the example Blink that flashes a led:
#include <Piduino.h> // all the magic is here ;-)
const int ledPin = 0; // Header Pin 11: GPIO17 for RPi, GPIOA0 for NanoPi
void setup() {
// initialize digital pin ledPin as an output.
pinMode (ledPin, OUTPUT);
}
void loop () {
// Press Ctrl+C to abort ...
digitalWrite (ledPin, HIGH); // turn the LED on (HIGH is the voltage level)
delay (1000); // wait for a second
digitalWrite (ledPin, LOW); // turn the LED off by making the voltage LOW
delay (1000); // wait for a second
}
Obviously, you need to know the pin number where you connected the LED !
This number depends on your model of Pi board, to know it quickly, we can type
the command pido readall 1
, which gives us, for example, the following display
on a Raspberry Pi B:
P1 (#1)
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| sOc | iNo | Name | Mode | V | Ph || Ph | V | Mode | Name | iNo | sOc |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| | | 3.3V | | | 1 || 2 | | | 5V | | |
| 2 | 8 | GPIO2 | IN | 1 | 3 || 4 | | | 5V | | |
| 3 | 9 | GPIO3 | IN | 1 | 5 || 6 | | | GND | | |
| 4 | 7 | GPIO4 | IN | 1 | 7 || 8 | 1 | ALT0 | TXD0 | 15 | 14 |
| | | GND | | | 9 || 10 | 1 | ALT0 | RXD0 | 16 | 15 |
| 17 | 0 | GPIO17 | IN | 0 | 11 || 12 | 0 | IN | GPIO18 | 1 | 18 |
| 27 | 2 | GPIO27 | IN | 0 | 13 || 14 | | | GND | | |
| 22 | 3 | GPIO22 | IN | 0 | 15 || 16 | 0 | IN | GPIO23 | 4 | 23 |
| | | 3.3V | | | 17 || 18 | 0 | IN | GPIO24 | 5 | 24 |
| 10 | 12 | GPIO10 | IN | 0 | 19 || 20 | | | GND | | |
| 9 | 13 | GPIO9 | IN | 0 | 21 || 22 | 0 | IN | GPIO25 | 6 | 25 |
| 11 | 14 | GPIO11 | IN | 0 | 23 || 24 | 1 | IN | GPIO8 | 10 | 8 |
| | | GND | | | 25 || 26 | 1 | IN | GPIO7 | 11 | 7 |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| sOc | iNo | Name | Mode | V | Ph || Ph | V | Mode | Name | iNo | sOc |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
The iNo column corresponds to the 'Arduino' number, the number 0 pin corresponds therefore at pin 11 of the GPIO connector (GPIO17).
To compile the blink program on the command line, you must type the command:
$ g++ -o blink blink.cpp $(pkg-config --cflags --libs piduino)
The last part of the command uses pkg-config
to add the build options to g++
in order to compile the program correctly.
To have a more user-friendly development environment, it is advisable to use Codelite, the installation of PiDuino adds a program template for PiDuino:
In Codelite, one can not only compile, but also edit and especially to debug the program:
the second example rtc_bq32k, uses the Wire library to read the time in a BQ32000 RTC circuit.
It allows to discover 2 important differences between an Arduino board and a Pi board:
- First, on a Pi board, the human-machine interface (screen and keyboard) is done on the command line (the console !). On Arduino, the serial port is used.
- On a Pi board, a program can finish to give the user a hand. On Arduino, the program never stops (in fact on a Linux system, the kernel program never stops either...)
To solve the first problem, PiDuino defines a Console
object whose
the usage is identical to the Serial
object (it is a class derived from Stream
).
In order to allow compilation on both platforms without modifying the source code,
we can add at the beginning of the sketch a block that tests if the target platform is
a Unix/Linux system (PiDuino), if so, the inclusion of the file
Piduino.h
is done, otherwise we define a Console alias which corresponds to
Serial, ie the human-machine interface is on the serial port.
#ifdef __unix__
#include <Piduino.h> // All the magic is here ;-)
#else
// Defines the serial port as the console on the Arduino platform
#define Console Serial
#endif
#include <Wire.h>
void printBcdDigit (byte val, bool end = false) {
val = (val / 16 * 10) + (val % 16); // BCD to DEC
if (val < 10) {
Console.write ('0'); // leading zero
}
if (end) {
Console.println (val);
}
else {
Console.print (val);
Console.write (':');
}
}
void setup() {
Console.begin (115200);
Wire.begin(); // Starting the i2c master
}
void loop() {
Wire.beginTransmission (0x68); // start of the frame for the RTC at slave address 0x68
Wire.write (0); // write the address of the register in the RTC, 0 first register
Wire.endTransmission (false); // restart condition
Wire.requestFrom (0x68, 3); // 3-byte read request
if (Wire.available() == 3) { // if the 3 bytes have been read
byte sec = Wire.read();
byte min = Wire.read();
byte hour = Wire.read() & 0x3F; // remove CENT_EN and CENT LSB bits
// time display
printBcdDigit (hour);
printBcdDigit (min);
printBcdDigit (sec, true);
}
exit (0); // exit the loop() function without ever coming back.
// On Arduino, exit() performs an infinite loop as explained on
// https://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
// on a Pi board, exit () stops the program by returning the supplied value.
}
To solve the second problem, it is possible to use on the 2
platforms the exit ()
function (which is defined in the
standard library).
This function, compatible with both platforms, allows to stop the execution
the loop () function.
On a Unix / Linux system, it stops the program and returns to the command line, on Arduino, it performs an infinite loop (after calling the destructor of C ++ objects).
The pido
command allows you to modify the mode, the pull resistance, to read
or write logical or analogical states (PWM) ...
On a raspberry pi model B, this allows to do for example:
$ pido readall
P1 (#1)
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| sOc | iNo | Name | Mode | V | Ph || Ph | V | Mode | Name | iNo | sOc |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| | | 3.3V | | | 1 || 2 | | | 5V | | |
| 2 | 8 | GPIO2 | IN | 1 | 3 || 4 | | | 5V | | |
| 3 | 9 | GPIO3 | IN | 1 | 5 || 6 | | | GND | | |
| 4 | 7 | GPIO4 | IN | 1 | 7 || 8 | 1 | ALT0 | TXD0 | 15 | 14 |
| | | GND | | | 9 || 10 | 1 | ALT0 | RXD0 | 16 | 15 |
| 17 | 0 | GPIO17 | IN | 0 | 11 || 12 | 0 | IN | GPIO18 | 1 | 18 |
| 27 | 2 | GPIO27 | IN | 0 | 13 || 14 | | | GND | | |
| 22 | 3 | GPIO22 | IN | 0 | 15 || 16 | 0 | IN | GPIO23 | 4 | 23 |
| | | 3.3V | | | 17 || 18 | 0 | IN | GPIO24 | 5 | 24 |
| 10 | 12 | GPIO10 | IN | 0 | 19 || 20 | | | GND | | |
| 9 | 13 | GPIO9 | IN | 0 | 21 || 22 | 0 | IN | GPIO25 | 6 | 25 |
| 11 | 14 | GPIO11 | IN | 0 | 23 || 24 | 1 | IN | GPIO8 | 10 | 8 |
| | | GND | | | 25 || 26 | 1 | IN | GPIO7 | 11 | 7 |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| sOc | iNo | Name | Mode | V | Ph || Ph | V | Mode | Name | iNo | sOc |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
P5 (#2)
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| sOc | iNo | Name | Mode | V | Ph || Ph | V | Mode | Name | iNo | sOc |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
| | | 5V | | | 1 || 2 | | | 3.3V | | |
| 28 | 17 | GPIO28 | IN | 0 | 3 || 4 | 0 | IN | GPIO29 | 18 | 29 |
| 30 | 19 | GPIO30 | IN | 0 | 5 || 6 | 0 | IN | GPIO31 | 20 | 31 |
| | | GND | | | 7 || 8 | | | GND | | |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
On a NanoPi Neo Plus 2, this allows to display for example:
$ pido readall
CON1 (#1)
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| sOc | iNo | Name | Mode | Pull | V | Ph || Ph | V | Pull | Mode | Name | iNo | sOc |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| | | 3.3V | | | | 1 || 2 | | | | 5V | | |
| 12 | 8 | I2C0SDA | ALT2 | OFF | | 3 || 4 | | | | 5V | | |
| 11 | 9 | I2C0SCK | ALT2 | OFF | | 5 || 6 | | | | GND | | |
| 91 | 7 | GPIOG11 | OFF | OFF | | 7 || 8 | | OFF | ALT2 | UART1TX | 15 | 86 |
| | | GND | | | | 9 || 10 | | OFF | ALT2 | UART1RX | 16 | 87 |
| 0 | 0 | GPIOA0 | OFF | OFF | | 11 || 12 | | OFF | OFF | GPIOA6 | 1 | 6 |
| 2 | 2 | GPIOA2 | OFF | OFF | | 13 || 14 | | | | GND | | |
| 3 | 3 | GPIOA3 | OFF | OFF | | 15 || 16 | | OFF | OFF | GPIOG8 | 4 | 88 |
| | | 3.3V | | | | 17 || 18 | | OFF | OFF | GPIOG9 | 5 | 89 |
| 22 | 12 | GPIOC0 | OFF | OFF | | 19 || 20 | | | | GND | | |
| 23 | 13 | GPIOC1 | OFF | OFF | | 21 || 22 | | OFF | OFF | GPIOA1 | 6 | 1 |
| 24 | 14 | GPIOC2 | OFF | OFF | | 23 || 24 | | UP | OFF | GPIOC3 | 10 | 25 |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| sOc | iNo | Name | Mode | Pull | V | Ph || Ph | V | Pull | Mode | Name | iNo | sOc |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
DBG_UART (#2)
+-----+-----+----------+------+------+---+----+
| sOc | iNo | Name | Mode | Pull | V | Ph |
+-----+-----+----------+------+------+---+----+
| | | GND | | | | 1 |
| | | 5V | | | | 2 |
| 4 | 17 | UART0TX | ALT2 | OFF | | 3 |
| 5 | 18 | UART0RX | ALT2 | UP | | 4 |
+-----+-----+----------+------+------+---+----+
INNER (#3)
+-----+-----+----------+------+------+---+----+
| sOc | iNo | Name | Mode | Pull | V | Ph |
+-----+-----+----------+------+------+---+----+
| 10 | 19 | GPIOA10 | OFF | OFF | | 1 |
| 104 | 32 | PWR_LED | OUT | OFF | 1 | 2 |
+-----+-----+----------+------+------+---+----+
CON2 (#4)
+-----+-----+----------+------+------+---+----+
| sOc | iNo | Name | Mode | Pull | V | Ph |
+-----+-----+----------+------+------+---+----+
| | | 5V | | | | 1 |
| | | USB-DP1 | | | | 2 |
| | | USB-DM1 | | | | 3 |
| | | USB-DP2 | | | | 4 |
| | | USB-DM2 | | | | 5 |
| 105 | 20 | GPIOL11 | OFF | OFF | | 6 |
| 17 | 11 | GPIOA17 | OFF | OFF | | 7 |
| 18 | 31 | GPIOA18 | OFF | OFF | | 8 |
| 19 | 30 | GPIOA19 | OFF | OFF | | 9 |
| 20 | 21 | GPIOA20 | OUT | OFF | 0 | 10 |
| 21 | 22 | GPIOA21 | OFF | OFF | | 11 |
| | | GND | | | | 12 |
+-----+-----+----------+------+------+---+----+
| sOc | iNo | Name | Mode | Pull | V | Ph |
+-----+-----+----------+------+------+---+----+
As can be seen above, on a NanoPi Neo Plus 2, there are 4 "connectors",
the connector INNER
corresponds to internal signals to the card which can be
useful to handle (here one has the signal of the Led ON and the Led STATUS (GPIOA10)).
Note also that in the case of the NanoPi, the readall
command displays a
column Pull
which allows to display the state of the pull resistor
(this feature is not available on a raspberry pi because the BCM2835 does
not can not do that).
We can specify the readall
command, the number of the connector to display
(the number of the connector is displayed above its table after the #
),
for example:
$ pido readall 1
CON1 (#1)
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| sOc | iNo | Name | Mode | Pull | V | Ph || Ph | V | Pull | Mode | Name | iNo | sOc |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| | | 3.3V | | | | 1 || 2 | | | | 5V | | |
| 12 | 8 | I2C0SDA | ALT2 | OFF | | 3 || 4 | | | | 5V | | |
| 11 | 9 | I2C0SCK | ALT2 | OFF | | 5 || 6 | | | | GND | | |
| 91 | 7 | GPIOG11 | OFF | OFF | | 7 || 8 | | OFF | ALT2 | UART1TX | 15 | 86 |
| | | GND | | | | 9 || 10 | | OFF | ALT2 | UART1RX | 16 | 87 |
| 0 | 0 | GPIOA0 | OFF | OFF | | 11 || 12 | | OFF | OFF | GPIOA6 | 1 | 6 |
| 2 | 2 | GPIOA2 | OFF | OFF | | 13 || 14 | | | | GND | | |
| 3 | 3 | GPIOA3 | OFF | OFF | | 15 || 16 | | OFF | OFF | GPIOG8 | 4 | 88 |
| | | 3.3V | | | | 17 || 18 | | OFF | OFF | GPIOG9 | 5 | 89 |
| 22 | 12 | GPIOC0 | OFF | OFF | | 19 || 20 | | | | GND | | |
| 23 | 13 | GPIOC1 | OFF | OFF | | 21 || 22 | | OFF | OFF | GPIOA1 | 6 | 1 |
| 24 | 14 | GPIOC2 | OFF | OFF | | 23 || 24 | | UP | OFF | GPIOC3 | 10 | 25 |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
| sOc | iNo | Name | Mode | Pull | V | Ph || Ph | V | Pull | Mode | Name | iNo | sOc |
+-----+-----+----------+------+------+---+----++----+---+------+------+----------+-----+-----+
To put pin number 0 in output:
$ pido mode 0 out
By default, it is the numbering of the iNo
column that is used, but we
could also designate the signal 0
by 1.11
:
$ pido mode 1.11 out
This notation C.N
, makes it possible to quickly designate the pin N
(here 11) of the C
connector (here 1).
To put this output in high state:
$ pido write 0 1
To put it in the low state:
$ pido write 0 0
You can also toggle the state:
$ pido toggle 0
Or generate a square signal on the pin :
$ pido blink 0 100
To put it in input with pull-up resistor:
$ pido mode 0 in
$ pido pull 0 up
And to read it:
$ pido read 0
Or we can wait for a falling front on this entry:
$ pido wfi 0 falling
The -h
option allows to know the different possible actions:
usage : pido [ options ] [ command ] [ parameters ] [ options ]
Allow the user easy access to the GPIO pins.
valid options are :
-g Use the SOC pins numbers rather than PiDuino pin numbers.
-s Use the System pin numbers rather than PiDuino pin numbers.
-f Force to use SysFS interface (/sys/class/gpio).
-1 Use the connector pin numbers rather than PiDuino pin numbers.
a number is written in the form C.P, eg: 1.5 denotes pin 5 of connector #1.
-v Output the current version including the board informations.
-h Print this message and exit
valid commands are :
mode <pin> <in/out/off/pwm/alt{0..9}>
Get/Set a pin mode into input, output, off, alt0..9 or pwm mode.
pull <pin> <up/down/off>
Get/Set the internal pull-up, pull-down or off controls.
read <pin>
Read the digital value of the given pin (0 or 1)
readall [#connector]
Output a table of all connectors with pins informations.
write <pin> <value>
Write the given value (0 or 1) to the given pin (output).
toggle <pin>
Changes the state of a GPIO pin; 0 to 1, or 1 to 0 (output).
blink <pin> [period]
Blinks the given pin on/off (explicitly sets the pin to output).
wfi <pin> <rising/falling/both> [timeout_ms]
Waits for the interrupt to happen. It's a non-busy wait.
pwm <pin> <value>
Write a PWM value (0-1023) to the given pin (pwm pin only).
The pinfo
command allows to know the information on the Pi board.
On a Raspberry Pi model B :
$ pinfo
Name : RaspberryPi B
Family : RaspberryPi
Database Id : 9
Manufacturer : Sony
Board Revision : 0xe
SoC : Bcm2708 (Broadcom)
Memory : 512MB
GPIO Id : 2
PCB Revision : 2
Serial Ports : /dev/ttyAMA0
On a NanoPi Neo Plus 2:
$ pinfo
Name : NanoPi Neo+ 2
Family : NanoPi
Database Id : 36
Manufacturer : Friendly ARM
Board Tag : nanopineoplus2
SoC : H5 (Allwinner)
Memory : 1024MB
GPIO Id : 4
I2C Buses : /dev/i2c-0
Serial Ports : /dev/ttyS0,/dev/ttyS1
The command displays only information in the list, -h
, allows to know the
different options.
What was done ?
- GPIO modeling, GPIO connectors and pins
- Creation of database model and addition of all variants of Raspberry Pi, Nano Pi Neo, Neo2, Neo Plus 2, M1, M1 Plus.
- Creation of SoC access layers for Broadcom BCM283X and AllWinner Hx.
- Creating
pido
andpinfo
utilities - Switching iomap in C++
- Creating virtual classes IoDevice and FileDevice
- analogWrite() with GPIO software PWM feature (Polling with thread)
- Emulate setup() and loop() for Arduino compatibility (in Arduino.h)
- Cleaning the architecture detection
- I2C Bus API
- SPI Bus API
- Serial Port API
- Arduino Classes (String, Print, Stream....)
- Update README
The rest of the things to do:
-
pidbman
for managing the database of boards with Qt (in development pidbman) - Enabling daemon mode for loop()
- Hardware PWM Pin support
- analogWrite() with Software PWM feature (Kernel driver module)
- analogWrite() with external DAC (IIO)
- analogRead() with external ADC or Sensor (IIO)
- Man Pages for Utilities
- Database Doxygen Documentation (English)
- Creating a web page