TABLE OF CONTENTS
**NEEDED CONTENT: THE ONLY THING LEFT - HOW TO TRAIN IMAGES FOR THE CLASSIFICATION.TIDL.CPP FILE.
PLEASE COMMENT IF YOU HAVE ANY LEADS**
INTRODUCTION
As of December 2019, the BeagleBone AI (BBAI) software is presently in an early community development state. It requires a certain combination of a kernel version, code tweaks, and trial and error pin settings to get the packaged examples working. The official system reference on GitHub has many "TBD/TODO" statements for the critical functionality of the board. Several tables are for the BeagleBone Black which are not matched to the BBAI chipset. The time-tested BeagleBoard code libraries at the time of hardware release are still developed for the past architectures. So, I converted my hours of research here in hopes to save some time for other BeagleBoard beginners like myself with the desire to explore the BBAI.
Way below are some key references to keep your eye on as the BBAI develops. Last, for document versioning of this blog, I'll use this convention to keep track of changes to this blog: Whole versions for when new software is added, decimal versions when I change the instructions only, and no version increments if I'm just correcting my Kentucky English.
BBAI SETUP CHECKLIST
- Download the latest image - be sure it is for BeagleBone AI:
https://beagleboard.org/latest-images
(https://debian.beagleboard.org/images/am57xx-debian-10.3-iot-tidl-armhf-2020-04-06-6gb.img.xz) - Burn it with Etcher to an SD card 8 to 32 Gig. (other sizes have reported problems)
https://www.techspot.com/downloads/6931-etcher.html
BeagleBoard.org - getting-started - Put the card in BBAI, power it, and connect PC to it using wifi SSID BeagleBoneXXXX and password BeagleBone. Connect to Cloud9 by navigating to 192.168.8.1.
- Follow on screen instructions in cloud9 to connect BBAI to your home wifi summarized here (if prompted for a root password, use temppwd - the default user is debian):
sudo connmanctl⏎
scan wifi⏎ (wait for response)
services⏎ (copy the long string representing your wifi)
agent on⏎
connect <paste your string>⏎
quit⏎ - Get the max storage capacity out of your SD Card:
sudo /opt/scripts/tools/grow_partition.sh⏎
sudo reboot⏎ - Get latest Cloud9 Examples:
cd /var/lib/cloud9⏎
git pull⏎ (in Cloud9, rightclick on the BeagleBone directory and click refresh to get the tidl directory) - Get latest updates:
sudo apt update⏎
sudo apt upgrade⏎ - Download the MPGStreamer for use with embedded vision projects
sudo apt install -y ti-tidl mjpg-streamer-opencv-python⏎ - Install Jason Kridner's perl package to show BeagleBone AI Pins (see useful commands below):
sudo apt install libinline-files-perl⏎ - Install an even better package to show pins by Matt Van Duin:
cd /usr/local/sbin⏎
sudo wget -N https://raw.githubusercontent.com/mvduin/bbb-pin-utils/bbai-experimental/show-pins⏎
sudo chmod a+x show-pins⏎ - Install BoneScript and setup a pin for use:
cd /usr/local/lib⏎
sudo npm install --unsafe-perm bonescript@0.7.4-beta1⏎
node -pe "require('bonescript').bone.getPinObject('p9.15').ai.gpio" (this sets up the pin in /sys/class/gpio) - Update the Kernal - Note be sure to stay in the 4.14x range or the classification.cpp example will not work.
cd /opt/scripts⏎
git pull⏎
sudo tools/update_kernel.sh⏎ - Update /var/lib/cloud9/BeagleBone/AI/tidl code to get a flashing LED:
blinkLED.py (this is because the Adafruit Python Library is still mapped to the BeagleBone Black)
out="P8_13" #actually 8_22 on BBAI, line 14
or
out="P8_39" #for pin 9_15 on BBAI, line 14
blinkLED.js
const leds = ["USR3", "P9_15"]; //change line 13 to this to get processing improvement.
14. Perform the Pimuxing Procedure a couple of sections below.
15. Use Win32DiskImager to make a backup of your SD card.
GOOD STUFF TO KNOW
- BBAI means BeagleBone AI (artificial intelligence). BBB means BeagleBone Black.
- Cloud9 is the development environment that you get when at Step 3 above. It is scary at first, but you'll love it after a week playing with it. It sustains your session. So, you can jump from one computer to another hours later and start where you left off. It also provides an editor that makes the Linux nano editor seem decades old ;-).
- To add code to Cloud9, just right click on an existing directory such as the AI folder under Beaglebone on the left and then select "new file".
- There are two pin headers on the BBAI. With the ethernet port on top, P9 is on the left and P8 is on the right. Pins are often referred to in the format P9.2, which would be the top right pin of the left header when oriented such that the ethernet port is on top.
- Anytime I say "type", I mean type in a Linux terminal window. You can pull up a new terminal window in Cloud9 by right clicking over a folder such as the AI folder and selecting "new terminal here". The current directory will be the folder you right clicked on.
- Dropping executables in the "autorun" directory in Cloud9 will have them start on boot up, theoretically. I haven't pulled that off, yet.
- PinMuxing means to configure the pin multiplexing of the BeagleBone chip to establish the optimal pin configuration of the headers that matches the peripherals that you will be using such as I2C devices, servos, leds, switches, etc.
- The "/sys" directory is a virtual directory in memory. You'll use subdirectories within it to set pins, but since its in memory, you don't have to be worried about read and writing a million times like you would an SD card. In fact, your programming language calls are identical to how you would access an SD card file. It's unsettling, but works well even for PWM.
- The show-pins utilities and BeagleBone Adafruit IO library are mismatched to the pin names because they are still developed for the BeagleBone Black which has a different chipset.
- You should only type "sudo" if you are doing something under the /boot or /lib directory. Don't do it for most "git" calls or you'll set root access required permissions to those local folders. So, if in doubt, don't use sudo unless you are told to by the system in response to not using it.
- If you accidentally use sudo on a git repository that you shouldn't have, use sudo chown -R debian: the_folder, where debian is your username and the_folder is the folder created when you made the repository. This will strip the root permission requirement back off of it.
- In C, PWM settings on pins are set with fprintf in /sys/class/pwm/. Type "ls /sys/class/pwm/" to study it from the bash window.
- In C, Digital GPIO pins can be set through fprintf at /sys/class/gpio/. Use the spreadsheet in the References to understand the cross reference from P9.X notation and the integer you see like gpiochip128 (which is P9.12). Do "ls /sys/class/gpio/" to study it from the bash window.
USEFUL COMMANDS
- Show pin configuration (aka the pinmux) - note the pin IDs in column 2 are off due to architecture differences with the BBB
/opt/scripts/device/bone/show-pins.pl⏎ or
show-pins⏎ - Show BoneScript Version
node -pe "require('bonescript').getPlatform().bonescript"⏎
- Show Debian Image Date
cat /etc/dogtag⏎ - Show kernel and boot up device tree info
sudo /opt/scripts/tools/version.sh⏎ - Show an internal pin number as BoneScript sees it and set it up for access from code
node -pe "require('bonescript').bone.getPinObject('p9.15').ai.gpio"⏎ - Install the 4.14x kernel if you accidentally went to 4.19+ (which will cause classification.cpp to fail)
sudo /opt/scripts/tools/update_kernel.sh --lts-4_14 --ti-channel⏎ - Auto run a debugged application at startup by copying to the cloud9 directory:
cp <filename> /var/lib/cloud9/ - Show your entire directory structure on the Workspace Tab of Cloud9. Type the statements below in the terminal. You can name "root_link" anything you like. After you enter in those comands, on the left in that Workspace Tab, scroll up until you see Favorites. Click the "gear" icon on the upper right of that section. Note: the gear is often hidden, you have to float your mouse over the top right of the Workspace section. Check the box "Show Home in Favorites":
cd ~
ln -s / root_link
- Show attached cameras:
v4l2-ctl --list-devices⏎
- Free up the Heap when your TIDL app fails from prior CTRL-c's:
ti-mct-heap-check -c⏎
PINMUXING
Pinmux Procedure
To get your GPIO to work from your code, you need to configure the pins as inputs, outputs, I2C, and PWM. This is a process called Pinmuxing (pin multiplexing). Here is a procedure for setting your pinmux configuration to the one that was used for my board:
cd ~ #(or wherever you want to clone the next line to) git clone https://github.com/beagleboard/BeagleBoard-DeviceTrees -b v4.14.x-ti nano BeagleBoard-DeviceTrees/src/arm/am5729-beagleboneai-custom.dts #(paste the dts file below) cd ../../BeagleBoard-DeviceTrees make src/arm/am5729-beagleboneai-custom.dtb sudo cp src/arm/am5729-beagleboneai-custom.dtb /boot/dtbs sudo nano /boot/uEnv.txt #(configure: dtb=am5729-beagleboneai-custom.dtb) sudo reboot
a BBAI compatible dts file
A dts file (Device Tree Source) is what configures your Pinmux. To match my setup used in this blog, use the Pinmux Procedure in the previous section and paste the text below in the nano editor at step 3.
#include "am5729-beagleboneai.dts" // make it easy to determine which dtb you're currently running on // (via /proc/device-tree/chosen/) / { chosen { base_dtb = "am5729-beagleboneai-custom.dts"; base_dtb_timestamp = __TIMESTAMP__; }; }; // eventually these should be available in a header #define P9_14 (0x3400 + 4 * 107) #define P9_16 (0x3400 + 4 * 108) #define P9_19a (0x3400 + 4 * 16) #define P9_19b (0x3400 + 4 * 95) #define P9_20a (0x3400 + 4 * 17) #define P9_20b (0x3400 + 4 * 94) // enable i2c-3 on P9.19 (scl) + P9.20 (sda) &i2c4 { status = "okay"; clock-frequency = <400000>; pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins>; }; &dra7_pmx_core { i2c4_pins: i2c4 { pinctrl-single,pins = < DRA7XX_CORE_IOPAD( P9_19a, PIN_INPUT_PULLUP | MUX_MODE7 ) // scl DRA7XX_CORE_IOPAD( P9_19b, PIN_INPUT_PULLUP | MUX_MODE14 ) // (shared pin) DRA7XX_CORE_IOPAD( P9_20a, PIN_INPUT_PULLUP | MUX_MODE7 ) // sda DRA7XX_CORE_IOPAD( P9_20b, PIN_INPUT_PULLUP | MUX_MODE14 ) // (shared pin) >; }; }; // enable pwm-2 on P9.14 (out-A) + P9.16 (out-B) &epwmss2 { status = "okay"; }; &ehrpwm2 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&ehrpwm2_pins>; }; &dra7_pmx_core { ehrpwm2_pins: ehrpwm2 { pinctrl-single,pins = < DRA7XX_CORE_IOPAD( P9_14, PIN_OUTPUT_PULLDOWN | MUX_MODE10 ) // out A DRA7XX_CORE_IOPAD( P9_16, PIN_OUTPUT_PULLDOWN | MUX_MODE10 ) // out B >; }; }; // Here's the obnoxious part: since u-boot doesn't have same pin defaults yet, all pins not // explicitly setup above should be overridden here. This will eventually no longer be needed. &cape_pins_default { pinctrl-single,pins = < DRA7XX_CORE_IOPAD( 0x372C, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P9.11a (no gpio) DRA7XX_CORE_IOPAD( 0x3620, PIN_INPUT | MUX_MODE14 ) // P9.11b DRA7XX_CORE_IOPAD( 0x36AC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.12 DRA7XX_CORE_IOPAD( 0x3730, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P9.13 (no gpio) // DRA7XX_CORE_IOPAD( 0x35AC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.14 DRA7XX_CORE_IOPAD( 0x3514, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.15 // DRA7XX_CORE_IOPAD( 0x35B0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.16 DRA7XX_CORE_IOPAD( 0x37CC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.17a DRA7XX_CORE_IOPAD( 0x36B8, PIN_INPUT | MUX_MODE14 ) // P9.17b DRA7XX_CORE_IOPAD( 0x37C8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.18a DRA7XX_CORE_IOPAD( 0x36B4, PIN_INPUT | MUX_MODE14 ) // P9.18b // DRA7XX_CORE_IOPAD( 0x3440, PIN_INPUT_PULLUP | MUX_MODE14 ) // P9.19a // DRA7XX_CORE_IOPAD( 0x357C, PIN_INPUT | MUX_MODE14 ) // P9.19b // DRA7XX_CORE_IOPAD( 0x3444, PIN_INPUT_PULLUP | MUX_MODE14 ) // P9.20a // DRA7XX_CORE_IOPAD( 0x3578, PIN_INPUT | MUX_MODE14 ) // P9.20b DRA7XX_CORE_IOPAD( 0x34F0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.21a DRA7XX_CORE_IOPAD( 0x37C4, PIN_INPUT | MUX_MODE14 ) // P9.21b DRA7XX_CORE_IOPAD( 0x369C, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.22a DRA7XX_CORE_IOPAD( 0x37C0, PIN_INPUT | MUX_MODE14 ) // P9.22b DRA7XX_CORE_IOPAD( 0x37B4, PIN_INPUT_PULLUP | MUX_MODE14 ) // P9.23 DRA7XX_CORE_IOPAD( 0x368C, PIN_INPUT_PULLUP | MUX_MODE14 ) // P9.24 DRA7XX_CORE_IOPAD( 0x3694, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.25 DRA7XX_CORE_IOPAD( 0x3688, PIN_INPUT_PULLUP | MUX_MODE14 ) // P9.26a DRA7XX_CORE_IOPAD( 0x3544, PIN_INPUT | MUX_MODE14 ) // P9.26b DRA7XX_CORE_IOPAD( 0x35A0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.27a DRA7XX_CORE_IOPAD( 0x36B0, PIN_INPUT | MUX_MODE14 ) // P9.27b DRA7XX_CORE_IOPAD( 0x36E0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.28 DRA7XX_CORE_IOPAD( 0x36D8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.29a DRA7XX_CORE_IOPAD( 0x36A8, PIN_INPUT | MUX_MODE14 ) // P9.29b DRA7XX_CORE_IOPAD( 0x36DC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.30 DRA7XX_CORE_IOPAD( 0x36D4, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.31a DRA7XX_CORE_IOPAD( 0x36A4, PIN_INPUT | MUX_MODE14 ) // P9.31b DRA7XX_CORE_IOPAD( 0x36A0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.41a DRA7XX_CORE_IOPAD( 0x3580, PIN_INPUT | MUX_MODE14 ) // P9.41b DRA7XX_CORE_IOPAD( 0x36E4, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P9.42a DRA7XX_CORE_IOPAD( 0x359C, PIN_INPUT | MUX_MODE14 ) // P9.42b DRA7XX_CORE_IOPAD( 0x379C, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.3 DRA7XX_CORE_IOPAD( 0x37A0, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.4 DRA7XX_CORE_IOPAD( 0x378C, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.5 DRA7XX_CORE_IOPAD( 0x3790, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.6 DRA7XX_CORE_IOPAD( 0x36EC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.7 DRA7XX_CORE_IOPAD( 0x36F0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.8 DRA7XX_CORE_IOPAD( 0x3698, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.9 DRA7XX_CORE_IOPAD( 0x36E8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.10 DRA7XX_CORE_IOPAD( 0x3510, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.11 DRA7XX_CORE_IOPAD( 0x350C, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.12 DRA7XX_CORE_IOPAD( 0x3590, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.13 DRA7XX_CORE_IOPAD( 0x3598, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.14 DRA7XX_CORE_IOPAD( 0x3570, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.15a DRA7XX_CORE_IOPAD( 0x35B4, PIN_INPUT | MUX_MODE14 ) // P8.15b DRA7XX_CORE_IOPAD( 0x35BC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.16 DRA7XX_CORE_IOPAD( 0x3624, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.17 DRA7XX_CORE_IOPAD( 0x3588, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.18 DRA7XX_CORE_IOPAD( 0x358C, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.19 DRA7XX_CORE_IOPAD( 0x3780, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.20 DRA7XX_CORE_IOPAD( 0x377C, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.21 DRA7XX_CORE_IOPAD( 0x3798, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.22 DRA7XX_CORE_IOPAD( 0x3794, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.23 DRA7XX_CORE_IOPAD( 0x3788, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.24 DRA7XX_CORE_IOPAD( 0x3784, PIN_INPUT_PULLUP | MUX_MODE14 ) // P8.25 DRA7XX_CORE_IOPAD( 0x35B8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.26 DRA7XX_CORE_IOPAD( 0x35D8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.27a DRA7XX_CORE_IOPAD( 0x3628, PIN_INPUT | MUX_MODE14 ) // P8.27b DRA7XX_CORE_IOPAD( 0x35C8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.28a DRA7XX_CORE_IOPAD( 0x362C, PIN_INPUT | MUX_MODE14 ) // P8.28b DRA7XX_CORE_IOPAD( 0x35D4, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.29a DRA7XX_CORE_IOPAD( 0x3630, PIN_INPUT | MUX_MODE14 ) // P8.29b DRA7XX_CORE_IOPAD( 0x35CC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.30a DRA7XX_CORE_IOPAD( 0x3634, PIN_INPUT | MUX_MODE14 ) // P8.30b DRA7XX_CORE_IOPAD( 0x3614, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.31a DRA7XX_CORE_IOPAD( 0x373C, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P8.31b (no gpio) DRA7XX_CORE_IOPAD( 0x3618, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.32a DRA7XX_CORE_IOPAD( 0x3740, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P8.32b (no gpio) DRA7XX_CORE_IOPAD( 0x3610, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.33a DRA7XX_CORE_IOPAD( 0x34E8, PIN_INPUT | MUX_MODE14 ) // P8.33b DRA7XX_CORE_IOPAD( 0x3608, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.34a DRA7XX_CORE_IOPAD( 0x3564, PIN_INPUT | MUX_MODE14 ) // P8.34b DRA7XX_CORE_IOPAD( 0x360C, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.35a DRA7XX_CORE_IOPAD( 0x34E4, PIN_INPUT | MUX_MODE14 ) // P8.35b DRA7XX_CORE_IOPAD( 0x3604, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.36a DRA7XX_CORE_IOPAD( 0x3568, PIN_INPUT | MUX_MODE14 ) // P8.36b DRA7XX_CORE_IOPAD( 0x35FC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.37a DRA7XX_CORE_IOPAD( 0x3738, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P8.37b (no gpio) DRA7XX_CORE_IOPAD( 0x3600, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.38a DRA7XX_CORE_IOPAD( 0x3734, PIN_INPUT_PULLDOWN | MUX_MODE15 ) // P8.38b (no gpio) DRA7XX_CORE_IOPAD( 0x35F4, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.39 DRA7XX_CORE_IOPAD( 0x35F8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.40 DRA7XX_CORE_IOPAD( 0x35EC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.41 DRA7XX_CORE_IOPAD( 0x35F0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.42 DRA7XX_CORE_IOPAD( 0x35E4, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.43 DRA7XX_CORE_IOPAD( 0x35E8, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.44 DRA7XX_CORE_IOPAD( 0x35DC, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.45a DRA7XX_CORE_IOPAD( 0x361C, PIN_INPUT | MUX_MODE14 ) // P8.45b DRA7XX_CORE_IOPAD( 0x35E0, PIN_INPUT_PULLDOWN | MUX_MODE14 ) // P8.46a DRA7XX_CORE_IOPAD( 0x3638, PIN_INPUT | MUX_MODE14 ) // P8.46b >; };
After doing the Pinmux procedure above and rebooting, you can show the pin configuration:
Note: the pin IDs shown in the second column are easily confused for GPIO references. For example, P9.15 is 76 versus 69. From the author of the spreadsheet, P9.15 connects to the net "AG4_GPIO3_12" which connects to VIN1A_D8 (ball AG4) of the AM572x. From the AM572x TRM: CTRL_CORE_PAD_VIN1A_D8 is at 0x4A003514, which is byte-offset 0x114 into the pinmux array, i.e. index 0x114/4 = 69. Thanks to Matthijs van Duin for the first hand info.
debianaglebone:~$ sudo show-pins [sudo] password for debian: Caution: Uses peripheral names from <https://goo.gl/jiazTL>. See README there for details. P9.19a 16 fast rx up 7 i²c 3 scl i2c@4807a000 (i2c4) P9.20a 17 fast rx up 7 i²c 3 sda i2c@4807a000 (i2c4) P8.35b 57 fast rx 14 gpio 2.00 P8.33b 58 fast rx 14 gpio 2.01 P9.21a 60 fast rx down 14 gpio 2.03 P8.12 67 fast rx down 14 gpio 2.10 P8.11 68 fast rx down 14 gpio 2.11 P9.15 69 fast rx down 14 gpio 2.12 lo >> sysfs P9.26b 81 fast rx 14 gpio 2.24 P8.34b 89 fast rx 14 gpio 3.00 P8.36b 90 fast rx 14 gpio 3.01 P8.15a 92 fast rx down 14 gpio 3.03 P9.20b 94 fast rx up 14 gpio 3.05 i2c@4807a000 (i2c4) P9.19b 95 fast rx up 14 gpio 3.06 i2c@4807a000 (i2c4) P9.41b 96 fast rx 14 gpio 3.07 P8.18 98 fast rx down 14 gpio 3.09 P8.19 99 fast rx down 14 gpio 3.10 P8.13 100 fast rx down 14 gpio 3.11 P8.14 102 fast rx down 14 gpio 3.13 P9.42b 103 fast rx 14 gpio 3.14 P9.27a 104 fast rx down 14 gpio 3.15 P9.14 107 fast down 10 pwm 2 A pwm@48442200 (ehrpwm2) P9.16 108 fast down 10 pwm 2 B pwm@48442200 (ehrpwm2) P8.15b 109 fast rx 14 gpio 3.27 P8.26 110 fast rx down 14 gpio 3.28 P8.16 111 fast rx down 14 gpio 3.29 P8.28a 114 fast rx down 14 gpio 3.19 P8.30a 115 fast rx down 14 gpio 3.20 P8.29a 117 fast rx down 14 gpio 3.22 P8.27a 118 fast rx down 14 gpio 3.23 P8.45a 119 fast rx down 14 gpio 7.00 P8.46a 120 fast rx down 14 gpio 7.01 P8.43 121 fast rx down 14 gpio 7.02 P8.44 122 fast rx down 14 gpio 7.03 P8.41 123 fast rx down 14 gpio 7.04 P8.42 124 fast rx down 14 gpio 7.05 P8.39 125 fast rx down 14 gpio 7.06 P8.40 126 fast rx down 14 gpio 7.07 P8.37a 127 fast rx down 14 gpio 7.08 P8.38a 128 fast rx down 14 gpio 7.09 P8.36a 129 fast rx down 14 gpio 7.10 P8.34a 130 fast rx down 14 gpio 7.11 P8.35a 131 fast rx down 14 gpio 7.12 P8.33a 132 fast rx down 14 gpio 7.13 P8.31a 133 fast rx down 14 gpio 7.14 P8.32a 134 fast rx down 14 gpio 7.15 P8.45b 135 fast rx 14 gpio 7.16 P9.11b 136 fast rx 14 gpio 7.17 P8.17 137 fast rx down 14 gpio 7.18 P8.27b 138 fast rx 14 gpio 7.19 P8.28b 139 fast rx 14 gpio 7.20 P8.29b 140 fast rx 14 gpio 7.21 P8.30b 141 fast rx 14 gpio 7.22 P8.46b 142 fast rx 14 gpio 7.23 P9.13b ? 160 fast down 15 unused P9.26a 162 fast rx up 14 gpio 5.14 P9.24 163 fast rx up 14 gpio 5.15 P9.25 165 fast rx down 14 gpio 5.17 P8.09 166 fast rx down 14 gpio 5.18 P9.22a 167 fast rx down 14 gpio 5.19 P9.41a 168 fast rx down 14 gpio 5.20 P9.31b 169 fast rx 14 gpio 6.31 P9.29b 170 fast rx 14 gpio 6.30 P9.12 171 fast rx down 14 gpio 4.00 << lo sysfs P9.27b 172 fast rx 14 gpio 4.01 P9.18b 173 fast rx 14 gpio 4.02 P9.17b 174 fast rx 14 gpio 4.03 P9.31a 181 fast rx down 14 gpio 4.10 P9.29a 182 fast rx down 14 gpio 4.11 P9.30 183 fast rx down 14 gpio 4.12 P9.28 184 fast rx down 14 gpio 3.17 P9.42a 185 fast rx down 14 gpio 3.18 P8.10 186 fast rx down 14 gpio 5.04 P8.07 187 fast rx down 14 gpio 5.05 P8.08 188 fast rx down 14 gpio 5.06 P9.11a 203 fast rx down 15 unused P9.13a 204 fast rx down 15 unused P8.38b 205 fast rx down 15 unused P8.37b 206 fast rx down 15 unused P8.31b 207 fast rx down 15 unused P8.32b 208 fast rx down 15 unused P8.21 223 fast rx up 14 gpio 5.29 P8.20 224 fast rx up 14 gpio 5.30 P8.25 225 fast rx up 14 gpio 5.31 P8.24 226 fast rx up 14 gpio 6.00 P8.05 227 fast rx up 14 gpio 6.01 P8.06 228 fast rx up 14 gpio 6.02 P8.23 229 fast rx up 14 gpio 0.22 P8.22 230 fast rx up 14 gpio 0.23 P8.03 231 fast rx up 14 gpio 0.24 P8.04 232 fast rx up 14 gpio 0.25 P9.23 237 fast rx up 14 gpio 6.11 P9.22b 240 fast rx 14 gpio 6.14 P9.21b 241 fast rx 14 gpio 6.15 P9.18a 242 fast rx down 14 gpio 6.16 P9.17a 243 fast rx down 14 gpio 6.17
Above you can see that Pin 9.15 and 9.12 are in use by my augmented blinkLED.js program shown in the Code Examples section below. The << means that P9.12 is an input and the >> means that P9.15 is an output. In this case, 12 is detecting no voltages (LOW), and in turn, my code is outputting LOW.
ANALOG INPUT
Analog input is useful for communicating a degree of magnitude from a component. It is actually the least used way to get input by me for any project I've ever done. In fact, I have only used it with potentiometers to communicate desired servo position or audio volume. Some older sensors, though, would use it to communicate the measured value within their output range. You would do math on the microcontroller to ratio that input to a useful value such as distance.
Although the utility show-pins doesn't show it and the spreadsheet referenced in the References section doesn't reflect it, pin P9.33 is an analog in paired to "in_voltage7_raw" in the "sys" folder. It reads 0-1.8V and outputs a range of 0-2000ish. I found it testing the output as shown here:
debian@beaglebone:/var/lib/cloud9/BeagleBone/AI/backupcamera$ cat /sys/bus/iio/devices/iio:device0/in_voltage7_raw #jumper between P9.33 and P9.01 (GND) 0 debian@beaglebone:/var/lib/cloud9/BeagleBone/AI/backupcamera$ cat /sys/bus/iio/devices/iio:device0/in_voltage7_raw #jumper between P9.33 and P9.03 (3.3V) 4095
With this we can simply read using any language that reads a text file. See analogIn.c in Code Examples below.
Note, the ADC reads up to 1.8Vs which can be supplied to your components reference voltage by Pin 9.32 (For example, the voltage for a potentiometer). However, I did test 3.3V on the analog in pins and it gave a stable 4095 as the return value. Thanks to Fred Bogardus, he confirmed that the ADC of 1.8V is for backwards compatibility with older Beagle boards. The AI will take 3.3V since the STMPE811QTR can handle 3.3V on the analog in as shown on this schematic:
STMPE811QTR Schematic
sys file pin mapping
I could only safely locate 3 pins for analog read, although the spreadsheet shows 8.
/sys/bus/iio/devices/iio:device0/in_voltage7_raw P9.33
/sys/bus/iio/devices/iio:device0/in_voltage4_raw P9.35
/sys/bus/iio/devices/iio:device0/in_voltage6_raw P9.36
I2C USE
I2C (Inter-Intergrated Circuit) is a serial communication protocol that allows a device to talk to many, many I2C compatible devices with just two pins, called the clock and data lines. They are commonly found for talking to LCD Displays and sensors. As found in the show-pins output above, pins 9.19 and 9.20 are I2C enabled SCL and SDA pins, respectively. You can test this by hooking up an I2C device of your choice such as an I2C enabled LCD Display. Run the i2cdetect command as shown here:
debian@beaglebone:~$ i2cdetect -r 3 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-3 using read byte commands. I will probe address range 0x03-0x77. Continue? [Y/n] y 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- debian@beaglebone:~$
My LCD Display address for i2C is x27 which received a confirmed hit with i2cdetect as shown above. See Code Examples for an I2C LCD c program.
PWM CONTROL
PWM stands for Pulse Width Modulation. It reminds me of Morse code at a high speed frequency. It provides a means to communicate with other devices typically to relay a magnitude you desire of a given parameter such as speed, degrees of rotation, or audio volume. It is very common for sending a fine tuned pulsed signal that can be interpreted by a servo to determine its position. It can also be used to imply an analog signal between 0-3.3V such as for the input of a transistor driving a DC motor.
Digging around the "/sys/class" directory, I found /sys/class/pwm/pwm-0:0 relates to P9.14 when you use the Pinmux procedure provided earlier in this blog. See pwmout.c in Code Examples below for an example of controlling it. It's a three step process: set the frequency, set the duty, then enable the pin.
AUDIO
Unlike the Raspberry Pi, the BBAI doesn't have a headphone jack. To enable sound from the BBAI USB port, you first need a USB-to-Audio cable to hook to an external speaker (see the Hardware section for a link to one). To enable it on the system, you need to create a sound config file. To create it, type the following at a terminal screen:
nano ~/.asoundrc
Then paste the following in the nano editor:
pcm.!default { type plug slave { pcm "hw:1,0" } } ctl.!default { type hw card 1 }
To test it, you need a file. To get an epic one quickly, type the following in the terminal:
wget https://goo.gl/CDF6sf -O ./audio-sample.wav
Then play it with:
aplay ./audio-sample.wav
If you can't hear anything, list your detected hardware and type:
aplay -l
It may show your card as "2" instead of "1". edit the ./asoudrc file to change all 1's to a 2.
Then, from your C or C++ code, you can play sound files on demand like with a line like this:
system("sudo -u debian aplay -q /yourpath/yourfile.wav &");
The reason for the "sudo -u" trick is that Cloud9 will run your app as root which for some reason prevents the audio from playing. This trick will get your sound out your speaker. The -q will play it without it piping output to the terminal and the & sumbol will play the sound as a separate process so your code doesn't stall waiting for the sound to complete.
CREATING A RAM DISK
Once you start making a complex robot of some sort, you will find that you may want services running. These are programs that have one function such as updating a text file with the local weather forecast every half hour. Rather than writing one big application that does all the sensor poling and IoT communication, you can have several services that can be leveraged into any number of projects. The fastest performance in this approach is to store the data those services acquire to a RAM Disk. You can then retrieve it by your main application at light speed without worry of corrupting an SD card due to hitting it every millisecond.
To create a RAM disk, first create a directory where you want it. For example, at the terminal type:
mkdir ~/ramdisk
sudo chmod +777 ~/ramdisk
Then, to have your ram disk available everytime you reboot, type the following:
sudo nano /etc/fstab
Paste the following at the bottom of the screen and press CTRL-x to save:
myramdisk /home/debian/ramdisk tmpfs defaults,size=64k,x-gvfs-show 0 0
This will give you a 64k ram disk. You may want it bigger for your needs.
Remember, RAM disappears after a reboot or power cycle. So, don't store anything you want to keep here. It is solely for communication between your programs in an uber modular fashion. Use your standard file methods in your language of choice to use it.
TRANSFERRING FILES TO AND FROM OTHER MACHINES
There will be a time you will want a file outside of your BBAI such as from a Windows PC on your network. Most commonly, this would be sound files, image files, and code. I have narrowed this down to the four easiest options: 1) Cloud9 Upload Feature, 2) Github, 3) wget, and 4) a Windows Shared folder.
Cloud 9 Upload Feature
The quickest way to get an external file to the BBAI is with the Cloud9 IDE. Here are the steps to do so:
- In the Cloud9 IDE, left click on the directory where you want the files to land.
- On the menu bar, click File-->Upload Local Files
- Browse out either a single file or a directory.
To get a file from the BBAI to your local machine running Cloud9, just right click it and select Download.
GitHub
I've grown to be a big fan of Github since it can backup my code and I can deploy it to multiple devices. I don't have to worry about bricking a device and losing everything I was developing. So, another option is to keep all your files and code in Github and do git clone <repository>. You can then upload files from Windows to Github and then pull them in to your BBAI repository.
wget
If the file can be served from a http: source, you can just open a terminal, cd to the directory where you want to place it, and then type wget <URL>
Windows Shared Directory
Last, if you want to access a Windows directory from a terminal running on the BBAI, you'll need a package that let's you see Windows Shared Folders on your network.
Type the following in your terminal:
sudo apt-get install cifs-utils
Let it install. No need to reboot.
Create a Linux directory to hold the share folder:
cd ~
mkdir windows
Then, to mount the drive in Linux on your BBAI, type the following:
sudo mount.cifs "//windowscomputername/windowsfolderpath" "windows" -o user=yourwindowsusername
You can name the "windows" directory whatever you want as long as you did a mkdir that matches. You can now browse the directory with Linux terminal commands. Of course, the Windows computer better be turned on!
CODE EXAMPLES
Below are working code examples that make use of the PinMux Procedure earlier in this blog. One extra thing to note is that when you click run on a .c or .cpp file, you must then change the "runner" of Cloud9 and then click run again. Do this as shown in the boxed rectangle in the picture here:
Setting the Runner in Cloud 9 for C and C++
To use this code, you can right click in the Cloud9 IDE on a directory of choice and select New File. You can name it what you like. Be sure the extension matches the programming language, though. (js for javascript files, c for C files, cpp for C++, py for Python). After pasting the code in the new empty file, press CTRL s to save and click the run button as desribed above.
Augmented blinkLED.js
adds demonstration of digital read as well as write. See comments section for wiring and setup.
#!/usr/bin/env node //////////////////////////////////////// // blinkLED.js // Blinks the USR LEDs and P9_15 when you connect 3.3V to P9_12. // Wiring: P9_15 connects to the plus lead of an LED. The negative lead of the // LED goes to a 220 Ohm resistor. The other lead of the resistor goes // to ground. A jumper goes in the 3.3V header (not 5V!). Other end goes into // P_12. Take it in and out to watch light turn on. // Setup: first type the following into the terminal to set up your pins if you haven't... // node -pe "require('bonescript').bone.getPinObject('P9.12').ai.gpio" // node -pe "require('bonescript').bone.getPinObject('P9.15').ai.gpio" // Issues: On first execution, it may through and error due to permissions. Try running // again. //////////////////////////////////////// const b = require('bonescript'); const leds = ["USR3", "P9_15"]; for(var i in leds) { b.pinMode(leds[i], b.OUTPUT); } b.pinMode("P9_12",b.INPUT); var state = b.HIGH; for(var i in leds) { b.digitalWrite(leds[i], state); } setInterval(toggle, 100); function toggle() { if (b.digitalRead("P9_12")==b.HIGH) state = b.HIGH; else state = b.LOW; for(var i in leds) { b.digitalWrite(leds[i], state); } }
classification.cpp
add the following else case shown on line 15 to get text even when an object is not seen.
if(is_object >= 0) //excerpt from cloud9/BeagleBone/AI/tidl/classification.cpp, Line 310 { cv::putText( dst, (*(labels_classes[is_object])).c_str(), cv::Point(15, 60), cv::FONT_HERSHEY_SIMPLEX, 1.5, cv::Scalar(0,255,0), 3, /* thickness */ 8 ); } //new code is below that allows for a constant message or tweaking as you see fit. else { char my_message[]="Searching..."; cv::putText( dst, my_message, cv::Point(30, 60), cv::FONT_HERSHEY_SIMPLEX, 1.5, cv::Scalar(0,255,0), 3, /* thickness */ 8 ); } //end of new code
analogIn.c
program to show how to read 0.3.3 voltage on an analog input pin with C
//////////////////////////////////////// // analogIn.c // reports 0-3.3V on P9.33 as 0-4095 // Author: Sean J. Miller // Wiring: Jumper a 0-3.3V source to P9.33 // // See: https://www.element14.com/community/community/designcenter/single-board-computers/next-genbeaglebone/blog/2019/10/27/beagleboard-ai-brick-recovery-procedure //////////////////////////////////////// #include <stdio.h> #include <unistd.h> int analogRead(){ FILE * my_in_pin = fopen("/sys/bus/iio/devices/iio:device0/in_voltage7_raw", "r");//P9.33 on the BBAI char the_voltage[5];//the characters in the file are 0 to 4095 fgets(the_voltage,6,my_in_pin); fclose(my_in_pin); printf("Voltage: %s\n", the_voltage); return 0; } int main() { while(1) { analogRead(); usleep(1000000); } }
i2cLCD.c
program to demonstrate talking to an I2C device. In this case, an LCD.
/* ----------------------------------------------------------------------- * * Title: i2clcd * * Description: C-code for PCF8574T backpack controlling LCD through I2C * * Tested on BeagleBone AI * * 11/1/2019 Sean Miller * * ported from: * * https://github.com/fm4dd/i2c-lcd/blob/master/pcf8574-lcd-demo.c * * * * Compilation: i2clcd.c -o i2clcd * *------------------------------------------------------------------------ */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/i2c-dev.h> #include <fcntl.h> #define I2C_BUS "/dev/i2c-3" // I2C bus device #define I2C_ADDR 0x27 // I2C slave address for the LCD module #define BINARY_FORMAT " %c %c %c %c %c %c %c %c\n" #define BYTE_TO_BINARY(byte) \ (byte & 0x80 ? '1' : '0'), \ (byte & 0x40 ? '1' : '0'), \ (byte & 0x20 ? '1' : '0'), \ (byte & 0x10 ? '1' : '0'), \ (byte & 0x08 ? '1' : '0'), \ (byte & 0x04 ? '1' : '0'), \ (byte & 0x02 ? '1' : '0'), \ (byte & 0x01 ? '1' : '0') int lcd_backlight; int debug; char address; int i2cFile; void i2c_start() { if((i2cFile = open(I2C_BUS, O_RDWR)) < 0) { printf("Error failed to open I2C bus [%s].\n", I2C_BUS); exit(-1); } // set the I2C slave address for all subsequent I2C device transfers if (ioctl(i2cFile, I2C_SLAVE, I2C_ADDR) < 0) { printf("Error failed to set I2C address [%s].\n", I2C_ADDR); exit(-1); } } void i2c_stop() { close(i2cFile); } void i2c_send_byte(unsigned char data) { unsigned char byte[1]; byte[0] = data; if(debug) printf(BINARY_FORMAT, BYTE_TO_BINARY(byte[0])); write(i2cFile, byte, sizeof(byte)); /* -------------------------------------------------------------------- * * Below wait creates 1msec delay, needed by display to catch commands * * -------------------------------------------------------------------- */ usleep(1000); } void main() { i2c_start(); debug=0; //change to 1 to see messages. /* -------------------------------------------------------------------- * * Initialize the display, using the 4-bit mode initialization sequence * * -------------------------------------------------------------------- */ if(debug) printf("Init Start:\n"); usleep(15000); // wait 15msec i2c_send_byte(0b00110100); // D7=0, D6=0, D5=1, D4=1, RS,RW=0 EN=1 i2c_send_byte(0b00110000); // D7=0, D6=0, D5=1, D4=1, RS,RW=0 EN=0 usleep(4100); // wait 4.1msec i2c_send_byte(0b00110100); // i2c_send_byte(0b00110000); // same usleep(100); // wait 100usec i2c_send_byte(0b00110100); // i2c_send_byte(0b00110000); // 8-bit mode init complete usleep(4100); // wait 4.1msec i2c_send_byte(0b00100100); // i2c_send_byte(0b00100000); // switched now to 4-bit mode /* -------------------------------------------------------------------- * * 4-bit mode initialization complete. Now configuring the function set * * -------------------------------------------------------------------- */ usleep(40); // wait 40usec i2c_send_byte(0b00100100); // i2c_send_byte(0b00100000); // keep 4-bit mode i2c_send_byte(0b10000100); // i2c_send_byte(0b10000000); // D3=2lines, D2=char5x8 /* -------------------------------------------------------------------- * * Next turn display off * * -------------------------------------------------------------------- */ usleep(40); // wait 40usec i2c_send_byte(0b00000100); // i2c_send_byte(0b00000000); // D7-D4=0 i2c_send_byte(0b10000100); // i2c_send_byte(0b10000000); // D3=1 D2=display_off, D1=cursor_off, D0=cursor_blink /* -------------------------------------------------------------------- * * Display clear, cursor home * * -------------------------------------------------------------------- */ usleep(40); // wait 40usec i2c_send_byte(0b00000100); // i2c_send_byte(0b00000000); // D7-D4=0 i2c_send_byte(0b00010100); // i2c_send_byte(0b00010000); // D0=display_clear /* -------------------------------------------------------------------- * * Set cursor direction * * -------------------------------------------------------------------- */ usleep(40); // wait 40usec i2c_send_byte(0b00000100); // i2c_send_byte(0b00000000); // D7-D4=0 i2c_send_byte(0b01100100); // i2c_send_byte(0b01100000); // print left to right /* -------------------------------------------------------------------- * * Turn on the display * * -------------------------------------------------------------------- */ usleep(40); // wait 40usec i2c_send_byte(0b00000100); // i2c_send_byte(0b00000000); // D7-D4=0 i2c_send_byte(0b11100100); // i2c_send_byte(0b11100000); // D3=1 D2=display_on, D1=cursor_on, D0=cursor_blink if(debug) printf("Init End.\n"); sleep(1); if(debug) printf("Writing HELLO to display\n"); if(debug) printf("D7 D6 D5 D4 BL EN RW RS\n"); /* -------------------------------------------------------------------- * * Start writing 'H' 'E' 'L' 'L' 'O' chars to the display, with BL=on. * * -------------------------------------------------------------------- */ i2c_send_byte(0b01001101); // i2c_send_byte(0b01001001); // send 0100=4 i2c_send_byte(0b10001101); // i2c_send_byte(0b10001001); // send 1000=8 = 0x48 ='H' i2c_send_byte(0b01001101); // i2c_send_byte(0b01001001); // send 0100=4 i2c_send_byte(0b01011101); // i2c_send_byte(0b01011001); // send 0101=1 = 0x41 ='E' i2c_send_byte(0b01001101); // i2c_send_byte(0b01001001); // send 0100=4 i2c_send_byte(0b11001101); // i2c_send_byte(0b11001001); // send 1100=12 = 0x4D ='L' i2c_send_byte(0b01001101); // i2c_send_byte(0b01001001); // send 0100=4 i2c_send_byte(0b11001101); // i2c_send_byte(0b11001001); // send 1100=12 = 0x4D ='L' i2c_send_byte(0b01001101); // i2c_send_byte(0b01001001); // send 0100=4 i2c_send_byte(0b11111101); // i2c_send_byte(0b11111001); // send 1111=15 = 0x4F ='O' if(debug) printf("Finished writing to display.\n"); i2c_stop(); }
tfmini.c
This program will talk to an I2C enabled TFmini LIDAR distance sensor.
/* ----------------------------------------------------------------------- * * Title: tfmini.c * * Description: C-code for TFMini Plus * * Tested on BeagleBone AI * * 11/6/2019 Sean J. Miller * * Prerequisites: * *------------------------------------------------------------------------ */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> #define I2C_BUS "/dev/i2c-3" // I2C bus device #define I2C_ADDR 0x10 // I2C slave address for the TFMini module int debug; int i2cFile; void i2c_start() { if((i2cFile = open(I2C_BUS, O_RDWR)) < 0) { printf("Error failed to open I2C bus [%s].\n", I2C_BUS); exit(-1); } else { if (debug)printf("Opened I2C Bus\n"); } // set the I2C slave address for all subsequent I2C device transfers if (ioctl(i2cFile, I2C_SLAVE, I2C_ADDR) < 0) { printf("Error failed to set I2C address [%s].\n", I2C_ADDR); exit(-1); } else { printf("Set Slave Address\n"); } } void i2c_stop() { close(i2cFile); } float readDistance() { //Routine to output the distance to the console int distance = 0; //distance int strength = 0; // signal strength int rangeType = 0; //range scale unsigned char incoming[7]; //an array of bytes to hold the returned data from the TFMini. unsigned char cmdBuffer[] = { 0x01, 0x02, 7 }; //the bytes to send the request of distance write( i2cFile, cmdBuffer, 3 ); usleep(100000); read(i2cFile, incoming, 7); for (int x = 0; x < 7; x++) { if (x == 0) { //Trigger done if (incoming[x] == 0x00) { } else if (incoming[x] == 0x01) { } } else if (x == 2) distance = incoming[x]; //LSB of the distance value "Dist_L" else if (x == 3) distance |= incoming[x] << 8; //MSB of the distance value "Dist_H" else if (x == 4) strength = incoming[x]; //LSB of signal strength value else if (x == 5) strength |= incoming[x] << 8; //MSB of signal strength value else if (x == 6) rangeType = incoming[x]; //range scale } float the_return = distance / (12 * 2.54); //convert to feet. return the_return; } void main() { i2c_start(); debug=1; //change to 1 to see messages. if(debug) printf("Init Start:\n"); float my_distance = readDistance(); if(debug) printf("the_distance: %f\n",my_distance); if(debug) printf("Finished reading.\n"); i2c_stop(); if(debug) printf("Finshed, Sean!\n\n"); }
pwmout.c
a program that will swell an LED on P9.14 using PWM
//////////////////////////////////////// // pwmout.c // generates pwm on a pin to glow an LED // Author: Sean J. Miller // Wiring: Jumper P9.14 to an LED through a 220ohm resistor to ground // // See: https://www.element14.com/community/community/designcenter/single-board-computers/next-genbeaglebone/blog/2019/10/27/beagleboard-ai-brick-recovery-procedure //////////////////////////////////////// #include <stdio.h> #include <unistd.h> void setupPWM() { FILE *period, *pwm; pwm = fopen("/sys/class/pwm/pwm-0:0/enable", "w"); fseek(pwm,0,SEEK_SET); fprintf(pwm,"%d",1); fflush(pwm); fclose(pwm); printf("Period...!\n"); period = fopen("/sys/class/pwm/pwm-0:0/period", "w"); fseek(period,0,SEEK_SET); fprintf(period,"%d",2500); fflush(period); fclose(period); } void pwm_duty(int the_duty_multiplier) { FILE *duty; duty = fopen("/sys/class/pwm/pwm-0:0/duty_cycle", "w"); fseek(duty,0,SEEK_SET); fprintf(duty,"%d",100*the_duty_multiplier); fflush(duty); fclose(duty); } int main() { int ii=0;int up=0; printf("Setting up\n"); setupPWM(); while(1) { printf("Swelling LED %d\n",ii); if (up==1) ii++; else ii--; if ((ii)>60) { up=0; } if (ii<3) { up=1; } pwm_duty(ii); usleep(25000); } }
servoPot.c
reads a potentiometer and translates it to a servo's position
//////////////////////////////////////// // servoPot.c // reads a pot and translates it to // a servos position. // Author: Sean J. Miller, 11/3/2019 // Wiring: Jumper P9.14 to a servo signal through a 220ohm resistor // Hook a potentiometers variable voltage to P9.33 (analog in). It's source should be Pin 32 (VDADC of 1.8V) // See: https://www.element14.com/community/community/designcenter/single-board-computers/next-genbeaglebone/blog/2019/10/27/beagleboard-ai-brick-recovery-procedure //////////////////////////////////////// #include <stdio.h> #include <unistd.h> int analogRead(){ int i; FILE * my_in_pin = fopen("/sys/bus/iio/devices/iio:device0/in_voltage7_raw", "r");//P9.33 on the BBAI char the_voltage[5];//the characters in the file are 0 to 4095 fgets(the_voltage,6,my_in_pin); fclose(my_in_pin); printf("Voltage: %s\n", the_voltage); sscanf(the_voltage, "%d", &i); return (i); } void setupPWM() { FILE *period, *pwm; pwm = fopen("/sys/class/pwm/pwm-0:0/enable", "w"); fseek(pwm,0,SEEK_SET); fprintf(pwm,"%d",1); fflush(pwm); fclose(pwm); period = fopen("/sys/class/pwm/pwm-0:0/period", "w"); fseek(period,0,SEEK_SET); fprintf(period,"%d",20000000);//20ms fflush(period); fclose(period); } void pwm_duty(int the_duty_multiplier) { FILE *duty; int duty_calc; duty = fopen("/sys/class/pwm/pwm-0:0/duty_cycle", "w"); fseek(duty,0,SEEK_SET); duty_calc=(600000 + (1700000*(float)((float)the_duty_multiplier/4095))) ; printf("Duty: %d\n", duty_calc);//1ms fprintf(duty,"%d",duty_calc);//1ms fflush(duty); fclose(duty); } int main() { int ii=0; printf("Setting up\n"); setupPWM(); while(1) { ii=analogRead(); pwm_duty(ii); usleep(20000); } }
HARDWARE
Peripherals
Below are the hardware components that will help you get the most out of the board:
3 Pin Serial Debug Connector3 Pin Serial Debug Connector - probably don't need it, but its an alternative to using WiFi for "headless" interaction with the BBAI.
Pins for 3 Pin Serial Debug ConnectorPins for 3 Pin Serial Debug Connector - probably don't need it, but its an alternative to using WiFi for "headless" interaction with the BBAI.
3A USB C Power Plug3A USB C Power Plug - the BBAI needs at least 2.5 As to stay stable
Cooling FanCooling Fan - needed to prevent overheating and sporadic shutdown
Cooling Fan Machine Screws Size: M3
$9 Web Cam - great little cheap web cam for your Visual AI projects
USB to Audio Cable - enables audio
USB 4 Port HubUSB 4 Port Hub - allows to connect audio and multiple web cams at same time.
Board Connector Original Images From the System Manual
Power and Ground Pins
DGND: this is the digital ground to connect any digital devices
GNDA_ADC: this is the analog ground used to connect any devices that return an analog signal such as a potentiometer
VDD_3V3 - use this to power 3.3v electronics
VDD_5V - use this to power the beagleboard (i.e. through a barrel jack, if you are going to put one on the cape/shield), NOT to power 5V electronics
SYS_5V - use this to power 5V electronics
VDD_ADC - use to connect power analog in devices such as Potentiometers. (It is 1.8V for backwards compatibility as discussed in the Analog Input section.)
BeagleBone Black Pin Reference:
It's pretty much the same, but things are not setup out of the box for use.
See the PinMux Procedure Section above.
Hardware Good Stuff to Know
PWR_BUT is 3.3V level as pulled up internally by the TPS6590379. It is activated by pulling the signal to GND. It won't do a soft Power Off like the BB Black did, but it will turn it on after a shutdown command.
- GPIO max current is still a mystery. I couldn't find it on the ARM 572 Sitara docs, yet. Some BBB tutorials stated a 8mA limit - which seems safe compared to other microcontrollers. So, I use a transistor as a switch to handle the load of any components that are doing anything but high impedance signal communication. For example, LEDs, Piezos, and DC motors should be transistor switched. Between the GPIO and transistor I use a 420 ohm current limiting resistor to keep the current under 8ma according to ohm's law.
AI VISION WITH TIDL
What is TIDL
At this point, I am just enough to be dangerous with making use of the TIDL acceleration of the BBAI through the modification of the classification.cpp example. As I learn, I'll add to this section what I gather. Let's begin...
The TI Deep Learning (TIDL) API allows for embedded devices to use TI’s proprietary, highly optimized neural implementation on the EVE and C66x DSP compute engines. This means you can get frame fast classification of your trained objects for your exact application - whether it be detecting abnormalities in microscope images of cells or assessing if you left the oven on.
The TIDL API leverages TI’s OpenCL product to offload deep learning applications to both EVEs and DSPs. This allows us to not fool with the mechanics of Arm DSP/EVE communication and implementing optimized network layers on EVE(s) and/or DSP(s). We can use OpenCV and rapidly code deep learning applications.
One thing to note, if you are not using the TIDL API for your Vision AI apps, such as by porting over Raspberry Pi OpenCV code, then you are not using the accelerated TIDL hardware. You're not gaining a thing.
Here is the development workflow for TIDL apps:
Panels 1 and 2 are the mystery for me now. Unfortunately, TI's link is presently broken on how to do those steps:
TIDL Utils
From a tip from @mander1, there appears to be utilities for importing tensorflow models available. I'm still trying to figure it out, but here is how you get it:
git clone https://git.ti.com/git/tidl/tidl-utils.git
This readme.txt states how to set up your environment variables in Linux: /tidl/tidl-utils/src/importTool/readme.txt
You can then type "make" in the following directory to compile the import tool:
/tidl/tidl-utils/src/importTool/modules/ti_dl/utils/tidlModelImport
More to come on this hopeful way of getting trained models available to the TIDL API.
More TIDL Examples
After installing the TIDL examples per the checklist at the beginning of this blog, you'll find more TIDL examples tucked away than what shows in Cloud9. You can them locate with the following:
cd /usr/share/ti/examples/tidl
ls
I found that I had to use sudo to run the examples. A full description of the examples can be found here:
Examples — TIDL API User's Guide
When running the examples, you may run into an error shown below. There is a utility you can run that will free up the heap to correct it. Below shows me working through this experience:
debian@beaglebone:/usr/share/ti/examples/tidl/two_eo_per_frame$ sudo ./two_eo_per_frame two_eo_per_frame: inc/executor.h:172: T* tidl::malloc_ddr(size_t) [with T = char; size_t = unsigned int]: Assertion `val != nullptr' failed. debian@beaglebone:/usr/share/ti/examples/tidl/two_eo_per_frame$ ti-mct-heap-check -c -- ddr_heap1 ------------------------------ Addr : 0xa2000000 Size : 0x16000000 Avail: 0x16000000 Align: 0x80 ----------------------------------------- debian@beaglebone:/usr/share/ti/examples/tidl/two_eo_per_frame$ sudo ./two_eo_per_frame PASSED
TIDL API
Texas instruments provides a good high level overview and the terminology of the TIDL API here:
Overview — TIDL API User's Guide
One good thing, there are only 4 C++ classes to learn: Configuration
, Executor
, ExecutionObject
, and ExecutionObjectPipeline
. In turn, you can tell code a mile away that doesn't make use of the hardware if you don't see the header files for them at the start of the code.
TI Software-I'm just scouting this one, but I think it might get us to generating trained images for the BBAI.
PROCESSOR-SDK-TDAX Processor SDK for TDAx ADAS SoCs - Linux and TI-RTOS Support | TI.com
.NET 5 CORE INSTALLATION
If you like to code in C# with .Net, you can install dotnet for Linux. The actual installation of the dotnet binaries is easy and quick. I made an Instructable here on how to do it as well as set up a .Net 5 Core web server with your BBAI:
https://www.instructables.com/Build-a-Very-Cheap-Net-5-Core-Web-Server-With-Beag/
REFERENCES
- https://github.com/beagleboard - Main BB github repository
- BeagleBoard.org - latest-images - Latest Debian Images
- https://github.com/beagleboard/bb.org-overlays - BeagleBone Kernel References
- https://www.hackster.io/175809/tidl-on-beaglebone-ai-1ee263#toc-make-sure-the-tidl-library-and-examples-are-installed-2 - Vision AI example
- https://www.elinux.org/EBC_Exercise_41_Pin_Muxing_for_the_AI - shows how to set up pins on board, but always bricks mine!
- https://groups.google.com/forum/embed/?place=forum/beagleboard&showsearch=true&showpopout=true&showtabs=false&hideforumt… - BeagleBone Forum
- https://training.ti.com/texas-instruments-deep-learning-tidl-overview - How to train the vision AI for the BBAI's Texas Instruments chipset
- http://BeagleBoard.org/chat - live chat with the board creators
- https://github.com/jadonk/bonescript - BoneScript API
- https://docs.google.com/spreadsheets/d/1fE-AsDZvJ-bBwzNBj1_sPDrutvEvsmARqFwvbw_HkrE/edit?usp=sharing- spreadsheet showing pin IDs and other useful info for pinmux configuration.
- Accessing GPIO and PWM on BeagleBone AI - e14 Discussion that is trying to sort out GPIO use for the BBAI
- https://github.com/beagleboard/cloud9-examples/issues/18 - issue created on beagleboard github on cloud9 examples not working
- https://github.com/adafruit/adafruit-beaglebone-io-python/issues/317 - Adafruit Github Issue created concerning python examples not working
- https://github.com/mvduin/bbb-pin-utils/tree/bbai-experimental#show-pins - a good utility for viewing pin configuration of your board.
- https://cdn-learn.adafruit.com/downloads/pdf/introduction-to-the-beaglebone-black-device-tree.pdf - all about device tree source files.
- BBAI Seein' Around Corners, Talkin', IoT Exploitin' Backup Car Cam with Onboard Vision AI - example BBAI project
- Instructables - Build a Very Cheap .Net 5 Core Web Server with a BBAI - .Net 5 Core Instructables
- https://www.youtube.com/channel/UCXAfHSB_IhaKhntZ4bWfmbw - my youtube channel of projects.
- https://github.com/beagleboard/beaglebone-ai/wiki/System-Reference-Manual- the under development reference manual on GitHub.
- BeagleBone AI BB-AI Photos for Documentation Purposes - excellent share by shabaz.
- https://blogs.nvidia.com/blog/2016/07/29/whats-difference-artificial-intelligence-machine-learning-deep-learning-ai/- great article on the history of AI, Machine Learning, and Deep Learning
- A Beginning Journey in TensorFlow #1: Regression
- Introduction — TIDL API User's Guide
SURVIVAL GUIDE CHANGE LOG
05/29/2921: V3.18 Added link to how to install .Net Core 5 and a .Net webserver
05/28/2021: V3.17 Update link for the current image and listed default passwords. Wishing I had a nickel for every time I bricked it.
06/28/2020: V3.16 updated the Power and Ground pins to reflect the V3.14 learning on analog pins.
06/02/2020: V3.15 corrected info on the returned output from the show-pins utility.
04/29/2020: V3.14 confirmed that 3.3V is acceptable for analog in versus just 1.8V. Credit to Fred Bogardus for the confirmation!
01/03/2020: V3.13 added how to get and compile the tidl utilities for importing models. Added how to have Cloud9 show directories at the root and beyond.
12/15/2019: V3.12 added more file transferring techniques using Cloud9, Github, and wget
11/19/2019: V3.11 added Creating a RAM Disk Section
11/18/2019: V3.10 added Exploring AI Vision with TIDL section
11/17/2019: V3.9 added a cd at Pinmux procedure to change the directory for the make statement to work
11/16/2019: V3.8 added more general definitions throughout to eliminate assumptions of experience level
11/13/2019: V3.7 added Sharing Files with a Window PC
11/13/2019: V3.6 added Audio section and linked a webcam under $10 and a cheap USB-to-Audio cable in the Hardware section.
11/09/2019: V3.5 added pinout picture under hardware and warnings that the ADC is 1.8Vs which can be supplied by pin P9.32.
11/09/2019: V3.4 added board images for pin reference in Hardware section as well as hardware good stuff to know. Also, gave link to system manual
11/07/2019: V3.3 added Hardware Add-ons Section
11/06/2019: V3.2 added TFMini.c. It shows how to read and write on I2C using a TFMini module.
11/03/2019: V3.1 added servoPot.c code example. It takes analog in from a potentiometer and translates it to a servo's position allowing you to control the servo with the potentiometer.
11/02/2019: V3.0 added PWM section and pwmout.c code - all pin features are now achieved!!!!!! Added Good Stuff to Know Section that sheds a lot of light on things.
11/02/2019: V2.4 added analogIn.c example for reading analog in.
11/02/2019: V2.3 added Analog Input Section
11/01/2019: V2.2 added i2clcd.c code to demonstrate using I2C on bus 3
11/01/2019: V2.1 added I2C section
10/31/2019: V2.0 added Pinmuxing Section to show how to setup pins and added Matt Van Duin's show-pins utility to setup. Move classification tweak to new Code Examples section.
10/31/2019: V1.2 added augmented blinkLED.js code to demonstrate using digital read/write.
10/27/2019: V1.1 added node -pe "require('bonescript').bone.getPinObject('p9.15').ai.gpio" to step 10. It's needed to setup the pin for use.
10/27/2019: V1.0 Published
Top Comments