BeagleBone

SBC (Single/Small Board Computer)

The BeagleBone (BB) [1] line supports the Linux kernel and GPIO hardware connections to devices via device trees [2]. It is simular to the Rasberry-PI line, only BB is open source hardware.

They run a full featured Debian distribution, capable of running C, C++, Rust, Python and node-js, all the way up to a PostgreSQL database. It comes with a web-based IDE called Cloud-9 [3] that can also run node-js programs on the BB. The AI line also supplies image recognition packages.

You can connect a display, keyboard and mouse, or run it headless.

All have USB connectors to ssh into from a connected computer, most have wired Ethernet RJ-45 sockets, and some have Bluetooth and WiFi. Controlling relays, lights, I2C sensors, and open switches can be done in most any supported language, even bash.

For robotics, they feature a Programmable real-time unit and industrial communications subsystem (PRU-ICSS) [4].

The forum for questions is here: https://forum.beagleboard.org/

For example:


  • BBB (Black) https://www.beagleboard.org/boards/beaglebone-black
  • beagle-black-wired-shadow_no5v-1-400x400.png
    • This runs very capabily:
      • Music Player Daemon (MDP) [5]. You can control what is played on the command line or through a Phone App.
      • Control lights and relays. You can use the Python based Flask [6] package to create nice looking web apps for this.

  • BBAI (AI 32-bit, arm71) https://www.beagleboard.org/boards/beaglebone-ai
  • beagleboane-ai-heatsink-500x356.png
    • Applications I used with this include:
      • NextCloud server (little slow).
      • Mini-Network Access Storage (NAS) with mirrored SSDs (mdadm).
      • HomeAssistant home automation (without cameras).


  • BeaglePlay is the latest offering (https://www.beagleboard.org/boards/beagleplay)
  • BeaglePlay-front-500x281.jpg
    • Quad Arm® Cortex®-A53 microprocessor subsystem @ 1.4GHz
    • Arm® Cortex®-M4F @ 400MHz
    • Dual-core PRU subsystem @ 333MHz
    • PowerVR® Rogue™ GPU

Features

  • Small 8cm x 8cm form-factor
  • 2GB RAM and 16GB on-board eMMC flash with high-speed interface
  • USB type-C for power and data and USB type-A host
  • Gigabit Ethernet, Single-pair Ethernet with PoDL
  • Integrated 2.4GHz and 5GHz WiFi
  • 2.4GHz and Sub-GHz programmable wireless MCU, integrated IEEE802.15.4 drivers/firmware
  • Full-size HDMI, OLDI, 4-lane CSI
  • Expansion via mikroBUS, Grove, QWIIC
  • Zero-download out-of-box software experience with Debian GNU/Linux

  1. https://www.beagleboard.org/
  2. https://www.beagleboard.org/blog/2022-03-31-device-tree-supporting-similar-boards-the-beaglebone-example
  3. https://github.com/c9
  4. https://beagleboard.org/pru
  5. https://www.musicpd.org/
  6. https://flask.palletsprojects.com/en/2.2.x/

Serial Debug Connection

You can get through severe boot errors where the network is not connecting or disk partition not mounted, using a USB to TTL-232 cable [1], also called FTDI. This will show all the boot messages and allow login, even recovery if the kernel will not boot.

Make sure it is 3.3 volt! Connect the black wire to pin 1, orange/green to pin 4, yellow/white to pin5 directly on the SBC board.

1 AU51n75Ls0JwfPeYMD6sIQ-547387362.png

  • USB to TTL cable
  1. https://www.adafruit.com/product/4331.

28W2088-40.webp

BBAI-64 Adapter

The BBAI-64 has a 3-pin connector so it needs an adapter; Micro JST MX 1.25 4Pins Connector Plug Socket 1.25mm Pitch Female Connector PCB Socket 150mm Cable. The red wire is not used. Plug the other three wires into the USB/TTL adapter above, matching colors.

Screen Shot 2022-10-22 at 9.18.32 AM.png

Screen on Linux

When you have connected USB-end of the serial cable to a Linux based system like Ubuntu, a new tty* device appears in the system. Note down its name. In my case, it was /dev/ttyUSB0. Open a term and issue below command

$ sudo screen /dev/ttyUSB0 115200

Do ls /dev/ before and after connecting cable to find the new device name

You may have to reboot the PC and BB after connection to clear garbled characters.

Recover from lost root password

Flash a new mini-sd card and boot off of it, then:

  1. Mount the eMMC flash:  mount /dev/mmcblk1p2 /media/card
  2. Change the root of the file system to be the partition on the eMMC flash which you just mounted: chroot /media/card
  3. Change the password of the root user to something you know: passwd root
  4. Exit out of the changed root: exit
  5. Shutdown the BeagleBone Black : shutdown -h now
  6. Disconnect the power from the board
  7. Eject the microSD card.
  8. Reconnect the power to the board
  9. Watch the board boot up, and log in as root. You should be able to log in with the password that you just set.

Flash new Operating System

Latest software: https://www.beagleboard.org/distros

Flashing refers to the process of transferring the Operating System image from a Micro-SD card to the on-board mmc memory disk.

WARNING: It will overlay the contents of your BBB soldered in mmc memory.

Be aware that the on-board mmc is only 15GB, so flashing an SD card with a partition larger than 15GB will fail with out of space.

Boot Order

The BB-AI 32-bit has a different disk device naming convention than 64-bit ;-)

BBAI-32 /dev/mmcblk0p1 = Micro-SD; /dev/mmcblk1p1 = On-board mmc

