Step02 – User LED Control

Continuing on from Getting Started…

The embedded equivalent of the Hello World paradime is in fact to blink an LED. In the embedded world, we’re used to looking at datasheets and simply toggling an IO pin followed by a pause before again toggling the IO pin which is connected to an LED, thus turning it on and off to blink it.

This section shows how Linux drivers control IO (peripherals) using the filesystem. Everything* in Linux is accessible as a file. The LEDs on the BeagleBone are no exception to this rule. To find the LEDs on the BeagleBone’s file system, we look in the directory /sys/class/leds:

[code]root@beaglebone:/sys/class/leds# dir
beaglebone::usr0 beaglebone::usr1 beaglebone::usr2 beaglebone::usr3[/code]

Normally in-between the colons we would have the LED colour, but on the BeagleBone we dont. Change directory into one of the LEDs and we have several files:

NOTE: In PuTTY it’s impossible using ls to see if a file is a directory or not. Normally the console is coloured and shows directories and files as different colours. If you want to see what’s a directory and what’s a file, simply use the command ls -l to list the directory contents instead.

[code]root@beaglebone:/sys/class/leds/beaglebone::usr1# ls

brightness device max_brightness power subsystem trigger uevent[/code]

We can read the files to see what state the LED control files are in. For example, we can see what (if any) trigger the LED has associated with it. LED 1 in the standard install has the MMC0 activity trigger. So when the card is being used the LED flickers, much like a HDD LED would do:

[code]root@beaglebone:/sys/class/leds/beaglebone::usr1# cat trigger

none [mmc0] timer heartbeat backlight gpio default-on[/code]

That’s probably useful, so lets not use this LED, let’s instead change to usr2 LED which in the standard install is doing nothing:


root@beaglebone:/sys/class/leds/beaglebone::usr2# ls
brightness device max_brightness power subsystem trigger uevent
root@beaglebone:/sys/class/leds/beaglebone::usr2# cat trigger
[none] mmc0 timer heartbeat backlight gpio default-on[/code]

To quickly test the led, we can set it’s trigger option to one of the options shown. Let’s test the USR2 LED by enabling a heartbeat trigger on it:

[code]root@beaglebone:/sys/class/leds/beaglebone::usr2# echo heartbeat > trigger

Now you should see LED2 flashing too. Note: It won’t be in-sync with the LED0 heartbeat.

So now you can at least see how to change the purpose of the LEDs. Remove the trigger for LED2 again:

[code]root@beaglebone:/sys/class/leds/beaglebone::usr2# echo none > trigger


Now lets have a quick look at what else we can play with. The brightness file accepts BCD numbers between 0 and 255. This determines the brightness of the LED, although in reality we’ll find that we can either switch the LED on (value != 0) and off (value == 0).

Give it a go by changing the brightness:

[code]root@beaglebone:/sys/class/leds/beaglebone::usr2# echo 255 > brightness

root@beaglebone:/sys/class/leds/beaglebone::usr2# echo 1 > brightness
root@beaglebone:/sys/class/leds/beaglebone::usr2# echo 0 > brightness

Observe that there’s no difference between brightness level 255 and brightness level 1, yet there is a complete change between 1 and 0! We can see the range is 0-255 by checking the contents of the file max_brightness.

NOTE: When you change the trigger mode, you might well get different files appear. The files will depend on the trigger mode selected and expose differing functionality for the LED control. For example set the trigger to backlight and an inverted file appears.

So now let’s do all that from C. Here’s a quick program which does the same as echo commands and is a bit dirty. But it ends up flashing USR2 LED at 0.5Hz which could be useful if you exit because of a failure or similar from one of your scripts or services. At least you’ll get a visual indication of something!

[code]#include <stdlib.h>
#include <stdio.h>

FILE* f;

int main(int argc, char* argv[])
f = fopen("/sys/class/leds/beaglebone::usr2/trigger", "w");

if (f == NULL)

fprintf(f, "timer");

f = fopen("/sys/class/leds/beaglebone::usr2/delay_on", "w");

if (f == NULL)

fprintf(f, "1000");

f = fopen("/sys/class/leds/beaglebone::usr2/delay_off", "w");

if (f == NULL)

fprintf(f, "1000");


Let’s face it – that’s more effort than we’d normal do in an embedded system to get an LED to blink – but we would have had to setup timers and what-not first and gotten all the hardware to a state where we could just flash an LED at 0.5Hz – so it’s probably quicker to get something done this way as the driver is very flexible. It’s a shame that the brightness cannot be varied on these LEDs, but it’s possible to do that via PWM channels with an LED connected to a GPIO line. Maybe that’ll be the next thing we do… 😉

*almost everything!

Leave a Reply