Tuesday, December 24, 2013

Adventures in AM335x PRU Lighting

For those that don't know me I'm a big fan of the AM335x SoC series since it really allows you do anything you want professionally or hobby-wise.

Lately in my own-time I've been interested in high-end lighting systems and how I could do it better than the current projects that exist using the Beaglebone. Namely using ones the PRU the wrong way and touching the pinmux and not using the GPO/GPI exposed on the R30  + R31 registers.

Required ingredients for this all to work:
To begin we need to understand all the components that come together to make driving WS281x LEDS at 100 FPS and better.

Basically we have firmware that is loaded on the PRU cores 0 + 1 , and a slim kernel interface to talk to the output pins with WS281x LEDS.

Clocking for the WS281x chipset is slightly modified from the datasheet to allow syncing of high and low bits timing on the outputs.

low bit   -> 1.25 microseconds high (start sequence) + 1.25 microseconds low
high bit  -> 1.25 microseconds highs (start sequence) + 1.25 microseconds high
latch      -> 50+ microseconds low all outputs

Currently this firmware supports 256 RGB slots on 12 outputs for a total of 3072 LEDS... however if you use true DMX you'll need split the 256 LEDs into at least 2 DMX universes of no more than 170 LEDS each (3 x 170 = 510 slots + 2 bytes commands and padding).  The less LEDs driven overall from each output the fastest the frame rate can be.

First you need load the ws281x-pru0 and ws281x-pru1 binaries into /lib/firmware and run "echo BB-BONE-PRU-05 > /sys/devices/bone\_capemgr.\*/slots" to load the remoteproc firmware on both PRU cores. These come from building the ws28xx-lighting-pru project or getting the binaries located in the repository.

Two interfaces are exposed for controlling the LEDs first is the virtio-serial which is really low bandwidth and not a serial port interface (think no flow control or termios), but the second is a faux spidev interface which is high speed and allows using Open Lighting Architecture to control them.

Now you may say you can only run 3072 RGB LEDs (currently with the latest firmware, saving a little memory and a future alpha/white channel for another part selection) and LEDscape can drive 500 meters of WS2812 LEDS at 30 FPS (30k LEDS)... but isn't the full cost isn't the Beaglebone by far but having ~18 DMX universes with 170 RGB LEDS that are ran deterministically.

Now this is all fine but you want to something useful with this.. and here is where OLA + spidev comes into play.

root@pru:~$ opkg install
root@pru:~$ adduser ola
root@pru:~$ su ola

*write the following to ~/.ola/ola-spi.conf*
base_uid = 7a70:00000100
device_prefix = spidev
enabled = true
spidev0.0-0-dmx-address = 1
spidev0.0-0-personality = 1
spidev0.0-0-pixel-count = 128
spidev0.0-1-dmx-address = 1
spidev0.0-1-personality = 1
spidev0.0-1-pixel-count = 128
spidev0.0-backend = software
spidev0.0-ports = 2
spidev0.0-spi-ce-high = false
spidev0.0-spi-speed = 100000
spidev0.0-sync-port = 0

ola@pru:~$ olad -f
*now you can use the OLA web interface or the various language APIs*

Example of light show on 16x16 array with 2 universes of 128 LEDS each (384 slots per universe).