TABLE OF CONTENTS

BBAI

 

**NEEDED CONTENT:  THE ONLY THING LEFT - WE NEED TO KNOW HOW TO TRAIN IMAGES FOR THE CLASSIFICATION.CPP FILE. 

COMMENT IF YOU HAVE MOJO!!!!****

INTRODUCTION

This is a companion blog to my Project14 Vision Thing contest entry:  BBAI Seein' Around Corners, Talkin', IoT Exploitin' Backup Car Cam with Onboard Vision AI

 

When I started the project in October, I found that the BeagleBone AI (BBAI) software is presently in an early - what I'd call - community development state.  It requires a certain combination of a kernel version, code tweaks, and trial and error pin settings to get the traditional 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 were still developed for the past architectures.  So, to get my project off the ground, I had to derail for a couple of weeks to hit the forums, chat rooms, and chip manufacturer datasheets to get its GPIO working.  It was clear there was an absence of info and BBAI experience across the web, so I converted my notes and hours of research to web memory here in hopes to eliminate frustration by the rest of the gang here on e14.

 

After I did all the steps in the checklist below and the Pinmux Procedure, I did a shutdown and burned an image of it so I can recover faster from future bricks.  Also, way below are some key references to keep your eye on as the AI develops.  Last, for document versioning, 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

 

  1. Download the latest image - be sure it is for BeagleBone AI:
    https://beagleboard.org/latest-images
    https://debian.beagleboard.org/images/am57xx-debian-9.9-lxqt-armhf-2019-08-03-4gb.img.xz
  2. 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
  3. Put the card in BBAI, power it, connect PC to it using wifi SSID BeagleBoneXXXX, and connect to Cloud9 by navigating to 192.168.8.1.
  4. Follow on screen instructions in cloud9 to connect BBAI to your home wifi summarized here:
    sudo connmanctl⏎
    scan wifi⏎  (wait for response)
    services⏎ (copy the long string representing your wifi)
    agent on⏎
    connect <paste your string>
    quit⏎
  5. Get the max storage capacity out of your SD Card:
    sudo /opt/scripts/tools/grow_partition.sh
    sudo reboot
  6. 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)
  7. Get latest updates:
    sudo apt update⏎
    sudo apt upgrade⏎
  8. Download the MPGStreamer for use with embedded vision projects
    sudo apt install -y ti-tidl mjpg-streamer-opencv-python
  9. Install Jason Kridner's perl package to show BeagleBone AI Pins (see useful commands below):
    sudo apt install libinline-files-perl
  10. 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
  11. 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)
  12. 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
  13. 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 sees 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.
  • 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".
  • 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 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 not yet correct as of 10/31/2019.  For example, P9.15 is actually 76, not 69.

 

debian@beaglebone:~$ 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).  If you have an external source in your circuit, be sure to get it down to 1.8Vs with a voltage divider.  However, I did test 3.3V on the analog in pins and it gave a stable 4095 as the return value.  I suspect that it is ranged to 3.3V, but I did find any docs to prove it, so stay at 1.8V.

 

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.

 

SHARING FILES WITH A WINDOWS PC

There will be a time you will want to access a Windows PC on your network to easily share a file.  Most commonly, this would be sound or image files, but maybe even some code.  To do so, 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

Warning:  Analog in is only 1.8V tolerant!!!*  Use the VDD_AADC as the reference voltage instead of 3.3V

*Note:  I'm going on hearsay on the 1.8V tolerant thing.  I tested 3.3V and it went to 0-4095 without issue, where 1.8V returned about half that.  But, since pin 32 puts out 1.8V as the ADC voltage, I'm going to stay using it as my analog reference voltage source until I hear otherwise.

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!!!!)

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:

TIDL Development Workflow

Panels 1 and 2 are the mystery for me now.  Unfortunately, TI's link is presently broken on how to do those steps:

http://software-dl.ti.com/processor-sdk-linux/esd/docs/latest/linux/Foundational_Components_TIDL.html

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

 

 

REFERENCES

 

ACKNOWLEDGEMENTS

  • Thanks to @zMatt (on BB chat), BB-AI/Sphere (Clem), Jason Kridner, Clem Meyers, shabaz for the picture, my cat Tank (aka ping-pong-ball to the BBAI), and Jon Morss for their leads, tips, and troubleshooting help so far.

 

 

SURVIVAL GUIDE CHANGE LOG

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