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.
Revision 25:751c89f7e654, committed 2014-01-02
- Comitter:
- bikeNomad
- Date:
- Thu Jan 02 19:42:14 2014 +0000
- Parent:
- 24:feb1dae0403a
- Child:
- 26:ac5d0e18c7b6
- Commit message:
- added second light strip to demo.
Changed in this revision
WS2811.cpp | Show annotated file Show diff for this revision Revisions of this file |
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/WS2811.cpp Thu Jan 02 11:26:44 2014 +0000 +++ b/WS2811.cpp Thu Jan 02 19:42:14 2014 +0000 @@ -54,15 +54,13 @@ static const uint32_t tpm_p0_period = NSEC_TO_TICKS(CLK_NSEC / 3); static const uint32_t tpm_p1_period = NSEC_TO_TICKS(CLK_NSEC * 2 / 3); -enum DMA_MUX_SRC -{ +enum DMA_MUX_SRC { DMA_MUX_SRC_TPM0_CH_0 = 24, DMA_MUX_SRC_TPM0_CH_1, DMA_MUX_SRC_TPM0_Overflow = 54, }; -enum DMA_CHAN -{ +enum DMA_CHAN { DMA_CHAN_START = 0, DMA_CHAN_0_LOW = 1, DMA_CHAN_1_LOW = 2, @@ -86,8 +84,7 @@ #define BITS_PER_RGB 24 #define DMA_TRAILING_ZEROS 1 -static struct -{ +static struct { uint32_t start_t1_low[ DMA_LEADING_ZEROS ]; uint32_t dmaWords[ BITS_PER_RGB * MAX_LEDS_PER_STRIP ]; uint32_t trailing_zeros_1[ DMA_TRAILING_ZEROS ]; @@ -97,7 +94,7 @@ uint32_t trailing_zeros_2[ DMA_TRAILING_ZEROS + 1 ]; } dmaData WORD_ALIGNED; -// class static +// class static bool WS2811::is_dma_done() { return dma_done; @@ -148,11 +145,9 @@ void WS2811::io_init() { uint32_t m = 1; - for (uint32_t i = 0; i < 32; i++) - { + for (uint32_t i = 0; i < 32; i++) { // set up each pin - if (m & enabledPins) - { + if (m & enabledPins) { IO_PORT->PCR[i] = PORT_PCR_MUX(1) // GPIO | PORT_PCR_DSE_MASK; // high drive strength } @@ -235,11 +230,13 @@ // class static void WS2811::startDMA() { + hw_init(); + DMA_Type volatile * dma = DMA0; TPM_Type volatile *tpm = TPM0; uint32_t nBytes = sizeof(dmaData.start_t1_low) - + sizeof(dmaData.dmaWords) - + sizeof(dmaData.trailing_zeros_1); + + sizeof(dmaData.dmaWords) + + sizeof(dmaData.trailing_zeros_1); tpm->SC &= ~TPM_SC_CMOD_MASK; // disable internal clocking tpm->CNT = tpm_p0_period - 2 ; @@ -267,20 +264,18 @@ dma->DMA[DMA_CHAN_1_LOW].SAR = (uint32_t)(void*)dmaData.start_t1_low; // set source address dma->DMA[DMA_CHAN_1_LOW].DSR_BCR = DMA_DSR_BCR_BCR_MASK & nBytes; // length of transfer in bytes - dma->DMA[DMA_CHAN_0_LOW].DAR - = dma->DMA[DMA_CHAN_1_LOW].DAR - = dma->DMA[DMA_CHAN_START].DAR + dma->DMA[DMA_CHAN_0_LOW].DAR + = dma->DMA[DMA_CHAN_1_LOW].DAR + = dma->DMA[DMA_CHAN_START].DAR = (uint32_t)(void*)&IO_GPIO->PDOR; // wait until done - while (!is_dma_done()) - { + while (!is_dma_done()) { __WFI(); } - + // ensure sufficient guard time - while (guardtime.read_us() < 50) - { + while (guardtime.read_us() < 50) { __NOP(); } @@ -324,8 +319,7 @@ // class static void WS2811::writeByte(uint8_t byte, uint32_t mask, uint32_t *dest) { - for (uint8_t bm = 0x80; bm; bm >>= 1) - { + for (uint8_t bm = 0x80; bm; bm >>= 1) { // MSBit first if (byte & bm) *dest |= mask; @@ -347,7 +341,7 @@ #if DEBUG for (unsigned i = DMA_LEADING_ZEROS; i < DMA_LEADING_ZEROS + BITS_PER_RGB; i++) - dmaData.dmaWords[i] = DEBUG_MASK; + dmaData.dmaWords[i] = DEBUG_MASK; #else memset(dmaData.dmaWords, 0x00, sizeof(dmaData.dmaWords)); #endif @@ -355,18 +349,14 @@ void WS2811::show() { - hw_init(); uint16_t i, n = numPixels(); // 3 bytes per LED uint8_t *p = pixels; - for (i=0; i<n; i++ ) - { + for (i=0; i<n; i++ ) { writePixel(i, p); p += 3; } - - startDMA(); } extern "C" void DMA0_IRQHandler() @@ -375,20 +365,17 @@ TPM_Type volatile *tpm = TPM0; uint32_t db = dma->DMA[DMA_CHAN_START].DSR_BCR; - if (db & DMA_DSR_BCR_DONE_MASK) - { + if (db & DMA_DSR_BCR_DONE_MASK) { dma->DMA[DMA_CHAN_START].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status } db = dma->DMA[DMA_CHAN_0_LOW].DSR_BCR; - if (db & DMA_DSR_BCR_DONE_MASK) - { + if (db & DMA_DSR_BCR_DONE_MASK) { dma->DMA[DMA_CHAN_0_LOW].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status } db = dma->DMA[DMA_CHAN_1_LOW].DSR_BCR; - if (db & DMA_DSR_BCR_DONE_MASK) - { + if (db & DMA_DSR_BCR_DONE_MASK) { dma->DMA[DMA_CHAN_1_LOW].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status dma_done = true; tpm->SC &= ~TPM_SC_CMOD_MASK; // disable internal clocking
--- a/main.cpp Thu Jan 02 11:26:44 2014 +0000 +++ b/main.cpp Thu Jan 02 19:42:14 2014 +0000 @@ -5,6 +5,7 @@ // per LED: 3 * 20 mA = 60mA max // 60 LEDs: 60 * 60mA = 3600 mA max +// 120 LEDs: 7200 mA max unsigned const nLEDs = MAX_LEDS_PER_STRIP; // I/O pin usage @@ -13,24 +14,26 @@ // PTD2 data output // PTD3 debug output -unsigned const DATA_OUT_PIN = 2; // PTD2 +unsigned const DATA_OUT_PIN1 = 2; // PTD2 +unsigned const DATA_OUT_PIN2 = 3; // PTD3 Serial pc(USBTX, USBRX); +Timer timeRunning; TSISensor touchSensor; Ticker touchTicker; float touchPercentage; -float const minBrite = 0.1; -float const maxBrite = 0.7; +unsigned frames; + +float const minBrite = 0.2; +float const maxBrite = 0.5; float brite; void readTouchSensor() { touchPercentage *= 0.9; touchPercentage += touchSensor.readPercentage() * 0.1; - brite = maxBrite * touchPercentage; - if (brite < minBrite) - brite = minBrite; + brite = minBrite + (maxBrite - minBrite) * touchPercentage; } // @brief sets different colors in each of the LEDs of a strip @@ -62,28 +65,28 @@ int main(void) { pc.baud(115200); - WS2811 lightStrip(nLEDs, DATA_OUT_PIN); + WS2811 lightStrip1(nLEDs, DATA_OUT_PIN1); + WS2811 lightStrip2(nLEDs, DATA_OUT_PIN2); touchTicker.attach(&readTouchSensor, 0.1); - lightStrip.begin(); + lightStrip1.begin(); + lightStrip2.begin(); float rainbowPeriod = 1 * 1.0e6; // usec float sat = 1.0; - Timer timeRunning; timeRunning.start(); bool printed = false; - unsigned frames = 0; uint8_t r =0; uint8_t g =0; uint8_t b =0; for (;;) { - if (r < 255) + if (r < 40) r++; - else if (g < 255) + else if (g < 40) g++; - else if (b < 255) + else if (b < 40) b++; else { unsigned running = timeRunning.read_us(); @@ -92,7 +95,10 @@ } wait(0.1); - showSolidColor(lightStrip, r, g, b); + showSolidColor(lightStrip1, r, g, b); + showSolidColor(lightStrip2, r, g, b); + WS2811::startDMA(); + frames++; } @@ -106,7 +112,10 @@ pc.printf("%u frames in %u usec = %u frames / sec\r\n", frames, running, frames * 1000000 / running); printed = true; } - showRainbow(lightStrip, sat, brite, hueShift); + showRainbow(lightStrip1, sat, brite, hueShift); + showRainbow(lightStrip2, sat, brite, hueShift + 0.5); + WS2811::startDMA(); + frames ++; } }