logo

qmk_firmware

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

is31fl3731.c (9033B)


  1. /* Copyright 2017 Jason Williams
  2. * Copyright 2018 Jack Humbert
  3. * Copyright 2021 Doni Crosby
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "is31fl3731.h"
  19. #include "i2c_master.h"
  20. #include "gpio.h"
  21. #include "wait.h"
  22. #define IS31FL3731_PWM_REGISTER_COUNT 144
  23. #define IS31FL3731_LED_CONTROL_REGISTER_COUNT 18
  24. #ifndef IS31FL3731_I2C_TIMEOUT
  25. # define IS31FL3731_I2C_TIMEOUT 100
  26. #endif
  27. #ifndef IS31FL3731_I2C_PERSISTENCE
  28. # define IS31FL3731_I2C_PERSISTENCE 0
  29. #endif
  30. const uint8_t i2c_addresses[IS31FL3731_DRIVER_COUNT] = {
  31. IS31FL3731_I2C_ADDRESS_1,
  32. #ifdef IS31FL3731_I2C_ADDRESS_2
  33. IS31FL3731_I2C_ADDRESS_2,
  34. # ifdef IS31FL3731_I2C_ADDRESS_3
  35. IS31FL3731_I2C_ADDRESS_3,
  36. # ifdef IS31FL3731_I2C_ADDRESS_4
  37. IS31FL3731_I2C_ADDRESS_4,
  38. # endif
  39. # endif
  40. #endif
  41. };
  42. // These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
  43. // Storing them like this is optimal for I2C transfers to the registers.
  44. // We could optimize this and take out the unused registers from these
  45. // buffers and the transfers in is31fl3731_write_pwm_buffer() but it's
  46. // probably not worth the extra complexity.
  47. typedef struct is31fl3731_driver_t {
  48. uint8_t pwm_buffer[IS31FL3731_PWM_REGISTER_COUNT];
  49. bool pwm_buffer_dirty;
  50. uint8_t led_control_buffer[IS31FL3731_LED_CONTROL_REGISTER_COUNT];
  51. bool led_control_buffer_dirty;
  52. } PACKED is31fl3731_driver_t;
  53. is31fl3731_driver_t driver_buffers[IS31FL3731_DRIVER_COUNT] = {{
  54. .pwm_buffer = {0},
  55. .pwm_buffer_dirty = false,
  56. .led_control_buffer = {0},
  57. .led_control_buffer_dirty = false,
  58. }};
  59. void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data) {
  60. #if IS31FL3731_I2C_PERSISTENCE > 0
  61. for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
  62. if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
  63. }
  64. #else
  65. i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT);
  66. #endif
  67. }
  68. void is31fl3731_select_page(uint8_t index, uint8_t page) {
  69. is31fl3731_write_register(index, IS31FL3731_REG_COMMAND, page);
  70. }
  71. void is31fl3731_write_pwm_buffer(uint8_t index) {
  72. // Assumes page 0 is already selected.
  73. // Transmit PWM registers in 9 transfers of 16 bytes.
  74. // Iterate over the pwm_buffer contents at 16 byte intervals.
  75. for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
  76. #if IS31FL3731_I2C_PERSISTENCE > 0
  77. for (uint8_t j = 0; j < IS31FL3731_I2C_PERSISTENCE; j++) {
  78. if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
  79. }
  80. #else
  81. i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT);
  82. #endif
  83. }
  84. }
  85. void is31fl3731_init_drivers(void) {
  86. i2c_init();
  87. #if defined(IS31FL3731_SDB_PIN)
  88. gpio_set_pin_output(IS31FL3731_SDB_PIN);
  89. gpio_write_pin_high(IS31FL3731_SDB_PIN);
  90. #endif
  91. for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
  92. is31fl3731_init(i);
  93. }
  94. for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
  95. is31fl3731_set_led_control_register(i, true, true, true);
  96. }
  97. for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
  98. is31fl3731_update_led_control_registers(i);
  99. }
  100. }
  101. void is31fl3731_init(uint8_t index) {
  102. // In order to avoid the LEDs being driven with garbage data
  103. // in the LED driver's PWM registers, first enable software shutdown,
  104. // then set up the mode and other settings, clear the PWM registers,
  105. // then disable software shutdown.
  106. is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
  107. // enable software shutdown
  108. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
  109. #ifdef IS31FL3731_DEGHOST // set to enable de-ghosting of the array
  110. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
  111. #endif
  112. // this delay was copied from other drivers, might not be needed
  113. wait_ms(10);
  114. // picture mode
  115. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
  116. // display frame 0
  117. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
  118. // audio sync off
  119. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
  120. is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
  121. // turn off all LEDs in the LED control register
  122. for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
  123. is31fl3731_write_register(index, IS31FL3731_FRAME_REG_LED_CONTROL + i, 0x00);
  124. }
  125. // turn off all LEDs in the blink control register (not really needed)
  126. for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
  127. is31fl3731_write_register(index, IS31FL3731_FRAME_REG_BLINK_CONTROL + i, 0x00);
  128. }
  129. // set PWM on all LEDs to 0
  130. for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i++) {
  131. is31fl3731_write_register(index, IS31FL3731_FRAME_REG_PWM + i, 0x00);
  132. }
  133. is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
  134. // disable software shutdown
  135. is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
  136. // select page 0 and leave it selected.
  137. // most usage after initialization is just writing PWM buffers in page 0
  138. // as there's not much point in double-buffering
  139. is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
  140. }
  141. void is31fl3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
  142. is31fl3731_led_t led;
  143. if (index >= 0 && index < IS31FL3731_LED_COUNT) {
  144. memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
  145. if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) {
  146. return;
  147. }
  148. driver_buffers[led.driver].pwm_buffer[led.r] = red;
  149. driver_buffers[led.driver].pwm_buffer[led.g] = green;
  150. driver_buffers[led.driver].pwm_buffer[led.b] = blue;
  151. driver_buffers[led.driver].pwm_buffer_dirty = true;
  152. }
  153. }
  154. void is31fl3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
  155. for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
  156. is31fl3731_set_color(i, red, green, blue);
  157. }
  158. }
  159. void is31fl3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue) {
  160. is31fl3731_led_t led;
  161. memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
  162. uint8_t control_register_r = led.r / 8;
  163. uint8_t control_register_g = led.g / 8;
  164. uint8_t control_register_b = led.b / 8;
  165. uint8_t bit_r = led.r % 8;
  166. uint8_t bit_g = led.g % 8;
  167. uint8_t bit_b = led.b % 8;
  168. if (red) {
  169. driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
  170. } else {
  171. driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
  172. }
  173. if (green) {
  174. driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
  175. } else {
  176. driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
  177. }
  178. if (blue) {
  179. driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
  180. } else {
  181. driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
  182. }
  183. driver_buffers[led.driver].led_control_buffer_dirty = true;
  184. }
  185. void is31fl3731_update_pwm_buffers(uint8_t index) {
  186. if (driver_buffers[index].pwm_buffer_dirty) {
  187. is31fl3731_write_pwm_buffer(index);
  188. driver_buffers[index].pwm_buffer_dirty = false;
  189. }
  190. }
  191. void is31fl3731_update_led_control_registers(uint8_t index) {
  192. if (driver_buffers[index].led_control_buffer_dirty) {
  193. for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
  194. is31fl3731_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
  195. }
  196. driver_buffers[index].led_control_buffer_dirty = false;
  197. }
  198. }
  199. void is31fl3731_flush(void) {
  200. for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
  201. is31fl3731_update_pwm_buffers(i);
  202. }
  203. }