Tag Archives: GPIO on SBCs

GPIO the Hard Way

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.

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.

Exec node[10]

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?

exec node[6]

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

Tesrts

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.

tests

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 - http://tech.scargill.net/uninterruptible-supplies/

Facebooktwittergoogle_pluspinterestlinkedin