Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
BeagleBone: Creative Projects for Hobbyists

You're reading from   BeagleBone: Creative Projects for Hobbyists Build amazing BeagleBone projects and maximize your skills with projects that walk, talk, and fly!

Arrow left icon
Product type Course
Published in Jul 2017
Publisher Packt
ISBN-13 9781788395656
Length 1020 pages
Edition 1st Edition
Languages
Concepts
Arrow right icon
Authors (3):
Arrow left icon
Rodolfo Giometti Rodolfo Giometti
Author Profile Icon Rodolfo Giometti
Rodolfo Giometti
Charles A. Hamilton Charles A. Hamilton
Author Profile Icon Charles A. Hamilton
Charles A. Hamilton
Richard Grimmett Richard Grimmett
Author Profile Icon Richard Grimmett
Richard Grimmett
Arrow right icon
View More author details
Toc

Chapter 5. Basic Programming Recipes with the Linux Kernel

In this chapter, we will cover the following recipes:

  • Kernel application binary interface
  • Installing the latest kernel image
  • Installing and building a custom kernel
  • Interactions with the kernel – sysfs entries and controlling the GPIOs
  • Device Tree and its roots
  • Device Tree / basic build
  • Device Tree / advanced – adding DT overlay to run a custom cape
  • Universal cape overlay
  • Running a script to check DT usage on GPIO pins

Introduction

We will now learn something about the real guts of our platform, the Linux kernel. Of course, understanding all the bits about the kernel is for another very large set of books and discussion. We won't be doing that here!

What we do want to explore is how to update, build, and modify the kernel in ways that will give us tighter control over our hardware and make the development process less opaque. Then, we'll conclude the chapter by working with one of the key differentiators for BeagleBone Black, the Device Tree, which is a clever way to describe the hardware in our system.

The best part is that if you do all the recipes, you'll be forever known as Colonel kernel. Well, lieutenant kernel. All right, maybe private kernel. But it's a start....

Kernel building basics

What is this mysterious kernel thing of which we speak? What does it look like? Where does it live? Well, on one level, it is merely a file. Let's take a peek. Open up a terminal on your BBB and type the following commands:

$ cd /boot
$ ls

The command should deliver this output:

Kernel building basics

There it is: the kernel, the file that begins with the name, vmlinuz. However, the file itself—an executable one—does not really do anything until you load it into memory and have it run. That happens, of course, when you have the right boot sequence established, which should be happening by default on your BBB Debian distro.

When the kernel begins running, it performs several key tasks, such as process management, file management, and I/O management. The latter is what we will mainly look at in this chapter as it is the most clearly recognizable—and relevant—function that the kernel performs for physical computing or while building hardware prototypes. For us, I/O means mostly GPIO pins, peripheral devices such as capes and daughterboards, and other add-ons as this is where most of the action is for this book.

See also

Understanding the boot sequence gives you a deeper understanding of the various processes and events occurring on your BBB and can play a key role in development and debugging. The following provide an excellent background on the boot cycle:

Kernel application binary interface

Now, let's do a quick, simple task with a command to find out which kernel we are running. The command can serve as a first-level "diagnostic" tool when we need to troubleshoot errors or incompatibilities with any software we want to add or compile for our system.

Getting ready

This is a simple setup, so all you need to do is connect your board via USB to your host computer and fire it up. Then, open a terminal window.

How to do it...

The steps to do this are simple:

  1. Firstly, log in as the root user using the following command:
    $ sudo -i
    
  2. Now, run a command that tells us a few important things about the kernel. Let's choose the -a option to show all information about the system, as follows:
    root@beaglebone:~# uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    From this command's output, we discover several items of interest, as follows:

    The kernel version: According to our output, the installed version of the Linux kernel is 3.8.13. There are other later, experimental versions (for example, 3.14.x) that many BeagleBone Black developers are currently using. However, version 3.8 is the current stable install.

    Kernel ABI : Our version is "bone67", a flavor specific to our board and one that provides an optimized environment to run a basic BBB system. The number "67" is the version number and not significant in itself, but it provides context for when we encounter incompatibilities or errors.

How it works…

So, what is the kernel ABI? Basically, it is an interface layer between the kernel and user space applications. One way of understanding it is by comparing it to an API, a familiar concept to any programmer. When you use an API, you can access the features of an external component, a third-party software feature, or an OS. An ABI is kind of similar to a compiled version of an API.

Think about the software that we built and compiled from source in our prior chapter. Once code is compiled at the kernel level, an application accesses the binary data through the ABI. Just like an API, an ABI defines the structures and methods that your compiled application will use to access an external library, for instance. Except with the kernel ABI, it happens at the lower machine-language level.

Getting ready

This is a simple setup, so all you need to do is connect your board via USB to your host computer and fire it up. Then, open a terminal window.

How to do it...

The steps to do this are simple:

  1. Firstly, log in as the root user using the following command:
    $ sudo -i
    
  2. Now, run a command that tells us a few important things about the kernel. Let's choose the -a option to show all information about the system, as follows:
    root@beaglebone:~# uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    From this command's output, we discover several items of interest, as follows:

    The kernel version: According to our output, the installed version of the Linux kernel is 3.8.13. There are other later, experimental versions (for example, 3.14.x) that many BeagleBone Black developers are currently using. However, version 3.8 is the current stable install.

    Kernel ABI : Our version is "bone67", a flavor specific to our board and one that provides an optimized environment to run a basic BBB system. The number "67" is the version number and not significant in itself, but it provides context for when we encounter incompatibilities or errors.

How it works…

So, what is the kernel ABI? Basically, it is an interface layer between the kernel and user space applications. One way of understanding it is by comparing it to an API, a familiar concept to any programmer. When you use an API, you can access the features of an external component, a third-party software feature, or an OS. An ABI is kind of similar to a compiled version of an API.

Think about the software that we built and compiled from source in our prior chapter. Once code is compiled at the kernel level, an application accesses the binary data through the ABI. Just like an API, an ABI defines the structures and methods that your compiled application will use to access an external library, for instance. Except with the kernel ABI, it happens at the lower machine-language level.

How to do it...

The steps to do this are simple:

  1. Firstly, log in as the root user using the following command:
    $ sudo -i
    
  2. Now, run a command that tells us a few important things about the kernel. Let's choose the -a option to show all information about the system, as follows:
    root@beaglebone:~# uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    From this command's output, we discover several items of interest, as follows:

    The kernel version: According to our output, the installed version of the Linux kernel is 3.8.13. There are other later, experimental versions (for example, 3.14.x) that many BeagleBone Black developers are currently using. However, version 3.8 is the current stable install.

    Kernel ABI : Our version is "bone67", a flavor specific to our board and one that provides an optimized environment to run a basic BBB system. The number "67" is the version number and not significant in itself, but it provides context for when we encounter incompatibilities or errors.

How it works…

So, what is the kernel ABI? Basically, it is an interface layer between the kernel and user space applications. One way of understanding it is by comparing it to an API, a familiar concept to any programmer. When you use an API, you can access the features of an external component, a third-party software feature, or an OS. An ABI is kind of similar to a compiled version of an API.

Think about the software that we built and compiled from source in our prior chapter. Once code is compiled at the kernel level, an application accesses the binary data through the ABI. Just like an API, an ABI defines the structures and methods that your compiled application will use to access an external library, for instance. Except with the kernel ABI, it happens at the lower machine-language level.

How it works…

So, what is the kernel ABI? Basically, it is an interface layer between the kernel and user space applications. One way of understanding it is by comparing it to an API, a familiar concept to any programmer. When you use an API, you can access the features of an external component, a third-party software feature, or an OS. An ABI is kind of similar to a compiled version of an API.

Think about the software that we built and compiled from source in our prior chapter. Once code is compiled at the kernel level, an application accesses the binary data through the ABI. Just like an API, an ABI defines the structures and methods that your compiled application will use to access an external library, for instance. Except with the kernel ABI, it happens at the lower machine-language level.

Installing the latest kernel image

All the way back in Chapter 1, Setting Up for the First Time, we used a set of tools that came with our Debian distro. In that case, we used a tool (a bash script) to expand our partition. In this case, we'll use another script from that toolset that runs a routine to update our kernel image. Let's go get it. With developer Robert Nelson's slick scripts (https://eewiki.net/display/linuxonarm/BeagleBone+Black), the process to update or build the kernel on Debian for the BBB has become a snap.

Getting ready

As in our preceding recipe, connect your board via USB to your host computer, boot up, and then open a terminal window.

How to do it...

Let's get started! To do this, perform the following steps:

  1. Firstly, log in as root with the following command:
    # sudo -i
    

    Following this, check the current version of your kernel through the following command:

    # uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    Note

    Write down the version number so that we can refer to it at the end of the recipe.

  2. You then need to go to the scripts directory that comes preloaded with your version of Debian for the BBB. You can do this by typing out the following command:
    $ cd /opt/scripts/tools
    
  3. Run the following git command to update your local files:
    $ git pull
    
  4. You have several options for the type of install you prefer: the stable, testing, or custom release. According to your preference, append the command with one of the following options:
    • For the stable release, use the following command:
      $ ./update_kernel.sh
      
    • For the testing release, the following command will be useful:
      $ ./update_kernel.sh --beta-kernel
      

    Running this script installs a version of the kernel that is still in the test phase. Although technically not a release, the testing versions of the kernel can still be quite stable and robust, albeit with some bugs.

    • For the custom release, run the following command (this has to be on rcn-ee.net):
      $ ./update_kernel.sh --kernel v.0.00-bone00
      

      For the custom option, you can replace the version number with the exact version you want to run. These versions would be available at Robert C. Nelson's site at http://www.rcn-ee.net/deb/.

  5. Reboot with your new kernel image and then check that it shows the newer kernel now installed with the following command:
    debian@beaglebone:~$ uname -a
    Linux beaglebone 3.8.13-bone[xx] #1 SMP [day mo date time UTC year] armv7l GNU/Linux
    

    The (xx) box should now reflect an updated version running.

Getting ready

As in our preceding recipe, connect your board via USB to your host computer, boot up, and then open a terminal window.

How to do it...

Let's get started! To do this, perform the following steps:

  1. Firstly, log in as root with the following command:
    # sudo -i
    

    Following this, check the current version of your kernel through the following command:

    # uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    Note

    Write down the version number so that we can refer to it at the end of the recipe.

  2. You then need to go to the scripts directory that comes preloaded with your version of Debian for the BBB. You can do this by typing out the following command:
    $ cd /opt/scripts/tools
    
  3. Run the following git command to update your local files:
    $ git pull
    
  4. You have several options for the type of install you prefer: the stable, testing, or custom release. According to your preference, append the command with one of the following options:
    • For the stable release, use the following command:
      $ ./update_kernel.sh
      
    • For the testing release, the following command will be useful:
      $ ./update_kernel.sh --beta-kernel
      

    Running this script installs a version of the kernel that is still in the test phase. Although technically not a release, the testing versions of the kernel can still be quite stable and robust, albeit with some bugs.

    • For the custom release, run the following command (this has to be on rcn-ee.net):
      $ ./update_kernel.sh --kernel v.0.00-bone00
      

      For the custom option, you can replace the version number with the exact version you want to run. These versions would be available at Robert C. Nelson's site at http://www.rcn-ee.net/deb/.

  5. Reboot with your new kernel image and then check that it shows the newer kernel now installed with the following command:
    debian@beaglebone:~$ uname -a
    Linux beaglebone 3.8.13-bone[xx] #1 SMP [day mo date time UTC year] armv7l GNU/Linux
    

    The (xx) box should now reflect an updated version running.

How to do it...

