logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

ws2812_bitbang.c (4344B)


  1. #include "ws2812.h"
  2. #include "gpio.h"
  3. #include "chibios_config.h"
  4. // DEPRECATED - DO NOT USE
  5. #if defined(NOP_FUDGE)
  6. # define WS2812_BITBANG_NOP_FUDGE NOP_FUDGE
  7. #endif
  8. /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
  9. #ifndef WS2812_BITBANG_NOP_FUDGE
  10. # if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
  11. # define WS2812_BITBANG_NOP_FUDGE 0.4
  12. # else
  13. # if defined(RP2040)
  14. # error "Please use `vendor` WS2812 driver for RP2040"
  15. # else
  16. # error "WS2812_BITBANG_NOP_FUDGE configuration required"
  17. # endif
  18. # define WS2812_BITBANG_NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
  19. # endif
  20. #endif
  21. // Push Pull or Open Drain Configuration
  22. // Default Push Pull
  23. #ifndef WS2812_EXTERNAL_PULLUP
  24. # define WS2812_OUTPUT_MODE PAL_MODE_OUTPUT_PUSHPULL
  25. #else
  26. # define WS2812_OUTPUT_MODE PAL_MODE_OUTPUT_OPENDRAIN
  27. #endif
  28. // The reset gap can be 6000 ns, but depending on the LED strip it may have to be increased
  29. // to values like 600000 ns. If it is too small, the pixels will show nothing most of the time.
  30. #ifndef WS2812_RES
  31. # define WS2812_RES (1000 * WS2812_TRST_US) // Width of the low gap between bits to cause a frame to latch
  32. #endif
  33. #define NUMBER_NOPS 6
  34. #define CYCLES_PER_SEC (CPU_CLOCK / NUMBER_NOPS * WS2812_BITBANG_NOP_FUDGE)
  35. #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
  36. #define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
  37. #define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
  38. #define wait_ns(x) \
  39. do { \
  40. for (int i = 0; i < NS_TO_CYCLES(x); i++) { \
  41. __asm__ volatile("nop\n\t" \
  42. "nop\n\t" \
  43. "nop\n\t" \
  44. "nop\n\t" \
  45. "nop\n\t" \
  46. "nop\n\t"); \
  47. } \
  48. } while (0)
  49. void sendByte(uint8_t byte) {
  50. // WS2812 protocol wants most significant bits first
  51. for (unsigned char bit = 0; bit < 8; bit++) {
  52. bool is_one = byte & (1 << (7 - bit));
  53. // using something like wait_ns(is_one ? T1L : T0L) here throws off timings
  54. if (is_one) {
  55. // 1
  56. gpio_write_pin_high(WS2812_DI_PIN);
  57. wait_ns(WS2812_T1H);
  58. gpio_write_pin_low(WS2812_DI_PIN);
  59. wait_ns(WS2812_T1L);
  60. } else {
  61. // 0
  62. gpio_write_pin_high(WS2812_DI_PIN);
  63. wait_ns(WS2812_T0H);
  64. gpio_write_pin_low(WS2812_DI_PIN);
  65. wait_ns(WS2812_T0L);
  66. }
  67. }
  68. }
  69. ws2812_led_t ws2812_leds[WS2812_LED_COUNT];
  70. void ws2812_init(void) {
  71. palSetLineMode(WS2812_DI_PIN, WS2812_OUTPUT_MODE);
  72. }
  73. void ws2812_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
  74. ws2812_leds[index].r = red;
  75. ws2812_leds[index].g = green;
  76. ws2812_leds[index].b = blue;
  77. #if defined(WS2812_RGBW)
  78. ws2812_rgb_to_rgbw(&ws2812_leds[index]);
  79. #endif
  80. }
  81. void ws2812_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
  82. for (int i = 0; i < WS2812_LED_COUNT; i++) {
  83. ws2812_set_color(i, red, green, blue);
  84. }
  85. }
  86. void ws2812_flush(void) {
  87. // this code is very time dependent, so we need to disable interrupts
  88. chSysLock();
  89. for (int i = 0; i < WS2812_LED_COUNT; i++) {
  90. // WS2812 protocol dictates grb order
  91. #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
  92. sendByte(ws2812_leds[i].g);
  93. sendByte(ws2812_leds[i].r);
  94. sendByte(ws2812_leds[i].b);
  95. #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
  96. sendByte(ws2812_leds[i].r);
  97. sendByte(ws2812_leds[i].g);
  98. sendByte(ws2812_leds[i].b);
  99. #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
  100. sendByte(ws2812_leds[i].b);
  101. sendByte(ws2812_leds[i].g);
  102. sendByte(ws2812_leds[i].r);
  103. #endif
  104. #ifdef WS2812_RGBW
  105. sendByte(ws2812_leds[i].w);
  106. #endif
  107. }
  108. wait_ns(WS2812_RES);
  109. chSysUnlock();
  110. }