Parcourir la source

Improve WS2812 waveform timing

main_ledos
PaulStoffregen il y a 7 ans
Parent
révision
abb72e07ec
2 fichiers modifiés avec 31 ajouts et 30 suppressions
  1. +30
    -29
      WS2812Serial.cpp
  2. +1
    -1
      examples/BasicTest/BasicTest.ino

+ 30
- 29
WS2812Serial.cpp Voir le fichier

@@ -14,7 +14,7 @@ bool WS2812Serial::begin()
case 26:
#endif
uart = &KINETISK_UART0;
divisor = BAUD2DIV(2400000);
divisor = BAUD2DIV(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART0_TX;
SIM_SCGC4 |= SIM_SCGC4_UART0;
@@ -27,7 +27,7 @@ bool WS2812Serial::begin()
case 58:
#endif
uart = &KINETISK_UART1;
divisor = BAUD2DIV2(2400000);
divisor = BAUD2DIV2(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART1_TX;
SIM_SCGC4 |= SIM_SCGC4_UART1;
@@ -36,7 +36,7 @@ bool WS2812Serial::begin()
case 8: // Serial3
case 20:
uart = &KINETISK_UART2;
divisor = BAUD2DIV3(2400000);
divisor = BAUD2DIV3(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART2_TX;
SIM_SCGC4 |= SIM_SCGC4_UART2;
@@ -46,7 +46,7 @@ bool WS2812Serial::begin()
case 32: // Serial4
case 62:
uart = &KINETISK_UART3;
divisor = BAUD2DIV3(2400000);
divisor = BAUD2DIV3(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART3_TX;
SIM_SCGC4 |= SIM_SCGC4_UART3;
@@ -54,7 +54,7 @@ bool WS2812Serial::begin()

case 33: // Serial5
uart = &KINETISK_UART4;
divisor = BAUD2DIV3(2400000);
divisor = BAUD2DIV3(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART4_RXTX;
SIM_SCGC1 |= SIM_SCGC1_UART4;
@@ -63,7 +63,7 @@ bool WS2812Serial::begin()
#if defined(__MK64FX512__)
case 48: // Serial6
uart = &KINETISK_UART5;
divisor = BAUD2DIV3(2400000);
divisor = BAUD2DIV3(4000000);
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART5_RXTX;
SIM_SCGC1 |= SIM_SCGC1_UART5;
@@ -74,21 +74,21 @@ bool WS2812Serial::begin()
case 1: // Serial1
case 5:
uart = &KINETISK_UART0;
divisor = 2;
divisor = 1;
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
hwtrigger = DMAMUX_SOURCE_UART0_TX;
SIM_SCGC4 |= SIM_SCGC4_UART0;
break;
case 4:
uart = &KINETISK_UART0;
divisor = 2;
divisor = 1;
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2);
hwtrigger = DMAMUX_SOURCE_UART0_TX;
SIM_SCGC4 |= SIM_SCGC4_UART0;
break;
case 24:
uart = &KINETISK_UART0;
divisor = 2;
divisor = 1;
portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(4);
hwtrigger = DMAMUX_SOURCE_UART0_TX;
SIM_SCGC4 |= SIM_SCGC4_UART0;
@@ -108,7 +108,7 @@ bool WS2812Serial::begin()
#elif defined(KINETISL)
uart->BDH = (divisor >> 8) & 0x1F;
uart->BDL = divisor & 0xFF;
uart->C4 = 9;
uart->C4 = 11;
#endif
uart->C1 = 0;
uart->C2 = UART_C2_TE | UART_C2_TIE;
@@ -136,16 +136,7 @@ void WS2812Serial::show()
yield();
}
#endif
// wait 300us WS2812 reset time
uint32_t min_elapsed = ((numled * 34134) >> 10) + 300;
if (min_elapsed < 2500) min_elapsed = 2500;
uint32_t m;
while (1) {
m = micros();
if ((m - prior_micros) > min_elapsed) break;
yield();
}
prior_micros = m;
// copy drawing buffer to frame buffer
const uint8_t *p = drawBuffer;
const uint8_t *end = p + (numled * 3);
uint8_t *fb = frameBuffer;
@@ -162,26 +153,36 @@ void WS2812Serial::show()
case WS2812_BRG: n = (b << 16) | (r << 8) | g; break;
case WS2812_BGR: n = (b << 16) | (g << 8) | r; break;
}
const uint8_t *stop = fb + 8;
const uint8_t *stop = fb + 12;
do {
uint8_t x = 0x92;
if (!(n & 0x00800000)) x |= 0x01;
if (!(n & 0x00400000)) x |= 0x04;
if (!(n & 0x00200000)) x |= 0x20;
n <<= 3;
uint8_t x = 0x08;
if (!(n & 0x00800000)) x |= 0x07;
if (!(n & 0x00400000)) x |= 0xE0;
n <<= 2;
*fb++ = x;
} while (fb < stop);
}
// wait 300us WS2812 reset time
uint32_t min_elapsed = (numled * 30) + 300;
if (min_elapsed < 2500) min_elapsed = 2500;
uint32_t m;
while (1) {
m = micros();
if ((m - prior_micros) > min_elapsed) break;
yield();
}
prior_micros = m;
// start DMA transfer to update LEDs :-)
#if defined(KINETISK)
dma->sourceBuffer(frameBuffer, numled * 8);
dma->sourceBuffer(frameBuffer, numled * 12);
dma->transferSize(1);
dma->transferCount(numled * 8);
dma->transferCount(numled * 12);
dma->disableOnCompletion();
dma->enable();
#elif defined(KINETISL)
dma->CFG->SAR = frameBuffer;
dma->CFG->DSR_BCR = 0x01000000;
dma->CFG->DSR_BCR = numled * 8;
dma->CFG->DSR_BCR = numled * 12;
dma->CFG->DCR = DMA_DCR_ERQ | DMA_DCR_CS | DMA_DCR_SSIZE(1) |
DMA_DCR_SINC | DMA_DCR_DSIZE(1) | DMA_DCR_D_REQ;
#endif

+ 1
- 1
examples/BasicTest/BasicTest.ino Voir le fichier

@@ -10,7 +10,7 @@ const int pin = 1;
// Teensy 3.6: 1, 5, 8, 10, 20, 26, 32, 33

byte drawingMemory[numled*3];
DMAMEM byte displayMemory[numled*8];
DMAMEM byte displayMemory[numled*12];

WS2812Serial leds(numled, displayMemory, drawingMemory, pin, WS2812_GRB);


Chargement…
Annuler
Enregistrer