You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
1.9KB

  1. #include "WS2812Serial.h"
  2. bool WS2812Serial::begin()
  3. {
  4. uint32_t divisor, portconfig, hwtrigger;
  5. KINETISK_UART_t *uart;
  6. switch (pin) {
  7. case 1:
  8. uart = &KINETISK_UART0;
  9. divisor = BAUD2DIV(2400000);
  10. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  11. hwtrigger = DMAMUX_SOURCE_UART0_TX;
  12. SIM_SCGC4 |= SIM_SCGC4_UART0;
  13. break;
  14. default:
  15. return false; // pin not supported
  16. }
  17. if (!dma) {
  18. dma = new DMAChannel;
  19. if (!dma) return false; // unable to allocate DMA channel
  20. }
  21. uart->BDH = (divisor >> 13) & 0x1F;
  22. uart->BDL = (divisor >> 5) & 0xFF;
  23. uart->C4 = divisor & 0x1F;
  24. uart->C1 = 0;
  25. uart->PFIFO = 0;
  26. uart->C2 = UART_C2_TE | UART_C2_TIE;
  27. uart->C3 = UART_C3_TXINV;
  28. uart->C5 = UART_C5_TDMAS;
  29. *(portConfigRegister(pin)) = portconfig;
  30. dma->destination(uart->D);
  31. dma->triggerAtHardwareEvent(hwtrigger);
  32. memset(drawBuffer, 0, numled * 3);
  33. return true;
  34. }
  35. void WS2812Serial::show()
  36. {
  37. // TODO: wait if prior DMA in progress
  38. // TODO: wait 300us WS2812 reset time
  39. const uint8_t *p = drawBuffer;
  40. const uint8_t *end = p + (numled * 3);
  41. uint8_t *fb = frameBuffer;
  42. while (p < end) {
  43. uint8_t b = *p++;
  44. uint8_t g = *p++;
  45. uint8_t r = *p++;
  46. uint32_t n=0;
  47. switch (config) {
  48. case WS2812_RGB: n = (r << 16) | (g << 8) | b; break;
  49. case WS2812_RBG: n = (r << 16) | (b << 8) | g; break;
  50. case WS2812_GRB: n = (g << 16) | (r << 8) | b; break;
  51. case WS2812_GBR: n = (g << 16) | (b << 8) | r; break;
  52. case WS2812_BRG: n = (b << 16) | (r << 8) | g; break;
  53. case WS2812_BGR: n = (b << 16) | (g << 8) | r; break;
  54. }
  55. const uint8_t *stop = fb + 8;
  56. do {
  57. uint8_t x = 0x92;
  58. if (!(n & 0x00800000)) x |= 0x01;
  59. if (!(n & 0x00400000)) x |= 0x04;
  60. if (!(n & 0x00200000)) x |= 0x20;
  61. n <<= 3;
  62. *fb++ = x;
  63. } while (fb < stop);
  64. }
  65. dma->sourceBuffer(frameBuffer, numled * 8);
  66. dma->transferSize(1);
  67. dma->transferCount(numled * 8);
  68. dma->disableOnCompletion();
  69. dma->enable();
  70. }