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.

150 lines
3.8KB

  1. #include "WS2812Serial.h"
  2. bool WS2812Serial::begin()
  3. {
  4. uint32_t divisor, portconfig, hwtrigger;
  5. #if defined(KINETISK)
  6. KINETISK_UART_t *uart;
  7. #elif defined(KINETISL)
  8. KINETISL_UART_t *uart;
  9. #endif
  10. switch (pin) {
  11. #if defined(KINETISK)
  12. case 1: // Serial1
  13. case 5:
  14. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  15. case 26:
  16. #endif
  17. uart = &KINETISK_UART0;
  18. divisor = BAUD2DIV(2400000);
  19. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  20. hwtrigger = DMAMUX_SOURCE_UART0_TX;
  21. SIM_SCGC4 |= SIM_SCGC4_UART0;
  22. break;
  23. case 10: // Serial2
  24. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  25. case 31:
  26. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
  27. case 58:
  28. #endif
  29. uart = &KINETISK_UART1;
  30. divisor = BAUD2DIV2(2400000);
  31. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  32. hwtrigger = DMAMUX_SOURCE_UART1_TX;
  33. SIM_SCGC4 |= SIM_SCGC4_UART1;
  34. break;
  35. case 8: // Serial3
  36. case 20:
  37. uart = &KINETISK_UART2;
  38. divisor = BAUD2DIV3(2400000);
  39. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  40. hwtrigger = DMAMUX_SOURCE_UART2_TX;
  41. SIM_SCGC4 |= SIM_SCGC4_UART2;
  42. break;
  43. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  44. case 32: // Serial4
  45. case 62:
  46. uart = &KINETISK_UART3;
  47. divisor = BAUD2DIV3(2400000);
  48. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  49. hwtrigger = DMAMUX_SOURCE_UART3_TX;
  50. SIM_SCGC4 |= SIM_SCGC4_UART3;
  51. break;
  52. case 33: // Serial5
  53. uart = &KINETISK_UART4;
  54. divisor = BAUD2DIV3(2400000);
  55. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  56. hwtrigger = DMAMUX_SOURCE_UART4_RXTX;
  57. SIM_SCGC1 |= SIM_SCGC1_UART4;
  58. break;
  59. #endif
  60. #if defined(__MK64FX512__)
  61. case 48: // Serial6
  62. uart = &KINETISK_UART5;
  63. divisor = BAUD2DIV3(2400000);
  64. portconfig = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3);
  65. hwtrigger = DMAMUX_SOURCE_UART5_RXTX;
  66. SIM_SCGC1 |= SIM_SCGC1_UART5;
  67. break;
  68. #endif
  69. #elif defined(KINETISL)
  70. // TODO: Teesny LC support....
  71. #endif
  72. default:
  73. return false; // pin not supported
  74. }
  75. if (!dma) {
  76. dma = new DMAChannel;
  77. if (!dma) return false; // unable to allocate DMA channel
  78. }
  79. uart->BDH = (divisor >> 13) & 0x1F;
  80. uart->BDL = (divisor >> 5) & 0xFF;
  81. uart->C4 = divisor & 0x1F;
  82. uart->C1 = 0;
  83. uart->PFIFO = 0;
  84. uart->C2 = UART_C2_TE | UART_C2_TIE;
  85. uart->C3 = UART_C3_TXINV;
  86. uart->C5 = UART_C5_TDMAS;
  87. *(portConfigRegister(pin)) = portconfig;
  88. dma->destination(uart->D);
  89. dma->triggerAtHardwareEvent(hwtrigger);
  90. memset(drawBuffer, 0, numled * 3);
  91. return true;
  92. }
  93. void WS2812Serial::show()
  94. {
  95. // wait if prior DMA still in progress
  96. while ((DMA_ERQ & (1 << dma->channel))) {
  97. yield();
  98. }
  99. // wait 300us WS2812 reset time
  100. uint32_t min_elapsed = ((numled * 34134) >> 10) + 300;
  101. if (min_elapsed < 2500) min_elapsed = 2500;
  102. uint32_t m;
  103. while (1) {
  104. m = micros();
  105. if ((m - prior_micros) > min_elapsed) break;
  106. yield();
  107. }
  108. prior_micros = m;
  109. const uint8_t *p = drawBuffer;
  110. const uint8_t *end = p + (numled * 3);
  111. uint8_t *fb = frameBuffer;
  112. while (p < end) {
  113. uint8_t b = *p++;
  114. uint8_t g = *p++;
  115. uint8_t r = *p++;
  116. uint32_t n=0;
  117. switch (config) {
  118. case WS2812_RGB: n = (r << 16) | (g << 8) | b; break;
  119. case WS2812_RBG: n = (r << 16) | (b << 8) | g; break;
  120. case WS2812_GRB: n = (g << 16) | (r << 8) | b; break;
  121. case WS2812_GBR: n = (g << 16) | (b << 8) | r; break;
  122. case WS2812_BRG: n = (b << 16) | (r << 8) | g; break;
  123. case WS2812_BGR: n = (b << 16) | (g << 8) | r; break;
  124. }
  125. const uint8_t *stop = fb + 8;
  126. do {
  127. uint8_t x = 0x92;
  128. if (!(n & 0x00800000)) x |= 0x01;
  129. if (!(n & 0x00400000)) x |= 0x04;
  130. if (!(n & 0x00200000)) x |= 0x20;
  131. n <<= 3;
  132. *fb++ = x;
  133. } while (fb < stop);
  134. }
  135. dma->sourceBuffer(frameBuffer, numled * 8);
  136. dma->transferSize(1);
  137. dma->transferCount(numled * 8);
  138. dma->disableOnCompletion();
  139. dma->enable();
  140. }