Let's get started! To do this, perform the following steps:

  1. Firstly, log in as root with the following command:
    # sudo -i
    

    Following this, check the current version of your kernel through the following command:

    # uname -a
    Linux beaglebone 3.8.13-bone67 #1 SMP Wed Sep 24 01:36:09 UTC 2014 armv7l GNU/Linux
    

    Note

    Write down the version number so that we can refer to it at the end of the recipe.

  2. You then need to go to the scripts directory that comes preloaded with your version of Debian for the BBB. You can do this by typing out the following command:
    $ cd /opt/scripts/tools
    
  3. Run the following git command to update your local files:
    $ git pull
    
  4. You have several options for the type of install you prefer: the stable, testing, or custom release. According to your preference, append the command with one of the following options:
    • For the stable release, use the following command:
      $ ./update_kernel.sh
      
    • For the testing release, the following command will be useful:
      $ ./update_kernel.sh --beta-kernel
      

    Running this script installs a version of the kernel that is still in the test phase. Although technically not a release, the testing versions of the kernel can still be quite stable and robust, albeit with some bugs.

    • For the custom release, run the following command (this has to be on rcn-ee.net):
      $ ./update_kernel.sh --kernel v.0.00-bone00
      

      For the custom option, you can replace the version number with the exact version you want to run. These versions would be available at Robert C. Nelson's site at http://www.rcn-ee.net/deb/.

  5. Reboot with your new kernel image and then check that it shows the newer kernel now installed with the following command:
    debian@beaglebone:~$ uname -a
    Linux beaglebone 3.8.13-bone[xx] #1 SMP [day mo date time UTC year] armv7l GNU/Linux
    

    The (xx) box should now reflect an updated version running.

Installing and building a custom kernel

This recipe will build the kernel and modules from scratch and copy them to a deploy or temporary directory.

Getting ready

Connect and power up your board via USB to your host computer; then, open a terminal window.

How to do it...

To perform this recipe, follow these steps:

  1. First, log in as the root user and then download the kernel file from Robert C. Nelson's git repo:
    $ sudo -i
    # git clone https://github.com/RobertCNelson/bb-kernel.git
    
  2. Navigate to the new directory that git created for you on your BBB with this command:
    # cd bb-kernel/
    
  3. At this point, you have two options for the kernel version you prefer to use: either v3.8.x or the latest experimental v3.14.x. You'll notice that the git command also generates a tmp directory for the build:
    • For the 3.8.x Wheezy branch (this version comes with full cape support) use this command:
      ~/bb-kernel# git checkout origin/am33x-v3.8 -b tmp
      
    • For the v3.14.x Jessie branch (which comes with better USB and Ethernet support but without full cape support) use the following command:
      ~/bb-kernel# git checkout origin/am33x-v3.14 -b tmp
      
  4. Now, we will build the kernel with this command:
    ~/bb-kernel# ./build_kernel.sh
    

    Be sure to take note of the space between # and . in the command. Otherwise, your command will not be executed. Also, beware that this build cycle may take a while, so be patient for it to finish.

    Note

    Since Linux, BeagleBone Black, and the open source community at large move pretty fast, what we deem experimental in this book may be nearly mainstream within a short period of time. For example, note that the current move toward the new Debian 8 Linux kernel "Jessie" (as opposed to the current version 7 nicknamed "Wheezy") is well underway. In 2015, it will likely have moved from the Debian/testing repos to the stable repos and is expected to be part of the BBB shipping firmware.

Getting ready

Connect and power up your board via USB to your host computer; then, open a terminal window.

How to do it...

To perform this recipe, follow these steps:

  1. First, log in as the root user and then download the kernel file from Robert C. Nelson's git repo:
    $ sudo -i
    # git clone https://github.com/RobertCNelson/bb-kernel.git
    
  2. Navigate to the new directory that git created for you on your BBB with this command:
    # cd bb-kernel/
    
  3. At this point, you have two options for the kernel version you prefer to use: either v3.8.x or the latest experimental v3.14.x. You'll notice that the git command also generates a tmp directory for the build:
    • For the 3.8.x Wheezy branch (this version comes with full cape support) use this command:
      ~/bb-kernel# git checkout origin/am33x-v3.8 -b tmp
      
    • For the v3.14.x Jessie branch (which comes with better USB and Ethernet support but without full cape support) use the following command:
      ~/bb-kernel# git checkout origin/am33x-v3.14 -b tmp
      
  4. Now, we will build the kernel with this command:
    ~/bb-kernel# ./build_kernel.sh
    

    Be sure to take note of the space between # and . in the command. Otherwise, your command will not be executed. Also, beware that this build cycle may take a while, so be patient for it to finish.

    Note

    Since Linux, BeagleBone Black, and the open source community at large move pretty fast, what we deem experimental in this book may be nearly mainstream within a short period of time. For example, note that the current move toward the new Debian 8 Linux kernel "Jessie" (as opposed to the current version 7 nicknamed "Wheezy") is well underway. In 2015, it will likely have moved from the Debian/testing repos to the stable repos and is expected to be part of the BBB shipping firmware.

How to do it...

To perform this recipe, follow these steps:

  1. First, log in as the root user and then download the kernel file from Robert C. Nelson's git repo:
    $ sudo -i
    # git clone https://github.com/RobertCNelson/bb-kernel.git
    
  2. Navigate to the new directory that git created for you on your BBB with this command:
    # cd bb-kernel/
    
  3. At this point, you have two options for the kernel version you prefer to use: either v3.8.x or the latest experimental v3.14.x. You'll notice that the git command also generates a tmp directory for the build:
    • For the 3.8.x Wheezy branch (this version comes with full cape support) use this command:
      ~/bb-kernel# git checkout origin/am33x-v3.8 -b tmp
      
    • For the v3.14.x Jessie branch (which comes with better USB and Ethernet support but without full cape support) use the following command:
      ~/bb-kernel# git checkout origin/am33x-v3.14 -b tmp
      
  4. Now, we will build the kernel with this command:
    ~/bb-kernel# ./build_kernel.sh
    

    Be sure to take note of the space between # and . in the command. Otherwise, your command will not be executed. Also, beware that this build cycle may take a while, so be patient for it to finish.

    Note

    Since Linux, BeagleBone Black, and the open source community at large move pretty fast, what we deem experimental in this book may be nearly mainstream within a short period of time. For example, note that the current move toward the new Debian 8 Linux kernel "Jessie" (as opposed to the current version 7 nicknamed "Wheezy") is well underway. In 2015, it will likely have moved from the Debian/testing repos to the stable repos and is expected to be part of the BBB shipping firmware.

Interactions with the kernel – sysfs entries and controlling the GPIOs

When first starting out with physical computing and a Linux board, such as the BBB in particular, it is less daunting to use preexisting libraries along with familiar programming tools. This is why we used tools such as Python libraries and BoneScript to gain access to BeagleBone Black's GPIO pins, methods that abstract the kernel layer from the user space layer.

However, it is useful to understand the nature of this abstraction a bit better, particularly when it comes to the GPIO pins. The Linux kernel uses a virtual file system interface—or sysfs—to read and write to the pins. Sysfs easily and effectively exposes drivers for the hardware—buttons, LEDs, sensors, add-ons, and so on. So, you can control them. Manipulating this system gives us insight into how the kernel and hardware can interoperate. In this section, we'll look at how to activate the sysfs interface.

To reiterate, instead of programming with a userland library, this time we want a more direct understanding of what's happening with the platform. So, we will control some pins using a code that transparently accesses the Linux kernel. To do this, it means blinky LED time; except that this time, we will map a pin directly into the filesystem.

Note

We've referenced it before, but you can never be reminded too many times of the value of a good GPIO reference diagram. Here it is again: http://elinux.org/Beagleboard:Cape_Expansion_Headers.

Getting ready

Access to the various pins in the headers on the left- and right-hand sides of the BBB is done through the Linux kernel using its GPIO interfaces. To demonstrate how to give this a spin, we will attach an LED to designated GPIO and GND pins directly on the board's header.

The following are needed:

  • A BBB powered via USB.
  • LED—a cheap LED of the ilk we used in the prior chapters.
  • Resistor—anywhere from 700 (700Ω) to 1k is fine. We will use a 700Ω here (the violet/black/brown/gold bands).
  • Two jumper wires that are easy to connect to the breadboard.
  • A breadboard.

How to do it...

Now that you're ready, let's begin as follows:

  1. Ensure that your BBB is powered down.
  2. Now, wire up your LED according to the diagram following these instructions:
    • Two jumper wires run from P8_2 (GND) and P8_14 on the P8 header of the BBB onto the breadboard.
    • Insert one end of the resistor (direction does not matter) into the slot corresponding to the P8_14 jumper wire and the other end a few slots above.
    • Line up the LED's anode (positive/longer) end into the breadboard slot at the upper end of the resistor, while the cathode (shorter/ground) end goes into the slot lined up with the ground wire.
    How to do it...
  3. You then need to power the BBB back up, logging in as the root user with this command:
    $ sudo -i
    
  4. Navigate to the gpio directory using the following command:
    # cd /sys/class/gpio
    
  5. While doing this, take stock of the directory with ls -l so that you can compare what you see now with what will occur after the next step. We will add the -l option to view the output in a list format, as follows:
    # ls -l
    
    --w------- 1 root root 4096 Oct 21 10:26 export
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Oct 21 10:32 unexport
    
  6. Once this is done, send an echo command as follows:
    # echo 26 > /sys/class/gpio/export
    
  7. Now, take a look at the directory to see how it has changed:
    # ls  -l
    
    total 0
    --w------- 1 root root 4096 Apr 23 16:24 export
    lrwxrwxrwx 1 root root    0 Apr 23 16:24 gpio26 -> ../../devices/virtual/gpio/gpio26
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Dec 31  1999 unexport
    

    This echo command has created a virtual directory, which now allows you to directly interact with the Linux kernel from user space. The kernel's virtual file system (VFS) is an abstraction of a filesystem and gives you a way to use standard functions for manipulating anything that could be a file on your system. You should also note that pin 26 on which we just ran echo corresponds to pin P8_14 that we wired up on the BBB.

  8. Go to the new directory created from the echo command and take a look inside using the following command:
    # cd gpio26
    # ls
    

    The output shows the options now available to control the pin as follows:

    active_low  direction  edge  power  subsystem  uevent  value
    
  9. Determine the current GPIO value. You should see its initial value as 0 or off, as follows:
    # cat value
    0
    
  10. Now, let's light her up by sending the following commands:
    # echo out > direction
    # echo 1 > value
    

    Voila! You should get a sexy, glowing red thing on your BBB.

  11. Repeat the same command but change the value back to 0, which should turn the LED back off, with this command:
    # echo 0 > value
    
  12. A variation on this is to use another one of the VFS options; in this case, this will be the high/low direction:

    This turns the LED on:

    # echo high > direction
    

    And then, it turns off:

    # echo low > direction.
    
  13. To finish up, it is considered good practice to clean up your pin usage before moving on to some other task. Use the following command lines for this:
    # cd /sys/class/gpio
    # echo 26 > unexport
    

    Note that the exported gpio26 has now evaporated:

    # ls
    # export  gpiochip0  gpiochip32  gpiochip64  gpiochip96  unexport
    

You may think that this exercise is just another blinking LED yawn. But really, we did something quite different this time; we reached directly into the kernel from the user space, added a virtual directory to enable control over a pin, and then controlled this pin via the command line. Seeing it work here at a deeper level will bear fruit as we advance toward fancier recipes in later chapters.

There's more…

For more information, refer to the following sources:

Pin states

Understanding pin states can be quite challenging. According to your use case, not only can they be set as input or output pins, but they can also be set as pull-up, pull-down, or floating. For more discussion and background on configuring your pins for these purposes, review Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, where we discussed GPIO pins.

Other tutorials

For a couple of interesting sysfs methods to turn off the USR LED heartbeat pattern, which many find annoying, follow along with one of these tutorials:

Getting ready

Access to the various pins in the headers on the left- and right-hand sides of the BBB is done through the Linux kernel using its GPIO interfaces. To demonstrate how to give this a spin, we will attach an LED to designated GPIO and GND pins directly on the board's header.

The following are needed:

  • A BBB powered via USB.
  • LED—a cheap LED of the ilk we used in the prior chapters.
  • Resistor—anywhere from 700 (700Ω) to 1k is fine. We will use a 700Ω here (the violet/black/brown/gold bands).
  • Two jumper wires that are easy to connect to the breadboard.
  • A breadboard.

How to do it...

