Skip to content

Beagle Bone Black cape and firmware for driving a large number of WS281x LED strips.

Notifications You must be signed in to change notification settings

campmindshark/LEDscape

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ashoat's notes

  1. To boot the Beaglebone Green from an SD card
    • Turn off the Beaglebone and remove it from power
    • Insert the SD card
    • Start the Beaglebone by providing power
    • If it doesn't work on first boot, it may be necessary to restart the Beaglebone by pressing the "RESET" button
  2. To flash the Beaglebone Green's onboard eMMC storage to match an SD card
    • Turn off the Beaglebone, remove it from power, and insert the SD card
    • Boot the Beaglebone (it will boot from the SD card), ssh in (see instructions under 5), sudo vim /boot/uEnv.txt, and uncomment the following line:
      cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
      
    • Restart the Beaglebone. This will trigger the flash script. It should take a while to transfer things over, and then the Beaglebone will shut down
    • Take the SD card out and boot the Beaglebone. The eMMC should be successfully flashed to match the SD card
    • Note that the line you commented out on the SD card will continue to stay commented on the SD card (though will be uncommented on the eMMC). If you want to return the SD card to its previous state, you can either mount it on the Beaglebone after booting from the onboard storage and recomment the line, or you can simply reflash the SD card (see 3 below)
  3. How to put the latest sharkbone image onto an SD card from a MacBook Pro
    • Download the latest sharkbone image as a .img.gz file
    • Unzip it by calling gunzip image.img.gz
    • Figure out which /dev/rdisk* corresponds to your SD card by comparing the results of ls -hla /dev | grep rdisk before and after plugging the microSD card into your laptop
    • If it's a new microSD card, it will get mounted, which will prevent the next step from working. Run diskutil unmount /dev/disk2s1, replacing 'disk2s1' with the results from the last step. Note there is no "r" at the start, but there is an "s1" at the end
    • With the SD card in, run sudo dd bs=1m if=image.img of=/dev/rdisk2, replacing rdisk2 with the result from the step before last. Note there is no "s1" at the end, but there is an "r" at the start
  4. How to create a new sharkbone image from a MacBook Pro
    • Boot the Beaglebone from an SD card (see above)
    • Mess around and do whatever you want
    • Turn off the Beaglebone and remove the SD card
    • Plug the SD card into your laptop and figure out which /dev/rdisk* corresponds to your SD card (see above)
    • Run sudo dd bs=1m if=/dev/rdisk2 of=image.img count=3400, replacing rdisk2 with the result from the last step
    • gzip image.img
  5. How to connect the Beaglebone to the Internet via USB connection to a Windows computer
    • If you just want to SSH in to the Beaglebone, and don't need the Beaglebone to have Internet
      • You should just be able to ssh 192.168.7.2 with username debian and password temppwd
      • You might need to keep resetting the Beaglebone until you can ping 192.168.7.2 and get a response back
    • To access the Internet on the Beaglebone via your Windows computer's connection, you'll need the BONE_D64 driver. Documentation here, download here
      • The BONE_D64 driver won't install on modern Windows machines until you reboot the OS into Safe Mode for the installation
      • Hold down the Shift key, go to the Start Menu, and select Restart via the Power menu
      • Then select Troubleshoot -> Advanced Options -> Startup Settings
      • Then press 7 to select "Disable driver signature enforcement"
      • Every time you update Windows to a new major release it will clear this driver, and you will have to reinstall it
    • Next we'll configure your Windows computer to share its Internet
      • Open the Networks Connections control panel item by opening ncpa.cpl via the Start Menu
      • You'll need to update some settings for both your working Internet connection (eg. Wi-Fi) and the connection to the Beaglebone (will mention Linux)
      • Note that the order of these steps matters. The actions in the next step will cause the IP address the Windows computer is using for its connection to the Beaglebone to reset, which necessitates the later step of resetting it
      • First, right-click the working Internet connection and hit Properties. Then go to Sharing, check both boxes, and select the Beaglebone connection in the dropdown
      • Next we'll open the Beaglebone's connection Properties and go to Internet Protocol Version 4's Properties and make sure the IP address is 192.168.7.1
    • Finally, we need to do some configuration on the Beaglebone's side
      • First, reboot the Beaglebone. The changes to Windows above necessitate a restart on the Beaglebone's side
      • SSH in to the Beaglebone (described above)
      • Run route_through_usb.sh
      • To confirm the Internet is working, try ping google.com or something
    • Doesn't work?
      • You might have to run route_through_usb.sh multiple times, until sudo ip route list says the default is 192.168.7.1
      • Sometimes literally just redoing the Windows configuration above can help
        • First disable the sharing of the Wi-Fi connection
        • Then run through all the Windows configuration step again
        • Don't restart the Beaglebone afterwards though
      • Maybe IP works but DNS doesn't
        • Try pinging Ashoat's server: ping 65.19.143.2
        • If that works but ping google.com doesn't, you can try to update /etc/resolv.conf to look like this (ie. sudo vim /etc/resolv.conf):
          domain localdomain
          search localdomain
          nameserver 8.8.8.8
          nameserver 8.8.4.4
          
    • Background reading here and here

