is31fl3218.c (6011B)
1 /* Copyright 2018 Jason Williams (Wilba) 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 17 #include "is31fl3218.h" 18 #include "i2c_master.h" 19 #include "gpio.h" 20 21 #define IS31FL3218_PWM_REGISTER_COUNT 18 22 #define IS31FL3218_LED_CONTROL_REGISTER_COUNT 3 23 24 #ifndef IS31FL3218_I2C_TIMEOUT 25 # define IS31FL3218_I2C_TIMEOUT 100 26 #endif 27 28 #ifndef IS31FL3218_I2C_PERSISTENCE 29 # define IS31FL3218_I2C_PERSISTENCE 0 30 #endif 31 32 typedef struct is31fl3218_driver_t { 33 uint8_t pwm_buffer[IS31FL3218_PWM_REGISTER_COUNT]; 34 bool pwm_buffer_dirty; 35 uint8_t led_control_buffer[IS31FL3218_LED_CONTROL_REGISTER_COUNT]; 36 bool led_control_buffer_dirty; 37 } PACKED is31fl3218_driver_t; 38 39 // IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining. 40 is31fl3218_driver_t driver_buffers = { 41 .pwm_buffer = {0}, 42 .pwm_buffer_dirty = false, 43 .led_control_buffer = {0}, 44 .led_control_buffer_dirty = false, 45 }; 46 47 void is31fl3218_write_register(uint8_t reg, uint8_t data) { 48 #if IS31FL3218_I2C_PERSISTENCE > 0 49 for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) { 50 if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; 51 } 52 #else 53 i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT); 54 #endif 55 } 56 57 void is31fl3218_write_pwm_buffer(void) { 58 #if IS31FL3218_I2C_PERSISTENCE > 0 59 for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) { 60 if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; 61 } 62 #else 63 i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT); 64 #endif 65 } 66 67 void is31fl3218_init(void) { 68 i2c_init(); 69 70 #if defined(IS31FL3218_SDB_PIN) 71 gpio_set_pin_output(IS31FL3218_SDB_PIN); 72 gpio_write_pin_high(IS31FL3218_SDB_PIN); 73 #endif 74 75 // In case we ever want to reinitialize (?) 76 is31fl3218_write_register(IS31FL3218_REG_RESET, 0x00); 77 78 // Turn off software shutdown 79 is31fl3218_write_register(IS31FL3218_REG_SHUTDOWN, 0x01); 80 81 // Set all PWM values to zero 82 for (uint8_t i = 0; i < IS31FL3218_PWM_REGISTER_COUNT; i++) { 83 is31fl3218_write_register(IS31FL3218_REG_PWM + i, 0x00); 84 } 85 86 // turn off all LEDs in the LED control register 87 for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) { 88 is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, 0x00); 89 } 90 91 // Load PWM registers and LED Control register data 92 is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01); 93 94 for (int i = 0; i < IS31FL3218_LED_COUNT; i++) { 95 is31fl3218_set_led_control_register(i, true, true, true); 96 } 97 98 is31fl3218_update_led_control_registers(); 99 } 100 101 void is31fl3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { 102 is31fl3218_led_t led; 103 104 if (index >= 0 && index < IS31FL3218_LED_COUNT) { 105 memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led)); 106 107 if (driver_buffers.pwm_buffer[led.r] == red && driver_buffers.pwm_buffer[led.g] == green && driver_buffers.pwm_buffer[led.b] == blue) { 108 return; 109 } 110 111 driver_buffers.pwm_buffer[led.r] = red; 112 driver_buffers.pwm_buffer[led.g] = green; 113 driver_buffers.pwm_buffer[led.b] = blue; 114 driver_buffers.pwm_buffer_dirty = true; 115 } 116 } 117 118 void is31fl3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { 119 for (int i = 0; i < IS31FL3218_LED_COUNT; i++) { 120 is31fl3218_set_color(i, red, green, blue); 121 } 122 } 123 124 void is31fl3218_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { 125 is31fl3218_led_t led; 126 memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led)); 127 128 uint8_t control_register_r = led.r / 6; 129 uint8_t control_register_g = led.g / 6; 130 uint8_t control_register_b = led.b / 6; 131 uint8_t bit_r = led.r % 6; 132 uint8_t bit_g = led.g % 6; 133 uint8_t bit_b = led.b % 6; 134 135 if (red) { 136 driver_buffers.led_control_buffer[control_register_r] |= (1 << bit_r); 137 } else { 138 driver_buffers.led_control_buffer[control_register_r] &= ~(1 << bit_r); 139 } 140 if (green) { 141 driver_buffers.led_control_buffer[control_register_g] |= (1 << bit_g); 142 } else { 143 driver_buffers.led_control_buffer[control_register_g] &= ~(1 << bit_g); 144 } 145 if (blue) { 146 driver_buffers.led_control_buffer[control_register_b] |= (1 << bit_b); 147 } else { 148 driver_buffers.led_control_buffer[control_register_b] &= ~(1 << bit_b); 149 } 150 151 driver_buffers.led_control_buffer_dirty = true; 152 } 153 154 void is31fl3218_update_pwm_buffers(void) { 155 if (driver_buffers.pwm_buffer_dirty) { 156 is31fl3218_write_pwm_buffer(); 157 // Load PWM registers and LED Control register data 158 is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01); 159 160 driver_buffers.pwm_buffer_dirty = false; 161 } 162 } 163 164 void is31fl3218_update_led_control_registers(void) { 165 if (driver_buffers.led_control_buffer_dirty) { 166 for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) { 167 is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, driver_buffers.led_control_buffer[i]); 168 } 169 170 driver_buffers.led_control_buffer_dirty = false; 171 } 172 }