Test program for my Multi_WS2811 library that started out as a fork of heroic/WS2811. My library uses hardware DMA on the FRDM-KL25Z to drive up to 16 strings of WS2811 or WS2812 LEDs in parallel.
Dependencies: Multi_WS2811 mbed MMA8451Q
Fork of WS2811 by
NOTE: I have accidentally pushed changes for another fork of this program that I used in the recent Georgetown Carnival Power Tool Races. When I get some time, I will restore the test program to its original glory.
You can see my power tool racer (Nevermore's Revenge) here

This tests my FRDM-KL25Z multi-string WS2811/WS2812 library. It uses the accelerometer to change the rainbow phase on two strings of LEDs as well as the touch sense to change brightness.
A video of this program in operation is here.
Here is the library that I developed to run the LEDs:
Import libraryMulti_WS2811
Library allowing up to 16 strings of 60 WS2811 or WS2812 LEDs to be driven from a single FRDM-KL25Z board. Uses hardware DMA to do a full 800 KHz rate without much CPU burden.
WS2812.cpp@15:331e139672b5, 2013-12-05 (annotated)
- Committer:
- bikeNomad
- Date:
- Thu Dec 05 15:12:47 2013 +0000
- Revision:
- 15:331e139672b5
inlined bit writes
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| bikeNomad | 15:331e139672b5 | 1 | // 800 KHz WS2812 driver, kinda. |
| bikeNomad | 15:331e139672b5 | 2 | // |
| bikeNomad | 15:331e139672b5 | 3 | // Parameterized and modified to use soft SPI. |
| bikeNomad | 15:331e139672b5 | 4 | // Jas Strong <jasmine@electronpusher.org> |
| bikeNomad | 15:331e139672b5 | 5 | // Modified to use hard SPI by Ned Konz <ned@bike-nomad.com> |
| bikeNomad | 15:331e139672b5 | 6 | /*****************************************************************************/ |
| bikeNomad | 15:331e139672b5 | 7 | |
| bikeNomad | 15:331e139672b5 | 8 | #include "LedStrip.h" |
| bikeNomad | 15:331e139672b5 | 9 | #include "WS2812.h" |
| bikeNomad | 15:331e139672b5 | 10 | |
| bikeNomad | 15:331e139672b5 | 11 | WS2812::WS2812(int n, PinName mosi, PinName sclk) : |
| bikeNomad | 15:331e139672b5 | 12 | LedStrip(n), |
| bikeNomad | 15:331e139672b5 | 13 | spi(mosi, NC, sclk) |
| bikeNomad | 15:331e139672b5 | 14 | { |
| bikeNomad | 15:331e139672b5 | 15 | #ifdef TARGET_KL25Z |
| bikeNomad | 15:331e139672b5 | 16 | spi.format(8, 3); |
| bikeNomad | 15:331e139672b5 | 17 | #else |
| bikeNomad | 15:331e139672b5 | 18 | spi.format(16, 3); |
| bikeNomad | 15:331e139672b5 | 19 | #endif |
| bikeNomad | 15:331e139672b5 | 20 | spi.frequency(800e3 * 16); // 12.8 MHz => 800KHz bit rate |
| bikeNomad | 15:331e139672b5 | 21 | } |
| bikeNomad | 15:331e139672b5 | 22 | |
| bikeNomad | 15:331e139672b5 | 23 | /* |
| bikeNomad | 15:331e139672b5 | 24 | * These chips use a one-wire protocol based on a sort of NRZ signalling- jas. |
| bikeNomad | 15:331e139672b5 | 25 | */ |
| bikeNomad | 15:331e139672b5 | 26 | |
| bikeNomad | 15:331e139672b5 | 27 | inline void WS2812::writebit(bool bit) |
| bikeNomad | 15:331e139672b5 | 28 | { |
| bikeNomad | 15:331e139672b5 | 29 | if (bit) { |
| bikeNomad | 15:331e139672b5 | 30 | #ifdef TARGET_KL25Z |
| bikeNomad | 15:331e139672b5 | 31 | spi.write(0xff); // 8 high |
| bikeNomad | 15:331e139672b5 | 32 | spi.write(0x00); // 8 low |
| bikeNomad | 15:331e139672b5 | 33 | #else |
| bikeNomad | 15:331e139672b5 | 34 | spi.write(0xff00); |
| bikeNomad | 15:331e139672b5 | 35 | #endif |
| bikeNomad | 15:331e139672b5 | 36 | } else { |
| bikeNomad | 15:331e139672b5 | 37 | #ifdef TARGET_KL25Z |
| bikeNomad | 15:331e139672b5 | 38 | spi.write(0xe0); // 3 high, 5 low |
| bikeNomad | 15:331e139672b5 | 39 | spi.write(0x00); // +8 low |
| bikeNomad | 15:331e139672b5 | 40 | #else |
| bikeNomad | 15:331e139672b5 | 41 | spi.write(0xe000); |
| bikeNomad | 15:331e139672b5 | 42 | #endif |
| bikeNomad | 15:331e139672b5 | 43 | } |
| bikeNomad | 15:331e139672b5 | 44 | } |
| bikeNomad | 15:331e139672b5 | 45 | |
| bikeNomad | 15:331e139672b5 | 46 | void WS2812::write(uint8_t byte) |
| bikeNomad | 15:331e139672b5 | 47 | { |
| bikeNomad | 15:331e139672b5 | 48 | writebit(byte & 0x80); |
| bikeNomad | 15:331e139672b5 | 49 | writebit(byte & 0x40); |
| bikeNomad | 15:331e139672b5 | 50 | writebit(byte & 0x20); |
| bikeNomad | 15:331e139672b5 | 51 | writebit(byte & 0x10); |
| bikeNomad | 15:331e139672b5 | 52 | writebit(byte & 0x08); |
| bikeNomad | 15:331e139672b5 | 53 | writebit(byte & 0x04); |
| bikeNomad | 15:331e139672b5 | 54 | writebit(byte & 0x02); |
| bikeNomad | 15:331e139672b5 | 55 | writebit(byte & 0x01); |
| bikeNomad | 15:331e139672b5 | 56 | } |
| bikeNomad | 15:331e139672b5 | 57 | |
| bikeNomad | 15:331e139672b5 | 58 | void WS2812::begin(void) |
| bikeNomad | 15:331e139672b5 | 59 | { |
| bikeNomad | 15:331e139672b5 | 60 | blank(); |
| bikeNomad | 15:331e139672b5 | 61 | show(); |
| bikeNomad | 15:331e139672b5 | 62 | } |
| bikeNomad | 15:331e139672b5 | 63 | |
| bikeNomad | 15:331e139672b5 | 64 | void WS2812::blank(void) |
| bikeNomad | 15:331e139672b5 | 65 | { |
| bikeNomad | 15:331e139672b5 | 66 | memset(pixels, 0x00, numPixelBytes()); |
| bikeNomad | 15:331e139672b5 | 67 | } |
| bikeNomad | 15:331e139672b5 | 68 | |
| bikeNomad | 15:331e139672b5 | 69 | void WS2812::show(void) |
| bikeNomad | 15:331e139672b5 | 70 | { |
| bikeNomad | 15:331e139672b5 | 71 | uint16_t i, nl3 = numPixelBytes(); // 3 bytes per LED |
| bikeNomad | 15:331e139672b5 | 72 | while (guardtime.read_us() < 50) |
| bikeNomad | 15:331e139672b5 | 73 | /* spin */; |
| bikeNomad | 15:331e139672b5 | 74 | __disable_irq(); |
| bikeNomad | 15:331e139672b5 | 75 | for (i=0; i<nl3; i++ ) { |
| bikeNomad | 15:331e139672b5 | 76 | write(pixels[i]); |
| bikeNomad | 15:331e139672b5 | 77 | } |
| bikeNomad | 15:331e139672b5 | 78 | __enable_irq(); |
| bikeNomad | 15:331e139672b5 | 79 | guardtime.reset(); |
| bikeNomad | 15:331e139672b5 | 80 | } |
| bikeNomad | 15:331e139672b5 | 81 | |
| bikeNomad | 15:331e139672b5 | 82 |
Ned Konz


Generic WS2811/WS2812