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.

Committer:
Ned Konz
Date:
Fri Jun 10 08:56:46 2016 -0700
Revision:
40:d5c8ce80b6c4
Parent:
39:e735259e1d2e
Added audio

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Ned Konz 34:cd56c00ed910 1 #include "mbed.h"
Ned Konz 34:cd56c00ed910 2 #include "Colors.h"
Ned Konz 34:cd56c00ed910 3 #include "MMA8451Q.h"
Ned Konz 34:cd56c00ed910 4
Ned Konz 34:cd56c00ed910 5 #define MMA8451_I2C_ADDRESS (0x1d<<1)
Ned Konz 34:cd56c00ed910 6
Ned Konz 34:cd56c00ed910 7 #define INSTANTIATE_TEMPLATES 1
Ned Konz 34:cd56c00ed910 8 #include "WS2811.h"
Ned Konz 34:cd56c00ed910 9
Ned Konz 40:d5c8ce80b6c4 10 #include "audio.h"
Ned Konz 40:d5c8ce80b6c4 11 using namespace NKAudio;
Ned Konz 40:d5c8ce80b6c4 12
Ned Konz 40:d5c8ce80b6c4 13 #include "1khz_1sec.h"
Ned Konz 40:d5c8ce80b6c4 14
Ned Konz 40:d5c8ce80b6c4 15 AudioFile audioFiles[] = {
Ned Konz 40:d5c8ce80b6c4 16 { __1khz_1sec_s8, __1khz_1sec_s8_len },
Ned Konz 40:d5c8ce80b6c4 17 { 0, 0 } // mark end
Ned Konz 40:d5c8ce80b6c4 18 };
Ned Konz 40:d5c8ce80b6c4 19
Ned Konz 34:cd56c00ed910 20 // I/O pin usage
Ned Konz 34:cd56c00ed910 21 // PTD2 (D11) data output for strip# 1
Ned Konz 34:cd56c00ed910 22 // PTD3 (D12) data output for strip# 2
Ned Konz 40:d5c8ce80b6c4 23 // PTA12 (D3) servomotor (20 msec period; 1.0-2.0msec ON)
Ned Konz 40:d5c8ce80b6c4 24 // PTA5 (D5) blinking eyes output (HI = ON)
Ned Konz 40:d5c8ce80b6c4 25 // PTE30
Ned Konz 34:cd56c00ed910 26
Ned Konz 36:9ee1ec2135d5 27 const unsigned DATA_OUT_PIN1 = 2; // PTD2
Ned Konz 36:9ee1ec2135d5 28 const unsigned DATA_OUT_PIN2 = 3; // PTD3
Ned Konz 38:3b1ce6902a1b 29
Ned Konz 38:3b1ce6902a1b 30 // actually, sides have 21 LEDs each, and ends have 10 LEDs each.
Ned Konz 38:3b1ce6902a1b 31 const unsigned MAX_LEDS_PER_STRIP = 31;
Ned Konz 34:cd56c00ed910 32
Ned Konz 34:cd56c00ed910 33 // per LED: 3 * 20 mA = 60mA max
Ned Konz 34:cd56c00ed910 34 // 60 LEDs: 60 * 60mA = 3600 mA max
Ned Konz 34:cd56c00ed910 35 // 120 LEDs: 7200 mA max
Ned Konz 36:9ee1ec2135d5 36 const unsigned nLEDs = MAX_LEDS_PER_STRIP;
Ned Konz 34:cd56c00ed910 37
Ned Konz 34:cd56c00ed910 38 template class WS2811<MAX_LEDS_PER_STRIP>;
Ned Konz 34:cd56c00ed910 39
Ned Konz 34:cd56c00ed910 40 typedef WS2811<MAX_LEDS_PER_STRIP> MyWS2811;
Ned Konz 34:cd56c00ed910 41
Ned Konz 38:3b1ce6902a1b 42 static MyWS2811 lightStrip1(nLEDs, DATA_OUT_PIN1);
Ned Konz 38:3b1ce6902a1b 43 static MyWS2811 lightStrip2(nLEDs, DATA_OUT_PIN2);
Ned Konz 34:cd56c00ed910 44
Ned Konz 34:cd56c00ed910 45 Serial pc(USBTX, USBRX);
Ned Konz 34:cd56c00ed910 46
Ned Konz 38:3b1ce6902a1b 47 // accelerometer
Ned Konz 38:3b1ce6902a1b 48 static MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
Ned Konz 38:3b1ce6902a1b 49
Ned Konz 38:3b1ce6902a1b 50 // RGB LED on FRDM board
Ned Konz 40:d5c8ce80b6c4 51 static DigitalOut rled(LED_RED); // PTB18 max = 0.0
Ned Konz 40:d5c8ce80b6c4 52 static DigitalOut gled(LED_GREEN); // PTB19 max = 0.0
Ned Konz 34:cd56c00ed910 53 // LED_BLUE is on PTD1
Ned Konz 38:3b1ce6902a1b 54
Ned Konz 40:d5c8ce80b6c4 55 static PwmOut servo(D3); // PTA12
Ned Konz 40:d5c8ce80b6c4 56 static DigitalOut eyes(D5); // PTA5
Ned Konz 39:e735259e1d2e 57
Ned Konz 39:e735259e1d2e 58 // static DigitalOut greenLED2(D4); // max = 1.0
Ned Konz 38:3b1ce6902a1b 59 static DigitalIn button1(D6); // low=ON, debounced
Ned Konz 39:e735259e1d2e 60 // static DigitalIn button2(D7); // low=ON, debounced
Ned Konz 34:cd56c00ed910 61
Ned Konz 36:9ee1ec2135d5 62 // Limits
Ned Konz 36:9ee1ec2135d5 63 const float maxBrite = 0.5;
Ned Konz 36:9ee1ec2135d5 64 const float minServo = -0.7; // -1.0 = -60°
Ned Konz 36:9ee1ec2135d5 65 const float maxServo = 0.6; // 1.0 = +60°
Ned Konz 39:e735259e1d2e 66
Ned Konz 39:e735259e1d2e 67 // const float minFlapTime = (maxServo - minServo) * 0.17; // 0.17 seconds / 60° at 4.8V
Ned Konz 39:e735259e1d2e 68 const float minFlapTime = 0.5;
Ned Konz 38:3b1ce6902a1b 69 const float maxFlapTime = 1.0;
Ned Konz 40:d5c8ce80b6c4 70 float currentPosition = 1.0;
Ned Konz 40:d5c8ce80b6c4 71 float currentSpeed = 1.0;
Ned Konz 34:cd56c00ed910 72
Ned Konz 34:cd56c00ed910 73 // @brief sets different colors in each of the LEDs of a strip
Ned Konz 34:cd56c00ed910 74 // @param strip the light strip
Ned Konz 34:cd56c00ed910 75 // @param sat saturation, 0.0 - 1.0
Ned Konz 34:cd56c00ed910 76 // @param brite brightness, 0.0 - 1.0
Ned Konz 34:cd56c00ed910 77 // @param hueShift shift, 0.0 - 1.0 is equivalent to 0 - 360 degrees
Ned Konz 39:e735259e1d2e 78 static void showRainbow(MyWS2811 &strip, float sat, float brite, float hueShift, float hueRange = 1.0, int span = 1, int skip=0)
Ned Konz 34:cd56c00ed910 79 {
Ned Konz 39:e735259e1d2e 80 int nLEDs = strip.numPixels();
Ned Konz 39:e735259e1d2e 81 int direction, first, last;
Ned Konz 39:e735259e1d2e 82
Ned Konz 39:e735259e1d2e 83 if (span < 0) {
Ned Konz 39:e735259e1d2e 84 direction = -1;
Ned Konz 39:e735259e1d2e 85 first = nLEDs-1;
Ned Konz 39:e735259e1d2e 86 last = -1;
Ned Konz 39:e735259e1d2e 87 span = -span;
Ned Konz 39:e735259e1d2e 88 skip = -skip;
Ned Konz 39:e735259e1d2e 89 } else {
Ned Konz 39:e735259e1d2e 90 direction = 1;
Ned Konz 39:e735259e1d2e 91 first = 0;
Ned Konz 39:e735259e1d2e 92 last = nLEDs;
Ned Konz 39:e735259e1d2e 93 }
Ned Konz 39:e735259e1d2e 94
Ned Konz 40:d5c8ce80b6c4 95 for (int i = first; i != last; i += direction) {
Ned Konz 34:cd56c00ed910 96 uint8_t r, g, b;
Ned Konz 38:3b1ce6902a1b 97 float hue = (i * hueRange / nLEDs) + hueShift;
Ned Konz 34:cd56c00ed910 98 HSBtoRGB(hue, sat, brite, &r, &g, &b);
Ned Konz 39:e735259e1d2e 99 if ((i + skip) % span == 0)
Ned Konz 39:e735259e1d2e 100 strip.setPixelColor((unsigned)i, r, g, b);
Ned Konz 39:e735259e1d2e 101 else
Ned Konz 39:e735259e1d2e 102 strip.setPixelColor((unsigned)i, 0, 0, 0);
Ned Konz 34:cd56c00ed910 103 }
Ned Konz 34:cd56c00ed910 104 strip.show();
Ned Konz 34:cd56c00ed910 105 }
Ned Konz 34:cd56c00ed910 106
Ned Konz 34:cd56c00ed910 107 static void showSolidColor(MyWS2811 &strip, uint8_t r, uint8_t g, uint8_t b)
Ned Konz 34:cd56c00ed910 108 {
Ned Konz 34:cd56c00ed910 109 unsigned nLEDs = strip.numPixels();
Ned Konz 40:d5c8ce80b6c4 110 for (unsigned i = 0; i < nLEDs; i++) {
Ned Konz 34:cd56c00ed910 111 strip.setPixelColor(i, r, g, b);
Ned Konz 34:cd56c00ed910 112 }
Ned Konz 34:cd56c00ed910 113 strip.show();
Ned Konz 34:cd56c00ed910 114 }
Ned Konz 34:cd56c00ed910 115
Ned Konz 36:9ee1ec2135d5 116 // range is -1.0 (full CCW) to +1.0 (full CW)
Ned Konz 36:9ee1ec2135d5 117 static void positionServo(float pos)
Ned Konz 36:9ee1ec2135d5 118 {
Ned Konz 38:3b1ce6902a1b 119 if (pos < minServo)
Ned Konz 38:3b1ce6902a1b 120 pos = minServo;
Ned Konz 38:3b1ce6902a1b 121 else if (pos > maxServo)
Ned Konz 38:3b1ce6902a1b 122 pos = maxServo;
Ned Konz 38:3b1ce6902a1b 123
Ned Konz 38:3b1ce6902a1b 124 if (pos < 0.0) {
Ned Konz 39:e735259e1d2e 125 rled = 0;
Ned Konz 39:e735259e1d2e 126 gled = 1;
Ned Konz 40:d5c8ce80b6c4 127 } else if (pos > 0.0) {
Ned Konz 39:e735259e1d2e 128 rled = 1;
Ned Konz 39:e735259e1d2e 129 gled = 0;
Ned Konz 40:d5c8ce80b6c4 130 } else {
Ned Konz 39:e735259e1d2e 131 rled = gled = 1;
Ned Konz 38:3b1ce6902a1b 132 }
Ned Konz 36:9ee1ec2135d5 133
Ned Konz 36:9ee1ec2135d5 134 servo.pulsewidth_us((1.5 + (pos / 2.0)) * 1000.0);
Ned Konz 36:9ee1ec2135d5 135 }
Ned Konz 36:9ee1ec2135d5 136
Ned Konz 40:d5c8ce80b6c4 137 void flap()
Ned Konz 40:d5c8ce80b6c4 138 {
Ned Konz 40:d5c8ce80b6c4 139 positionServo(currentPosition);
Ned Konz 40:d5c8ce80b6c4 140 currentPosition = -currentPosition;
Ned Konz 40:d5c8ce80b6c4 141 }
Ned Konz 40:d5c8ce80b6c4 142
Ned Konz 36:9ee1ec2135d5 143 static void selfTestServo()
Ned Konz 34:cd56c00ed910 144 {
Ned Konz 36:9ee1ec2135d5 145 pc.printf("Servo:\r\n");
Ned Konz 36:9ee1ec2135d5 146 pc.printf("CCW, ");
Ned Konz 36:9ee1ec2135d5 147 positionServo(-1.0);
Ned Konz 36:9ee1ec2135d5 148 wait(1.0);
Ned Konz 36:9ee1ec2135d5 149 pc.printf("CW, ");
Ned Konz 36:9ee1ec2135d5 150 positionServo(+1.0);
Ned Konz 36:9ee1ec2135d5 151 wait(1.0);
Ned Konz 36:9ee1ec2135d5 152 pc.printf("center.\r\n");
Ned Konz 36:9ee1ec2135d5 153 positionServo(0.0);
Ned Konz 36:9ee1ec2135d5 154 }
Ned Konz 34:cd56c00ed910 155
Ned Konz 36:9ee1ec2135d5 156 static void selfTestLEDs()
Ned Konz 36:9ee1ec2135d5 157 {
Ned Konz 34:cd56c00ed910 158 pc.printf("LEDs .");
Ned Konz 39:e735259e1d2e 159 rled = 0; // red LED on
Ned Konz 38:3b1ce6902a1b 160 wait(0.5);
Ned Konz 34:cd56c00ed910 161 pc.printf(".");
Ned Konz 39:e735259e1d2e 162 rled = 1; // red LED off, green LED on
Ned Konz 39:e735259e1d2e 163 gled = 0;
Ned Konz 38:3b1ce6902a1b 164 wait(0.5);
Ned Konz 34:cd56c00ed910 165 pc.printf(".");
Ned Konz 39:e735259e1d2e 166 gled = 1; // green LED off, eyes on
Ned Konz 39:e735259e1d2e 167 eyes = 1;
Ned Konz 38:3b1ce6902a1b 168 wait(0.5);
Ned Konz 34:cd56c00ed910 169 pc.printf(".");
Ned Konz 39:e735259e1d2e 170 eyes = 0;
Ned Konz 36:9ee1ec2135d5 171 pc.printf("\r\n");
Ned Konz 36:9ee1ec2135d5 172 }
Ned Konz 34:cd56c00ed910 173
Ned Konz 38:3b1ce6902a1b 174 static void refreshLightStrips()
Ned Konz 38:3b1ce6902a1b 175 {
Ned Konz 38:3b1ce6902a1b 176 MyWS2811::startDMA();
Ned Konz 38:3b1ce6902a1b 177 // 24 bits per LED, 800kHz (1.25usec/bit)
Ned Konz 38:3b1ce6902a1b 178 // wait_us((MAX_LEDS_PER_STRIP * 24 * 10 / 8) + 100);
Ned Konz 38:3b1ce6902a1b 179 }
Ned Konz 38:3b1ce6902a1b 180
Ned Konz 38:3b1ce6902a1b 181 static void blankLightStrips()
Ned Konz 38:3b1ce6902a1b 182 {
Ned Konz 38:3b1ce6902a1b 183 showSolidColor(lightStrip1, 0, 0, 0);
Ned Konz 38:3b1ce6902a1b 184 showSolidColor(lightStrip2, 0, 0, 0);
Ned Konz 38:3b1ce6902a1b 185 refreshLightStrips();
Ned Konz 38:3b1ce6902a1b 186 }
Ned Konz 38:3b1ce6902a1b 187
Ned Konz 36:9ee1ec2135d5 188 static void selfTestLightStrips()
Ned Konz 36:9ee1ec2135d5 189 {
Ned Konz 38:3b1ce6902a1b 190 blankLightStrips();
Ned Konz 34:cd56c00ed910 191 pc.printf("light strips");
Ned Konz 37:e25d212ee3fe 192 uint8_t rgb[4] = { (uint8_t)(255 * maxBrite), 0, 0, 0 };
Ned Konz 40:d5c8ce80b6c4 193 for (int i = 0; i < 3; i++) {
Ned Konz 34:cd56c00ed910 194 showSolidColor(lightStrip1, rgb[0], rgb[1], rgb[2]);
Ned Konz 34:cd56c00ed910 195 showSolidColor(lightStrip2, rgb[1], rgb[2], rgb[0]);
Ned Konz 38:3b1ce6902a1b 196 refreshLightStrips();
Ned Konz 34:cd56c00ed910 197 wait(1.0);
Ned Konz 34:cd56c00ed910 198 rgb[3] = rgb[2];
Ned Konz 34:cd56c00ed910 199 rgb[2] = rgb[1];
Ned Konz 34:cd56c00ed910 200 rgb[1] = rgb[0];
Ned Konz 34:cd56c00ed910 201 rgb[0] = rgb[3];
Ned Konz 34:cd56c00ed910 202 pc.printf(".");
Ned Konz 34:cd56c00ed910 203 }
Ned Konz 38:3b1ce6902a1b 204 blankLightStrips();
Ned Konz 34:cd56c00ed910 205 pc.printf("\r\n");
Ned Konz 34:cd56c00ed910 206 }
Ned Konz 34:cd56c00ed910 207
Ned Konz 36:9ee1ec2135d5 208 static void selfTest()
Ned Konz 36:9ee1ec2135d5 209 {
Ned Konz 36:9ee1ec2135d5 210 pc.printf("self test: ");
Ned Konz 36:9ee1ec2135d5 211
Ned Konz 39:e735259e1d2e 212 selfTestLightStrips();
Ned Konz 36:9ee1ec2135d5 213 selfTestServo();
Ned Konz 36:9ee1ec2135d5 214 selfTestLEDs();
Ned Konz 40:d5c8ce80b6c4 215
Ned Konz 40:d5c8ce80b6c4 216 pc.printf("done\n");
Ned Konz 38:3b1ce6902a1b 217 }
Ned Konz 38:3b1ce6902a1b 218
Ned Konz 38:3b1ce6902a1b 219 // rainbow that wraps around entire frame
Ned Konz 38:3b1ce6902a1b 220 void updateStripsRainbow()
Ned Konz 38:3b1ce6902a1b 221 {
Ned Konz 39:e735259e1d2e 222 static int skip = 0;
Ned Konz 39:e735259e1d2e 223
Ned Konz 39:e735259e1d2e 224 showRainbow(lightStrip1, 1.0, maxBrite, currentSpeed, 0.5, 3, skip);
Ned Konz 39:e735259e1d2e 225 showRainbow(lightStrip2, 1.0, maxBrite, currentSpeed + 0.5, 0.5, -3, skip);
Ned Konz 38:3b1ce6902a1b 226 refreshLightStrips();
Ned Konz 39:e735259e1d2e 227 skip++;
Ned Konz 39:e735259e1d2e 228 skip %= 3;
Ned Konz 38:3b1ce6902a1b 229 }
Ned Konz 38:3b1ce6902a1b 230
Ned Konz 40:d5c8ce80b6c4 231 void updateEyes()
Ned Konz 38:3b1ce6902a1b 232 {
Ned Konz 40:d5c8ce80b6c4 233 static bool eyesOn;
Ned Konz 40:d5c8ce80b6c4 234 eyes = eyesOn ? 1 : 0;
Ned Konz 40:d5c8ce80b6c4 235 eyesOn = !eyesOn;
Ned Konz 38:3b1ce6902a1b 236 }
Ned Konz 38:3b1ce6902a1b 237
Ned Konz 34:cd56c00ed910 238 int main(void)
Ned Konz 34:cd56c00ed910 239 {
Ned Konz 34:cd56c00ed910 240 pc.baud(115200);
Ned Konz 36:9ee1ec2135d5 241 pc.printf("\r\n\r\nNevermore's Revenge!\r\ncompiled " __DATE__ ", " __TIME__ "\r\n");
Ned Konz 34:cd56c00ed910 242
Ned Konz 34:cd56c00ed910 243 lightStrip1.begin();
Ned Konz 34:cd56c00ed910 244 lightStrip2.begin();
Ned Konz 34:cd56c00ed910 245
Ned Konz 38:3b1ce6902a1b 246 rled = 1.0;
Ned Konz 38:3b1ce6902a1b 247 gled = 1.0;
Ned Konz 36:9ee1ec2135d5 248 servo.period_ms(20);
Ned Konz 34:cd56c00ed910 249
Ned Konz 34:cd56c00ed910 250 selfTest();
Ned Konz 34:cd56c00ed910 251
Ned Konz 40:d5c8ce80b6c4 252 Timer elapsedTime;
Ned Konz 38:3b1ce6902a1b 253
Ned Konz 40:d5c8ce80b6c4 254 Ticker flapper;
Ned Konz 40:d5c8ce80b6c4 255 flapper.attach(flap, maxFlapTime);
Ned Konz 40:d5c8ce80b6c4 256
Ned Konz 40:d5c8ce80b6c4 257 Ticker stripUpdater;
Ned Konz 40:d5c8ce80b6c4 258 stripUpdater.attach(updateStripsRainbow, 0.3);
Ned Konz 40:d5c8ce80b6c4 259
Ned Konz 40:d5c8ce80b6c4 260 Ticker eyeUpdater;
Ned Konz 40:d5c8ce80b6c4 261 eyeUpdater.attach(updateEyes, 0.2);
Ned Konz 40:d5c8ce80b6c4 262
Ned Konz 39:e735259e1d2e 263 elapsedTime.start();
Ned Konz 39:e735259e1d2e 264
Ned Konz 40:d5c8ce80b6c4 265 bool lastButton = button1.read();
Ned Konz 34:cd56c00ed910 266
Ned Konz 40:d5c8ce80b6c4 267 for (;; ) {
Ned Konz 40:d5c8ce80b6c4 268 bool buttonValue = button1.read();
Ned Konz 40:d5c8ce80b6c4 269 if (buttonValue != lastButton) {
Ned Konz 40:d5c8ce80b6c4 270 if (!buttonValue) {
Ned Konz 40:d5c8ce80b6c4 271 flapper.detach();
Ned Konz 40:d5c8ce80b6c4 272 flapper.attach(flap, maxFlapTime);
Ned Konz 40:d5c8ce80b6c4 273 stripUpdater.detach();
Ned Konz 40:d5c8ce80b6c4 274 stripUpdater.attach(updateStripsRainbow, 0.3);
Ned Konz 40:d5c8ce80b6c4 275 } else {
Ned Konz 40:d5c8ce80b6c4 276 flapper.detach();
Ned Konz 40:d5c8ce80b6c4 277 flapper.attach(flap, minFlapTime);
Ned Konz 40:d5c8ce80b6c4 278 stripUpdater.detach();
Ned Konz 40:d5c8ce80b6c4 279 stripUpdater.attach(updateStripsRainbow, 0.1);
Ned Konz 40:d5c8ce80b6c4 280 }
Ned Konz 38:3b1ce6902a1b 281 }
Ned Konz 38:3b1ce6902a1b 282
Ned Konz 40:d5c8ce80b6c4 283 wait(0.1);
Ned Konz 34:cd56c00ed910 284 }
Ned Konz 34:cd56c00ed910 285 }