Now that you're ready, let's begin as follows:

  1. Ensure that your BBB is powered down.
  2. Now, wire up your LED according to the diagram following these instructions:
    • Two jumper wires run from P8_2 (GND) and P8_14 on the P8 header of the BBB onto the breadboard.
    • Insert one end of the resistor (direction does not matter) into the slot corresponding to the P8_14 jumper wire and the other end a few slots above.
    • Line up the LED's anode (positive/longer) end into the breadboard slot at the upper end of the resistor, while the cathode (shorter/ground) end goes into the slot lined up with the ground wire.
    How to do it...
  3. You then need to power the BBB back up, logging in as the root user with this command:
    $ sudo -i
    
  4. Navigate to the gpio directory using the following command:
    # cd /sys/class/gpio
    
  5. While doing this, take stock of the directory with ls -l so that you can compare what you see now with what will occur after the next step. We will add the -l option to view the output in a list format, as follows:
    # ls -l
    
    --w------- 1 root root 4096 Oct 21 10:26 export
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Oct 21 10:32 unexport
    
  6. Once this is done, send an echo command as follows:
    # echo 26 > /sys/class/gpio/export
    
  7. Now, take a look at the directory to see how it has changed:
    # ls  -l
    
    total 0
    --w------- 1 root root 4096 Apr 23 16:24 export
    lrwxrwxrwx 1 root root    0 Apr 23 16:24 gpio26 -> ../../devices/virtual/gpio/gpio26
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Dec 31  1999 unexport
    

    This echo command has created a virtual directory, which now allows you to directly interact with the Linux kernel from user space. The kernel's virtual file system (VFS) is an abstraction of a filesystem and gives you a way to use standard functions for manipulating anything that could be a file on your system. You should also note that pin 26 on which we just ran echo corresponds to pin P8_14 that we wired up on the BBB.

  8. Go to the new directory created from the echo command and take a look inside using the following command:
    # cd gpio26
    # ls
    

    The output shows the options now available to control the pin as follows:

    active_low  direction  edge  power  subsystem  uevent  value
    
  9. Determine the current GPIO value. You should see its initial value as 0 or off, as follows:
    # cat value
    0
    
  10. Now, let's light her up by sending the following commands:
    # echo out > direction
    # echo 1 > value
    

    Voila! You should get a sexy, glowing red thing on your BBB.

  11. Repeat the same command but change the value back to 0, which should turn the LED back off, with this command:
    # echo 0 > value
    
  12. A variation on this is to use another one of the VFS options; in this case, this will be the high/low direction:

    This turns the LED on:

    # echo high > direction
    

    And then, it turns off:

    # echo low > direction.
    
  13. To finish up, it is considered good practice to clean up your pin usage before moving on to some other task. Use the following command lines for this:
    # cd /sys/class/gpio
    # echo 26 > unexport
    

    Note that the exported gpio26 has now evaporated:

    # ls
    # export  gpiochip0  gpiochip32  gpiochip64  gpiochip96  unexport
    

You may think that this exercise is just another blinking LED yawn. But really, we did something quite different this time; we reached directly into the kernel from the user space, added a virtual directory to enable control over a pin, and then controlled this pin via the command line. Seeing it work here at a deeper level will bear fruit as we advance toward fancier recipes in later chapters.

There's more…

For more information, refer to the following sources:

Pin states

Understanding pin states can be quite challenging. According to your use case, not only can they be set as input or output pins, but they can also be set as pull-up, pull-down, or floating. For more discussion and background on configuring your pins for these purposes, review Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, where we discussed GPIO pins.

Other tutorials

For a couple of interesting sysfs methods to turn off the USR LED heartbeat pattern, which many find annoying, follow along with one of these tutorials:

How to do it...

Now that you're ready, let's begin as follows:

  1. Ensure that your BBB is powered down.
  2. Now, wire up your LED according to the diagram following these instructions:
    • Two jumper wires run from P8_2 (GND) and P8_14 on the P8 header of the BBB onto the breadboard.
    • Insert one end of the resistor (direction does not matter) into the slot corresponding to the P8_14 jumper wire and the other end a few slots above.
    • Line up the LED's anode (positive/longer) end into the breadboard slot at the upper end of the resistor, while the cathode (shorter/ground) end goes into the slot lined up with the ground wire.
    How to do it...
  3. You then need to power the BBB back up, logging in as the root user with this command:
    $ sudo -i
    
  4. Navigate to the gpio directory using the following command:
    # cd /sys/class/gpio
    
  5. While doing this, take stock of the directory with ls -l so that you can compare what you see now with what will occur after the next step. We will add the -l option to view the output in a list format, as follows:
    # ls -l
    
    --w------- 1 root root 4096 Oct 21 10:26 export
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Oct 21 10:32 unexport
    
  6. Once this is done, send an echo command as follows:
    # echo 26 > /sys/class/gpio/export
    
  7. Now, take a look at the directory to see how it has changed:
    # ls  -l
    
    total 0
    --w------- 1 root root 4096 Apr 23 16:24 export
    lrwxrwxrwx 1 root root    0 Apr 23 16:24 gpio26 -> ../../devices/virtual/gpio/gpio26
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip32 -> ../../devices/virtual/gpio/gpiochip32
    
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip64 -> ../../devices/virtual/gpio/gpiochip64
    lrwxrwxrwx 1 root root    0 Dec 31  1999 gpiochip96 -> ../../devices/virtual/gpio/gpiochip96
    --w------- 1 root root 4096 Dec 31  1999 unexport
    

    This echo command has created a virtual directory, which now allows you to directly interact with the Linux kernel from user space. The kernel's virtual file system (VFS) is an abstraction of a filesystem and gives you a way to use standard functions for manipulating anything that could be a file on your system. You should also note that pin 26 on which we just ran echo corresponds to pin P8_14 that we wired up on the BBB.

  8. Go to the new directory created from the echo command and take a look inside using the following command:
    # cd gpio26
    # ls
    

    The output shows the options now available to control the pin as follows:

    active_low  direction  edge  power  subsystem  uevent  value
    
  9. Determine the current GPIO value. You should see its initial value as 0 or off, as follows:
    # cat value
    0
    
  10. Now, let's light her up by sending the following commands:
    # echo out > direction
    # echo 1 > value
    

    Voila! You should get a sexy, glowing red thing on your BBB.

  11. Repeat the same command but change the value back to 0, which should turn the LED back off, with this command:
    # echo 0 > value
    
  12. A variation on this is to use another one of the VFS options; in this case, this will be the high/low direction:

    This turns the LED on:

    # echo high > direction
    

    And then, it turns off:

    # echo low > direction.
    
  13. To finish up, it is considered good practice to clean up your pin usage before moving on to some other task. Use the following command lines for this:
    # cd /sys/class/gpio
    # echo 26 > unexport
    

    Note that the exported gpio26 has now evaporated:

    # ls
    # export  gpiochip0  gpiochip32  gpiochip64  gpiochip96  unexport
    

You may think that this exercise is just another blinking LED yawn. But really, we did something quite different this time; we reached directly into the kernel from the user space, added a virtual directory to enable control over a pin, and then controlled this pin via the command line. Seeing it work here at a deeper level will bear fruit as we advance toward fancier recipes in later chapters.

There's more…

For more information, refer to the following sources:

Pin states

Understanding pin states can be quite challenging. According to your use case, not only can they be set as input or output pins, but they can also be set as pull-up, pull-down, or floating. For more discussion and background on configuring your pins for these purposes, review Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, where we discussed GPIO pins.

Other tutorials

For a couple of interesting sysfs methods to turn off the USR LED heartbeat pattern, which many find annoying, follow along with one of these tutorials:

There's more…

For more information, refer to the following sources:

Pin states

Understanding pin states can be quite challenging. According to your use case, not only can they be set as input or output pins, but they can also be set as pull-up, pull-down, or floating. For more discussion and background on configuring your pins for these purposes, review Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, where we discussed GPIO pins.

Other tutorials

For a couple of interesting sysfs methods to turn off the USR LED heartbeat pattern, which many find annoying, follow along with one of these tutorials:

Device Tree and its roots

Linus Torvalds was sad and mad. ARM was making Linus sad and mad. There were too many cooks, too many ingredients, too many new hardware variations in the world of ARM devices. The architecture had become so popular in the embedded computing world that a thicket of third-party devices were being cooked up to work with ARM. Custom hardware drivers and custom kernels were everywhere. This was making the Linux kernel playground increasingly chaotic.

So, Linus roared: go back to the kitchen, cooks, and make a better recipe! So, they did. Or, so the story goes. Thus was born Device Tree....

For beginners, Device Tree can be a bit difficult to wrap one's head around. However, in order to use BeagleBone Black in more interesting projects, an understanding is often critical. Basically, Device Tree is a data structure to describe the hardware that you add on to your board. With Device Tree, the details of a device are available to the board without needing to be hardcoded into the kernel. Prior to its existence, the kernel image—the single binary (vmlinuz) that we looked at earlier in the chapter—contained any description needed for the hardware. Beginning with version 3.8 of the Linux kernel for ARM, however, another binary was loaded at boot along with the kernel, Device Tree Blob (DTB).

BeagleBone Black—with its 3.8 kernel (the shipping version, at least)—is one of the first ARM devices to incorporate the new order of things with Device Tree (DT). Its benefits for the BBB are many:

  • Upstream dev: This provides us with the ability to receive and contribute to all the benefits of upstream kernel development.
  • Kernel build simplification: This avoids the hassle of maintaining a custom kernel.
  • Cape development: Developers of cape expansion boards enjoy a standardized logic in the kernel. This greatly simplifies life for the cape maker and end user as recompiling the kernel to make the cape function is rarely a requirement.

To reiterate, Device Tree is a binary that describes the system hardware and loads at boot time. Its "tree" nomenclature refers to the fact that it is written in a hierarchical node or tree data structure. The nodes describe the physical device in the system.

The Device Tree overlay

Device Tree is what is used by the kernel during bootup and is common to all modern ARM devices. On BeagleBone Black and its earlier cousins, Device Tree also comes accompanied with a kind of "patch" or overlay. Applied at runtime, Device Tree overlay helps reconfigure hardware resources on the board, such as capes, GPIO pins, LCDs, and so on, and is handled by bone-capemgr (the cape manager).

Although we will do a recipe on the Device Tree overlay (dtbo) in a later section, it might be helpful to browse the following directory to take a look at many of the dtbo files that come with the firmware:

# cd /lib/firmware
# ls -l

The sample output looks like this:

-rw-r--r-- 1 root root   1056 Apr 23 16:57 BB-ADC-00A0.dtbo
-rw-r--r-- 1 root root   2885 Apr 23 16:57 BB-BONE-AUDI-01-00A0.dtbo
-rw-r--r-- 1 root root   2288 May 18  2014 BB-BONE-AUDI-02-00A0.dtbo
-rw-r--r-- 1 root root   2583 May 18  2014 BB-BONE-AUDI-02-00A0.dts
-rw-r--r-- 1 root root   4273 Apr 23 16:57 BB-BONE-BACON-00A0.dtbo
-rw-r--r-- 1 root root   3259 Apr 23 16:57 BB-BONE-BACONE-00A0.dtbo
-rw-r--r-- 1 root root   4536 Apr 23 16:57 BB-BONE-BACONE2-00A0.dtbo
-rw-r--r-- 1 root root   3592 Apr 23 16:57 BB-BONE-CAM-VVDN-00A0.dtbo

There's more…

Here are a few other key things to keep in mind about Device Tree and the BBB:

  • Many embedded architectures have a wide variety of nondiscoverable hardware, daughterboards, add-ons, and so on
  • Depending on the architecture, this hardware is described using either C-code directly within the kernel or a special hardware description language in Device Tree
  • Other architectures besides the BBB's ARM also use Device Tree, including PowerPC, OpenRISC, ARC, and Microblaze
  • A DTS is compiled into a binary Device Tree Blob (DTB) data structure and passed at boot time to the kernel
  • The bootloader must load both the kernel image and Device Tree Blob in memory before starting the kernel

There's more…

