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.

216 lines
6.7 KiB

  1. /* Copyright 2021 Drashna Jael're
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include QMK_KEYBOARD_H
  17. #include "rgb_functions.h"
  18. #ifdef RGBLIGHT_ENABLE
  19. # include "ws2812.h"
  20. # include <avr/interrupt.h>
  21. # include <avr/io.h>
  22. # include <util/delay.h>
  23. # define pinmask(pin) (_BV((pin)&0xF))
  24. /*
  25. * Forward declare internal functions
  26. *
  27. * The functions take a byte-array and send to the data output as WS2812 bitstream.
  28. * The length is the number of bytes to send - three per LED.
  29. */
  30. static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t masklo, uint8_t maskhi);
  31. /*
  32. This routine writes an array of bytes with RGB values to the Dataout pin
  33. using the fast 800kHz clockless WS2811/2812 protocol.
  34. */
  35. // Timing in ns
  36. # define w_zeropulse 350
  37. # define w_onepulse 900
  38. # define w_totalperiod 1250
  39. // Fixed cycles used by the inner loop
  40. # define w_fixedlow 2
  41. # define w_fixedhigh 4
  42. # define w_fixedtotal 8
  43. // Insert NOPs to match the timing, if possible
  44. # define w_zerocycles (((F_CPU / 1000) * w_zeropulse) / 1000000)
  45. # define w_onecycles (((F_CPU / 1000) * w_onepulse + 500000) / 1000000)
  46. # define w_totalcycles (((F_CPU / 1000) * w_totalperiod + 500000) / 1000000)
  47. // w1_nops - nops between rising edge and falling edge - low
  48. # if w_zerocycles >= w_fixedlow
  49. # define w1_nops (w_zerocycles - w_fixedlow)
  50. # else
  51. # define w1_nops 0
  52. # endif
  53. // w2_nops - nops between fe low and fe high
  54. # if w_onecycles >= (w_fixedhigh + w1_nops)
  55. # define w2_nops (w_onecycles - w_fixedhigh - w1_nops)
  56. # else
  57. # define w2_nops 0
  58. # endif
  59. // w3_nops - nops to complete loop
  60. # if w_totalcycles >= (w_fixedtotal + w1_nops + w2_nops)
  61. # define w3_nops (w_totalcycles - w_fixedtotal - w1_nops - w2_nops)
  62. # else
  63. # define w3_nops 0
  64. # endif
  65. // The only critical timing parameter is the minimum pulse length of the "0"
  66. // Warn or throw error if this timing can not be met with current F_CPU settings.
  67. # define w_lowtime ((w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000)
  68. # if w_lowtime > 550
  69. # error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
  70. # elif w_lowtime > 450
  71. # warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
  72. # warning "Please consider a higher clockspeed, if possible"
  73. # endif
  74. # define w_nop1 "nop \n\t"
  75. # define w_nop2 "rjmp .+0 \n\t"
  76. # define w_nop4 w_nop2 w_nop2
  77. # define w_nop8 w_nop4 w_nop4
  78. # define w_nop16 w_nop8 w_nop8
  79. static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t masklo, uint8_t maskhi) {
  80. uint8_t curbyte, ctr, sreg_prev;
  81. sreg_prev = SREG;
  82. cli();
  83. while (datlen--) {
  84. curbyte = (*data++);
  85. asm volatile(" ldi %0,8 \n\t"
  86. "loop%=: \n\t"
  87. " out %2,%3 \n\t" // '1' [01] '0' [01] - re
  88. # if (w1_nops & 1)
  89. w_nop1
  90. # endif
  91. # if (w1_nops & 2)
  92. w_nop2
  93. # endif
  94. # if (w1_nops & 4)
  95. w_nop4
  96. # endif
  97. # if (w1_nops & 8)
  98. w_nop8
  99. # endif
  100. # if (w1_nops & 16)
  101. w_nop16
  102. # endif
  103. " sbrs %1,7 \n\t" // '1' [03] '0' [02]
  104. " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
  105. " lsl %1 \n\t" // '1' [04] '0' [04]
  106. # if (w2_nops & 1)
  107. w_nop1
  108. # endif
  109. # if (w2_nops & 2)
  110. w_nop2
  111. # endif
  112. # if (w2_nops & 4)
  113. w_nop4
  114. # endif
  115. # if (w2_nops & 8)
  116. w_nop8
  117. # endif
  118. # if (w2_nops & 16)
  119. w_nop16
  120. # endif
  121. " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
  122. # if (w3_nops & 1)
  123. w_nop1
  124. # endif
  125. # if (w3_nops & 2)
  126. w_nop2
  127. # endif
  128. # if (w3_nops & 4)
  129. w_nop4
  130. # endif
  131. # if (w3_nops & 8)
  132. w_nop8
  133. # endif
  134. # if (w3_nops & 16)
  135. w_nop16
  136. # endif
  137. " dec %0 \n\t" // '1' [+2] '0' [+2]
  138. " brne loop%=\n\t" // '1' [+3] '0' [+4]
  139. : "=&d"(ctr)
  140. : "r"(curbyte), "I"(_SFR_IO_ADDR(PORTx_ADDRESS(RGBLIGHT_DI_PIN))), "r"(maskhi), "r"(masklo));
  141. }
  142. SREG = sreg_prev;
  143. }
  144. void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) {
  145. DDRx_ADDRESS(RGBLIGHT_DI_PIN) |= pinmask(RGBLIGHT_DI_PIN);
  146. uint8_t masklo = ~(pinmask(RGBLIGHT_DI_PIN)) & PORTx_ADDRESS(RGBLIGHT_DI_PIN);
  147. uint8_t maskhi = pinmask(RGBLIGHT_DI_PIN) | PORTx_ADDRESS(RGBLIGHT_DI_PIN);
  148. ws2812_sendarray_mask((uint8_t *)start_led, num_leds * sizeof(LED_TYPE), masklo, maskhi);
  149. _delay_us(WS2812_TRST_US);
  150. }
  151. #endif
  152. #ifdef RGB_MATRIX_ENABLE
  153. bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
  154. if (!process_record_user(keycode, record)) { return false; }
  155. if (record->event.pressed) {
  156. switch(keycode) {
  157. case RGB_MATRIX_TOGGLE: // toggle rgb matrix
  158. rgb_matrix_toggle();
  159. return false;
  160. case RGB_MATRIX_MODE_INC:
  161. rgb_matrix_step();
  162. return false;
  163. case RGB_MATRIX_MODE_DEC:
  164. rgb_matrix_step_reverse();
  165. return false;
  166. case RGB_MATRIX_HUE_INC:
  167. rgb_matrix_increase_hue();
  168. return false;
  169. case RGB_MATRIX_HUE_DEC:
  170. rgb_matrix_decrease_hue();
  171. return false;
  172. case RGB_MATRIX_SAT_INC:
  173. rgb_matrix_increase_sat();
  174. return false;
  175. case RGB_MATRIX_SAT_DEC:
  176. rgb_matrix_decrease_sat();
  177. return false;
  178. case RGB_MATRIX_VAL_INC:
  179. rgb_matrix_increase_val();
  180. return false;
  181. case RGB_MATRIX_VAL_DEC:
  182. rgb_matrix_decrease_val();
  183. return false;
  184. default:
  185. break;
  186. }
  187. }
  188. return true;
  189. }
  190. #endif