NULLCape. How to Roll your own BeagleBone Capes (Part IV)

If you have been following this tutorial, you should have a fully functional NULLCape. Probably, you would also be thinking: "Yes, that's right, but this NULLCape is useless". And you are completely right... However, this can be easily improved with just some wires... Keep reading to know how.

IT'S A BUS!

For the time being, you had probably seen a lot of projects connecting stuff to a BeagleBone (or any other minicomputer) using the I2C bus. Usually, those projects just connect one device to the I2C pins but... those I2C pins allow the board to connect to a I2C bus!!.. What does that mean?. It basically means that you can connect several devices to those pins simultaneously.

So, based on this information we can make our NULLCape, actually a real, useful and functional cape, just connecting more stuff to the I2C bus that we are already using.

To make this modification we had just added a right-angle 4 pin header at one end of the cape, and then wired those pins to: 3V3, GND, SDA, SCL. That's it. Now we can connect any I2C device to our Beaglebone using our NULLCape and this new connector. In principle, we could even add a couple extra headers and connect more devices at the same time... If anyone wants to try, please let us know.

NULLCape Part 4. Modified CapeNULLCape Modified to expose the I2C bus, Vcc and GND

AN I2C DEVICE FOR TESTING

The cape modification was very simple, but to be able to test it, we need some I2C device. Some time ago, we bought an MCP23017 and never had a chance to play with it. This looks like a great opportunity to meet each other.