Here are a few other key things to keep in mind about Device Tree and the BBB:

  • Many embedded architectures have a wide variety of nondiscoverable hardware, daughterboards, add-ons, and so on
  • Depending on the architecture, this hardware is described using either C-code directly within the kernel or a special hardware description language in Device Tree
  • Other architectures besides the BBB's ARM also use Device Tree, including PowerPC, OpenRISC, ARC, and Microblaze
  • A DTS is compiled into a binary Device Tree Blob (DTB) data structure and passed at boot time to the kernel
  • The bootloader must load both the kernel image and Device Tree Blob in memory before starting the kernel

Device Tree / basic build

On the BBB, there are three essential steps to create and run a Device Tree file:

  1. Create a source file (dts).
  2. Compile it and make a binary (dtb)—also known as blob—of the file.
  3. Ensure that the kernel knows where to find the new blob.

Let's start with a simple recipe, one that turns off one of the onboard LEDs: specifically, USR0, which is the LED that blinks with the "heartbeat" pattern. There are simpler ways to do this, as we did the same thing with BoneScript in Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python. However, it remains a useful introductory recipe to understand Device Tree's interaction with the kernel.

Getting ready

For the next recipe, simply power up your board via the USB port. Internet connectivity is not required.

How to do it...

You need to perform the following steps:

  1. Log in as root with this command:
    $ sudo -i
    #
    
  2. Grab the file that we need for this recipe. Going forward in the book, we will more commonly have you use our GitHub repository to get the code instead of downloading a file directly as we did in earlier chapters. Use this command:
    # git clone https://github.com/HudsonWerks/device-tree.git
    
  3. Browse the downloaded folder and open up the following file:
    # cd device-tree
    # nano bspm_USR0_10-00A0.dts
    

    Take a look at the code visible in the nano window. The intention of this step is for you to review the code structure before we actually move it to its appropriate directory:

    /*
     * This is a (mostly) template-generated file from BoneScript, modified from Kilobaser.com's Device-Tree Overlay Generator
     */
    
    /dts-v1/;
    /plugin/;
    
    /{
        compatible = "ti,beaglebone", "ti,beaglebone-black";
    
        /* identification */
        part_number = "BS_PINMODE_USR0_0x0";
    
        /* state the resources used */
        exclusive-use =
            "USR0",
            "gpmc_a5";
    
        /* the LED is set to pulldown or off */
        fragment@0 {
            target = <&am33xx_pinmux>;
            __overlay__ {
                bs_pinmode_USR0_0x0: pinmux_bs_pinmode_USR0_0x0 {
                    pinctrl-single,pins = <0x054 0x0>;
                };
            };
        };
    
        fragment@1 {
            target = <&ocp>;
            __overlay__ {
                bs_pinmode_USR0_0x0_pinmux {
                    compatible = "bone-pinmux-helper";
                    status = "okay";
                    pinctrl-names = "default";
                    pinctrl-0 = <&bs_pinmode_USR0_0x0>;
                };
            };
        };
    }
    
  4. Now, close the window by pressing CTRL + x, then type N (for no), and run the following to move the file to its correct directory:
    # mv bspm_USR0_10-00A0.dts /lib/firmware/
    
  5. Compile the file using this command, which should finish within seconds:
    # dtc -O dtb -o /lib/firmware/bspm_USR0_10-00A0.dtbo -b 0 -@ /lib/firmware/bspm_USR0_10-00A0.dts
    

    The command can basically be broken down in the following fashion:

    dtc [options] <input file>
    

    -O: This capital "O" (not zero) is the output flag that is followed by the type of output desired, which is a dtb file or Device Tree Blob (also known as binary) in this case

    -b: This means that you want the file (blob) to be loaded at boot time

    0: This "zero" shows the physical boot ID, which is 0

    -@: This ampersand means that the compiler will generate a symbol node, which makes it possible to dynamically load the Device Tree

    <file name/source file>: The command ends with the source file target

  6. Assuming you received no error message, confirm that the compile did what you expected and built the bspm_USR0_10-00A0.dtbo file using the following command:
    # ls
    
  7. Next, we want to enable the overlay file that we just created with the following command:
    # echo bspm_USR0_10 > /sys/devices/bone_capemgr.*/slots
    

    You will now see the heartbeat-flashing USR0 LED turn on immediately. Hallelujah! That darned blink is annoying, isn't it?

    Note

    Although at the time of writing this book the cape manager is at version 9, we use the wildcard option (*) to ensure that later versions of bone_capemgr will still respond to this command.

  8. We should now look at what just happened by doing the following:
    # dmesg | tail -10
    

    Your screen output should look similar to this:

     [   33.848704] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
    [  153.829529] bone-capemgr bone_capemgr.9: part_number 'bspm_USR0_10', version 'N/A'
    [  153.829601] bone-capemgr bone_capemgr.9: slot #7: generic override
    [  153.829617] bone-capemgr bone_capemgr.9: bone: Using override eeprom data at slot 7
    [  153.829633] bone-capemgr bone_capemgr.9: slot #7: 'Override Board Name,00A0,Override Manuf,bspm_USR0_10'
    [  153.829723] bone-capemgr bone_capemgr.9: slot #7: Requesting part number/version based 'bspm_USR0_10-00A0.dtbo
    [  153.829738] bone-capemgr bone_capemgr.9: slot #7: Requesting firmware 'bspm_USR0_10-00A0.dtbo' for board-name 'Override Board Name', version '00A0'
    [  153.834371] bone-capemgr bone_capemgr.9: slot #7: dtbo 'bspm_USR0_10-00A0.dtbo' loaded; converting to live tree
    [  153.834620] bone-capemgr bone_capemgr.9: slot #7: #2 overlays
    [  153.835294] bone-capemgr bone_capemgr.9: slot #7: Applied #2 overlays.
    

    When we run dmesg, it tells us more about the sequence of events, including whether the previous commands were successful. The -10 option outputs the last ten messages from the kernel. You can make the number higher or lower according to how many messages you want stdout to display.

  9. Further forensics are useful for a greater insight into the process, so navigate to the following designated directory and run the following:
    # cd /sys/devices/bone_capemgr.*
    # cat slots
    0: 54:PF---
    1: 55:PF---
    2: 56:PF---
    3: 57:PF---
    4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
    5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
    7: ff:P-O-L Override Board Name,00A0,Override Manuf,bspm_USR0_10
    

    The preceding output tells us something important: that the Device Tree blob that we just built is recognized by the kernel and slotted into position.

Beautiful kernel magic.

Getting ready

For the next recipe, simply power up your board via the USB port. Internet connectivity is not required.

How to do it...

You need to perform the following steps:

  1. Log in as root with this command:
    $ sudo -i
    #
    
  2. Grab the file that we need for this recipe. Going forward in the book, we will more commonly have you use our GitHub repository to get the code instead of downloading a file directly as we did in earlier chapters. Use this command:
    # git clone https://github.com/HudsonWerks/device-tree.git
    
  3. Browse the downloaded folder and open up the following file:
    # cd device-tree
    # nano bspm_USR0_10-00A0.dts
    

    Take a look at the code visible in the nano window. The intention of this step is for you to review the code structure before we actually move it to its appropriate directory:

    /*
     * This is a (mostly) template-generated file from BoneScript, modified from Kilobaser.com's Device-Tree Overlay Generator
     */
    
    /dts-v1/;
    /plugin/;
    
    /{
        compatible = "ti,beaglebone", "ti,beaglebone-black";
    
        /* identification */
        part_number = "BS_PINMODE_USR0_0x0";
    
        /* state the resources used */
        exclusive-use =
            "USR0",
            "gpmc_a5";
    
        /* the LED is set to pulldown or off */
        fragment@0 {
            target = <&am33xx_pinmux>;
            __overlay__ {
                bs_pinmode_USR0_0x0: pinmux_bs_pinmode_USR0_0x0 {
                    pinctrl-single,pins = <0x054 0x0>;
                };
            };
        };
    
        fragment@1 {
            target = <&ocp>;
            __overlay__ {
                bs_pinmode_USR0_0x0_pinmux {
                    compatible = "bone-pinmux-helper";
                    status = "okay";
                    pinctrl-names = "default";
                    pinctrl-0 = <&bs_pinmode_USR0_0x0>;
                };
            };
        };
    }
    
  4. Now, close the window by pressing CTRL + x, then type N (for no), and run the following to move the file to its correct directory:
    # mv bspm_USR0_10-00A0.dts /lib/firmware/
    
  5. Compile the file using this command, which should finish within seconds:
    # dtc -O dtb -o /lib/firmware/bspm_USR0_10-00A0.dtbo -b 0 -@ /lib/firmware/bspm_USR0_10-00A0.dts
    

    The command can basically be broken down in the following fashion:

    dtc [options] <input file>
    

    -O: This capital "O" (not zero) is the output flag that is followed by the type of output desired, which is a dtb file or Device Tree Blob (also known as binary) in this case

    -b: This means that you want the file (blob) to be loaded at boot time

    0: This "zero" shows the physical boot ID, which is 0

    -@: This ampersand means that the compiler will generate a symbol node, which makes it possible to dynamically load the Device Tree

    <file name/source file>: The command ends with the source file target

  6. Assuming you received no error message, confirm that the compile did what you expected and built the bspm_USR0_10-00A0.dtbo file using the following command:
    # ls
    
  7. Next, we want to enable the overlay file that we just created with the following command:
    # echo bspm_USR0_10 > /sys/devices/bone_capemgr.*/slots
    

    You will now see the heartbeat-flashing USR0 LED turn on immediately. Hallelujah! That darned blink is annoying, isn't it?

    Note

    Although at the time of writing this book the cape manager is at version 9, we use the wildcard option (*) to ensure that later versions of bone_capemgr will still respond to this command.

  8. We should now look at what just happened by doing the following:
    # dmesg | tail -10
    

    Your screen output should look similar to this:

     [   33.848704] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
    [  153.829529] bone-capemgr bone_capemgr.9: part_number 'bspm_USR0_10', version 'N/A'
    [  153.829601] bone-capemgr bone_capemgr.9: slot #7: generic override
    [  153.829617] bone-capemgr bone_capemgr.9: bone: Using override eeprom data at slot 7
    [  153.829633] bone-capemgr bone_capemgr.9: slot #7: 'Override Board Name,00A0,Override Manuf,bspm_USR0_10'
    [  153.829723] bone-capemgr bone_capemgr.9: slot #7: Requesting part number/version based 'bspm_USR0_10-00A0.dtbo
    [  153.829738] bone-capemgr bone_capemgr.9: slot #7: Requesting firmware 'bspm_USR0_10-00A0.dtbo' for board-name 'Override Board Name', version '00A0'
    [  153.834371] bone-capemgr bone_capemgr.9: slot #7: dtbo 'bspm_USR0_10-00A0.dtbo' loaded; converting to live tree
    [  153.834620] bone-capemgr bone_capemgr.9: slot #7: #2 overlays
    [  153.835294] bone-capemgr bone_capemgr.9: slot #7: Applied #2 overlays.
    

    When we run dmesg, it tells us more about the sequence of events, including whether the previous commands were successful. The -10 option outputs the last ten messages from the kernel. You can make the number higher or lower according to how many messages you want stdout to display.

  9. Further forensics are useful for a greater insight into the process, so navigate to the following designated directory and run the following:
    # cd /sys/devices/bone_capemgr.*
    # cat slots
    0: 54:PF---
    1: 55:PF---
    2: 56:PF---
    3: 57:PF---
    4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
    5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
    7: ff:P-O-L Override Board Name,00A0,Override Manuf,bspm_USR0_10
    

    The preceding output tells us something important: that the Device Tree blob that we just built is recognized by the kernel and slotted into position.

Beautiful kernel magic.

How to do it...

