My old BeagleBone had problems to get data from the uarts after an update. I decided to use a new BeagleBone black (bbb) with new kernel (4.4) to use eMMC instead the SD-card.
The old GPIO lib did not work with the new kernel, so I needed the the adafruit gpio lib.
Unfortunately this change was not easy and extremely time consuming. The used GPIOs are not free with the new device tree overlays and I had to dig deep to get it work.
A good help was the page from Derek Molloy. Another useful link is the introduction to device tree by adafruit.
The device tree is a data structure for describing hardware. So there is no further need to do this in the kernel for all the different arm controller boards. This data structure is passed to the operating system at boot time.
A dts-file (device tree source) is describing the data structure in a human readable format. A compiler (dtc; decvice tree compiler) converts the dts file to compact device tree blob file used by the kernel. This files have the ending dtb (device tree blob). The dtb files can be found on bbb in /boot/dtbs
.
It is possible to change these dtb files in /boot/dtbs
, but we have to reboot every time after we change the device tree. A more flexible way is to use device tree overlays in user space to change the device tree in runtime.
An important file is /boot/uEnv.txt
. In this file we find the kernel version: uname_r=4.4.9-ti-r25
and we are able to change the loading of device tree overlays.
I don't want to change my cape so I need the head pins P0915 (PINS Nr 16), P0923 (PINS Nr 17), P0925 (PINS Nr 107) and P0846 (PINS Nr 41). These pins are blocked by hdmi audio (mcasp0) and nxphdmibonelt.
In /boot/uEnv.txt
I have to uncomment the following dtb line:
##BeagleBone Black: HDMI (Audio/Video) disabled:
dtb=am335x-boneblack-emmc-overlay.dtb
and to change the following line
cmdline=coherent_pool=1M quiet cape_universal=enable
to:
cmdline=coherent_pool=1M quiet
After a reboot I want to check the pins and loaded capes. The simplest way is to create two shell variables as environment variables. Add the two following lines to ~/.profile
:
export SLOTS=/sys/devices/platform/bone_capemgr/slots
export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins
The command cat $SLOTS
shows that there are no capes or overlays loaded (the first slots are assigned by EEPROM IDs on the capes):
weigu@beaglebone:~$ cat $SLOTS
0: PF---- -1
1: PF---- -1
2: PF---- -1
3: PF---- -1
With the command sudo cat $PINS
i can check the state of the pins:
weigu@beaglebone:~$ sudo cat $PINS
registered pins: 142
pin 16 (44e10840.0) 00000008 pinctrl-single
pin 17 (44e10844.0) 00000027 pinctrl-single
pin 41 (44e108a4.0) 0000002f pinctrl-single
pin 107 (44e109ac.0) 00000027 pinctrl-single
Pin number is not the GPIO number! See in Dereks PDFs for GPIO number!
Now its time to write the device tree source file by changing Dereks example file.
First I change the part number to part-number = "WEIGU1"
. I want my 4 Pins set as output, so the code has to by 0x07. The offset is found in Dereks PDFs.
/*
* 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 Purpose License Version 2 as
* published by the Free Software Foundation
*
* Original from: github.com/jadonk/validation-scripts/blob/master/test-capemgr/
*
* Modified by Derek Molloy for the example on www.derekmolloy.ie
* that maps GPIO pins for the example
*/
/dts-v1/;
/plugin/;
/{
compatible = "ti,beaglebone", "ti,beaglebone-black";
part-number = "WEIGU1";
version = "00A0";
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
pinctrl_test: DM_GPIO_Test_Pins {
pinctrl-single,pins = <
0x044 0x07 /* P9_23 49 OUTPUT MODE7 - MUXA */
0x040 0x07 /* P9_15 48 OUTPUT MODE7 - MUXB */
0x1ac 0x07 /* P9_25 117 OUTPUT MODE7 - MUXT conflict mcasp0! */
0x0a4 0x07 /* P8_46 71 OUTPUT MODE7 - RTS conflict hdmi_bonelt! */
/* OUTPUT GPIO(mode7) 0x07 pulldown, 0x17 pullup, 0x?f no pullup/down */
/* INPUT GPIO(mode7) 0x27 pulldown, 0x37 pullup, 0x?f no pullup/down */
>;
};
};
};
fragment@1 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
status = "okay";
};
};
};
};
The file is saved as WEIGU1.dts
. The compiler will help to create my overlay file:
dtc -O dtb -o WEIGU1-00A0.dtbo -b 0 -@ WEIGU1.dts
Now we have to copy the file to /lib/firmware
.
sudo cp WEIGU1-00A0.dtbo /lib/firmware/
To enable the overlay sudo
is not enough. Use the following commands:
sudo su
echo WEIGU1 > /sys/devices/platform/bone_capemgr/slots
Exit with Ctrl+D
.
After this the command cat $SLOTS
shows my new overlay:
weigu@beaglebone:~$ cat $SLOTS
0: PF---- -1
1: PF---- -1
2: PF---- -1
3: PF---- -1
4: P-O-L- 0 Override Board Name,00A0,Override Manuf,WEIGU1
sudo cat $PINS
shows now that my pins are configures as output:
weigu@beaglebone:~$ sudo cat $PINS
registered pins: 142
pin 16 (44e10840.0) 00000007 pinctrl-single
pin 17 (44e10844.0) 00000007 pinctrl-single
pin 41 (44e108a4.0) 00000007 pinctrl-single
pin 107 (44e109ac.0) 00000007 pinctrl-single
There is a simple way to force the overlay to be loaded at boot. In /boot/uEnv.txt
we have to add this line:
cape_enable=capemgr.enable_partno=WEIGU1
With cape_enable=capemgr.enable_partno=
you can tell the kernel to load any overlay found in /lib/firmware
. As I want to use all 4 UARTs, I complete the line with 4 part numbers:
cape_enable=bone_capemgr.enable_partno=BB-UART1,BB-UART2,BB-UART4,BB-UART5,WEIGU1
Same it is also possible to disable parts:
cape_disable=bone_capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
The source code (with the part numbers) of the BB-UART overlays can be found in /opt/source/bb.org-overlays/src/arm
.
Now we are able to test our GPIOs:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# test_gpio.py testing gpios
# www.weigu.lu
import Adafruit_BBIO.GPIO as GPIO
from time import sleep
A = "P9_23" # GPIO1_17 Header P9 Pin 23
B = "P9_15" # GPIO1_16 Header P9 Pin 15
T = "P9_25" # GPIO3_21 Header P9 Pin 25
R = "P8_46" # GPIO2_7 Header P8 Pin 46
GPIO.setup(A, GPIO.OUT)
GPIO.setup(B, GPIO.OUT)
GPIO.setup(T, GPIO.OUT)
GPIO.setup(R, GPIO.OUT)
try:
while True:
print('0')
GPIO.output(A,GPIO.LOW)
GPIO.output(B,GPIO.LOW)
GPIO.output(T,GPIO.LOW)
GPIO.output(R,GPIO.LOW)
sleep(1)
print('1')
GPIO.output(A,GPIO.HIGH)
GPIO.output(B,GPIO.HIGH)
GPIO.output(T,GPIO.HIGH)
GPIO.output(R,GPIO.HIGH)
sleep(1)
except KeyboardInterrupt:
pass
GPIO.cleanup()
The program has to be called as superuser:
sudo python3 test_gpio.py
And here the program for testing the UARTs:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# test_uart.py testing 4 uarts
# www.weigu.lu
import Adafruit_BBIO.UART as UART
import serial
from time import sleep
UART.setup("UART1")
UART.setup("UART2")
UART.setup("UART4")
UART.setup("UART5")
ser1 = serial.Serial(port = "/dev/ttyO1", baudrate=9600)
ser1.close()
ser1.open()
if ser1.isOpen():
print('UART1 opened')
ser2 = serial.Serial(port = "/dev/ttyO2", baudrate=9600)
ser2.close()
ser2.open()
if ser2.isOpen():
print('UART2 opened')
ser3 = serial.Serial(port = "/dev/ttyO4", baudrate=9600)
ser3.close()
ser3.open()
if ser3.isOpen():
print('UART4 opened')
ser4 = serial.Serial(port = "/dev/ttyO5", baudrate=9600)
ser4.close()
ser4.open()
if ser4.isOpen():
print('UART5 opened')
try:
while True:
ser1.write('A'.encode())
ser2.write('B'.encode())
ser3.write('C'.encode())
ser4.write('D'.encode())
sleep(0.01)
except KeyboardInterrupt:
pass
ser1.close()
ser2.close()
ser3.close()
ser4.close()
UART.cleanup()
sudo python3 test_uart.py