$ sudo inxi -D
Drives:    Local Storage: total: 1005.80 GiB used: 338.77 GiB (33.7%) 
           ID-1: /dev/mmcblk0 model: BC1S5 size: 59.69 GiB 
           ID-2: /dev/mmcblk1 model: TB2916 size: 14.60 GiB 
...

See how cleverly the number 0 uses the natural Linux boot ordering.

BBAI-64 /dev/mmcblk1p1 = Micro-SD; /dev/mmcblk0p1 = On-board mmc

$ sudo inxi -D
Drives:    Local Storage: total: raw: 1.92 TiB usable: 1.01 TiB used: 156.93 GiB (15.2%) 
           ID-1: /dev/mmcblk0 vendor: Kingston model: TB2916 size: 14.6 GiB 
           ID-2: /dev/mmcblk1 model: BC1S5 size: 59.69 GiB 
...
BB-AI 64-bit uses a new approach, extlinux.conf [1], that will probably be the standard going forward [2].

Here it is set to boot from mmcblk1p2.

File: /boot/firmware/extlinux/extlinux.conf

label Linux microSD
    kernel /Image
    fdt /k3-j721e-beagleboneai64-no-shared-mem.dtb
    append console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0
    fdtdir /
    initrd /initrd.img

On the BBAI-64, by default we are using U-Boot’s now (finally) standard extlinux.conf, you’ll find it in the first fat partition of either the eMMC or microSD… (I have a long term goal to convert our custom “am335x/am57xx” uEnv.txt solution to extlinux.conf…) [2]

Reference:

  1. https://wiki.syslinux.org/wiki/index.php?title=EXTLINUX
  2. https://forum.beagleboard.org/t/bbai-64-boot-order/33129

Enable Flashing

BBAI-32: Flash

  • For example, download and burn a Micro-SD card, BBAI (32-bit) flasher: https://www.beagleboard.org/distros

    • Burn the download file to a Micro-SD, normally using Etcher https://etcher.balena.io

    • Turn off the BBB, insert the SD card and apply power.

    • This will copy the boot files on top of the mmc on-board disk,

If you start with the non-flasher and verify that it will boot, THEN edit the

/boot/uEnv.txt 

file to activate (un-comment) the flasher script (last line in the file) and reboot the device to flash it.

File: /boot/uEnv.txt

##enable Generic eMMC Flasher:
cmdline=init=/usr/sbin/init-beagle-flasher

BBAI-64: Flash

* To flash a microSD to eMMC:

Run:

sudo apt update ; sudo apt upgrade
sudo beagle-flasher

Or to create a dedicated flasher:

sudo apt update ; sudo apt upgrade
sudo enable-beagle-flasher
sudo reboot

Reference: https://forum.beagleboard.org/t/ai-64-how-to-flash-emmc/32384/2

Flashing Process

You will see the lights doing a bouncing flash; 1,2,3,4 - 4,3,2,1 - etc… for several minutes, eventually it will turn itself off. Then pop out the SD card and re-apply power to boot up the newly flashed on-board mmc.

Disable Flashing

After booting the newly flashed on-board mmc;

BB-AI 32-Bit

  1. mount the SD card:
sudo mount /dev/mmcblk0p1 /media/card
  1. Comment out the ‘flashing’ line in uEnv.txt like this:
$ tail /media/card/boot/uEnv.txt 
...
##enable Generic eMMC Flasher:
#cmdline=init=/usr/sbin/init-beagle-flasher
  1. It is now safe to boot off the SD card! Push it back in and it will be selected during the boot process, before the mmc.

I usually boot onto the Micro-SD and run that way. If it fails you can always remove it and still have a bootable environment.

BB-AI 64-Bit

Disable a dedicated flasher, download the latest non-flasher and re-burn the Micro-SD card.

To Check, mount it on a PC and look at directory :

File: <mount point>/boot/firmware/extlinux/extlinux.conf

...
    append console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0
...

Above shows a normal boot file. A flasher will point to a beagle-flasher image to boot onto.

Duplicate Micro-SD card

It is a good idea to backup the active Micro0SD card after all your hard work. Re-imaging and installing all the packages is a pain!

This process will copy everything on the SD card, even blank data. So a 64GB card will make a 64GB img file. Your destination card must be at least as big as the original.

Insert the original SD card and check the name of the device (usually mmcblkX or sdcX):

$ sudo lsblkid -a
...
mmcblk0     179:0    0  59.7G  0 disk  
├─mmcblk0p1 179:1    0   128M  0 part  /media/don/BOOT
└─mmcblk0p2 179:2    0  59.6G  0 part  /media/don/rootfs
$ sudo fdisk -l
...
Device         Boot   Start      End  Sectors  Size Id Type
/dev/mmcblk0p1 *       2048  2099199  2097152    1G  c W95 FAT32 (LBA)
/dev/mmcblk0p2      2099200 31116287 29017088 13.9G 83 Linux

In my case the SD card is /dev/mmcblk0 (the *p1 and *p2 are the partitions).

You have to unmount the devices:

$ sudo umount /dev/mmcblk0p1
$ sudo umount /dev/mmcblk0p2

To create an image of the device:

$ sudo dd if=/dev/mmcblk0 of=~/sd-card-copy.img bs=4M status=progress

This will take a while.

Once it's finished, insert the empty SD card. If the device is different (USB or other type of SD card reader) verify its name and be sure to unmount it:

$ sudo fdisk -l
$ sudo umount /dev/mmcblk0p1
$ sudo umount /dev/mmcblk0p2

Write the image to the device:

$ sudo dd if=~/sd-card-copy.img of=/dev/mmcblk0 bs=4M status=progress

The write operation is much slower than before.

Update Software

