Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Multi_WS2811 mbed MMA8451Q
Fork of WS2811 by
Diff: WS2811.cpp
- Revision:
- 20:b9d76e567637
- Parent:
- 17:b4e9d8f4baa9
- Child:
- 21:4541da183397
--- a/WS2811.cpp Fri Dec 06 06:58:12 2013 +0000
+++ b/WS2811.cpp Sat Dec 21 04:32:21 2013 +0000
@@ -7,52 +7,107 @@
#include "LedStrip.h"
#include "WS2811.h"
+extern void dump_spi_settings(SPI_Type const *spi);
+extern Serial pc;
+extern DigitalOut debugOut;
-WS2811::WS2811(int n, PinName mosi, PinName sclk) :
+static const unsigned DMA_MUX_SRC_SPI0_Transmit = 17;
+// const unsigned DMA_MUX_SRC_SPI1_Transmit = 19;
+
+static const unsigned dmaWriteChannel = 0;
+static const unsigned dmaXmitMuxSrc = DMA_MUX_SRC_SPI0_Transmit;
+
+static volatile bool dma_done = false;
+
+// 12.8 MHz => 800KHz bit rate (1.25 usec/byte)
+
+WS2811::WS2811(int n, SPI_Type *_spi, PinName _mosi, PinName sclk) :
LedStrip(n),
- spi(mosi, NC, sclk)
+ spi(_spi),
+ mosi(_mosi)
{
-#ifdef TARGET_KL25Z
- spi.format(8, 3);
-#else
- spi.format(16, 3);
-#endif
- spi.frequency(800e3 * 16); // 12.8 MHz => 800KHz bit rate
+ SPI spitemp(_mosi, NC, sclk);
+ spitemp.format(8,3);
+ spitemp.frequency(800e3 * 16 * 2); // 12 MHz (48MHz/60) => 750KHz rate (1.33 usec/byte)
+
+ //Enable DMA clocking
+ SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK; // Enable clock to DMA mux
+ SIM->SCGC7 |= SIM_SCGC7_DMA_MASK; // Enable clock to DMA
+
+ // reset DMAMUX
+ DMAMUX0->CHCFG[dmaWriteChannel] = 0;
+ DMAMUX0->CHCFG[dmaWriteChannel] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(dmaXmitMuxSrc);
+
+ // Enable DMA features within the SPI registers
+ spi->C1 |= SPI_C1_SPTIE_MASK | // enable transmit-interrupt
+ SPI_C1_MSTR_MASK;
}
/*
- * These chips use a one-wire protocol based on a sort of NRZ signalling- jas.
+ * These chips use a one-wire protocol based on a sort of NRZ signalling- jas.
+ * Spec is 1.25usec +/- 600nsec => 650nsec to 1850nsec
*/
-inline void WS2811::writebit(bool bit)
+
+void WS2811::startDMA()
{
- if (bit) {
-#ifdef TARGET_KL25Z
- spi.write(0xff); // 8 high
- spi.write(0x00); // 8 low
-#else
- spi.write(0xff00);
-#endif
- } else {
-#ifdef TARGET_KL25Z
- spi.write(0xe0); // 3 high, 5 low
- spi.write(0x00); // +8 low
-#else
- spi.write(0xe000);
-#endif
- }
+ DMA0->DMA[dmaWriteChannel].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status
+ DMA0->DMA[dmaWriteChannel].SAR = (uint32_t)(void*)dmaBytes; // set source address
+ DMA0->DMA[dmaWriteChannel].DAR = (uint32_t)(void*)&(spi->D); // set dest address: SPI0_Data register
+ DMA0->DMA[dmaWriteChannel].DSR_BCR |= DMA_DSR_BCR_BCR_MASK & sizeof(dmaBytes); // length of transfer
+ DMA0->DMA[dmaWriteChannel].DCR = DMA_DCR_EINT_MASK | // enable interrupt on end of transfer
+ DMA_DCR_ERQ_MASK |
+ DMA_DCR_SINC_MASK |
+ DMA_DCR_SSIZE(0x01) |
+ DMA_DCR_DSIZE(0x01) |
+ // DMA_DCR_START_MASK |
+ DMA_DCR_D_REQ_MASK; // clear ERQ on end of transfer
+
+ dump_spi_settings(spi);
+
+ debugOut = 1;
+
+ while (!(spi->S & SPI_S_SPTEF_MASK))
+ __NOP();
+ spi->D = dmaBytes[0];
+
+ dma_done = false;
+
+ spi->C2 |= SPI_C2_TXDMAE_MASK;
+
+ // wait until done
+ // while (!(DMA0->DMA[dmaWriteChannel].DSR_BCR & DMA_DSR_BCR_DONE_MASK))
+ while (!dma_done)
+ __NOP();
+
+ spi->C2 &= ~SPI_C2_TXDMAE_MASK;
+ debugOut = 0;
+
+ dump_spi_settings(spi);
+
}
-void WS2811::write(uint8_t byte)
+void WS2811::writePixel(uint8_t *p)
{
- writebit(byte & 0x80);
- writebit(byte & 0x40);
- writebit(byte & 0x20);
- writebit(byte & 0x10);
- writebit(byte & 0x08);
- writebit(byte & 0x04);
- writebit(byte & 0x02);
- writebit(byte & 0x01);
+ writeByte(*p++, dmaBytes + 0);
+ writeByte(*p++, dmaBytes + 16);
+ writeByte(*p, dmaBytes + 32);
+// printf("DMA Bytes:\r\n");
+// for (int i = 0; i < sizeof(dmaBytes); i++)
+// printf(" %02x", dmaBytes[i]);
+// printf("\r\n");
+ startDMA();
+}
+
+void WS2811::writeByte(uint8_t byte, uint8_t *dest)
+{
+ for (uint8_t mask = 0x80; mask; mask >>= 1) {
+ if (mask & byte)
+ *dest++ = 0xff; // 8 high
+ else
+ *dest++ = 0xe0; // 3 high, 5 low
+ *dest++ = 0x00; // 8 more low
+ }
}
void WS2811::begin(void)
@@ -66,17 +121,25 @@
memset(pixels, 0x00, numPixelBytes());
}
+
void WS2811::show(void)
{
- uint16_t i, nl3 = numPixelBytes(); // 3 bytes per LED
+ uint16_t i, n = numPixels(); // 3 bytes per LED
+ uint8_t *p = pixels;
while (guardtime.read_us() < 50)
- /* spin */;
- __disable_irq();
- for (i=0; i<nl3; i++ ) {
- write(pixels[i]);
+ __NOP();
+ for (i=0; i<n; i++ ) {
+ writePixel(p);
+ pc.printf("%d> ", i);
+ pc.getc();
+ p += 3;
}
- __enable_irq();
guardtime.reset();
}
+extern "C" void DMA0IntHandler()
+{
+ DMA0->DMA[dmaWriteChannel].DSR_BCR = DMA_DSR_BCR_DONE_MASK; // clear/reset DMA status
+ dma_done = true;
+}

Generic WS2811/WS2812