You need to perform the following steps:

  1. Log in as root with this command:
    $ sudo -i
    #
    
  2. Grab the file that we need for this recipe. Going forward in the book, we will more commonly have you use our GitHub repository to get the code instead of downloading a file directly as we did in earlier chapters. Use this command:
    # git clone https://github.com/HudsonWerks/device-tree.git
    
  3. Browse the downloaded folder and open up the following file:
    # cd device-tree
    # nano bspm_USR0_10-00A0.dts
    

    Take a look at the code visible in the nano window. The intention of this step is for you to review the code structure before we actually move it to its appropriate directory:

    /*
     * This is a (mostly) template-generated file from BoneScript, modified from Kilobaser.com's Device-Tree Overlay Generator
     */
    
    /dts-v1/;
    /plugin/;
    
    /{
        compatible = "ti,beaglebone", "ti,beaglebone-black";
    
        /* identification */
        part_number = "BS_PINMODE_USR0_0x0";
    
        /* state the resources used */
        exclusive-use =
            "USR0",
            "gpmc_a5";
    
        /* the LED is set to pulldown or off */
        fragment@0 {
            target = <&am33xx_pinmux>;
            __overlay__ {
                bs_pinmode_USR0_0x0: pinmux_bs_pinmode_USR0_0x0 {
                    pinctrl-single,pins = <0x054 0x0>;
                };
            };
        };
    
        fragment@1 {
            target = <&ocp>;
            __overlay__ {
                bs_pinmode_USR0_0x0_pinmux {
                    compatible = "bone-pinmux-helper";
                    status = "okay";
                    pinctrl-names = "default";
                    pinctrl-0 = <&bs_pinmode_USR0_0x0>;
                };
            };
        };
    }
    
  4. Now, close the window by pressing CTRL + x, then type N (for no), and run the following to move the file to its correct directory:
    # mv bspm_USR0_10-00A0.dts /lib/firmware/
    
  5. Compile the file using this command, which should finish within seconds:
    # dtc -O dtb -o /lib/firmware/bspm_USR0_10-00A0.dtbo -b 0 -@ /lib/firmware/bspm_USR0_10-00A0.dts
    

    The command can basically be broken down in the following fashion:

    dtc [options] <input file>
    

    -O: This capital "O" (not zero) is the output flag that is followed by the type of output desired, which is a dtb file or Device Tree Blob (also known as binary) in this case

    -b: This means that you want the file (blob) to be loaded at boot time

    0: This "zero" shows the physical boot ID, which is 0

    -@: This ampersand means that the compiler will generate a symbol node, which makes it possible to dynamically load the Device Tree

    <file name/source file>: The command ends with the source file target

  6. Assuming you received no error message, confirm that the compile did what you expected and built the bspm_USR0_10-00A0.dtbo file using the following command:
    # ls
    
  7. Next, we want to enable the overlay file that we just created with the following command:
    # echo bspm_USR0_10 > /sys/devices/bone_capemgr.*/slots
    

    You will now see the heartbeat-flashing USR0 LED turn on immediately. Hallelujah! That darned blink is annoying, isn't it?

    Note

    Although at the time of writing this book the cape manager is at version 9, we use the wildcard option (*) to ensure that later versions of bone_capemgr will still respond to this command.

  8. We should now look at what just happened by doing the following:
    # dmesg | tail -10
    

    Your screen output should look similar to this:

     [   33.848704] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
    [  153.829529] bone-capemgr bone_capemgr.9: part_number 'bspm_USR0_10', version 'N/A'
    [  153.829601] bone-capemgr bone_capemgr.9: slot #7: generic override
    [  153.829617] bone-capemgr bone_capemgr.9: bone: Using override eeprom data at slot 7
    [  153.829633] bone-capemgr bone_capemgr.9: slot #7: 'Override Board Name,00A0,Override Manuf,bspm_USR0_10'
    [  153.829723] bone-capemgr bone_capemgr.9: slot #7: Requesting part number/version based 'bspm_USR0_10-00A0.dtbo
    [  153.829738] bone-capemgr bone_capemgr.9: slot #7: Requesting firmware 'bspm_USR0_10-00A0.dtbo' for board-name 'Override Board Name', version '00A0'
    [  153.834371] bone-capemgr bone_capemgr.9: slot #7: dtbo 'bspm_USR0_10-00A0.dtbo' loaded; converting to live tree
    [  153.834620] bone-capemgr bone_capemgr.9: slot #7: #2 overlays
    [  153.835294] bone-capemgr bone_capemgr.9: slot #7: Applied #2 overlays.
    

    When we run dmesg, it tells us more about the sequence of events, including whether the previous commands were successful. The -10 option outputs the last ten messages from the kernel. You can make the number higher or lower according to how many messages you want stdout to display.

  9. Further forensics are useful for a greater insight into the process, so navigate to the following designated directory and run the following:
    # cd /sys/devices/bone_capemgr.*
    # cat slots
    0: 54:PF---
    1: 55:PF---
    2: 56:PF---
    3: 57:PF---
    4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
    5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
    7: ff:P-O-L Override Board Name,00A0,Override Manuf,bspm_USR0_10
    

    The preceding output tells us something important: that the Device Tree blob that we just built is recognized by the kernel and slotted into position.

Beautiful kernel magic.

Device Tree / advanced – adding DT overlay to run a custom cape

BeagleBone Black introduced the idea of Device Tree overlays that provide even more functionality to DT by modifying the tree in user space, typified in our prior example. With DT overlay, there is no need to reboot.

We saw in our earlier section on sysfs usage the directory/extension .capemgr, which refers to cape manager. The BeagleBone kernel uses cape manager as a way to provide dynamic loading and unloading of device tree fragments both at compile time and from user space after the device has booted. We will demonstrate this again here; except this time, we will use DT to enable a custom cape, one which delivers audio I/O functionality to the BBB.

Getting ready