Update examples in the Cloud9 IDE workspace

cd /var/lib/cloud9
git pull
...
Update the boot-up scripts and Linux kernel

cd /opt/scripts
git pull

Update Kernel

cd /opt/scripts
sudo tools/update_kernel.sh

Expand SD filesystem

Sometimes when you burn an .iso image to the SD card and boot up the BB, the filesystem will be 4GB while your SD card could be 32GB.

This script will expand the filesystem after your first boot up onto it.

$ sudo /opt/scripts/tools/grow_partition.sh
  • If the script is not available, use this:

Examine the partitioning on your external SD card:

$ sudo fdisk /dev/mmcblk0

Then enter 'p', An important value to note is the start sector of the Linux partition, enter 'd' to delete the Linux partition. (If you have two partitions it will ask which partition to delete, which should be 2.).

Enter 'n' to create a new partition. For the first two questions (partition type and number) just press enter. For the start sector, be absolutely sure to use the same number it had originally. For the last sector, you can use whatever you want in case you don't want to use your whole micro SD, but you can just hit enter to use the default (the max size possible).

If you are satisfied with your changes at this point you can enter 'w' to commit to your changes.

A warning above will appear if you're repartitioning the disk you've booted from. In that case, reboot your system

Lastly, after your BeagleBone Black reboots, you need to expand the file system. Before expanding you need to run fsck as root, otherwise next command will fail to run:

$ sudo fsck /dev/mmcblk0p1

Finally, run the following command (again as root):

$ sudo resize2fs /dev/mmcblk0p1

Once this command completes, you're done!

Reference:

Disable cloud9 development platform

This allows over the web programming on the system, which is a security risk if not being used.

Disable:

systemctl disable cloud9.service
systemctl disable bonescript.service
systemctl disable bonescript.socket
systemctl disable bonescript-autorun.service

Example of service file

debian@pocketbeagle:~$ cat /lib/systemd/system/cloud9.service 
[Unit] 
Description=Cloud9 IDE 
ConditionPathExists=|/var/lib/cloud9 

[Service] 
WorkingDirectory=/opt/cloud9/build/standalonebuild 
EnvironmentFile=/etc/default/cloud9 
ExecStartPre=/opt/cloud9/cloud9-symlink 
ExecStart=/usr/bin/nodejs server.js --packed -w /var/lib/cloud9 SyslogIdentifier=cloud9ide 
User=1000 

bb-bbai-tether system

This is used to connect your device/PC to => BB-AI and BBB over WiFi.

