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 Heroic Robotics

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

/media/uploads/bikeNomad/img_0482.jpg

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.

main.cpp

Committer:
Ned Konz
Date:
2015-06-12
Revision:
37:e25d212ee3fe
Parent:
36:9ee1ec2135d5
Child:
38:3b1ce6902a1b

File content as of revision 37:e25d212ee3fe:

#include "mbed.h"
#include "Colors.h"
#include "MMA8451Q.h"

#define MMA8451_I2C_ADDRESS (0x1d<<1)

#define INSTANTIATE_TEMPLATES 1
#include "WS2811.h"

// I/O pin usage
// PTD0 TPM0 CH0 monitor
// PTD1 TPM0 CH1 monitor
// PTD2 (D11) data output for strip# 1
// PTD3 (D12) data output for strip# 2
// PTA2 (D3) blinking eyes output (HI = ON)
// PTA5 (D5) servomotor (20 msec period; 1.0-2.0msec ON)

const unsigned DATA_OUT_PIN1 = 2; // PTD2
const unsigned DATA_OUT_PIN2 = 3; // PTD3
const unsigned MAX_LEDS_PER_STRIP = 32;

// per LED: 3 * 20 mA = 60mA max
// 60 LEDs: 60 * 60mA = 3600 mA max
// 120 LEDs: 7200 mA max
const unsigned nLEDs = MAX_LEDS_PER_STRIP;

template class WS2811<MAX_LEDS_PER_STRIP>;

typedef WS2811<MAX_LEDS_PER_STRIP> MyWS2811;

MyWS2811 lightStrip1(nLEDs, DATA_OUT_PIN1);
MyWS2811 lightStrip2(nLEDs, DATA_OUT_PIN2);

Serial pc(USBTX, USBRX);

MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
PwmOut rled(LED_RED);       // max = 0.0
PwmOut gled(LED_GREEN);     // max = 0.0
// LED_BLUE is on PTD1
PwmOut eyes(D3);            // also redLED1; max = 1.0
PwmOut servo(D5);
DigitalOut greenLED2(D4);   // max = 1.0
DigitalIn button1(D6);      // low=ON, debounced
DigitalIn button2(D7);      // low=ON, debounced

// Limits
const float maxBrite = 0.5;

const float minServo = -0.7; // -1.0 = -60°
const float maxServo = 0.6; // 1.0 = +60°

// @brief sets different colors in each of the LEDs of a strip
// @param strip the light strip
// @param sat saturation, 0.0 - 1.0
// @param brite brightness, 0.0 - 1.0
// @param hueShift shift, 0.0 - 1.0 is equivalent to 0 - 360 degrees
static void showRainbow(MyWS2811 &strip, float sat, float brite, float hueShift)
{
    unsigned nLEDs = strip.numPixels();
    for (unsigned i = 0; i < nLEDs; i++) {
        uint8_t r, g, b;
        float hue = ((float)i / (float)nLEDs) + hueShift;
        HSBtoRGB(hue, sat, brite, &r, &g, &b);
        strip.setPixelColor(i, r, g, b);
    }
    strip.show();
}

static void showSolidColor(MyWS2811 &strip, uint8_t r, uint8_t g, uint8_t b)
{
    unsigned nLEDs = strip.numPixels();
    for (unsigned i = 0; i < nLEDs; i++) {
        strip.setPixelColor(i, r, g, b);
    }
    strip.show();
}

// range is -1.0 (full CCW) to +1.0 (full CW)
static void positionServo(float pos)
{
    if (pos < minServo) pos = minServo;
    else if (pos > maxServo) pos = maxServo;

    servo.pulsewidth_us((1.5 + (pos / 2.0)) * 1000.0);
}

static void selfTestServo()
{
    pc.printf("Servo:\r\n");
    pc.printf("CCW, ");
    positionServo(-1.0);
    wait(1.0);
    pc.printf("CW, ");
    positionServo(+1.0);
    wait(1.0);
    pc.printf("center.\r\n");
    positionServo(0.0);
}

static void selfTestLEDs()
{
    pc.printf("LEDs .");
    rled = 0.0; // red LED on
    wait(1.0);
    pc.printf(".");
    rled = 1.0; // red LED off, green LED on
    gled = 0.0;
    wait(1.0);
    pc.printf(".");
    gled = 1.0; // green LED off, eyes on
    eyes = 1.0;
    wait(1.0);
    pc.printf(".");
    eyes = 0.0;
    pc.printf("\r\n");
}

static void selfTestLightStrips()
{
    pc.printf("light strips");
    uint8_t rgb[4] = { (uint8_t)(255 * maxBrite), 0, 0, 0 };
    for (int i = 0; i < 3; i++) {
        showSolidColor(lightStrip1, rgb[0], rgb[1], rgb[2]);
        showSolidColor(lightStrip2, rgb[1], rgb[2], rgb[0]);
        MyWS2811::startDMA();
        if (i == 2) break;
        wait(1.0);
        rgb[3] = rgb[2];
        rgb[2] = rgb[1];
        rgb[1] = rgb[0];
        rgb[0] = rgb[3];
        pc.printf(".");
    }

    pc.printf("\r\n");
}

static void selfTest()
{
    pc.printf("self test: ");

    selfTestServo();
    selfTestLEDs();
    selfTestLightStrips();
}

int main(void)
{
    pc.baud(115200);
    pc.printf("\r\n\r\nNevermore's Revenge!\r\ncompiled " __DATE__ ", " __TIME__ "\r\n");

    lightStrip1.begin();
    lightStrip2.begin();

    rled = 1.0;
    gled = 1.0;
    eyes = 0.0;
    greenLED2 = 0.0;
    servo.period_ms(20);

    selfTest();

    float xyz[3];
    unsigned rep = 0;

    for (;;) {
        rep ++;
        acc.getAccAllAxis(xyz);
        pc.printf("%8u x: %f y: %f z: %f\r\n", rep, xyz[0], xyz[1], xyz[2]);
        rled = 1.0 - fabs(xyz[0]);
        gled = 1.0 - fabs(xyz[1]);
        eyes = fabs(xyz[2]);
        showRainbow(lightStrip1, 1.0, maxBrite, fabs(xyz[0]));
        showRainbow(lightStrip2, 1.0, maxBrite, fabs(xyz[1]));
        MyWS2811::startDMA();
        MyWS2811::wait_for_dma_done();
        wait_us(100);
    }
}