In addition to your usual BBB setup, we will use Audio Cape Rev. B, available from CircuitCo (http://boardzoo.com/index.php/beaglebone-black/bone-audio.html). Attach the cape to your BBB's header stack, following the orientation shown in the following pictures:

Note

If you ran the recipe in the previous chapter to send the IP address of your BBB to your email address, you can run your system remotely and in a headless way.

Getting ready

Be sure to match the header pin rows (P8 and P9) on the audio cape to those of the BeagleBone Black.

Getting ready

The output jack is green and the input jack is light blue.

In order to do the last part of this recipe, you may also want to either plug a microphone into the input jack on the cape or use a USB mic in the USB port.

How to do it...

Now that you're prepared, let's get started:

  1. First, download and unzip the DT overlay from the manufacturer (http://elinux.org/images/1/10/BB-BONE-AUDI-02-00A0.zip). For the fastest method, just download it to your client machine.
  2. In a text editor on your client machine, open up a file with the name, BB-BONE-AUDI-02-00A0.dts.
  3. On your BBB, log in as root and navigate to the firmware directory:
    # cd /lib/firmware
    

    As an optional step, you can check the contents of the directory. You should see dozens of Device Tree overlay files (.dtbo). Otherwise, you can skip this.

  4. Open a nano window on the BBB with the following filename:
    # nano BB-BONE-AUDI-02-00A0.dts
    
  5. Copy the Device Tree overlay file contents from the text editor window on your client machine into the nano window on your BBB by executing the following code:
    /*
     * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     */
    /dts-v1/;
    /plugin/;
    
    / {
      compatible = "ti,beaglebone", "ti,beaglebone-black";
    
      /* identification */
      part-number = "BB-BONE-AUDI-02";
      version = "00A0", "A0";
    
    
    
  6. Then, compile the Device Tree overlay as follows:
    dtc -O dtb -o BB-BONE-AUDI-02-00A0.dtbo -b 0 -@ BB-BONE-AUDI-02-00A0.dts
    
  7. Now, we'll open up nano to edit the boot file. You can optionally open the same file by browsing your client Mac or PC desktop and drilling down into the BEAGLE_BONE/ volume with the following code:
    # nano /boot/uEnv.txt
    
    
    ##Audio Cape (needs HDMI Audio disabled)
    cape_disable=capemgr.disable_partno=BB-BONELT-HDMI
    cape_enable=capemgr.enable_partno=BB-BONE-AUDI-02
    

    Once opened, we want to uncomment (remove #) from the section labeled Disable HDMI, and the following command comes in handy:

    optargs=capemgr.disable_partno=BB-BONELT-HDMI
    

    Note

    Take note of two things while modifying the uEnv.txt file for this step:

    • You only need to disable BB-BONELT-HDMI. BB-BONELT-HDMI as it will not conflict with the audio cape.
    • You may, however, run into a different overlay conflict if you ran other recipes or DT experiments. If so, be sure to also comment out any new lines you might have added for other recipes as these may prevent the AUDI-02 overlay from loading.

    Finally, you need to close and save the uEnv.txt file.

  8. Now, run the export command:
    # export SLOTS=/sys/devices/bone_capemgr.*/slots
    
  9. After this, go to the following directory:
    # cd /sys/devices/bone_capemgr.*
    
  10. Then, run the echo command.
    # echo BB-BONE-AUDI-02 > slots
    

    This command takes the output of echo, BB-BONE-AUDI-02, and writes it in the slots file, which in turn enables the drivers and device for AUDI-02 using the Device Tree overlay.

  11. Now, reboot the BBB as follows:
    # reboot
    
  12. Confirm that the DT overlay loaded properly by going to the designated directory and running the following command:
    # cd /sys/devices/bone_capemgr.9#
    # cat slots
    
    0: 54:PF---
     1: 55:PF---
     2: 56:PF---
     3: 57:PF---
     4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
     5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
     6: ff:P-O-L Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
     7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-BONE-AUDI-02
    

    You should see in the last line our AUDI-02 device now enabled.

  13. So, let's test the default audio output first. For this, use the following command:
    # speaker-test
    

    You should hear white noise playing. To quit, press Ctrl + c.

    Note

    Avoid using Ctrl + z as the process will likely not end gracefully and prevent you from running additional tests on the cape.

  14. Finally, we can optionally test the input and the output. This assumes that you have a microphone plugged into the input jack on the cape or a USB mic via the USB port.
  15. First, capture an audio sample using the following command:
    # arecord -D default:CARD=devicename -r 44100 -c 1 -f S16_LE -t wav -vv -d 10 example.wav
    

    Then, play it back by simply using:

    # aplay example.wav
    

There's more…

Once you get the cape working, you will probably find that audio levels are too low. So, we need to adjust this with the following commands using an installed audio application called amixer, which is part of Advanced Linux Sound Architecture (ALSA)'s utilities toolset. ALSA is the multifaceted layer that connects to the kernel and provides audio functionality to user space:

$ amixer set PCM 5dB
$ amixer set 'Right PGA Mixer Mic3R' on
$ amixer set 'Left PGA Mixer Mic3L' on

Additionally, if you want to plug in a music player or another audio source, you need to switch audio from in to out:

$ amixer set 'Right HP Mixer PGAR Bypass' on
$ amixer set 'Left HP Mixer PGAL Bypass' on

Finally, use these commands to adjust the gain:

  1. To increase volume (for example, to 10%), run the following:
    $ amixer set PGA 10%+
    
  2. To decrease the volume (for example, to 5%), run the following:
    $ amixer set PGA 5%-
    
  3. To toggle mute, run the following:
    $ amixer set PGA toggle
    

See also

There is a wealth of supporting information to satisfy your curiosity and take your understanding of Device Tree to new heights:

Getting ready

In addition to your usual BBB setup, we will use Audio Cape Rev. B, available from CircuitCo (http://boardzoo.com/index.php/beaglebone-black/bone-audio.html). Attach the cape to your BBB's header stack, following the orientation shown in the following pictures:

Note

If you ran the recipe in the previous chapter to send the IP address of your BBB to your email address, you can run your system remotely and in a headless way.

Getting ready

Be sure to match the header pin rows (P8 and P9) on the audio cape to those of the BeagleBone Black.

Getting ready

The output jack is green and the input jack is light blue.

In order to do the last part of this recipe, you may also want to either plug a microphone into the input jack on the cape or use a USB mic in the USB port.

How to do it...

Now that you're prepared, let's get started:

  1. First, download and unzip the DT overlay from the manufacturer (http://elinux.org/images/1/10/BB-BONE-AUDI-02-00A0.zip). For the fastest method, just download it to your client machine.
  2. In a text editor on your client machine, open up a file with the name, BB-BONE-AUDI-02-00A0.dts.
  3. On your BBB, log in as root and navigate to the firmware directory:
    # cd /lib/firmware
    

    As an optional step, you can check the contents of the directory. You should see dozens of Device Tree overlay files (.dtbo). Otherwise, you can skip this.

  4. Open a nano window on the BBB with the following filename:
    # nano BB-BONE-AUDI-02-00A0.dts
    
  5. Copy the Device Tree overlay file contents from the text editor window on your client machine into the nano window on your BBB by executing the following code:
    /*
     * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     */
    /dts-v1/;
    /plugin/;
    
    / {
      compatible = "ti,beaglebone", "ti,beaglebone-black";
    
      /* identification */
      part-number = "BB-BONE-AUDI-02";
      version = "00A0", "A0";
    
    
    
  6. Then, compile the Device Tree overlay as follows:
    dtc -O dtb -o BB-BONE-AUDI-02-00A0.dtbo -b 0 -@ BB-BONE-AUDI-02-00A0.dts
    
  7. Now, we'll open up nano to edit the boot file. You can optionally open the same file by browsing your client Mac or PC desktop and drilling down into the BEAGLE_BONE/ volume with the following code:
    # nano /boot/uEnv.txt
    
    
    ##Audio Cape (needs HDMI Audio disabled)
    cape_disable=capemgr.disable_partno=BB-BONELT-HDMI
    cape_enable=capemgr.enable_partno=BB-BONE-AUDI-02
    

    Once opened, we want to uncomment (remove #) from the section labeled Disable HDMI, and the following command comes in handy:

    optargs=capemgr.disable_partno=BB-BONELT-HDMI
    

    Note

    Take note of two things while modifying the uEnv.txt file for this step:

    • You only need to disable BB-BONELT-HDMI. BB-BONELT-HDMI as it will not conflict with the audio cape.
    • You may, however, run into a different overlay conflict if you ran other recipes or DT experiments. If so, be sure to also comment out any new lines you might have added for other recipes as these may prevent the AUDI-02 overlay from loading.

    Finally, you need to close and save the uEnv.txt file.

  8. Now, run the export command:
    # export SLOTS=/sys/devices/bone_capemgr.*/slots
    
  9. After this, go to the following directory:
    # cd /sys/devices/bone_capemgr.*
    
  10. Then, run the echo command.
    # echo BB-BONE-AUDI-02 > slots
    

    This command takes the output of echo, BB-BONE-AUDI-02, and writes it in the slots file, which in turn enables the drivers and device for AUDI-02 using the Device Tree overlay.

  11. Now, reboot the BBB as follows:
    # reboot
    
  12. Confirm that the DT overlay loaded properly by going to the designated directory and running the following command:
    # cd /sys/devices/bone_capemgr.9#
    # cat slots
    
    0: 54:PF---
     1: 55:PF---
     2: 56:PF---
     3: 57:PF---
     4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
     5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
     6: ff:P-O-L Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
     7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-BONE-AUDI-02
    

    You should see in the last line our AUDI-02 device now enabled.

  13. So, let's test the default audio output first. For this, use the following command:
    # speaker-test
    

    You should hear white noise playing. To quit, press Ctrl + c.

    Note

    Avoid using Ctrl + z as the process will likely not end gracefully and prevent you from running additional tests on the cape.

  14. Finally, we can optionally test the input and the output. This assumes that you have a microphone plugged into the input jack on the cape or a USB mic via the USB port.
  15. First, capture an audio sample using the following command:
    # arecord -D default:CARD=devicename -r 44100 -c 1 -f S16_LE -t wav -vv -d 10 example.wav
    

    Then, play it back by simply using:

    # aplay example.wav
    

There's more…

Once you get the cape working, you will probably find that audio levels are too low. So, we need to adjust this with the following commands using an installed audio application called amixer, which is part of Advanced Linux Sound Architecture (ALSA)'s utilities toolset. ALSA is the multifaceted layer that connects to the kernel and provides audio functionality to user space:

$ amixer set PCM 5dB
$ amixer set 'Right PGA Mixer Mic3R' on
$ amixer set 'Left PGA Mixer Mic3L' on

Additionally, if you want to plug in a music player or another audio source, you need to switch audio from in to out:

$ amixer set 'Right HP Mixer PGAR Bypass' on
$ amixer set 'Left HP Mixer PGAL Bypass' on

Finally, use these commands to adjust the gain:

  1. To increase volume (for example, to 10%), run the following:
    $ amixer set PGA 10%+
    
  2. To decrease the volume (for example, to 5%), run the following:
    $ amixer set PGA 5%-
    
  3. To toggle mute, run the following:
    $ amixer set PGA toggle
    

See also

There is a wealth of supporting information to satisfy your curiosity and take your understanding of Device Tree to new heights:

How to do it...

Now that you're prepared, let's get started:

  1. First, download and unzip the DT overlay from the manufacturer (http://elinux.org/images/1/10/BB-BONE-AUDI-02-00A0.zip). For the fastest method, just download it to your client machine.
  2. In a text editor on your client machine, open up a file with the name, BB-BONE-AUDI-02-00A0.dts.
  3. On your BBB, log in as root and navigate to the firmware directory:
    # cd /lib/firmware
    

    As an optional step, you can check the contents of the directory. You should see dozens of Device Tree overlay files (.dtbo). Otherwise, you can skip this.

  4. Open a nano window on the BBB with the following filename:
    # nano BB-BONE-AUDI-02-00A0.dts
    
  5. Copy the Device Tree overlay file contents from the text editor window on your client machine into the nano window on your BBB by executing the following code:
    /*
     * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     */
    /dts-v1/;
    /plugin/;
    
    / {
      compatible = "ti,beaglebone", "ti,beaglebone-black";
    
      /* identification */
      part-number = "BB-BONE-AUDI-02";
      version = "00A0", "A0";
    
    
    
  6. Then, compile the Device Tree overlay as follows:
    dtc -O dtb -o BB-BONE-AUDI-02-00A0.dtbo -b 0 -@ BB-BONE-AUDI-02-00A0.dts
    
  7. Now, we'll open up nano to edit the boot file. You can optionally open the same file by browsing your client Mac or PC desktop and drilling down into the BEAGLE_BONE/ volume with the following code:
    # nano /boot/uEnv.txt
    
    
    ##Audio Cape (needs HDMI Audio disabled)
    cape_disable=capemgr.disable_partno=BB-BONELT-HDMI
    cape_enable=capemgr.enable_partno=BB-BONE-AUDI-02
    

    Once opened, we want to uncomment (remove #) from the section labeled Disable HDMI, and the following command comes in handy:

    optargs=capemgr.disable_partno=BB-BONELT-HDMI
    

    Note

    Take note of two things while modifying the uEnv.txt file for this step:

    • You only need to disable BB-BONELT-HDMI. BB-BONELT-HDMI as it will not conflict with the audio cape.
    • You may, however, run into a different overlay conflict if you ran other recipes or DT experiments. If so, be sure to also comment out any new lines you might have added for other recipes as these may prevent the AUDI-02 overlay from loading.

    Finally, you need to close and save the uEnv.txt file.

  8. Now, run the export command:
    # export SLOTS=/sys/devices/bone_capemgr.*/slots
    
  9. After this, go to the following directory:
    # cd /sys/devices/bone_capemgr.*
    
  10. Then, run the echo command.
    # echo BB-BONE-AUDI-02 > slots
    

    This command takes the output of echo, BB-BONE-AUDI-02, and writes it in the slots file, which in turn enables the drivers and device for AUDI-02 using the Device Tree overlay.

  11. Now, reboot the BBB as follows:
    # reboot
    
  12. Confirm that the DT overlay loaded properly by going to the designated directory and running the following command:
    # cd /sys/devices/bone_capemgr.9#
    # cat slots
    
    0: 54:PF---
     1: 55:PF---
     2: 56:PF---
     3: 57:PF---
     4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
     5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
     6: ff:P-O-L Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
     7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-BONE-AUDI-02
    

    You should see in the last line our AUDI-02 device now enabled.

  13. So, let's test the default audio output first. For this, use the following command:
    # speaker-test
    

    You should hear white noise playing. To quit, press Ctrl + c.

    Note

    Avoid using Ctrl + z as the process will likely not end gracefully and prevent you from running additional tests on the cape.

  14. Finally, we can optionally test the input and the output. This assumes that you have a microphone plugged into the input jack on the cape or a USB mic via the USB port.
  15. First, capture an audio sample using the following command:
    # arecord -D default:CARD=devicename -r 44100 -c 1 -f S16_LE -t wav -vv -d 10 example.wav
    

    Then, play it back by simply using:

    # aplay example.wav
    

There's more…

Once you get the cape working, you will probably find that audio levels are too low. So, we need to adjust this with the following commands using an installed audio application called amixer, which is part of Advanced Linux Sound Architecture (ALSA)'s utilities toolset. ALSA is the multifaceted layer that connects to the kernel and provides audio functionality to user space:

$ amixer set PCM 5dB
$ amixer set 'Right PGA Mixer Mic3R' on
$ amixer set 'Left PGA Mixer Mic3L' on

Additionally, if you want to plug in a music player or another audio source, you need to switch audio from in to out:

$ amixer set 'Right HP Mixer PGAR Bypass' on
$ amixer set 'Left HP Mixer PGAL Bypass' on

Finally, use these commands to adjust the gain:

  1. To increase volume (for example, to 10%), run the following:
    $ amixer set PGA 10%+
    
  2. To decrease the volume (for example, to 5%), run the following:
    $ amixer set PGA 5%-
    
  3. To toggle mute, run the following:
    $ amixer set PGA toggle
    

See also

There is a wealth of supporting information to satisfy your curiosity and take your understanding of Device Tree to new heights:

There's more…

Once you get the cape working, you will probably find that audio levels are too low. So, we need to adjust this with the following commands using an installed audio application called amixer, which is part of Advanced Linux Sound Architecture (ALSA)'s utilities toolset. ALSA is the multifaceted layer that connects to the kernel and provides audio functionality to user space:

$ amixer set PCM 5dB
$ amixer set 'Right PGA Mixer Mic3R' on
$ amixer set 'Left PGA Mixer Mic3L' on

Additionally, if you want to plug in a music player or another audio source, you need to switch audio from in to out:

$ amixer set 'Right HP Mixer PGAR Bypass' on
$ amixer set 'Left HP Mixer PGAL Bypass' on

Finally, use these commands to adjust the gain:

  1. To increase volume (for example, to 10%), run the following:
    $ amixer set PGA 10%+
    
  2. To decrease the volume (for example, to 5%), run the following:
    $ amixer set PGA 5%-
    
  3. To toggle mute, run the following:
    $ amixer set PGA toggle
    

See also

There is a wealth of supporting information to satisfy your curiosity and take your understanding of Device Tree to new heights:

See also

There is a wealth of supporting information to satisfy your curiosity and take your understanding of Device Tree to new heights:

Universal cape overlay

Developer Charles Steinkuehler developed an enormously useful addition to the BeagleBone Black and DT world with his universal cape overlay. Now included by default on the current 3.7 and 3.8 kernels, the code greatly simplifies pin and cape management via simple command-line calls. The toolset can, in some cases, obviate the need to use many types of sysfs calls, some of which you learned earlier in the chapter.

Getting ready

A BBB hooked up and powered via USB.

How to do it…

Perform the following steps:

  1. Begin by logging in as the root user and then loading the cape overlay using the following commands:
    $ sudo -i
    # echo cape-universaln > /sys/devices/bone_capemgr.*/slots
    

    This command loads all devices and exports gpio. The pins currently default to gpio inputs. However, with the next set of commands, we can easily change their state.

  2. Let's consider the example of the P8_12 pin and run a command to find out its state:
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 0
    

    You will recall from earlier recipes that the 0 value means that the pin is set at low or off.

  3. Then, we can easily change its state with the following commands:
    # config-pin P8.12 hi
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 1
    

    Now, the value will change from 0 (low) to 1 (high). Indeed, this is a much snappier method to manipulate pins than the sysfs approach we discussed earlier.

  4. The toolset has additional functionality and options that you can further explore with the following command:
    # config-pin -h
    

There's more…

Getting ready

A BBB hooked up and powered via USB.

How to do it…

Perform the following steps:

  1. Begin by logging in as the root user and then loading the cape overlay using the following commands:
    $ sudo -i
    # echo cape-universaln > /sys/devices/bone_capemgr.*/slots
    

    This command loads all devices and exports gpio. The pins currently default to gpio inputs. However, with the next set of commands, we can easily change their state.

  2. Let's consider the example of the P8_12 pin and run a command to find out its state:
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 0
    

    You will recall from earlier recipes that the 0 value means that the pin is set at low or off.

  3. Then, we can easily change its state with the following commands:
    # config-pin P8.12 hi
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 1
    

    Now, the value will change from 0 (low) to 1 (high). Indeed, this is a much snappier method to manipulate pins than the sysfs approach we discussed earlier.

  4. The toolset has additional functionality and options that you can further explore with the following command:
    # config-pin -h
    

There's more…

How to do it…

Perform the following steps:

  1. Begin by logging in as the root user and then loading the cape overlay using the following commands:
    $ sudo -i
    # echo cape-universaln > /sys/devices/bone_capemgr.*/slots
    

    This command loads all devices and exports gpio. The pins currently default to gpio inputs. However, with the next set of commands, we can easily change their state.

  2. Let's consider the example of the P8_12 pin and run a command to find out its state:
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 0
    

    You will recall from earlier recipes that the 0 value means that the pin is set at low or off.

  3. Then, we can easily change its state with the following commands:
    # config-pin P8.12 hi
    # config-pin -q P8.12
    P8_12 Mode: gpio Direction: out Value: 1
    

    Now, the value will change from 0 (low) to 1 (high). Indeed, this is a much snappier method to manipulate pins than the sysfs approach we discussed earlier.

  4. The toolset has additional functionality and options that you can further explore with the following command:
    # config-pin -h
    

There's more…

There's more…

Running a script to check DT usage on GPIO pins

When modifying or working with Device Tree files, we frequently need to check pin usage so that we do not inadvertently try to write to claimed or unsuitable pins.

The following recipe employs two scripts that you can run with Node.js and helps us locate which pins are free. The scripts exist thanks to the coding work of Professor Mark Yoder at Rose-Hulman Institute of Technology.

Getting ready

You do not need anything more than your basic BBB kit for this recipe, which is a board connected to your host computer via USB.

How to do it…

To run this script, you need to follow these steps:

  1. You first need to open up the Cloud9 IDE and create a new script called freeGPIO.js.
  2. If you ran the recipe Device Tree Basic Build earlier in this chapter, you will find the file freeGPIO.js in the directory that you got from our GitHub repo. This was available by running the following command:
    git clone https://github.com/HudsonWerks/device-tree.git
    

    Otherwise, you can cut and paste the same code below into the IDE window. If you run into problems with the cut-and-paste version here, then just grab the same code from the directory file on the GitHub repo.

    #!/usr/bin/node
    // Lists all gpio pins with MUX UNCLAIMED and GPIO UNCLAIMED in $PINMUX
    // Usage:  freeGPIO.js    # List free GPIOs using P8 or P9 pin number
    //
    // Approach:
    //  1. search PINMUX for all entries with "(MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  2. An entry looks like "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  3. Extract the address (44e10820) and subtract 0x44e10800 to ge the offset
    //  4. Format the offset as 0x020, with leading 0's to give 3 digits
    //  5. Search for the address in the muxRegOffset field in b.bone.pins
    //  6. Print the matching key
    
    var PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    exec('grep "(MUX UNCLAIMED) (GPIO UNCLAIMED)" ' + PINMUX,
                function (error, stdout, stderr) {
                    var list,    // Array of unused pins
                        pin,     // pin offset in form 0x020
                        addr,    // pin address, 44e10820
                        keylist = []; // List of all unused header pins, P9_12
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
    //                console.log(stdout);
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    list = stdout.split('\n');
    //                console.log(list);
                    for(var i in list) {
                        // list[i] is of form "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
                        // Get the address from the 2nd field and remove the ()'s
                        addr = list[i].split(' ')[2].substring(1,9);
                        // Find the offset and return as 0x020, that is, zero padded to 3 digits.
                        pin = '0x' + ('000' + (parseInt(addr,16)-0x44e10800).toString(16)).slice(-3);
    //                    console.log(pin + " " + list[i]);
                        for(var j in b.bone.pins) {
                            if (b.bone.pins[j].muxRegOffset === pin) {
    //                      console.log(b.bone.pins[j].key);
                            keylist.push(b.bone.pins[j].key);
                                break;
                            }
                        }
                    }
                    keylist.sort();
                    console.log(keylist.join(' '));
                });
  3. In the Cloud9 IDE, click the Run button.
    P8_10 P8_11 P8_12 P8_13 P8_14 P8_15 P8_16 P8_17 P8_18 P8_19 P8_26 P8_7 P8_8 P8_9 P9_11 P9_12 P9_13 P9_14 P9_15 P9_16 P9_23 P9_24 P9_26 P9_27 P9_30 P9_41 P9_42 USR0 USR1 USR2 USR3
    

    This script gave us a list of pins that are not currently in use by the BBB and can be exploited for other purposes.

  4. Next, we will create and use a second script that we will name findGPIO.js, a script which will identify more information about an unused pin. To get the code, you can cut and paste the code below into the IDE, or follow the same step described in the prior step of getting it from our GitHub repo. Look for the file findGPIO.js in the device-tree directory that you downloaded.
    #!/usr/bin/node
    // Program to test looking up information in /usr/share/bone101/static/bone.js
    // Usage:  findGPIO.js 7     # Look up info for gpio7 (internal pin number)
    //         findGPIO.js P9_12 # Look up using header pin number (external)
    //         findGPIO.js P9_12 P9_13 ...  # Look up multiple pins and use one line
    //                                      # output for each.
    // Returns current pin mux
    
    var PINS = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pins",
        PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    /*
    process.argv.forEach(function(val, index, array) {
      console.log(index + ': ' + val);
    });
    */
    
    function pinMux(gpio, flag) {
        var addr = '(' + (0x44e10800 + 
                        parseInt(gpio.muxRegOffset, 16)).toString(16) + ')';
        
    //    console.log('grep "' + addr + '" ' + PINS);
        exec('grep "' + addr + '" ' + PINS,
                function (error, stdout, stderr) {
                    var mux,    // Current mux setting
                        out,   // output string
                        dir = 'down';    // Direction of pullup or pulldown
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    // console.log(stdout);
                    mux = parseInt(stdout.split(" ")[3], 16);// Get the mux field
                    out = gpio.key + ' (gpio ' + gpio.gpio + ") mode: " + (mux & 0x7) + 
                            " (" + gpio.options[mux & 0x7] + ") " + gpio.muxRegOffset;
                    if(!(mux & 0x8)) {   // Pullup or down is enabled
                        if(mux & 0x10) {
                            dir = 'up';
                        }
                        out += ' pull' + dir;
                    }
                    if(mux & 0x20) {
                        out += " Receiver Active";
                    }
                    if(mux & 0x40) {
                        out += " Slew Control Slow";
                    }
                    console.log(out);
                });
        if(flag) {
            exec('grep "' + addr + '" ' + PINMUX,
                function (error, stdout, stderr) {
    
                    if(error) { console.log('error: ' + error); }
                    if(stderr) {console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    console.log(stdout);
                });
        }
    }
    
    var gpio,
        flag = process.argv.length < 4,
        i;
    
    for(i=2; i<process.argv.length; i++) {
        gpio = process.argv[i].toUpperCase();
        if (gpio[0] === 'P' | gpio[0] === 'U') {
            if(flag) {
                console.log(b.bone.pins[gpio]);
            }
            pinMux(b.bone.pins[gpio], flag);
        } else {
            console.log("Looking for gpio " + gpio);
            for (var i in b.bone.pins) {
                if (b.bone.pins[i].gpio === parseInt(gpio,10)) {
                    if(flag) {
                        console.log(b.bone.pins[i]);
                    }
                    pinMux(b.bone.pins[i], flag);
                }
            }
        }
    }
  5. To run this script, we do not just click the RUN button in the IDE. Instead, we type the following command into the IDE's bash terminal window. Note that we append the command with one of the pins, specifically any of the pins that we saw output as available in the previous script's output (here we used P8_13). The output reveals a great deal of information about this pin, as follows:
    # node findGPIO.js P8_13
    
    
    { name: 'EHRPWM2B',
      gpio: 23,
      mux: 'gpmc_ad9',
      eeprom: 15,
      pwm:
       { module: 'ehrpwm2',
         index: 1,
         muxmode: 4,
         path: 'ehrpwm.2:1',
         name: 'EHRPWM2B' },
      key: 'P8_13',
      muxRegOffset: '0x024',
      options:
       [ 'gpmc_ad9',
         'lcd_data22',
         'mmc1_dat1',
         'mmc2_dat5',
         'ehrpwm2B',
         'pr1_mii0_col',
         'NA',
         'gpio0_23' ] }
    P8_13 (gpio 23) mode: 7 (gpio0_23) 0x024 pulldown Receiver Active
    pin 9 (44e10824): (MUX UNCLAIMED) (GPIO UNCLAIMED)

    Among other items of interest, what we learn from the preceding example is that the P8_13 pin is one of the PWM cadre—more specifically, EHRPWM2B, the type of pin we learned about in Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, that controls devices like motors.

Getting ready

You do not need anything more than your basic BBB kit for this recipe, which is a board connected to your host computer via USB.

How to do it…

To run this script, you need to follow these steps:

  1. You first need to open up the Cloud9 IDE and create a new script called freeGPIO.js.
  2. If you ran the recipe Device Tree Basic Build earlier in this chapter, you will find the file freeGPIO.js in the directory that you got from our GitHub repo. This was available by running the following command:
    git clone https://github.com/HudsonWerks/device-tree.git
    

    Otherwise, you can cut and paste the same code below into the IDE window. If you run into problems with the cut-and-paste version here, then just grab the same code from the directory file on the GitHub repo.

    #!/usr/bin/node
    // Lists all gpio pins with MUX UNCLAIMED and GPIO UNCLAIMED in $PINMUX
    // Usage:  freeGPIO.js    # List free GPIOs using P8 or P9 pin number
    //
    // Approach:
    //  1. search PINMUX for all entries with "(MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  2. An entry looks like "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  3. Extract the address (44e10820) and subtract 0x44e10800 to ge the offset
    //  4. Format the offset as 0x020, with leading 0's to give 3 digits
    //  5. Search for the address in the muxRegOffset field in b.bone.pins
    //  6. Print the matching key
    
    var PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    exec('grep "(MUX UNCLAIMED) (GPIO UNCLAIMED)" ' + PINMUX,
                function (error, stdout, stderr) {
                    var list,    // Array of unused pins
                        pin,     // pin offset in form 0x020
                        addr,    // pin address, 44e10820
                        keylist = []; // List of all unused header pins, P9_12
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
    //                console.log(stdout);
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    list = stdout.split('\n');
    //                console.log(list);
                    for(var i in list) {
                        // list[i] is of form "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
                        // Get the address from the 2nd field and remove the ()'s
                        addr = list[i].split(' ')[2].substring(1,9);
                        // Find the offset and return as 0x020, that is, zero padded to 3 digits.
                        pin = '0x' + ('000' + (parseInt(addr,16)-0x44e10800).toString(16)).slice(-3);
    //                    console.log(pin + " " + list[i]);
                        for(var j in b.bone.pins) {
                            if (b.bone.pins[j].muxRegOffset === pin) {
    //                      console.log(b.bone.pins[j].key);
                            keylist.push(b.bone.pins[j].key);
                                break;
                            }
                        }
                    }
                    keylist.sort();
                    console.log(keylist.join(' '));
                });
  3. In the Cloud9 IDE, click the Run button.
    P8_10 P8_11 P8_12 P8_13 P8_14 P8_15 P8_16 P8_17 P8_18 P8_19 P8_26 P8_7 P8_8 P8_9 P9_11 P9_12 P9_13 P9_14 P9_15 P9_16 P9_23 P9_24 P9_26 P9_27 P9_30 P9_41 P9_42 USR0 USR1 USR2 USR3
    

    This script gave us a list of pins that are not currently in use by the BBB and can be exploited for other purposes.

  4. Next, we will create and use a second script that we will name findGPIO.js, a script which will identify more information about an unused pin. To get the code, you can cut and paste the code below into the IDE, or follow the same step described in the prior step of getting it from our GitHub repo. Look for the file findGPIO.js in the device-tree directory that you downloaded.
    #!/usr/bin/node
    // Program to test looking up information in /usr/share/bone101/static/bone.js
    // Usage:  findGPIO.js 7     # Look up info for gpio7 (internal pin number)
    //         findGPIO.js P9_12 # Look up using header pin number (external)
    //         findGPIO.js P9_12 P9_13 ...  # Look up multiple pins and use one line
    //                                      # output for each.
    // Returns current pin mux
    
    var PINS = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pins",
        PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    /*
    process.argv.forEach(function(val, index, array) {
      console.log(index + ': ' + val);
    });
    */
    
    function pinMux(gpio, flag) {
        var addr = '(' + (0x44e10800 + 
                        parseInt(gpio.muxRegOffset, 16)).toString(16) + ')';
        
    //    console.log('grep "' + addr + '" ' + PINS);
        exec('grep "' + addr + '" ' + PINS,
                function (error, stdout, stderr) {
                    var mux,    // Current mux setting
                        out,   // output string
                        dir = 'down';    // Direction of pullup or pulldown
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    // console.log(stdout);
                    mux = parseInt(stdout.split(" ")[3], 16);// Get the mux field
                    out = gpio.key + ' (gpio ' + gpio.gpio + ") mode: " + (mux & 0x7) + 
                            " (" + gpio.options[mux & 0x7] + ") " + gpio.muxRegOffset;
                    if(!(mux & 0x8)) {   // Pullup or down is enabled
                        if(mux & 0x10) {
                            dir = 'up';
                        }
                        out += ' pull' + dir;
                    }
                    if(mux & 0x20) {
                        out += " Receiver Active";
                    }
                    if(mux & 0x40) {
                        out += " Slew Control Slow";
                    }
                    console.log(out);
                });
        if(flag) {
            exec('grep "' + addr + '" ' + PINMUX,
                function (error, stdout, stderr) {
    
                    if(error) { console.log('error: ' + error); }
                    if(stderr) {console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    console.log(stdout);
                });
        }
    }
    
    var gpio,
        flag = process.argv.length < 4,
        i;
    
    for(i=2; i<process.argv.length; i++) {
        gpio = process.argv[i].toUpperCase();
        if (gpio[0] === 'P' | gpio[0] === 'U') {
            if(flag) {
                console.log(b.bone.pins[gpio]);
            }
            pinMux(b.bone.pins[gpio], flag);
        } else {
            console.log("Looking for gpio " + gpio);
            for (var i in b.bone.pins) {
                if (b.bone.pins[i].gpio === parseInt(gpio,10)) {
                    if(flag) {
                        console.log(b.bone.pins[i]);
                    }
                    pinMux(b.bone.pins[i], flag);
                }
            }
        }
    }
  5. To run this script, we do not just click the RUN button in the IDE. Instead, we type the following command into the IDE's bash terminal window. Note that we append the command with one of the pins, specifically any of the pins that we saw output as available in the previous script's output (here we used P8_13). The output reveals a great deal of information about this pin, as follows:
    # node findGPIO.js P8_13
    
    
    { name: 'EHRPWM2B',
      gpio: 23,
      mux: 'gpmc_ad9',
      eeprom: 15,
      pwm:
       { module: 'ehrpwm2',
         index: 1,
         muxmode: 4,
         path: 'ehrpwm.2:1',
         name: 'EHRPWM2B' },
      key: 'P8_13',
      muxRegOffset: '0x024',
      options:
       [ 'gpmc_ad9',
         'lcd_data22',
         'mmc1_dat1',
         'mmc2_dat5',
         'ehrpwm2B',
         'pr1_mii0_col',
         'NA',
         'gpio0_23' ] }
    P8_13 (gpio 23) mode: 7 (gpio0_23) 0x024 pulldown Receiver Active
    pin 9 (44e10824): (MUX UNCLAIMED) (GPIO UNCLAIMED)

    Among other items of interest, what we learn from the preceding example is that the P8_13 pin is one of the PWM cadre—more specifically, EHRPWM2B, the type of pin we learned about in Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, that controls devices like motors.

How to do it…

To run this script, you need to follow these steps:

  1. You first need to open up the Cloud9 IDE and create a new script called freeGPIO.js.
  2. If you ran the recipe Device Tree Basic Build earlier in this chapter, you will find the file freeGPIO.js in the directory that you got from our GitHub repo. This was available by running the following command:
    git clone https://github.com/HudsonWerks/device-tree.git
    

    Otherwise, you can cut and paste the same code below into the IDE window. If you run into problems with the cut-and-paste version here, then just grab the same code from the directory file on the GitHub repo.

    #!/usr/bin/node
    // Lists all gpio pins with MUX UNCLAIMED and GPIO UNCLAIMED in $PINMUX
    // Usage:  freeGPIO.js    # List free GPIOs using P8 or P9 pin number
    //
    // Approach:
    //  1. search PINMUX for all entries with "(MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  2. An entry looks like "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
    //  3. Extract the address (44e10820) and subtract 0x44e10800 to ge the offset
    //  4. Format the offset as 0x020, with leading 0's to give 3 digits
    //  5. Search for the address in the muxRegOffset field in b.bone.pins
    //  6. Print the matching key
    
    var PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    exec('grep "(MUX UNCLAIMED) (GPIO UNCLAIMED)" ' + PINMUX,
                function (error, stdout, stderr) {
                    var list,    // Array of unused pins
                        pin,     // pin offset in form 0x020
                        addr,    // pin address, 44e10820
                        keylist = []; // List of all unused header pins, P9_12
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
    //                console.log(stdout);
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    list = stdout.split('\n');
    //                console.log(list);
                    for(var i in list) {
                        // list[i] is of form "pin 8 (44e10820): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
                        // Get the address from the 2nd field and remove the ()'s
                        addr = list[i].split(' ')[2].substring(1,9);
                        // Find the offset and return as 0x020, that is, zero padded to 3 digits.
                        pin = '0x' + ('000' + (parseInt(addr,16)-0x44e10800).toString(16)).slice(-3);
    //                    console.log(pin + " " + list[i]);
                        for(var j in b.bone.pins) {
                            if (b.bone.pins[j].muxRegOffset === pin) {
    //                      console.log(b.bone.pins[j].key);
                            keylist.push(b.bone.pins[j].key);
                                break;
                            }
                        }
                    }
                    keylist.sort();
                    console.log(keylist.join(' '));
                });
  3. In the Cloud9 IDE, click the Run button.
    P8_10 P8_11 P8_12 P8_13 P8_14 P8_15 P8_16 P8_17 P8_18 P8_19 P8_26 P8_7 P8_8 P8_9 P9_11 P9_12 P9_13 P9_14 P9_15 P9_16 P9_23 P9_24 P9_26 P9_27 P9_30 P9_41 P9_42 USR0 USR1 USR2 USR3
    

    This script gave us a list of pins that are not currently in use by the BBB and can be exploited for other purposes.

  4. Next, we will create and use a second script that we will name findGPIO.js, a script which will identify more information about an unused pin. To get the code, you can cut and paste the code below into the IDE, or follow the same step described in the prior step of getting it from our GitHub repo. Look for the file findGPIO.js in the device-tree directory that you downloaded.
    #!/usr/bin/node
    // Program to test looking up information in /usr/share/bone101/static/bone.js
    // Usage:  findGPIO.js 7     # Look up info for gpio7 (internal pin number)
    //         findGPIO.js P9_12 # Look up using header pin number (external)
    //         findGPIO.js P9_12 P9_13 ...  # Look up multiple pins and use one line
    //                                      # output for each.
    // Returns current pin mux
    
    var PINS = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pins",
        PINMUX = "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins",
        b = require('bonescript'),
        exec = require('child_process').exec;
    
    /*
    process.argv.forEach(function(val, index, array) {
      console.log(index + ': ' + val);
    });
    */
    
    function pinMux(gpio, flag) {
        var addr = '(' + (0x44e10800 + 
                        parseInt(gpio.muxRegOffset, 16)).toString(16) + ')';
        
    //    console.log('grep "' + addr + '" ' + PINS);
        exec('grep "' + addr + '" ' + PINS,
                function (error, stdout, stderr) {
                    var mux,    // Current mux setting
                        out,   // output string
                        dir = 'down';    // Direction of pullup or pulldown
    
                    if(error)  { console.log('error: '  + error ); }
                    if(stderr) { console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    // console.log(stdout);
                    mux = parseInt(stdout.split(" ")[3], 16);// Get the mux field
                    out = gpio.key + ' (gpio ' + gpio.gpio + ") mode: " + (mux & 0x7) + 
                            " (" + gpio.options[mux & 0x7] + ") " + gpio.muxRegOffset;
                    if(!(mux & 0x8)) {   // Pullup or down is enabled
                        if(mux & 0x10) {
                            dir = 'up';
                        }
                        out += ' pull' + dir;
                    }
                    if(mux & 0x20) {
                        out += " Receiver Active";
                    }
                    if(mux & 0x40) {
                        out += " Slew Control Slow";
                    }
                    console.log(out);
                });
        if(flag) {
            exec('grep "' + addr + '" ' + PINMUX,
                function (error, stdout, stderr) {
    
                    if(error) { console.log('error: ' + error); }
                    if(stderr) {console.log('stderr: ' + stderr); }
                    
                    stdout = stdout.substring(0,stdout.length-1);  // Get rid of extra \n
                    console.log(stdout);
                });
        }
    }
    
    var gpio,
        flag = process.argv.length < 4,
        i;
    
    for(i=2; i<process.argv.length; i++) {
        gpio = process.argv[i].toUpperCase();
        if (gpio[0] === 'P' | gpio[0] === 'U') {
            if(flag) {
                console.log(b.bone.pins[gpio]);
            }
            pinMux(b.bone.pins[gpio], flag);
        } else {
            console.log("Looking for gpio " + gpio);
            for (var i in b.bone.pins) {
                if (b.bone.pins[i].gpio === parseInt(gpio,10)) {
                    if(flag) {
                        console.log(b.bone.pins[i]);
                    }
                    pinMux(b.bone.pins[i], flag);
                }
            }
        }
    }
  5. To run this script, we do not just click the RUN button in the IDE. Instead, we type the following command into the IDE's bash terminal window. Note that we append the command with one of the pins, specifically any of the pins that we saw output as available in the previous script's output (here we used P8_13). The output reveals a great deal of information about this pin, as follows:
    # node findGPIO.js P8_13
    
    
    { name: 'EHRPWM2B',
      gpio: 23,
      mux: 'gpmc_ad9',
      eeprom: 15,
      pwm:
       { module: 'ehrpwm2',
         index: 1,
         muxmode: 4,
         path: 'ehrpwm.2:1',
         name: 'EHRPWM2B' },
      key: 'P8_13',
      muxRegOffset: '0x024',
      options:
       [ 'gpmc_ad9',
         'lcd_data22',
         'mmc1_dat1',
         'mmc2_dat5',
         'ehrpwm2B',
         'pr1_mii0_col',
         'NA',
         'gpio0_23' ] }
    P8_13 (gpio 23) mode: 7 (gpio0_23) 0x024 pulldown Receiver Active
    pin 9 (44e10824): (MUX UNCLAIMED) (GPIO UNCLAIMED)

    Among other items of interest, what we learn from the preceding example is that the P8_13 pin is one of the PWM cadre—more specifically, EHRPWM2B, the type of pin we learned about in Chapter 3, Physical Computing Recipes Using JavaScript, the BoneScript Library, and Python, that controls devices like motors.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image