BBAI-64 uses systemd-networkd [1] (files: /etc/systemd/network/*)

Config file: /etc/default/bb-wl18xx

# TETHER_ENABLED: Whether or not to run the /usr/bin/bb-wl18xx-tether daemon; set to no to disable.
#TETHER_ENABLED=yes
TETHER_ENABLED=no

# USE_CONNMAN_TETHER: Whether or not to just use connman tether inteface; set to no to disable.
USE_CONNMAN_TETHER=no

# USE_WL18XX_IP_PREFIX: default IP block of SoftAP0 interface
USE_WL18XX_IP_PREFIX="192.168.18"

# USE_INTERNAL_WL18XX_MAC_ADDRESS: use internal mac address; set to no to disable.
USE_INTERNAL_WL18XX_MAC_ADDRESS=yes

# USE_WL18XX_MAC_ADDRESS: use custom mac address, for when work wifi starts sending deauthentication packet spam.
#USE_WL18XX_MAC_ADDRESS="AB:10:23:C:16:78"

# USE_WL18XX_POWER_MANAGMENT: (sudo iwconfig wlan0 power [on/off]). on = boot default, off is more reliable for accessing idle systems over time
USE_WL18XX_POWER_MANAGMENT=off

# USE_PERSONAL_SSID: set custom ssid
#USE_PERSONAL_SSID="BeagleBone"
USE_PERSONAL_SSID="AB10"

# USE_PERSONAL_PASSWORD: set ssid password
USE_PERSONAL_PASSWORD="BeagleBone"

# USE_GENERATED_DNSMASQ: use generated version of /etc/dnsmasq.d/SoftAp0; set to no so user can modify /etc/dnsmasq.d/SoftAp0
USE_GENERATED_DNSMASQ=yes

# USE_GENERATED_HOSTAPD: use generated version of /etc/hostapd.conf; set to no so user can modify /etc/hostapd.conf
USE_GENERATED_HOSTAPD=yes

# USE_APPENDED_SSID: appends mac address after SSID (aka -WXYZ, BeagleBone-WXYZ)
USE_APPENDED_SSID=yes

# USE_PERSONAL_COUNTRY: (default is US, but note enabled (#) with comment) 
#USE_PERSONAL_COUNTRY=US

Service:

$ sudo systemctl status bb-bbai-tether 
● bb-bbai-tether.service - BBAI brcmfmac tether Service
    Loaded: loaded (/lib/systemd/system/bb-bbai-tether.service; enabled; vendor preset: enabled)
    Active: activating (start) since Sun 2022-09-04 12:19:48 EDT; 16s ago 
Cntrl PID: 2585 (bb-bbai-tether)
     Tasks: 2 (limit: 937)
    Memory: 752.0K
    CGroup: /system.slice/bb-bbai-tether.service
            ├─2585 /bin/bash -e /usr/bin/bb-bbai-tether
            └─2605 sleep 5 Sep 04 12:19:48 bbb.example.com systemd[1]: Starting BBAI brcmfmac tether Service... 
Sep 04 12:19:53 bbb.example.com bb-bbai-tether[2585]: bbai:tether waiting for /sys/class/net/wlan0 
Sep 04 12:19:58 bbb.example.com bb-bbai-tether[2585]: bbai:tether waiting for /sys/class/net/wlan0 
Sep 04 12:20:03 bbb.example.com bb-bbai-tether[2585]: bbai:tether waiting for /sys/class/net/wlan0 
don@app:~$ sudo systemctl stop bb-bbai-tether
  1. https://wiki.debian.org/SystemdNetworkd

BBAI-64 Switches

Push-buttons used on the board.

  1. A switch is provided to allow switching between the modes.
    • Holding the boot switch down during a removal and reapplication of power without a microSD card inserted will force the boot source to be the USB port and if nothing is detected on the USB client port, it will go to the serial port for download.

    • Without holding the switch, the board will boot try to boot from the eMMC. If it is empty, then it will try booting from the microSD slot, followed by the serial port, and then the USB port.

    • If you hold the boot switch down during the removal and reapplication of power to the board, and you have a microSD card inserted with a bootable image, the board will boot from the microSD card.

      NOTE: Pressing the RESET button on the board will NOT result in a change of the boot mode. You MUST remove power and reapply power to change the boot mode. The boot pins are sampled during power on reset from the PMIC to the processor. The reset button on the board is a warm reset only and will not force a boot mode change.

BBAI-64 HDMI Display Connection

When connecting to an HDMI monitor, make sure your miniDP adapter is active. A passive adapter will not work. See Fig: Display adaptors.

BBAI-64 default memory device tree

Reference: https://forum.beagleboard.org/t/beaglebone-ai-64-memory-4gb-or-2gb-ram/32270

the AI-64 has 4GB installed, the other 2GB is reserved in the default image thru remoteproc for the other companion cores (c6, c7x, and R5)…

We have a custom device tree for you if you’d like to disable the other cores and use all 4GB with the A72’s…

=> No Shared Memory => k3-j721e-beagleboneai64-no-shared-mem.dtb

debian@BeagleBone:~$ sudo find /boot/ -name extlinux.conf
/boot/firmware/extlinux/extlinux.conf

debian@BeagleBone:~$ sudo ls /boot/firmware
extlinux  Image       k3-j721e-beagleboneai64.dtb         k3-j721e-common-proc-board.dtb    k3-j721e-sk.dtb  sysfw.itb     tispl.bin
ID.txt      initrd.img  k3-j721e-beagleboneai64-no-shared-mem.dtb  k3-j721e-proc-board-tps65917.dtb  overlays        tiboot3.bin  u-boot.img

..

so in /boot/firmware/extlinux/extlinux.conf just set:

fdt /k3-j721e-beagleboneai64-no-shared-mem.dtb

take it out to go back to sharing memory for PRU.

$ cat /boot/firmware/extlinux/extlinux.conf 
label Linux microSD
    kernel /Image
    fdt /k3-j721e-beagleboneai64-no-shared-mem.dtb
    append console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0
    fdtdir /
    initrd /initrd.img

BBAI-64 Fix 'broken boot'

Finger on both boot and reset:
Insert power
lift finger on reset
wait till led lights
lift finger on boot.

Since you have the serial boot log, stop u-boot with the “space” key…

# run emmc_erase_boot0

=> Reboot with SD card inserted, newly burned image: bbai64-debian-11.3-xfce-arm64-2022-06-14-10gb.img.xz

$ sudo apt update

$ sudo apt upgrade

debian@BeagleBone:~$ sudo /opt/u-boot/bb-u-boot-beagleboneai64/install-emmc.sh
Changing ext_csd[BOOT_BUS_CONDITIONS] from 0x02 to 0x02
H/W Reset is already permanently enabled on /dev/mmcblk0
Clearing eMMC boot0
dd if=/dev/zero of=/dev/mmcblk0boot0 count=32 bs=128k
32+0 records in
32+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.549462 s, 7.6 MB/s
dd if=/opt/u-boot/bb-u-boot-beagleboneai64/tiboot3.bin of=/dev/mmcblk0boot0 bs=128k
2+1 records in
2+1 records out
283940 bytes (284 kB, 277 KiB) copied, 1.13585 s, 250 kB/s
debian@BeagleBone:~$ sudo /opt/u-boot/bb-u-boot-beagleboneai64/install-microsd.sh
'/opt/u-boot/bb-k3-image-gen-j721e-evm/sysfw.itb' -> '/boot/firmware/sysfw.itb'
'/opt/u-boot/bb-u-boot-beagleboneai64/tiboot3.bin' -> '/boot/firmware/tiboot3.bin'
'/opt/u-boot/bb-u-boot-beagleboneai64/tispl.bin' -> '/boot/firmware/tispl.bin'
'/opt/u-boot/bb-u-boot-beagleboneai64/u-boot.img' -> '/boot/firmware/u-boot.img'

$ sudo reboot 

=> Login

$ uname -a

Linux BeagleBone 5.10.120-ti-arm64-r50 #1bullseye SMP PREEMPT Tue Jun 28 20:37:27 UTC 2022 aarch64 GNU/Linux

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            1.8G     0  1.8G   0% /dev
tmpfs           371M  2.0M  369M   1% /run
/dev/mmcblk1p2   59G  9.7G   47G  18% /
tmpfs           1.9G   16K  1.9G   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
/dev/mmcblk1p1  127M   47M   80M  38% /boot/firmware

BBAI-64 User LEDs

LEDGPIO SignalDefault Function
D2GPIO3_17Heartbeat when Linux is running
D3GPIO5_5microSD Activity
D4GPIO3_15CPU Activity
D5GPIO3_14eMMC Activity
D8GPIO3_7WiFi/Bluetooth Activity

BB_AI_USERLEDS_800px.png

BBAI Survival Guide

https://community.element14.com/challenges-projects/project14/visionthing/b/blog/posts/beaglebone-ai-survival-guide-v3-18-pwm-i2c-analog-digital-read-write-vision-ai-video-text-overlays-audio-hardware

Real Time Clock (RTC) system service and setup

Any clock needs to keep it's time when the power goes out. Since the PocketBeagle is not always connected to WiFi to sync with Network Time Services, we will install a Real Time Clock with a small battery [1].

Real Time Clock setup using i2c, ExploringBB: pp350 [1]

Here is the wiring diagram for a PocketBeagle:

  • PocketBeagle <-> DS3231 RTC
  • I2C1:
    • Pin 14 - VCC
    • Pin 16 - GND
    • Pin 9 - SCL
    • Pin 11 - SDA
  1. https://learn.adafruit.com/adafruit-ds3231-precision-rtc-breakout/overview

Setup proedure:

$ sudo apt install i2c-tools
$ i2cdetect
$ i2cdump -y 1 0x68 b
$ hwclock -r -f /dev/rtc1 
# (Note: rtc0 is active on-board)

$ sudo modprobe rtc-ds1307
$ sudo /bin/sh -c "/bin/echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device"
#  Now /dev/rtc1 should show up, echo delete_device to remove it.

# hwclock -r (read)
# hwclock -w (write)
# hwclock -s (set RTC to system time)
$ hwclock --set --date "2019-01-01 00:00:00" 
# (set new time)

$ sudo systemctl enable hwclock.service
$ sudo systemctl status hwclock.service
$ reboot
  1. http://derekmolloy.ie/exploring-beaglebone-tools-and-techniques-for-building-with-embedded-linux/

Service File

File: /etc/systemd/system/clock.service

[Unit]

Description=RTC Service
Before=getty.target

[Service]
Type=oneshot
ExecStartPre=/bin/sh -c "/bin/echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device"
ExecStart=/sbin/hwclock -s -f /dev/rtc1
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Seven Segment Display

Now we can install a Seven Segment Display [1] to show the time. I used an old Garfield clock with sentimental memories, and brought it back to life.

NOTE: If running python3, substitute python for python3 below.

  1. https://www.adafruit.com/product/1270
$ sudo apt-get update
$ sudo apt-get install build-essential python-pip python-dev python-smbus git

$ git clone https://github.com/adafruit/Adafruit_Python_GPIO.git
$ cd Adafruit_Python_GPIO
$ sudo python setup.py install

$ git clone https://github.com/adafruit/Adafruit_Python_LED_Backpack.git

$ cd Adafruit_Python_LED_Backpack
$ sudo python setup.py install

$ git clone https://github.com/adafruit/Adafruit-GFX-Library.git

$ cd Adafruit_GFX
$ sudo python setup.py install
Adafruit Python LED Backpack

Python library for controlling LED backpack displays such as 8x8 matrices, bar graphs, and 7/14-segment displays on a Raspberry Pi or BeagleBone Black.

Designed specifically to work with the Adafruit LED backpack displays ----> https://learn.adafruit.com/adafruit-led-backpack/overview

For all platforms (Raspberry Pi and Beaglebone Black) make sure your system is able to compile Python extensions. On Raspbian or Beaglebone Black's Debian/Ubuntu image you can ensure your system is ready by executing:

$ sudo apt-get update
$ sudo apt-get install build-essential python-dev

You will also need to make sure the python-smbus and python-imaging library is installed by executing:

$ sudo apt-get install python-smbus python-imaging

Install the library by downloading with the download link on the right, unzipping the archive, navigating inside the library's directory and executing:

$ sudo python setup.py install

See example of usage in the examples folder.

Clock testing

$ sudo apt install python-pip
$ pip install adafruit_gpio

$ cd Adafruit_Python_LED_Backpack/examples

$ python sevensegment_test.py

Clock Code

File: clock.py

import time

from Adafruit_LED_Backpack import SevenSegment


# Create display instance on default I2C address (0x70) and bus number.
display = SevenSegment.SevenSegment()

# Alternatively, create a display with a specific I2C address and/or bus.
# display = SevenSegment.SevenSegment(address=0x74, busnum=1)

# On BeagleBone, try busnum=2 if IOError occurs with busnum=1
# display = SevenSegment.SevenSegment(address=0x74, busnum=2)

# Initialize the display. Must be called once before using the display.
display.begin()

# Keep track of the colon being turned on or off.
colon = True

import datetime
now = datetime.datetime.now()
print ("Current date and time : ")
print (now.strftime("%Y-%m-%d %H:%M:%S"))
#
OLD_MIN = "99"
while True:
  MIN = now.strftime("%M")
  if ( MIN != OLD_MIN ):
         OLD_MIN = now.strftime("%M")
         # Clear the display buffer.
         display.clear()
         # Print the time to the display.
         display.print_number_str(now.strftime("%l%M"))
         # PM flag, lower right dot
         display.set_decimal(3, 1)
         # ... set a segment of a digit ...
         #display.set_digit_raw(0, 1)
         # Set the colon on or off (True/False).
         display.set_colon(colon)
         # Write the display buffer to the hardware.  This must be called to
         # update the actual display LEDs.
         display.write_display()
         # Delay for a second.
     time.sleep(1.0)
     now = datetime.datetime.now()
     # Flip colon on or off.
     colon = not colon
     display.set_colon(colon)
     # Write the display buffer to the hardware.  This must be called to
     # update the actual display LEDs.
     display.write_display()

Music Player for the Car

This is a BBB under the seat with a wired mint box running Music Player Daemon [1].

Installed three buttons

  • Back - run mpc prev

  • Play/Stop - run mpc pause/play

  • Forward - run mpc next

Wiring Pins

BeagleBone-AI-2_1.png

BeagleBone-AI-2_2.png

Service

File: /etc/systemd/system/remote.service

[Unit]
Description=Remote Control Music Player
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=root
ExecStop=/data/home/remote/remote_stop.sh
ExecStart=/data/home/remote/remote.sh

[Install]
WantedBy=multi-user.target

Forward

File: forward.js

/**********************************************************************
 File: forward.js
 Usage: Wire 3.3v (P9_3) and GPIO (P8_8, P8_7, P8_9) to switches
 Service: remote.service
 Author: Don Cohoon
 History
 16-Oct-2019   Created
**********************************************************************/
var b = require('bonescript');
const { exec } = require('child_process');
// GPIO inputs
const FORWARD = 'P8_8';
const PLAY    = 'P8_7'; // Also STOP
const REVERSE = 'P8_9';
// Is button pressed or released?
const RELEASE = 0;
const PRESS   = 1;
//
b.pinMode(FORWARD, b.INPUT);
b.pinMode(PLAY,    b.INPUT);
b.pinMode(REVERSE, b.INPUT);
setInterval(check,1000);
//
// ---------------------------
function check(){
	b.digitalRead(FORWARD, checkForward);
}

// ---------------------------
function checkForward(err, response){
	if (response == 1){
		console.log('Forward pushed');
		exec('/usr/bin/mpc next', ( err, stdout, stderr) => {
			if (err) {
				console.log(stderr);
				return;
			}
		});
	} else {
	null; //	console.log('Button NOT pushed');
	}

}

Play

File: play.js

/**********************************************************************
 File: play.js
 Usage: Wire 3.3v (P9_3) and GPIO (P8_8, P8_7, P8_9) to switches
 Service: remote.service
 Author: Don Cohoon
 History
 16-Oct-2019   Created
**********************************************************************/
var b = require('bonescript');
const { exec } = require('child_process');
// GPIO inputs
const FORWARD = 'P8_8';
const PLAY    = 'P8_7'; // Also STOP
const REVERSE = 'P8_9';
// Is button pressed or released?
const RELEASE = 0;
const PRESS   = 1;
//
b.pinMode(FORWARD, b.INPUT);
b.pinMode(PLAY,    b.INPUT);
b.pinMode(REVERSE, b.INPUT);
setInterval(check,1000);
//
// ---------------------------
function check(){
	b.digitalRead(PLAY, checkPlay);
}

// ---------------------------
function checkPlay(err, response){
	if (response == 1){
		console.log('Play pushed');
		exec('/usr/bin/mpc current', ( err, stdout, stderr) => {
			if (err) {
				console.log(stderr);
				return;
			}
			if (stdout) {
				console.log('Stop playing ',stdout);
				exec('/usr/bin/mpc stop', ( err, stdout, stderr) => {
					if (err) {
						console.log(stderr);
						return;
					}
				});
				return;
			} else {
				console.log('Play resumed');
				exec('/usr/bin/mpc play', ( err, stdout, stderr) => {
					if (err) {
						console.log(stderr);
						return;
					}
				});
				return;
			}

		}); // current
	} else {
	null; //	console.log('Button NOT pushed');
	}

}

Remote

File: remote.sh

#!/bin/bash
export NODE_PATH=/usr/local/lib/node_modules/
export NODE_MODULES_CONTEXT=1
PIDFILE=/var/run/remote.pid
# node -pe "require('bonescript').getPlatform().bonescript"
#
function log() {
	echo "`date` $@ " >> /var/log/remote.log
}
#
procs=(
     '/data/home/remote/forward.js'
     '/data/home/remote/play.js '
     '/data/home/remote/reverse.js'
    )
n_procs=0
while [ "x${procs[n_procs]}" != "x" ]
do
	   n_procs=$(( $n_procs + 1 ))
done
inx=1
#
echo $$ > $PIDFILE
cd /data/home/remote
log "Starting $$"
while true
do
	# run processes and store pids in array
	for i in ${procs[@]}; do
	  echo "Starting /usr/bin/node ${i}"
	  /usr/bin/node ${i} &
	  pids[${inx}]=$!
	  let "inx = $inx + 1"
	done

	# wait for all pids
	echo ${pids[*]}
	for pid in ${pids[*]}; do
	      wait $pid
	    done
	sleep 30
	log "Restarting after error"
done

Remote Stop

File: remote_stop.sh

#!/bin/bash
TPID=$( /bin/cat /var/run/remote.pid )
/bin/kill -9 ${TPID}
/usr/bin/killall -e /usr/bin/node

Reverse

File: reverse.js

/**********************************************************************
 File: reverse.js
 Usage: Wire 3.3v (P9_3) and GPIO (P8_8, P8_7, P8_9) to switches
 Service: remote.service
 Author: Don Cohoon
 History
 16-Oct-2019   Created
**********************************************************************/
var b = require('bonescript');
const { exec } = require('child_process');
// GPIO inputs
const FORWARD = 'P8_8';
const PLAY    = 'P8_7'; // Also STOP
const REVERSE = 'P8_9';
// Is button pressed or released?
const RELEASE = 0;
const PRESS   = 1;
//
b.pinMode(FORWARD, b.INPUT);
b.pinMode(PLAY,    b.INPUT);
b.pinMode(REVERSE, b.INPUT);
setInterval(check,1000);
//
// ---------------------------
function check(){
	b.digitalRead(REVERSE, checkReverse);
}

// ---------------------------
function checkReverse(err, response){
	if (response == 1){
		console.log('Reverse pushed');
		exec('/usr/bin/mpc prev', ( err, stdout, stderr) => {
			if (err) {
				console.log(stderr);
				return;
			}
		});
	} else {
	null; //	console.log('Button NOT pushed');
	}

}
  1. https://www.musicpd.org/

Power on/off another PC

This project uses a web application written in flask to power on or off two different PCs remotely, and also a PowerTail Switch.

  • Server one:

    • Wire pins P8_11 in parallel to power button
    • Wire pins P8_12 in parallel to reset button
  • Server two:

    • Wire pins P8_13 in parallel to power button
    • Wire pins P8_14 in parallel to reset button
  • PowerTail Light [1]

    • Wire pins P9_21 to the PowerTail input control screws
  1. https://www.adafruit.com/product/2935

File: boot.py

import time, datetime
from itertools import cycle                                                     
import os
from werkzeug.debug import DebuggedApplication

from flask import Flask, render_template, request, Response, session, redirect, url_for
from functools import wraps
import subprocess
import logging
logging.basicConfig(filename='boot.log',level=logging.DEBUG,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# Limit ddos
from werkzeug.wrappers import BaseRequest , BaseResponse
class Response ( BaseResponse):
    # limit 1m for input request and form response
    max_content_length = 1024 * 1024 * 1
    max_form_memory_size = 1024 * 1024 * 1

import Adafruit_BBIO.GPIO as GPIO
GPIO.setup("P9_21", GPIO.OUT)
GPIO.output("P9_21", GPIO.HIGH) # TimeLight off
GPIO.setup("P8_11", GPIO.OUT)
GPIO.output("P8_11", GPIO.HIGH)
GPIO.setup("P8_12", GPIO.OUT)
GPIO.output("P8_12", GPIO.HIGH)
GPIO.setup("P8_13", GPIO.OUT)
GPIO.output("P8_13", GPIO.HIGH)
GPIO.setup("P8_14", GPIO.OUT)
GPIO.output("P8_14", GPIO.HIGH)


ASSETS_DIR = os.path.dirname(os.path.abspath(__file__))
app = Flask(__name__)                                            

#@app.before_request # to get your header token and check for its validity

#---------------------------------
# route for handling the login page logic
@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'SecretUser' or request.form['password'] != 'SecretPassword':
            error = 'Invalid Credentials. Please try again.'
            session['logged_in'] = False
        else:
            session['logged_in'] = True
            return redirect(url_for('secret_page'))

    return render_template('login.html', error=error)

#---------------------------------
# default page
@app.route("/")                                                                 
@app.route("/index")                                                          
def hello():                                                    

    return render_template('index.html')

#---------------------------------
# control server boot actions
@app.route('/secret-page', methods=['GET','POST'])
def secret_page():
    msg='';
    if 'logged_in' in session:
      start_time = session.get('session_time', None)
      if start_time is None:
        start_time = datetime.datetime.now()
        session['session_time'] = start_time
      end_time = start_time + datetime.timedelta(minutes=5)
      if datetime.datetime.now() > end_time: 
        session.clear()
        start_time = session.get('session_time', None)
        return redirect(url_for('login', next=request.url))
    else:
      return redirect(url_for('login', next=request.url))

    app.logger.warning('Agent: %s',request.headers.get('User-Agent'))
    app.logger.warning('Host: %s',request.headers.get('Host'))
    app.logger.warning('Auth: %s',request.headers.get('Authorization'))
    proc = subprocess.Popen(["uptime"], stdout=subprocess.PIPE)
    (out, err) = proc.communicate()
    #print "program output:", out
    option = ''
    if request.method == 'POST':
      option = request.form.get('options', 'empty')
      #option = request.form['options']
      #print "option:", option
      if option == 'on':                                                           
  	#app.logger.debug('A value for debugging')
  	#app.logger.warning('A warning occurred (%d apples)', 42)
  	#app.logger.error('An error occurred')
  	app.logger.warning('Server was turned on')
        GPIO.output("P8_11", GPIO.LOW)
    	time.sleep(3)                                                          
        GPIO.output("P8_11", GPIO.HIGH)
  	app.logger.warning('Server was turned on (end)')
  	msg = 'Server turned on.'
      elif option == 'off':                                                          
  	app.logger.warning('Server was turned off')
        GPIO.output("P8_11", GPIO.LOW)
  	time.sleep(6)
        GPIO.output("P8_11", GPIO.HIGH)
  	app.logger.warning('Server was turned off (end)')
  	msg = 'Server turned off.'
      elif option == 'reset':                                                          
  	app.logger.warning('Server was reset')
        GPIO.output("P8_12", GPIO.LOW)
  	time.sleep(2)
        GPIO.output("P8_12", GPIO.HIGH)
  	app.logger.warning('Server was reset (end)')
  	msg = 'Server reset.'
      elif option == 'on2':                                                           
  	#app.logger.debug('A value for debugging')
  	#app.logger.warning('A warning occurred (%d apples)', 42)
  	#app.logger.error('An error occurred')
  	app.logger.warning('NAS was turned on')
        GPIO.output("P8_14", GPIO.LOW)
    	time.sleep(3)                                                          
        GPIO.output("P8_14", GPIO.HIGH)
  	app.logger.warning('NAS was turned on (end)')
  	msg = 'NAS turned on.'
      elif option == 'off2':                                                          
  	app.logger.warning('NAS was turned off')
        GPIO.output("P8_14", GPIO.LOW)
  	time.sleep(6)
        GPIO.output("P8_14", GPIO.HIGH)
  	app.logger.warning('NAS was turned off (end)')
  	msg = 'NAS turned off.'
      elif option == 'reset2':                                                          
  	app.logger.warning('Server was reset')
        GPIO.output("P8_13", GPIO.LOW)
  	time.sleep(2)
        GPIO.output("P8_13", GPIO.HIGH)
  	app.logger.warning('NAS was reset (end)')
  	msg = 'NAS reset.'
      elif option == 'on3':                                                           
  	app.logger.warning('TimeLight was turned on')
        GPIO.output("P9_21", GPIO.LOW)
  	app.logger.warning('TimeLight was turned on (end)')
  	msg = 'TimeLight turned on.'
      elif option == 'off3':                                                          
  	app.logger.warning('TimeLight was turned off')
        GPIO.output("P9_21", GPIO.HIGH)
  	app.logger.warning('TimeLight was turned off (end)')
  	msg = 'TimeLight turned off.'
      else:
        msg = 'Pick one.'
  	app.logger.warning('No option picked')
    template_data = {                                                           
        'title' : option,                                                        
        'msg'   : msg,
        'out'   : out,
    }                                                                           
    return render_template('secret_page.html', **template_data)

@app.after_request
def apply_caching(response):
    response.headers["Server"] = "Waiter"
    return response

if __name__ == "__main__":                                                      
    app.run('0.0.0.0', debug=True, port=12345)

File: secret_page.html

<!DOCTYPE html>                                                                 
   <head>                                                                       
    <title>{{ title }}</title> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css"
      href="{{url_for('static',filename='bootstrap.css')}}">
    <link rel="stylesheet" type= "text/css"
      href="{{url_for('static',filename='bootstrap-theme.css')}}">
    <script>
   function clickAndDisable(link) {
     // disable subsequent clicks
     link.onclick = function(event) {
        event.preventDefault();
        document.getElementById("sub").className = "btn btn-default disabled";
     }
   }   
    </script>
    </head>                                                                     
    <body>                                                                      
      <div class="container">
       <div class="col-lg-1 col-centered">
          <br><p class="row"> {{ out }} </p>
         <form name="boot" class="form-check" action="" method="post" onsubmit="">
           <p>
             <div class="form-check">
               <label class="form-check-label">
                 <input class="form-check-input" type="radio" name="options" id="on" value="on">
                 S-On
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                <input class="form-check-input" type="radio" name="options" id="off" value="off">
                 S-Off
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                <input class="form-check-input" type="radio" name="options" id="reset" value="reset">
                 S-Reset
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                 <input class="form-check-input" type="radio" name="options" id="on2" value="on2">
                 N-On
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                <input class="form-check-input" type="radio" name="options" id="off2" value="off2">
                 N-Off
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                <input class="form-check-input" type="radio" name="options" id="reset2" value="reset2">
                 N-Reset
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                 <input class="form-check-input" type="radio" name="options" id="on3" value="on3">
                 L-On
               </label>
             </div>
             <div class="form-check">
               <label class="form-check-label">
                <input class="form-check-input" type="radio" name="options" id="off3" value="off3">
                 L-Off
               </label>
             </div>
           </p>
           <p> <input type=submit value=Submit id="sub"
                  onclick="clickAndDisable(this);"
                  class="btn btn-default">
           </p>
         </form> 
           {{ msg }}
       </div>
      </div>
    </body>                                                                     
</html>

File: login.html

<!DOCTYPE html>
  <head>
    <title>login page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css"
      href="{{url_for('static',filename='bootstrap.css')}}">
    <link rel="stylesheet" type= "text/css"
      href="{{url_for('static',filename='bootstrap-theme.css')}}">
  </head>
  <body>
    <div class="container">
     <div class="col-lg-1 col-centered">
      <h1>Please login</h1>
      <br>
      <form action="" method="post">
       <div class="form-group row">
        <input type="text" placeholder="Username" name="username" value="{{
          request.form.username }}">
       </div>
       <div class="form-group row">
         <input type="password" placeholder="Password" name="password" value="{{
          request.form.password }}">
       </div>
       <div class="form-group row">
        <input class="btn btn-default" type="submit" value="Login">
       </div>
      </form>
      {% if error %}
        <p class="error"><strong>Error:</strong> {{ error }}
      {% endif %}
     </div>
    </div>
  </body>
</html>

File: main.html

<!DOCTYPE html>                                                                 
   <head>                                                                       
    <title>{{ title }}</title>                                                                                   
    </head>                                                                     
    <body>                                                                      
	  <h1>
			<a href="/on" id="on" class="large_button">ON</a>
	  </h1>
	  <h1>
			<a href="/off" id="off" class="large_button">OFF</a>
	  </h1>
    </body>                                                                     
</html>

Put the bootstrap css package in directory ./static.

Reference: https://getbootstrap.com/

Reference

@book{9781119533160,
   Author = {Derek Molloy},
   Title = {Exploring BeagleBone: Tools and Techniques for Building with Embedded Linux},
   Publisher = {Wiley},
   Edition = {Second},
   Year = {2019},
   ISBN = {9781119533160},
   URL = {http://www.exploringbeaglebone.com/}
}

Code for book: https://github.com/derekmolloy/exploringBB

Continue

Now that you have experimented with BeagleBone SBC, next our travels take us far away to Media Land. The sights and sounds of Video and Audio controlled and maintained by your computer.

Proceed in the order presented, some things are depending on prior setups.

Book Last Updated: 29-March-2024



Electronics on a BeagleBone - Linux in the House - https://linux-in-the-house.org Creative Commons License