The MCP23X17 (http://ww1.microchip.com/downloads/en/devicedoc/21952b.pdf) is a 16bits I/O expander with Serial Interface. There are two versions of the chip: the MCP23017 with an I2C interface and the MCP23S17 with a SPI interface. Ours is a MCP23017 so, I2C interface.

Instead of building the MCP23017 in the cape itself (we had plenty of space there), we preferred to build a small daughter board. It seemed to us that such a small board might be useful with other controllers (Arduino, Attinys, Rpi,...).

The board is pretty simple. An IC socket with headers around, a 2-DIP switch to be able to change the I2C address (yes, we'd got some after we wrote the last part of this tutorial) and some wires to connect power, ground and the I2C signals (SDA, SCL). We added some pull-up resistors in the MCP23017 address pins and were done.

This is how our MCP23017 board looks like.

MCP23017 Daughterboard for NULLCapeMCP23017 Daughterboard for NULLCape

Note the two female pins close to the main connector. They are just ground connections. In the first iteration we haven't include them and it was difficult to connect anything to the board. All the ground pins in the BeagleBone were blocked by the cape so we decided to add these two pins in the daughter board.

TESTING

Everything is ready now and we can just try out our BeagleBone GPIO Expander cape with the usual blinking LED. But before we do that, let's do some basic checks. First thing was to check that the expansion board was properly detected at the right address. That can be done using i2cdetect (you already know about that).

# i2cdetect -y -r 1
root@beaglebone:~/mcp23017# i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 
Then, we change the switches in the MCP23017 board and checked that the address can be properly selected. Selecting OFF position on both DIP switches in the board produces this output:
# i2cdetect -y -r 1
root@beaglebone:~/mcp23017# i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- 21 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                    
(NOTE: we wired A0 on the MCP23017 to VCC so only odd addresses are selectable. Do not ask why) Now we need to effectively check that the I/O expander works. For that, we used the great Python module from Adafruit (https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/maste...).

A NOTE ON THE SOFTWARE

Yep, that code from Adafruit is supposed to be Raspberry Pi specific. However, the only Pi part in the code, is a function to check the Rpi Revision in order to properly select the I2C bus for Rev A and Rev B boards. Anything else is actually the standard SMBUS stuff (do not forget to install this module apt-get install python-smbus). All that courtesy of the I2C subsystem in the Linux kernel... Good! So, in order to use this great python module with our BeagleBone we just changed the call to the constructor in the Adafruit_MCP230xx.py module to force the I2C bus we wanted to use (1 in our case). By default (no busnum provided), the module makes the selection, but such a selection only works for the Raspberry Pi. The original Adafruit_MCP230xx.pye, at line 45, contains the following:
self.i2c = Adafruit_I2C(address=address)
And we need to change it to:
self.i2c = Adafruit_I2C(address=address, busnum = 1)
Now we can write our blinking script.
#!/usr/bin/python
import time
from Adafruit_MCP230xx import Adafruit_MCP230XX

mcp = Adafruit_MCP230XX(0x27, 16)
    
# Set pin 0 to output
mcp.config(0, mcp.OUTPUT)
	       
while (True):
	mcp.output(0, 1) # Pin 0 High
	time.sleep(2)
	mcp.output(0, 0) # Pin 1 Low
	time.sleep(2)
And that is it. A complete functional cape example that uses the minimal interface with the BegableBone, power and I2C, and can do something useful. To finish, this is a picture showing the whole setup. NULLCape Testing MCP23017 BoardNULLCape Testing MCP23017 Board There will be one last part of this tutorial, but it will not be about the NULLCape. It will be about using the other pins in the BeagleBone, and therefore, it does not uses the minimal interface any more... So the name NULLCape does not make sense anymore. Which name do you think would be cool for it?. Make your suggestion in the comments below. CU The picoFlamingo Team

Comments

Loading Pin Configuration Directly from EEPROM

Really a great tutorial!

Unfortunately, I also ended up with the cape manager not finding the .dtbo file under /lib/firmware/.
But since my actual goal would be to store the pin configuration directly in the EEPROM on the cape, this should not really bother me. Unfortunately, it didn't work for me so far... Did you ever try the latter yourself?

Imagine the EEPROM on the cape has been correctly filled with all the necessary information. How does the BBB then know that it should use the pin configuration stored in the EEPROM of the cape? Somehow, it still tries to load a .dtbo file from /lib/firmware/:

[...]
[ 0.566627] bone-capemgr bone_capemgr.9: Baseboard: 'A335BNLT,00C0,3214BBBK5087'
[ 0.566651] bone-capemgr bone_capemgr.9: compatible-baseboard=ti,beaglebone-black
[...]
[ 0.591985] bone-capemgr bone_capemgr.9: slot #0: 'MY-CAPE-NAME,00A0,MY-COMPANY,MY-DTO'
[ 0.622742] bone-capemgr bone_capemgr.9: slot #1: No cape found
[...]
[ 0.703753] bone-capemgr bone_capemgr.9: initialized OK.
[ 0.706593] bone-capemgr bone_capemgr.9: loader: before slot-0 MY-DTO:00A0 (prio 0)
[ 0.706607] bone-capemgr bone_capemgr.9: loader: check slot-0 MY-DTO:00A0 (prio 0)
[ 0.706622] bone-capemgr bone_capemgr.9: loader: after slot-0 MY-DTO:00A0 (prio 0)
[ 0.706637] bone-capemgr bone_capemgr.9: slot #0: Requesting part number/version based 'MY-DTO-00A0.dtbo
[ 0.706660] bone-capemgr bone_capemgr.9: slot #0: Requesting firmware 'MY-DTO-00A0.dtbo' for board-name 'MY-CAPE-NAME', version '00A0'
[ 1.066921] bone-capemgr bone_capemgr.9: failed to load firmware 'MY-DTO-00A0.dtbo'
[ 1.075824] bone-capemgr bone_capemgr.9: loader: failed to load slot-0 MY-DTO:00A0 (prio 0)
[...]

Any advice is very appreciated!

Cheers,
Thomas

I believe it is not happening automatically

Hi Thomas,

There is a while since I do not have time to use my BBB and keep working on the capes. At the time these tutorials were written, the answer was no. It was no possible to configure the pins from the data stored in the EEPROM content. That is why I added the option to generate dts files from BBCape_EEPROM (https://github.com/picoflamingo/BBCape_EEPROM) and I do not really fill the pins information there.

Said that, I do not know if somebody has gone farther on this topic. In principle, it should be possible to modify the capemanager or write a similar application to actually configure the muxes in the pins (as per the attached EEPROM), instead of processing the Device Tree file... actually that is one of the things that happens when the dtbo file is loaded...

Not sure if there is some user space interface like the one on Pandaboard some years ago (http://papermint-designs.com/community/node/231), otherwise I think you will need a small Kernel module to "poke" the mux values.

cheers
picoFlamingo

NULLCape name

Hi,

Well, given that I "come" from the PDP8 and PDP11 time, where we had
lots and lots of LEDs on the front panels (ahh, the days of the Console
Switch Register...!) I have always liked my projects to have many LEDs
on them.

One of our old names for those were "blinkenlites", and, indeed, many
"first time" Embedded Systems programs start out with just doing that,
blinking an LED. Your cape does this as well.

So, why not name it the BlinkyCape, or BlinkenCape ? ;)

Fred
fred@dutch-star.eu

dtbo loading problem

Hi, thanks for a nice tutorial. Which Beaglebone firmware/kernel are you using? I have a strange problem:

echo BB-NULLCape > /sys/devices/bone_capemgr.*/slots

works as supposed but in dmesg after boot I get:

[ 1.857667] bone-capemgr bone_capemgr.9: slot #3: Requesting firmware 'BB-NULLCape-00A0.dtbo' for board-name 'BeagleBone NULLCape', version '00A0'
[ 2.760697] bone-capemgr bone_capemgr.9: failed to load firmware 'BB-NULLCape-00A0.dtbo'
[ 2.769223] bone-capemgr bone_capemgr.9: loader: done slot-3 BB-NULLCape:00A0 (prio 0)

Angstrom version

Hi,

I am using Angstrom 2012.12 with a kernel 3.8.13.

Also note that the command "echo BB-NULLCape > /sys/devices/bone_capemgr.*/slots" will work even without the cape plugged in.

cheers
picoFlamingo

Will check BB version later Today

Hi,

I cannot check the version I'm using right now. I will update this answer later Today.

It is indeed strange. Did you change the Cape part-number or HW version in the EEProm or the original .dts?

You can use the latest version of BBCape_EEPROM (https://github.com/picoflamingo/BBCape_EEPROM) to read and parse your EEPROM content (after dumping it in a file)

Be free to send me your current dts, eeprom content and full dmesg output for further analysis.

As said I will update later Today.

Hi, it looks like my kernel

Hi,

it looks like my kernel (3.8.11 on BeagleBone Black) can not load the overlay from file system - perhaps the file system is not mounted early enough. After compiling the overlay into kernel everything works fine.

Good to heard you solve

Hi,

Good to heard you solve it. I´d try a newer kernel and check if the problem persist. If you are working on your own capes I think is very useful to have all this cape manager infrastructure working.

cheers
picoFlamingo

custom .dtbo loading at boot

Hi,

I'm another cape hacker and really found your series on capes a great resource while I was try to figure all this stuff out.

If I understand it all there is an issue with drivers in /lib/firmware trying to get loaded before that file system is mounted in the new kernels (I'm angstrom 3.8.13) I'm my case the boot stalls for 60 seconds and then continues with a successful retry to load my cape driver and all is happy. Here's where I got this info:
https://groups.google.com/forum/#!msg/beagleboard/Iem_mHknIUM/tcHvzUmIAsgJ

I'm using a bunch of uarts as well (1,2,4,5) and have a service to load the depends on them so currently limping along with time delays to let this timeout happen before starting the service until I get ambitious enough to build my own kernel.

Perry
perry@rtk-pi.com