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:
bikeNomad
Date:
Sat Dec 21 04:32:21 2013 +0000
Revision:
20:b9d76e567637
Parent:
17:b4e9d8f4baa9
Child:
21:4541da183397
still trying to get DMA to work

Who changed what in which revision?

UserRevisionLine numberNew contents of line
heroic 10:62368b801d16 1 // 800 KHz WS2811 driver, kinda.
heroic 8:e3249c2b7607 2 //
heroic 8:e3249c2b7607 3 // Parameterized and modified to use soft SPI.
heroic 8:e3249c2b7607 4 // Jas Strong <jasmine@electronpusher.org>
bikeNomad 17:b4e9d8f4baa9 5 // Modified to use hard SPI by Ned Konz <ned@bike-nomad.com>
heroic 8:e3249c2b7607 6 /*****************************************************************************/
heroic 8:e3249c2b7607 7
heroic 8:e3249c2b7607 8 #include "LedStrip.h"
heroic 8:e3249c2b7607 9 #include "WS2811.h"
bikeNomad 20:b9d76e567637 10 extern void dump_spi_settings(SPI_Type const *spi);
bikeNomad 20:b9d76e567637 11 extern Serial pc;
bikeNomad 20:b9d76e567637 12 extern DigitalOut debugOut;
heroic 8:e3249c2b7607 13
bikeNomad 20:b9d76e567637 14 static const unsigned DMA_MUX_SRC_SPI0_Transmit = 17;
bikeNomad 20:b9d76e567637 15 // const unsigned DMA_MUX_SRC_SPI1_Transmit = 19;
bikeNomad 20:b9d76e567637 16
bikeNomad 20:b9d76e567637 17 static const unsigned dmaWriteChannel = 0;
bikeNomad 20:b9d76e567637 18 static const unsigned dmaXmitMuxSrc = DMA_MUX_SRC_SPI0_Transmit;
bikeNomad 20:b9d76e567637 19
bikeNomad 20:b9d76e567637 20 static volatile bool dma_done = false;
bikeNomad 20:b9d76e567637 21
bikeNomad 20:b9d76e567637 22 // 12.8 MHz => 800KHz bit rate (1.25 usec/byte)
bikeNomad 20:b9d76e567637 23
bikeNomad 20:b9d76e567637 24 WS2811::WS2811(int n, SPI_Type *_spi, PinName _mosi, PinName sclk) :
bikeNomad 17:b4e9d8f4baa9 25 LedStrip(n),
bikeNomad 20:b9d76e567637 26 spi(_spi),
bikeNomad 20:b9d76e567637 27 mosi(_mosi)
bikeNomad 17:b4e9d8f4baa9 28 {
bikeNomad 20:b9d76e567637 29 SPI spitemp(_mosi, NC, sclk);
bikeNomad 20:b9d76e567637 30 spitemp.format(8,3);
bikeNomad 20:b9d76e567637 31 spitemp.frequency(800e3 * 16 * 2); // 12 MHz (48MHz/60) => 750KHz rate (1.33 usec/byte)
bikeNomad 20:b9d76e567637 32
bikeNomad 20:b9d76e567637 33 //Enable DMA clocking
bikeNomad 20:b9d76e567637 34 SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK; // Enable clock to DMA mux
bikeNomad 20:b9d76e567637 35 SIM->SCGC7 |= SIM_SCGC7_DMA_MASK; // Enable clock to DMA
bikeNomad 20:b9d76e567637 36
bikeNomad 20:b9d76e567637 37 // reset DMAMUX
bikeNomad 20:b9d76e567637 38 DMAMUX0->CHCFG[dmaWriteChannel] = 0;
bikeNomad 20:b9d76e567637 39 DMAMUX0->CHCFG[dmaWriteChannel] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(dmaXmitMuxSrc);
bikeNomad 20:b9d76e567637 40
bikeNomad 20:b9d76e567637 41 // Enable DMA features within the SPI registers
bikeNomad 20:b9d76e567637 42 spi->C1 |= SPI_C1_SPTIE_MASK | // enable transmit-interrupt
bikeNomad 20:b9d76e567637 43 SPI_C1_MSTR_MASK;
heroic 8:e3249c2b7607 44 }
heroic 8:e3249c2b7607 45
heroic 8:e3249c2b7607 46 /*
bikeNomad 20:b9d76e567637 47 * These chips use a one-wire protocol based on a sort of NRZ signalling- jas.
bikeNomad 20:b9d76e567637 48 * Spec is 1.25usec +/- 600nsec => 650nsec to 1850nsec
heroic 8:e3249c2b7607 49 */
bikeNomad 17:b4e9d8f4baa9 50
bikeNomad 20:b9d76e567637 51
bikeNomad 20:b9d76e567637 52 void WS2811::startDMA()
bikeNomad 17:b4e9d8f4baa9 53 {
bikeNomad 20:b9d76e567637 54 DMA0->DMA[dmaWriteChannel].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status
bikeNomad 20:b9d76e567637 55 DMA0->DMA[dmaWriteChannel].SAR = (uint32_t)(void*)dmaBytes; // set source address
bikeNomad 20:b9d76e567637 56 DMA0->DMA[dmaWriteChannel].DAR = (uint32_t)(void*)&(spi->D); // set dest address: SPI0_Data register
bikeNomad 20:b9d76e567637 57 DMA0->DMA[dmaWriteChannel].DSR_BCR |= DMA_DSR_BCR_BCR_MASK & sizeof(dmaBytes); // length of transfer
bikeNomad 20:b9d76e567637 58 DMA0->DMA[dmaWriteChannel].DCR = DMA_DCR_EINT_MASK | // enable interrupt on end of transfer
bikeNomad 20:b9d76e567637 59 DMA_DCR_ERQ_MASK |
bikeNomad 20:b9d76e567637 60 DMA_DCR_SINC_MASK |
bikeNomad 20:b9d76e567637 61 DMA_DCR_SSIZE(0x01) |
bikeNomad 20:b9d76e567637 62 DMA_DCR_DSIZE(0x01) |
bikeNomad 20:b9d76e567637 63 // DMA_DCR_START_MASK |
bikeNomad 20:b9d76e567637 64 DMA_DCR_D_REQ_MASK; // clear ERQ on end of transfer
bikeNomad 20:b9d76e567637 65
bikeNomad 20:b9d76e567637 66 dump_spi_settings(spi);
bikeNomad 20:b9d76e567637 67
bikeNomad 20:b9d76e567637 68 debugOut = 1;
bikeNomad 20:b9d76e567637 69
bikeNomad 20:b9d76e567637 70 while (!(spi->S & SPI_S_SPTEF_MASK))
bikeNomad 20:b9d76e567637 71 __NOP();
bikeNomad 20:b9d76e567637 72 spi->D = dmaBytes[0];
bikeNomad 20:b9d76e567637 73
bikeNomad 20:b9d76e567637 74 dma_done = false;
bikeNomad 20:b9d76e567637 75
bikeNomad 20:b9d76e567637 76 spi->C2 |= SPI_C2_TXDMAE_MASK;
bikeNomad 20:b9d76e567637 77
bikeNomad 20:b9d76e567637 78 // wait until done
bikeNomad 20:b9d76e567637 79 // while (!(DMA0->DMA[dmaWriteChannel].DSR_BCR & DMA_DSR_BCR_DONE_MASK))
bikeNomad 20:b9d76e567637 80 while (!dma_done)
bikeNomad 20:b9d76e567637 81 __NOP();
bikeNomad 20:b9d76e567637 82
bikeNomad 20:b9d76e567637 83 spi->C2 &= ~SPI_C2_TXDMAE_MASK;
bikeNomad 20:b9d76e567637 84 debugOut = 0;
bikeNomad 20:b9d76e567637 85
bikeNomad 20:b9d76e567637 86 dump_spi_settings(spi);
bikeNomad 20:b9d76e567637 87
heroic 8:e3249c2b7607 88 }
heroic 8:e3249c2b7607 89
bikeNomad 20:b9d76e567637 90 void WS2811::writePixel(uint8_t *p)
bikeNomad 17:b4e9d8f4baa9 91 {
bikeNomad 20:b9d76e567637 92 writeByte(*p++, dmaBytes + 0);
bikeNomad 20:b9d76e567637 93 writeByte(*p++, dmaBytes + 16);
bikeNomad 20:b9d76e567637 94 writeByte(*p, dmaBytes + 32);
bikeNomad 20:b9d76e567637 95 // printf("DMA Bytes:\r\n");
bikeNomad 20:b9d76e567637 96 // for (int i = 0; i < sizeof(dmaBytes); i++)
bikeNomad 20:b9d76e567637 97 // printf(" %02x", dmaBytes[i]);
bikeNomad 20:b9d76e567637 98 // printf("\r\n");
bikeNomad 20:b9d76e567637 99 startDMA();
bikeNomad 20:b9d76e567637 100 }
bikeNomad 20:b9d76e567637 101
bikeNomad 20:b9d76e567637 102 void WS2811::writeByte(uint8_t byte, uint8_t *dest)
bikeNomad 20:b9d76e567637 103 {
bikeNomad 20:b9d76e567637 104 for (uint8_t mask = 0x80; mask; mask >>= 1) {
bikeNomad 20:b9d76e567637 105 if (mask & byte)
bikeNomad 20:b9d76e567637 106 *dest++ = 0xff; // 8 high
bikeNomad 20:b9d76e567637 107 else
bikeNomad 20:b9d76e567637 108 *dest++ = 0xe0; // 3 high, 5 low
bikeNomad 20:b9d76e567637 109 *dest++ = 0x00; // 8 more low
bikeNomad 20:b9d76e567637 110 }
heroic 8:e3249c2b7607 111 }
heroic 8:e3249c2b7607 112
bikeNomad 17:b4e9d8f4baa9 113 void WS2811::begin(void)
bikeNomad 17:b4e9d8f4baa9 114 {
heroic 8:e3249c2b7607 115 blank();
heroic 8:e3249c2b7607 116 show();
heroic 8:e3249c2b7607 117 }
heroic 8:e3249c2b7607 118
bikeNomad 17:b4e9d8f4baa9 119 void WS2811::blank(void)
bikeNomad 17:b4e9d8f4baa9 120 {
bikeNomad 17:b4e9d8f4baa9 121 memset(pixels, 0x00, numPixelBytes());
heroic 8:e3249c2b7607 122 }
heroic 8:e3249c2b7607 123
bikeNomad 20:b9d76e567637 124
bikeNomad 17:b4e9d8f4baa9 125 void WS2811::show(void)
bikeNomad 17:b4e9d8f4baa9 126 {
bikeNomad 20:b9d76e567637 127 uint16_t i, n = numPixels(); // 3 bytes per LED
bikeNomad 20:b9d76e567637 128 uint8_t *p = pixels;
heroic 8:e3249c2b7607 129 while (guardtime.read_us() < 50)
bikeNomad 20:b9d76e567637 130 __NOP();
bikeNomad 20:b9d76e567637 131 for (i=0; i<n; i++ ) {
bikeNomad 20:b9d76e567637 132 writePixel(p);
bikeNomad 20:b9d76e567637 133 pc.printf("%d> ", i);
bikeNomad 20:b9d76e567637 134 pc.getc();
bikeNomad 20:b9d76e567637 135 p += 3;
heroic 8:e3249c2b7607 136 }
heroic 8:e3249c2b7607 137 guardtime.reset();
heroic 8:e3249c2b7607 138 }
heroic 8:e3249c2b7607 139
bikeNomad 20:b9d76e567637 140 extern "C" void DMA0IntHandler()
bikeNomad 20:b9d76e567637 141 {
bikeNomad 20:b9d76e567637 142 DMA0->DMA[dmaWriteChannel].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status
bikeNomad 20:b9d76e567637 143 dma_done = true;
bikeNomad 20:b9d76e567637 144 }
heroic 8:e3249c2b7607 145