EBC Exercise 17 Switching a GPIO to an LED

From eLinux.org
Jump to: navigation, search

thumb‎ Embedded Linux Class by Mark A. Yoder

[1] Most GPIOs are accessed through /sys/class/gpio. The builtin LEDs are accessed through /sys/class/leds. LEDs accessed this way have special powers (the trigger).

This exercise shows how to make an LED attached to on of the GPIO to appear in the /sys/class/leds interface.


First wire an LED with a 220Ω current limiting resistor to P9_14. Test it using the /sys/class/gpio interface. Do this by first seeing which GPIO number corresponds to P9_14.

bone$ gpioinfo
gpiochip1 - 32 lines:
  line   0:   "GPMC_AD0"      "P8_25"   input  active-high [used]
  line   1:   "GPMC_AD1"      "P8_24"   input  active-high [used]
  line  17:    "GPMC_A1"      "P9_23"   input  active-high [used]
  line  18:    "GPMC_A2"      "P9_14"   input  active-high [used]
  line  19:    "GPMC_A3"      "P9_16"   input  active-high [used]

I've left out a bunch of output, but you see the P9_14 is on gpiochip 1 and line 18. You convert this to the GPIO number used in /sys/class/gpio by multipying the chip number by 32 and adding it to the line number. Here we get 1*32+18=50.

So check out GPIO 50.

bone$ cd /sys/class/gpio
bone$ ls
gpio112  gpio13   gpio23  gpio33  gpio4   gpio5   gpio65  gpio71  gpio78  gpio88  unexport
gpio113  gpio14   gpio26  gpio34  gpio44  gpio50  gpio66  gpio72  gpio79  gpio89

If you don't see gpio50 do the following:

bone$ echo 50 > export


bone$ cd /sys/class/gpio/gpio50
bone$ ls
active_low  device  direction  edge  label  power  subsystem  uevent  value
bone$ cat direction

We see it defaults to an input. Switch it to an output.

bone$ echo out > direction

Now turn it on.

bone$ echo 1 > value

The LED should be on. If not, check your wiring.

The device tree

Finding which device tree to edit

We will switch the P9_14 GPIO to an LED by editing the device tree. But which one? Run the following to see.

bone$ cat /proc/device-tree/chosen/base_dtb

Here we see am335x-boneblack-uboot-univ.dtb is being used. The source for this is already on the Bone.

Note: If you want to edit the source using cloud9 use the following trick to make the file visible in your home directory.

bone$ cd  # Change to your home directory
bone$ ln -s / root  # create a symbolic link from root in your home directory to / the root of the filesystem.

Now find the file to edit.

bone$ cd /opt/source   # There are a bunch of source files here
bone$ ls
adafruit-beaglebone-io-python  dtb-4.14-ti  librobotcontrol  py-uio           u-boot_v2020.10-rc2
BBIOConfig                     dtb-4.19-ti  list.txt         rcpy
bb.org-overlays                dtb-5.4-ti   pyctrl           u-boot_v2019.04

The directory we want starts with dtb, but there are three of them. The one you pick depends on which kernel you are running. We are running:

bone$ uname -r

We are running the 4.19 kernel, so cd to that directory.

bone$ cd /opt/source/dtb-4.19-ti

It's a git repo, so be sure it's up to date.

bone$ git pull
Already up to date.

Compiling the device trees

Good. First lets compile all the device trees.

bone$ make
  DTC     src/arm/am335x-chiliboard.dtb
  DTC     src/arm/am335x-boneblack-bbb-exp-c.dtb
  DTC     src/arm/am335x-boneblack-bbbmini.dtb
  DTC     src/arm/am335x-boneblack-uboot-univ.dtb
  DTC     src/arm/am335x-baltos-ir3220.dtb

We see that the one we were looking for compiled.

Finding the source

Now the source is in:

bone$ cd /opt/source/dtb-4.19-ti/src/arm
bone$ ls am335x-boneblack-uboot*
am335x-boneblack-uboot.dtb  am335x-boneblack-uboot-univ.dtb
am335x-boneblack-uboot.dts  am335x-boneblack-uboot-univ.dts

The dts file is the source and the dtb file is the compiled version.

Edit this file with you favorite editor and look for a definition of led.

You won't find any, but you do find:

#include "am33xx.dtsi"
#include "am335x-bone-common.dtsi"
#include "am335x-bone-common-univ.dtsi"
#include "bbb-bone-buses.dtsi"

One of these include files must have the leds defined. Look in each one.