Ashoat's old notes from the 2010s

  1. First, we need to burn a Linux image onto a microSD card. Since LEDscape relies on the outdated uio_pruss kernel module, we need an old image.
    • We're going to start by burning a Linux image onto the microSD card. These directions should work on macOS.
      • First, download the latest Debian 7 (Wheezy) image on BeagleBoard.org/latest-images. Here's a direct link.
      • gunzip bone-debian-7.11-lxde-4gb-armhf-2016-06-15-4gb.img.xz
      • Figure out which /dev/rdisk* corresponds to your microSD card by comparing the results of ls -hla /dev | grep rdisk before and after plugging the microSD card into your laptop.
      • If it's a new microSD card, it will get mounted, which will prevent the next step from working. Run diskutil unmount /dev/disk2s1, replacing 'disk2s1' in the last step with the results from the last step. Note there is no "r" at the start, but there is an "s1" at the end
      • With the microSD card in, run sudo dd bs=1m if=bone-debian-7.11-lxde-4gb-armhf-2016-06-15-4gb.img of=/dev/rdisk2, replacing rdisk2 with the result from the step before last. Note there is no "s1" at the end, but there is an "r" at the start
    • Next, we need to resize the partitions in the partition table and the filesystems contained therein.
      • Put the new microSD in your Beaglebone, hold the BOOT button (the one next to the microSD slot), and then connect the Beaglebone to your computer via USB to power it on.
      • SSH into the Beaglebone: ssh [email protected]
      • sudo fdisk /dev/mmcblk0
        • p
        • If there are two partitions, then
          • d 2
          • n, p, 2, Enter, Enter
        • If there is only one partition, then
          • d 1
          • n, p, 1, Enter, Enter
          • a, 1
        • w
        • If it doesn't crash and exit automatically, then Ctrl+D to leave
      • sudo reboot
      • SSH in again
      • sudo resize2fs /dev/mmcblk0p2 if there were two partitions
      • sudo resize2fs /dev/mmcblk0p1 if there was one partition
  2. Next, we need to get LEDscape onto the image.
    • If you have a Windows computer, you can share your Internet connection and run git clone directly on the Beaglebone.
      • Follow the instructions to first install drivers, and then configure both network adapters on your Windows computer
      • SSH to your Beaglebone using Putty or something
        • vim ~/.bash_profile:
          export GIT_SSL_NO_VERIFY=1
          export PATH=$PATH:~/bin
        • . ~/.bash_profile
        • Create the following file named route_through_usb.sh in ~/bin (ie. vim ~/bin/route_through_usb.sh):
          #!/bin/sh
          sudo /sbin/route add default gw 192.168.7.1
        • chmod +x ~/bin/route_through_usb.sh
        • route_through_usb.sh
        • Update /etc/resolv.conf to look like this (ie. sudo vim /etc/resolv.conf):
          domain localdomain
          search localdomain
          nameserver 8.8.8.8
          nameserver 8.8.4.4
          
        • If everything is working correctly now, you should be able to clone the repo directly
          • cd
          • git clone https://github.com/campmindshark/LEDscape
    • If you don't have a Windows computer or a way to connect your Beaglebone directly to the Internet, your best bet is to run git clone on your macOS or Linux machine, and then to SCP it over to the Beaglebone.
  3. Now we simply need to install and configure LEDscape.
    • SSH to your Beaglebone: ssh [email protected]
    • cd ~/LEDscape
    • sudo ./install-service.sh
    • sudo cp ledscape-config.json /etc/
    • sudo cp uEnv.txt /boot/
    • sudo reboot
    • Now we should be able to run LEDscape: sudo ./run-ledscape

