11.A1 Flashing the LEDs using C++



Introduction

One of the first things you would like to do when you connect to the Beaglebone Black is see that you are having an impact on the hardware. In this short post I am going to look at how you can change the behaviour of the Beaglebone on-board LEDs – the four (blue on the BBB) LEDs in the corner near the reset button.

Now, the LEDs are there for a reason, and that reason is to give information about the Beaglebone state (from beaglebone.org):

USR0 is configured at boot to blink in a heartbeat pattern
USR1 is configured at boot to light during microSD card accesses
USR2 is configured at boot to light during CPU activity
USR3 is configured at boot to light during eMMC accesses

We can change the behaviour of these LEDs, but obviously we will temporarily lose this valuable information. The heartbeat tells you that the BBB is alive, which is always useful to know. The others are fairly self explanatory (the eMMC is the solid state memory that you are booting from).

First – At the command line

Sysfs is a virtual file system that is available under Linux that gives information and access to devices and drivers that would otherwise only be accessible in Kernel Space. It gives us a virtual file system in Linux User Space, which is convenient to use; however, it is not highly efficient.

At the command line, we can go to to directory /sys/class/leds:

1
2
3
4
5
6
7
8
9
root@beaglebone:/sys/class/leds# ls -al
total 0
drwxr-xr-x  2 root root 0 Jan  1 00:00 .
drwxr-xr-x 48 root root 0 Jan  1 00:00 ..
lrwxrwxrwx  1 root root 0 Jan  1 00:00 beaglebone:green:usr0 -> ../../devices/ocp.2/gpio-leds.7/leds/beaglebone:green:usr0
lrwxrwxrwx  1 root root 0 Jan  1 00:00 beaglebone:green:usr1 -> ../../devices/ocp.2/gpio-leds.7/leds/beaglebone:green:usr1
lrwxrwxrwx  1 root root 0 Jan  1 00:00 beaglebone:green:usr2 -> ../../devices/ocp.2/gpio-leds.7/leds/beaglebone:green:usr2
lrwxrwxrwx  1 root root 0 Jan  1 00:00 beaglebone:green:usr3 -> ../../devices/ocp.2/gpio-leds.7/leds/beaglebone:green:usr3
root@beaglebone:/sys/class/leds#

You can see the four (green!) LEDs, usr0, usr1, usr2 and usr3 and their mappings.

We can go into the directory of the first LED:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@beaglebone:/sys/class/leds# cd beaglebone:green:usr0
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# ls -al
total 0
drwxr-xr-x 3 root root    0 Jan  1 00:00 .
drwxr-xr-x 6 root root    0 Jan  1 00:00 ..
-rw-r--r-- 1 root root 4096 Jan  1 02:08 brightness
lrwxrwxrwx 1 root root    0 Jan  1 02:08 device -> ../../../gpio-leds.7
-r--r--r-- 1 root root 4096 Jan  1 02:08 max_brightness
drwxr-xr-x 2 root root    0 Jan  1 02:08 power
lrwxrwxrwx 1 root root    0 Jan  1 02:08 subsystem -> ../../../../../class/leds
-rw-r--r-- 1 root root 4096 Jan  1 02:08 trigger
-rw-r--r-- 1 root root 4096 Jan  1 00:00 uevent
root@beaglebone:/sys/class/leds/beaglebone:green:usr0#

Here you see various different sub-directories that give us further information and access to settings. We can find out the current status of the LED by:

1
2
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# more trigger
none nand-disk mmc0 mmc1 timer oneshot [heartbeat] backlight gpio cpu0 default-on transient

You can see that the trigger is set up as a “heartbeat”

We can turn this off by:

1
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo none > trigger

And you will see (hopefully) that the LED stops flashing. So, let’s try a few different options:

Turning on the LED

Now that the trigger is off, we can turn on the LED using the brightness setting:

1
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo 1 > brightness

The first LED should go on.

Turning off the LED

We can turn off the LED using the brightness setting:

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

The first LED should go off.

 Making the LED Flash

We can use the timer trigger to make the LED flash, so do the following:

1
2
3
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo timer > trigger
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo 50 > delay_on
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo 50 > delay_off

You have to set up the timer before writing to delay_on and delay_off. So the first line sets up a timer and on the second and third lines we set up the time for the first LED to be on and off (in milliseconds). So this will cause the first LED to flash 10 times per second (i.e. time on + time off =  100ms, so 10 flashes per second).

Setting it Back to a Heartbeat

We can set it back to the way it was before we started:

1
root@beaglebone:/sys/class/leds/beaglebone:green:usr0# echo heartbeat > trigger

It should go back to the heartbeat trigger.

 

C++ Implementation

