Difference between revisions of "EBC Exercise 17 Switching a GPIO to an LED"

From eLinux.org
Jump to: navigation, search
m (Finding which device tree to edit: Simplified discovering which device tree.)
Line 53: Line 53:
=== Finding which device tree to edit ===
=== Finding which device tree to edit ===
We will switch the '''P9_14''' GPIO to an LED by editing the device tree.
We will switch the '''P9_14''' GPIO to an LED by editing the device tree.
But which one?  This happens at boot time, so you need to follow the directions at
But which one?  Run the following to see.
[[EBC_Exercise_21a_Boot_Sequence|Boot_Sequence]] to setup the serial port to
watch the boot sequence. You'll see something like the following if you are on
a BeagleBone Black.
  U-Boot SPL 2019.04-00002-gc9b3922522 (Aug 24 2020 - 16:42:18 -0500)
  bone$ '''cat /proc/device-tree/chosen/base_dtb'''
Trying to boot from MMC1
Loading Environment from EXT4... ** File not found /boot/uboot.env **
** Unable to read "/boot/uboot.env" from mmc0:1 **
debug: [enable_uboot_overlays=1] ...
debug: [enable_uboot_cape_universal=1] ...
debug: [uboot_base_dtb_univ='''am335x-boneblack-uboot-univ.dtb'''] ...
uboot_overlays: [uboot_base_dtb=am335x-boneblack-uboot-univ.dtb] ...
uboot_overlays: Switching too: dtb=am335x-boneblack-uboot-univ.dtb ...
  loading /boot/dtbs/4.19.94-ti-r50/am335x-boneblack-uboot-univ.dtb ...
Here we see '''am335x-boneblack-uboot-univ.dtb''' is being used. The source for this
Here we see '''am335x-boneblack-uboot-univ.dtb''' is being used. The source for this

Latest revision as of 10:09, 21 November 2020

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