I struggled with the title for this one as I figured if I put /sys/class/anything in the title – everyone would run away as I usually do.
This entry came about because of my utter annoyance that so many little Linux SBCs out there come with ZERO or very little support for GPIO. Well, all of that is changing…
Let’s take as a working example the NEO2 from FriendlyArm (and I’m not speaking out of turn – they know my views about not supporting this stuff). Lovely little board – and today I was playing with my extremely un-elegant power supply backup solution (see previous blogs) and realised I had no idea how to access the ports. It looks great in the advert:
- GPIO1: 2.54mm pitch 24 pin-header, compatible with Raspberry Pi’s GPIO pin1 – pin 24. It includes UART, SPI, I2C, IO etc
- GPIO2: 2.54mm pitch 12 pin-header. It includes USB, IR receiver, I2S, IO etc
Lovely – grab your favourite Raspberry Pi utility – I like GPIO – the command line utility – or maybe the nodes in Node-Red – and your off and playing with GPIO.
I’m joking of course – none of that stuff works on these other boards though one or two have “equivalents”! Sometimes the manufacturer provides utilities. I remember one provided some C code – lovely – then told me it only works for ROOT users… you know – the user you are not supposed to be !!! I can only get ONE of the four serial ports to actually work in Node-Red even thought it reports they are there (not permissions – tried that).
Anyway, recently I sat down with a large glass of artificial strawberry drink and started reading.
There is a directory in most of these boards in Linux called /sys/class/gpio
So I went looking – sure enough the NEO2 had this – and a couple of files and 2 shortcuts to GPIO that meant absolutely nothing to me.
So here’s what I’ve learned – just by messing about mind you.
You have to expose the GPIO – so let’s take GPIO0 as a working example.
As root user:
echo 0 > /sys/class/gpio/export
This made a GPIO0 magically appear.
echo out > /sys/class/gpio/gpio0/direction
This made the GPIO an output
echo 1 > /sys/class/gpio/gpio0/value
This made the output go high.
Sounds simple – but which I/O – I made 2 variations of that last command – one with 1, one with 0 – and played them back and forth while sticking a LED on the various potential IO pins on the NEO2. Voila – a lot simpler than I was expecting it turns out that GPIO0 was PA6 on the NEO2.
Now I was getting excited – but here’s the thing – I needed to control this output from Node-Red – and my Node-Red is user PI and you can’t DO this command as user Pi. You could use SUDO but SUDO doesn’t work with echo.
pi@neo2:~$ echo 1 > /sys/class/gpio/gpio0/value
-bash: /sys/class/gpio/gpio0/value: Permission denied
Arggghh. But simple? Use Sudo
pi@neo2:~$ sudo echo 1 > /sys/class/gpio/gpio0/value
-bash: /sys/class/gpio/gpio0/value: Permission denied
Aaarrrrrggghhh.
So I spoke to my friend Antonio and he came up with TEE.
echo 1 | sudo tee /sys/class/gpio/gpio0/value
Aaaaaah. WORKS – so now I put this into an EXEC node in Node-Red and tested – WORKS.
As you can imagine the next step would be to waste hours trying to find out which ports you can use – but then I realised that at least in this case – FriendlyArm supply the Linux GPIO names! I tried GPIO2 – bingo! Nothing is permanent – so a little code in Node-Red would need to check if a port had been used before – and set it up as an output first if not – that’s easy – a lookup table for meaningful names and a bit of substitution in a function would also be easy.
Could I get this to work with inputs? SURE – almost the same starting with “in” instead of “out” assuming you’ve already exposed gpio0…
echo in | sudo tee /sys/class/gpio/gpio0/direction
The next part was sheer guesswork
cat /sys/class/gpio/gpio0/value
Sure enough – this returned the value of that port – either 1 or 0. Would it work in Node-Red EXEC?
YUP! Works a treat. So you could write something for this outside of Node-Red but the latter is a nice friendly environment – and the use of a global would let you check if the input or output was already in use – this is readily adapted to other gpio-software-challenged boards.
This is course is trivial – it does not answer how to use peripheral features such as I2c etc. but if you’ve been struggling just to get the very basic input and output – perhaps that part of your struggle is now over.
Someday soon I hope to have proper drivers for the ports on this and other devices – but then someday soon I hope to win the pools. Best not wait around too long for either.
Meanwhile I have my input and now I can set about detecting low power – and shutting the device down gracefully – just need to write a little code to set up that input automatically.
So – first things first – here’s a setup I’ve made for the NEO2 – a simple text file called “pins.def” (for want of a better name) in the /home/pi/.node-red directory (for want of a better place).
{ “0”:”in”,”203″:”in”,”6″:”out”,”67″:”out”}
A simple piece of json defining the ports I’m interested in – and their direction.
I discovered that if I sent the two commands separately there was no guarantee that they would get there in the right order – so I joined them together… for example for GPIO0
echo 0 | sudo tee /sys/class/gpio/export; echo in | sudo tee /sys/class/gpio/gpio0/direction
And here is my test rig in Node-Red
One of those ports – GPIO6 is an output and is a good test…(pin12 on the dual connector on the NEO2).
Simple enough – on power up the injector node fires off anything to the yellow function node which sets up the ports by exporting them and setting their direction.
var fs = global.get(“fs”);
var fl=”/home/pi/.node-red/pins.def”;var pins=JSON.parse(fs.readFileSync(fl).toString());
for (var port in pins) {
if (pins.hasOwnProperty(port)) {
msg.payload=port + ” | sudo tee /sys/class/gpio/export; “;
msg.payload+=”echo ” + pins[port] + ” | sudo tee /sys/class/gpio/gpio” + port + “/direction”; node.send(msg);
}
}
Insert your own error stuff as desired.
That’s it – the tests simply fire off the right info as described above to the EXEC node – I’ve tested this from reboot – it works.
Now – remember the point of this – I wanted to be able to check a port to see if I should gracefully power down the Pi if the port was low? Well, I can check that every 10 seconds like this.
Of COURSE I can make this more graceful. So every 10 seconds – I trigger the cat command on GPIO0 – RBE merely outputs only on change – probably not needed.. then a simple function returns ONLY if the output is HIGH…. and shuts down the NEO2.
Easy – you could adapt this to any setup.
And here is a new project where this is in use – https://tech.scargill.net/uninterruptible-supplies/
Thanks to the information here and https://github.com/friendlyarm/WiringNP/blob/master/gpio/gpio.c was able to get a relay programmatically working on a NanoPC-T2 with Qt C++ and Debian. This could apply to other uses and similar boards, such as LEDs and the NanoPi-2.
I am using GPIOB31 or pin 15. So as John Czaia points out above, you must first get the table. It generated 32 for B (the ‘B’ is from GPIOB31), so add 31 (also from GPIOB31) = 63. This is the value that must be “exported” with something like: echo 63 > export (in /sys/class/gpio). Once that value is exported, another device will appear: gpio63.
Also as pointed out above, once exported, it is volatile. In other words, gpio63 will disappear after a reboot (or an unexport, ie: echo 63 > unexport). Exporting (and unexporting) must be done as root so that becomes a problem because my application could not initialize or export the pin. So it has to been done at the system level on boot.
So I created an executable script file named gpioexport in /etc/init.d. This may not be completely accurate but it works. The contents are:
#!/bin/bash
# /etc/init.d/gpioexport
# initializes pin 15 or GPIOB31 on NanoPC-T2 for relay functionality
# direction and dis/enable set by application
# create symlink S99gpioexport in /etc/rc5.d with:
# sudo ln -s /etc/init.d/gpioexport /etc/rc5.d/S99gpioexport
# then add to run level with:
# sudo update-rc.d gpioexport defaults
### BEGIN INIT INFO
# Provides: gpioexport
# Required-Start: $remote-fs $syslog
# Required-Stop: $remote-fs $syslog
# Default-Start: 5
# Default-Stop:
# Short-Description: un/exports gpio pin
### END INIT INFO
case “$1” in
start)
echo 63 | tee /sys/class/gpio/export
echo “GPIO exported”
;;
stop)
echo 63 | tee /sys/class/gpio/unexport
echo “GPIO unexported”
;;
*)
echo “Usage: /etc/init.d/gpioexport {start|stop}”
exit 1
;;
esac
exit 0
Notice the trick using “tee”, which I first learned about here, then discovered more information why a simple “echo 63 > export” will not work. Also, once the update-rc.d is performed, the system will assign its own value from the S99.
So the last things to do are open the exposed port, set the direction, “in” or “out”, and then value “0” (off) or “1” (on) in the application with something like:
if ((fd = fopen(“/sys/class/gpio/gpio63/direction”, “w”)) != NULL)
fprintf(fd, “out”); // set direction out
if ((fd = fopen(“/sys/class/gpio/gpio63/value”, “w”)) != NULL)
fprintf(fd, “1”); // enable
Of course, there may be some disagreeable programming practices in that but they are not the focus of this discussion.
There are other options available in gpio63 but direction and value are all I needed for my purposes.
I got that using this command (new to me)
cut -d: -f1 /etc/group | sort
good 🙂
so, to check which devices are created, IF they are…
grep gpio /proc/devices
then do this:
ls -l /dev/WHAT_YOU_HAVE_FOUND_BEFORE
these will be your gpio devices, and in case are root:root we can just create an ad hoc group or just have them have group “pi”
Alight – as it is Sunday I’ll bite…
The first command yields:
“254 gpiochip”
without the quotes. What does that mean exactly?
pi@neo2:~/.node-red$ sudo ls -l /dev/gpiochip
ls: cannot access ‘/dev/gpiochip’: No such file or directory
I think you might have to try doing your echo magic first since you’ve already said that they are in-memory only (reset on reboot).
All I did on the Pi was:
ls -la /sys/class/gpio
which shows you the user and group ownership as well as other details.
Well, as the SUDO method now works so well and can be called from Node-Red I’m not too worried about reducing this to non-SUDO.
Or in alphabetical order to make life easier..
adm
audio
avahi
backup
bin
bluetooth
cdrom
colord
crontab
daemon
dialout
dip
disk
fa
fax
floppy
games
gnats
input
irc
kmem
list
lp
mail
man
messagebus
mosquitto
netdev
news
nogroup
operator
pi
plugdev
proxy
root
sambashare
sasl
scanner
shadow
src
ssh
ssl-cert
staff
sudo
sys
systemd-bus-proxy
systemd-journal
systemd-network
systemd-resolve
systemd-timesync
tape
tty
users
utmp
uucp
video
voice
winbindd_priv
www-data
Thanks for the feedback guys – in the case of the NEO2 – as mentioned elsewhere I found a version of WIRINGPI (hence GPIO) that works – but of course you have to figure out the pins by trial and error. More importantly however I think I may have convinced FriendyArm of the importance of releasing a version of WIRINGPI with a board rather than putting it out there with no info. If they follow up on this we’ll not have to do this experimenting in future and hopefully those programs will also allow easy access to serial and other facilities – which really, I don’t think is too much to expect. Fingers crossed.
But to develop this – on the NEO2 there does not appear to be a group called GPIO. Root is a member of root and the total groups out there appear to be…
root
daemon
bin
sys
adm
tty
disk
lp
mail
news
uucp
man
proxy
kmem
dialout
fax
voice
cdrom
floppy
tape
sudo
audio
dip
www-data
backup
operator
list
irc
src
gnats
shadow
utmp
video
sasl
plugdev
staff
games
users
nogroup
input
systemd-journal
systemd-timesync
systemd-network
systemd-resolve
systemd-bus-proxy
pi
netdev
messagebus
ssh
bluetooth
scanner
colord
fa
ssl-cert
avahi
crontab
sambashare
winbindd_priv
mosquitto
Regarding permissions. A quick check on my Pi shows that ownership of those virtual files and folders belongs to root/gpio.
Which means that you only need to add the user running Node-RED to the gpio group and you shouldn’t need any messing with sudo!
Obviously, other SBC’s may have different ownership but hopefully they have something similar.
so:
sudo adduser pi gpio
or:
sudo useradd -G gpio pi
exact same result
Thanks for this, Pete!
Very informative and I was finally able to use the GPIO pins on the NanoPi2 Fire for the shutdown button I have on all other Pis.
Being a complete Linux noob even after reading your article, I still had a hard time understanding how the GPIO’s are addressed on the NanoPi2 Fire. I could not toggle anything.
After quite some googling I found a forum entry (You posted there too) where someone haphazardly explained how this works (while still being partly wrong and making killer typos).
Below table is essential when using echo commands to toggle/set/get GPIOs, sorted and added letters in front for easier reference:
A nxp-gpio.0: 0
B nxp-gpio.1: 32
C nxp-gpio.2: 64
D nxp-gpio.3: 96
E nxp-gpio.4: 128
F nxp-gpio.5: 160
You can get this via:
cd /sys/class/gpio
for i in gpiochip* ; do echo `cat $i/label`: `cat $i/base` ; done
Example: A GPIO pin labeled GPIOC8, one would expect this to be echo 8 > … but in reality it is: echo 72 > …
So if the letter behind GPIO is C for instance, take the GPIO number and add (in this case) 64, and one has the correct GPIO number for the echo commands.
Once I understood this, and it worked, everything else was much easier. After being able to use NodeRed to manipulate GPIOs I even managed to get the Matrix-Python code to run, which in contrast to this method uses PIN numbers instead of the odd GPIO math. Now boots with the system and with one button press I can shut down the NanoPi2 Fire.
One thing I still don’t get is what does PA stand for? I sometimes see it that someone says: “This is on PA6.” And how is it counted, straight down, unlike the pin numbering on the data sheets, which go left right, or …?
The observant reader may note that some posts have disappeared including a couple of my own. That is because I saw the beginnings of one of those endless “my language is better than yours” discussions which usually devolve into arguments.
I set tabs to 4 spaces in vim, even for other languages then python.
For the readability perspective, I don´t see any reason to keep braces, they are an annoyance to figure out when they start and when they end, plus you can make a oneliner and have unreadable code, which is a nightmare for human readers, not so much for machines.
https://diyprojects.io/orange-pi-onelite-tutorial-use-gpio-python-pinouts/#.WQ1brPmGPZ6
I completely agree on the point of python being odd and a time sink due to it’s design around whitespace / indentation significance. But in those cases where you absolutely must do something with it, my personal recommendation would be to use this: https://www.jetbrains.com/pycharm/ – it takes a lot of pain out of the mundane and what would be 100% obvious in most other languages. You can even line step debug with it – what a time to be alive!
Refresh the blog entry – it is mutating – got all the GPIO working – now added a little cheap OLED display – which I have to say looks very nice. Will add links etc.
If you mean curly braces – absolutely – and that would be made even better by removing case-sensitivity (I’ve probably just started WW3).
technically, /sys (as /proc) is not just a directory but a “virtual filesystem”… as /dev is an interface to devices, both /sys and /proc are interfaces to the kernel itself and let you tune it or read some values… it’s virtual as it’s volatile, created on the fly during boot and destroyed on shutdown, so NOT persistent…
Easy to add persistence via Node-Red and thanks for spotting the deliberate mistakes – hopefully now all gone. I have an input and an output working no problem. Knowledge is a wonderful thing.
and sharing knowledge as you do, is invaluable 🙂