Mindshark yearly updates

2019

We encountered the change-to-frame-reset-time issue this year. Yona showed up and saved our asses by updating the SLEEPNS directive in pru/templates/ws281x.p. We noticed the number he picked is lower than what got merged upstream, so if you ever notice weird flickering frames, it may be worth trying to push this number higher, maybe from 200usec to 300usec.

Overview

LEDscape is a library and service for controlling individually addressable LEDs from a Beagle Bone Black or Beagle Bone Green using the onboard PRUs. It currently supports WS281x (WS2811, WS2812, WS2812b), WS2801 and initial support for DMX.

It can support up to 48 connected strings and can drive them with very little load on the main processor.

Background

LEDscape was originally written by Trammell Hudson (http://trmm.net/Category:LEDscape) for controlling WS2811-based LEDs. Since his original work, his version (https://github.com/osresearch/LEDscape) has been repurposed to drive a different type of LED panel (e.g. http://www.adafruit.com/products/420).

This version of the library was forked from his original WS2811 work. Various improvements have been made in the attempt to make an accessible and powerful LED driver based on the BBB. Many thanks to Trammell for his excellent work in scaffolding the BBB and PRUs for driving LEDs.

Installation

It is necessary to have access to a shell onto the Beaglebone using serial, Ethernet, or USB connections.
Examples on how to do this can be found at BeagleBoard.org or at Adafruit's Learning Site.

Start with a compatible Linux image

To use LEDscape, you must use a version of the Linux kernel that supports the uio_pruss module. The Beaglebone.org Wheezy Linux images work well.

Checking existing Linux version

Check which Debian version you are currently running by entering...

cat /etc/debian_version

This README was tested with version 7.11, but any 7.x version should work. Version 8.x is currently not compatible because it does not support the PRUSS subsystem that LEDScape used to talk to the PRU units.

Installing a compatible Linux version

If you have an incompatible version currently installed or just want to start with a clean install of to the most recent compatible version, you can follow the instructions here under "Update board with latest software"...

http://beagleboard.org/getting-started

Make sure you pick a "Wheezy" version of the Linux kernel since the "Jessie" versions do not yet work by default. This readme was tested against the "Debian 7.11 2015-06-15 4GB SD LXDE" image.

Installing the LEDscape software

Log into a compatible Linux version as root and enter the following commands at a command line...

git clone git://github.com/Yona-Appletree/LEDscape
cd LEDscape
chmod +x install-software.sh
./install-software.sh
reboot

This will do the following....

  1. Clone the LEDscape repository to your local machine in a directory called "LEDscape" under whatever directory you started in.
  2. Make the install script executable.
  3. Build the LEDscape software from the sources. This takes a couple of minutes and you will see lots of scrolling.
  4. Copy the new flattened device tree files to your /boot directory. These files enable the PRU subsystem. Note that the old files are backed up with the extension preledscape_bk.
  5. Copy a default config file to /etc/ledscape-config.json if that file does not already exist.
  6. Install the uio_pruss kernel module to let LEDscape talk to the PRU subsystem.
  7. Reboot the machine.

Updating an existing install

If you are using an older version of LEDscape that keeps the configuration in a JSON file inside the LEDscape directory, you should copy your modified config to /etc/ledscape-config.json.

You should be able to update an existing install with the above procedure without overwriting your configuration in /etc/ledscape-config.json.

Note that the install process will not preserve any modified pin mappings.

Testing the install

Once the machine has rebooted, log in as root, enter the following commands to switch into the LEDscape directory you created above and manually start the LEDscape server...

cd LEDscape
./run-ledscape

It should print some diagnostic messages and continue running until you press Control-C or logout or reboot.

By default, the server starts sending a demo pattern in the WS2812B format on the output pins. If you connect the DI of some strings to these pins, they should light up. Pins P8-8, P8-10, P8-12, P8-14, P8-16, and P8-18 are great for testing since they are located near a ground on pin P8-2, they are all right next to each other, and they should always have pixel data in the default configuration.

Setting the server to run automatically as a service

If you want LEDscape to automatically start every time the machine is rebooted, you can install it as a service with the following command (run from a command line inside the LEDscape directory as root)...

sudo ./install-service.sh

Open Pixel Control Server

Configuration

By default LEDscape is configured for strings of 256 WS2811 pixels, accepting OPC data on port 7890. You can adjust this by editing run-ledscape and editing the parameters to opc-server

Data Format

The opc-server server accepts data on OPC channel 0. It expects the data for each LED strip concatenated together. This is done because LEDscape requires that data for all strips be present at once before flushing data data out to the LEDs.

opc-server supports both TCP and UDP data packets. The TCP port is specified with --tcp-port <port> and the UDP port with --udp-port <port>. Entering 0 for a port number will disable that server.

Note that if using the UDP server, opc-server will limit the number of pixels to 21835, or 454 pixels per port if using all 48 ports.

Output Modes

LEDscape is capable of outputting several types of signal. By default, a ws2811-compatible signal is generated. The output mode can be specified with the --mode <mode-id> parameter. A list of available modes and their descriptions can be obtained by running opc-server -h.

Frame Rates for WS2812 Leds

512 per channel ~= 060 fps
256 per channel ~= 120 fps
128 per channel ~= 240 fps
064 per channel ~= 400 fps

Pin Mappings

Each output mode of LEDscape is compatible with several different pin mappings. These pin-mappings are declared in pru/mappings as json files and each contain information about the mapping. They can be provided to LEDscape with the --mapping <mapping-id> parameter, where <mapping-id> is the filename of the json file without it's extension.

The mappings are designed for use with various different cape configurations to simplify the hardware designed. Additional mappings can be created by adding new json files to the pru/mappings directory and rebuilding.

A human-readable pinout for a mapping can be generated by running

node pru/pinmap.js --mapping <mapping-id>

Default pin mappings

By default, LEDscape is set up to drive 48 strings of WS2812B LEDs, with each string having up to 600 pixels. You can connect shorter strings with no problems except that the update rate will be slower. If you connect longer strings, only the first 600 pixels will update.

Here is the default mapping of channels (in green) to pins...

Here are the default pin assignments for the first 6 channels so you can get your bearings...

These are the pins you would connect the to each string's DI (Data In).

HDMI conflict

BeagleBone Green

The BeagleBone Green has no HDMI port, so all 48 channels are available on the mapped pins by default.

In fact, if you try to do the edit below you can make the board unbootable!

BeagleBone Black

On the BeagleBone Black, the HDMI port uses pins P8-27 through P8-46 so these channels (basically the bottom half of the right header) will not be usable for pixel data by default. If you need less than 28 channels total, you can just use pins that are not assigned to the HDMI port.

If you want to use the pins assigned to the HDMI port for pixel data, then you will need to disable the HDMI port by entering the command...

nano /boot/uEnv.txt

Find the lines that say...

##BeagleBone Black: HDMI (Audio/Video) disabled:
#dtb=am335x-boneblack-emmc-overlay.dtb

...and change them to say...

##BeagleBone Black: HDMI (Audio/Video) disabled:
dtb=am335x-boneblack-emmc-overlay.dtb

(delete the # at the beginning of the second line).

Then save the file by pressing Control-X and answering y, and then reboot by entering reboot.

When the board comes back up, the HDMI should be disabled and the pins available for LEDs.

Multi-Pin Channels

Some mappings, such as ws2801, use multiple pins to output each channel. In these cases, fewer than the full 48 channels are available. In the case of ws2801, each channel uses two pins, DATA on the first pin and CLOCK on the next. Only 24 channels of output are available and to reduce CPU usage, opc-server should be called with --strip-count 24 or lower.

Output Features

opc-server supports Fadecandy-inspired temporal dithering and interpolation to enhance the smoothness of the output data. By default, it will apply a luminance curve, interpolate and dither input data at the highest framerate possible with the given number of LEDs.

These options can be configured by command-line switches that are documented in the help output from opc-server -h.

To disable all signal enhancements, use opc-server -lut

Demo Modes

opc-server supports several demo modes that will drive the attached pixels autonomously. This can help greatly with testing.

The demo mode is set using the demoMode parameter and can have the following values...

demoMode behavior
none No demo running. Pixels will only update in response to incoming OPC packets
id Set the pixel to the strip index unless the pixel has the same index as the strip, then light it up grey with bit value: 1010 1010
fade Display a pleasing pattern of rotating color hues with a border that steps across the pixels every 12 seconds
black All pixels off
power All pixels on full white (based on current settings)- good for testing for maximum power requirements for current settings

The default demo-mode set in the supplied ws281x-config.json configuration file is fade.

Note that received OPC data will override any currently running demo-mode. The currently running demo-mode will resume display 5 seconds after the last OPC data is displayed.

Configuration

Config info is typically stored in /etc/ledscape-config.json.

Default config

The default config after installation is set up to drive WS281X strips connected to all of the 48 available output pins. Note that not all pins will work on BeagleBone Black unless you [disable the HDMI port](#HDMI Conflict).

A description of the file format and some example configurations are available in the configs/ subdirectory of this repo.

Directly editing the current config

You can edit the config file directly by typing...

nano /etc/ledscape-config.json

If the server is already running as a service, you'll need to enter the following command to get it to read the new config file...

sudo systemctl restart ledscape.service

Processing Examples

LEDscape provides versions of the FadeCandy processing examples modified to work better with LEDscape in the processing directory. Clone this repo on a computer and run these sketches, edited to point at your BBB hostname or ip address after starting opc-server or installing the system service.

Hardware Tips

Remember that the BBB outputs data at 3.3v. Depending on the specific LED strips, it is often possible to connect the DI on directly to one of the output pins on the BeagleBone, especially if the strips are high quality and the connecting wire is short. Many [recommend](https://forum.pjrc.com/threads/24648-Newbie-findings-re-WS281X-signal-quality(wire-length-resistors-and-grounds-Oh-my!) also adding an impedance matching resistor to smooth out the signal.

If your strips require 5V on DI, you will need to use a level-shifter of some sort. Adafruit has a decent one which works well. For custom circuit boards we recommend the TI SN74LV245.

While there may be others, RGB123 makes an excellent 24/48 pin cape designed specifically for this version of LEDscape: 24 pin or 48 pin

API

ledscape.h defines the API. The key components are:

ledscape_t * ledscape_init(unsigned num_pixels)
ledscape_frame_t * ledscape_frame(ledscape_t*, unsigned frame_num);
ledscape_draw(ledscape_t*, unsigned frame_num);
unsigned ledscape_wait(ledscape_t*)

You can double buffer like this:

const int num_pixels = 256;
ledscape_t * const leds = ledscape_init(num_pixels);

unsigned i = 0;
while (1)
{
	// Alternate frame buffers on each draw command
	const unsigned frame_num = i++ % 2;
	ledscape_frame_t * const frame
		= ledscape_frame(leds, frame_num);

	render(frame);

	// wait for the previous frame to finish;
	ledscape_wait(leds);
	ledscape_draw(leds, frame_num);
}

ledscape_close(leds);

The 24-bit RGB data to be displayed is laid out with BRGA format, since that is how it will be translated during the clock out from the PRU. The frame buffer is stored as a "strip-major" array of pixels.

typedef struct {
	uint8_t b;
	uint8_t r;
	uint8_t g;
	uint8_t a;
} __attribute__((__packed__)) ledscape_pixel_t;

typedef struct {
	ledscape_pixel_t strip[32];
} __attribute__((__packed__)) ledscape_frame_t;

Low level API

If you want to poke at the PRU directly, there is a command structure shared in PRU DRAM that holds a pointer to the current frame buffer, the length in pixels, a command byte and a response byte. Once the PRU has cleared the command byte you are free to re-write the dma address or number of pixels.

typedef struct
{
	// in the DDR shared with the PRU
	const uintptr_t pixels_dma;

	// Length in pixels of the longest LED strip.
	unsigned num_pixels;

	// write 1 to start, 0xFF to abort. will be cleared when started
	volatile unsigned command;

	// will have a non-zero response written when done
	volatile unsigned response;
} __attribute__((__packed__)) ws281x_command_t;

Reference

About

Beagle Bone Black cape and firmware for driving a large number of WS281x LED strips.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 63.1%
  • Processing 28.8%
  • OpenEdge ABL 3.1%
  • Shell 2.2%
  • JavaScript 1.8%
  • Makefile 0.7%
  • GLSL 0.3%