Now that we have this working at the command line it would be useful if we could write programs that interface to the LEDs in a similar fashion. My C++ implementation code is below. It uses the C++ fstream and iostream libraries to read and write data to the input/outputs using sysfs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/** Simple On-board LED flashing program - written by Derek Molloy
    for the ee402 module
 
    This program uses USR LED 0 and can be executed in three ways:
         makeLED on
         makeLED off
         makeLED flash  (flash at 100ms intervals - on 50ms/off 50ms)
         makeLED status (get the trigger status)
*/
 
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
 
#define LED0_PATH "/sys/class/leds/beaglebone:green:usr0"
 
void removeTrigger(){
   // remove the trigger from the LED
   std::fstream fs;
   fs.open( LED0_PATH "/trigger", std::fstream::out);
   fs << "none";
   fs.close();
}
 
int main(int argc, char* argv[]){
   if(argc!=2){
    cout << "Usage is makeLED and one of: on, off, flash or status"
<< endl;
    cout << "e.g. makeLED flash" << endl;
   }
 
   string cmd(argv[1]);
   std::fstream fs;
   cout << "Starting the LED flash program" << endl;
   cout << "The LED Path is: " << LED0_PATH << endl;    
 
   // select whether it is on, off or flash
   if(cmd=="on"){
    removeTrigger();
    fs.open (LED0_PATH "/brightness", std::fstream::out);
    fs << "1";
    fs.close();
   }
   else if (cmd=="off"){
    removeTrigger();
    fs.open (LED0_PATH "/brightness", std::fstream::out);
    fs << "0";
    fs.close();
   }
   else if (cmd=="flash"){
    fs.open (LED0_PATH "/trigger", std::fstream::out);
    fs << "timer";
    fs.close();
    fs.open (LED0_PATH "/delay_on", std::fstream::out);
    fs << "50";
    fs.close();
    fs.open (LED0_PATH "/delay_off", std::fstream::out);
    fs << "50";
    fs.close();
   }
   else if (cmd=="status"){
    // display the current trigger details
    fs.open( LED0_PATH "/trigger", std::fstream::in);
    string line;
    while(getline(fs,line)) cout << line;
    fs.close();      
   }
   else{
    cout << "Invalid command" << endl;
   }
   cout << "Finished the LED flash program" << endl;
   return 0;
}

Effectively, this code carries out the exact same steps as what I did in the first part of this post; however, now it is wrapped up as a command that we can add to our $PATH in order that it can be called from any location. The way you build the code on the Beaglebone Black is as follows:

1
2
3
4
#!/bin/bash
echo "EE402 - Building the Test LED program on the Beaglebone Black"
g++ makeLED.cpp -o makeLED
echo "Finished"

I have made all of the code available via github, so you can download this by the following steps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@beaglebone:~/temp# git clone git://github.com/derekmolloy/ee402
Cloning into ee402...
remote: Counting objects: 52, done.
remote: Compressing objects: 100% (43/43), done.
remote: Total 52 (delta 19), reused 35 (delta 8)
Receiving objects: 100% (52/52), 33.71 KiB, done.
Resolving deltas: 100% (19/19), done.
root@beaglebone:~/temp# ls
ee402
root@beaglebone:~/temp# cd ee402/
root@beaglebone:~/temp/ee402# ls
LEDcpp  LICENSE  README.md  scripts  testcpp  testjava
root@beaglebone:~/temp/ee402# cd LEDcpp/
root@beaglebone:~/temp/ee402/LEDcpp# ls -al
total 32
drwxr-xr-x 2 root root  4096 Nov 20 23:24 .
drwxr-xr-x 7 root root  4096 Nov 20 23:24 ..
-rwxr-xr-x 1 root root   124 Nov 20 23:24 build
-rwxr-xr-x 1 root root 13955 Nov 20 23:24 makeLED
-rw-r--r-- 1 root root  1834 Nov 20 23:24 makeLED.cpp

Now, build the code and execute it:

1
2
3
4
5
6
7
8
9
10
11
12
root@beaglebone:~/temp/ee402/LEDcpp# ./build
EE402 - Building the Test LED program on the Beaglebone Black
Finished
root@beaglebone:~/temp/ee402/LEDcpp# ./makeLED status
Starting the LED flash program
The LED Path is: /sys/class/leds/beaglebone:green:usr0
none nand-disk mmc0 mmc1 timer oneshot [heartbeat] backlight gpio cpu0 default-on transient Finished the LED flash program
root@beaglebone:~/temp/ee402/LEDcpp# ./makeLED flash
Starting the LED flash program
The LED Path is: /sys/class/leds/beaglebone:green:usr0
Finished the LED flash program
root@beaglebone:~/temp/ee402/LEDcpp#

The way we can interact with GPIOs is not much different than this; however, we have complexities to deal with to do with the Device Tree, and we have to use Device Tree Overlays. See my post: GPIOs on the Beaglebone Black using the Device Tree Overlays on this topic.



These notes are copyright Dr. Derek Molloy, School of Electronic Engineering, Dublin City University, Ireland 2013-present. Please contact him directly before reproducing any of the content in any way.
Comments