In am335x-bone-common.dtsi you will find:

 	leds { 
		pinctrl-names = "default";
		pinctrl-0 = <&user_leds_s0>; 

		compatible = "gpio-leds";

		led2 {
			label = "beaglebone:green:usr0";
			gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "heartbeat";
			default-state = "off";

		led3 {
			label = "beaglebone:green:usr1";
			gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "mmc0";
			default-state = "off";

		led4 {
			label = "beaglebone:green:usr2";
			gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "cpu0";
			default-state = "off";

		led5 {
			label = "beaglebone:green:usr3";
			gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "mmc1";
			default-state = "off";

This is where the four internal LEDs are defined. Each has a label, the name the appears in /sys/class/leds, gpios which tells which chip and line the LED appears on, default-trigger which tells how to blink and the default-state.

Adding our LED

All we have to do is copy one of these and edit it to do what we want it to. Here's mine:

		led6 {
			label = "red:indicator";
			gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "heartbeat";
			default-state = "off";

How did I know to use gpio1 and 18? See https://www.kernel.org/doc/html/latest/leds/leds-class.html for naming conventions.

Recovering from a miss-edit

You are editing a system file here. What if you really mess it up? Not to worry, it's in a git repo. You can see what's been changed with:

bone$ git status
On branch v4.19.x-ti-overlays
Your branch is up to date with 'origin/v4.19.x-ti-overlays'. 

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   src/arm/am335x-bone-common.dtsi

no changes added to commit (use "git add" and/or "git commit -a")

Good, we've only changed one file. Here's what's been changed:

bone$ git diff src/arm/am335x-bone-common.dtsi
diff --git a/src/arm/am335x-bone-common.dtsi b/src/arm/am335x-bone-common.dtsi
index 8952fe1..59e277f 100644
--- a/src/arm/am335x-bone-common.dtsi
+++ b/src/arm/am335x-bone-common.dtsi
@@ -52,6 +52,13 @@
                        linux,default-trigger = "mmc1";
                        default-state = "off";
+               led6 {
+                       label = "red:indicator";
+                       gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       default-state = "off";
+               };

        vmmcsd_fixed: fixedregulator0 {

The +'s show what's been added.

If you really mess things up you can always start over with:

bone$ git checkout src/arm/am335x-bone-common.dtsi

and you will be back where you started.

Compiling again

Back up two levels to run make and...

bone$ cd /opt/source/dtb-4.19-ti
bone$ make

And nothing happens! make only recompiles the files that have changed. It does this by comparing dates, but it doesn't check the included files. We didn't change am335x-boneblack-uboot-univ.dts, so it didn't compile. Just change the date on am335x-boneblack-uboot-univ.dts and try again. touch sets the date of the file to the current time.

bone$ touch src/arm/am335x-boneblack-uboot-univ.dts
bone$ make
  DTC     src/arm/am335x-boneblack-uboot-univ.dtb

It recompiled, now install.

bone$ sudo make install
# install Device Tree
mkdir -p /boot/dtbs/4.19.94-ti-r50/
cp -v src/arm/*.dtb /boot/dtbs/4.19.94-ti-r50/
'src/arm/am335x-abbbi.dtb' -> '/boot/dtbs/4.19.94-ti-r50/am335x-abbbi.dtb'
'src/arm/am335x-boneblack-roboticscape.dtb' -> '/boot/dtbs/4.19.94-ti-r50/am335x-boneblack-roboticscape.dtb'
'src/arm/am335x-boneblack-uboot-univ.dtb' -> '/boot/dtbs/4.19.94-ti-r50/am335x-boneblack-uboot-univ.dtb'
'src/arm/am335x-boneblack-uboot.dtb' -> '/boot/dtbs/4.19.94-ti-r50/am335x-boneblack-uboot.dtb'


It's now installed, reboot and see what happens.

bone$ sudo reboot

Your P9_14 LED should be flashing a heartbeat.

Checking /sys/class/leds

Check and make sure your LED appears with the others.

bone$ cd /sys/class/leds
bone$ ls
beaglebone:green:usr0  beaglebone:green:usr1  beaglebone:green:usr2  beaglebone:green:usr3  red:indicator

Yup, there is the newest LED on the right end. Check it out:

bone$ cd /sys/class/leds/red:indicator
bone$ ls
brightness  device  invert  max_brightness  power  subsystem  trigger  uevent
bone$ cat trigger 
none rfkill-any rfkill-none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 
mmc1 usb-gadget usb-host timer oneshot disk-activity disk-read disk-write ide-disk mtd nand-disk [heartbeat] backlight gpio cpu cpu0 activity default-on panic netdev

It looks like the other LEDs. Try changing the trigger and see what happens.

  1. Tested on: bone$ cat /etc/dogtag BeagleBoard.org Debian Buster IoT Image 2020-08-25 bone$ uname -a Linux ece434 4.19.94-ti-r50 #1buster SMP PREEMPT Mon Aug 24 23:03:55 UTC 2020 armv7l GNU/Linux

thumb‎ Embedded Linux Class by Mark A. Yoder