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.
Diff: WS2811.cpp
- Revision:
- 25:751c89f7e654
- Parent:
- 23:33df42ff2541
- Child:
- 26:ac5d0e18c7b6
--- 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
Ned Konz


Generic WS2811/WS2812