is31fl3218-mono.c (5171B)
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-mono.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); 96 } 97 98 is31fl3218_update_led_control_registers(); 99 } 100 101 void is31fl3218_set_value(int index, uint8_t value) { 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.v] == value) { 108 return; 109 } 110 111 driver_buffers.pwm_buffer[led.v] = value; 112 driver_buffers.pwm_buffer_dirty = true; 113 } 114 } 115 116 void is31fl3218_set_value_all(uint8_t value) { 117 for (int i = 0; i < IS31FL3218_LED_COUNT; i++) { 118 is31fl3218_set_value(i, value); 119 } 120 } 121 122 void is31fl3218_set_led_control_register(uint8_t index, bool value) { 123 is31fl3218_led_t led; 124 memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led)); 125 126 uint8_t control_register = led.v / 6; 127 uint8_t bit_value = led.v % 6; 128 129 if (value) { 130 driver_buffers.led_control_buffer[control_register] |= (1 << bit_value); 131 } else { 132 driver_buffers.led_control_buffer[control_register] &= ~(1 << bit_value); 133 } 134 135 driver_buffers.led_control_buffer_dirty = true; 136 } 137 138 void is31fl3218_update_pwm_buffers(void) { 139 if (driver_buffers.pwm_buffer_dirty) { 140 is31fl3218_write_pwm_buffer(); 141 // Load PWM registers and LED Control register data 142 is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01); 143 144 driver_buffers.pwm_buffer_dirty = false; 145 } 146 } 147 148 void is31fl3218_update_led_control_registers(void) { 149 if (driver_buffers.led_control_buffer_dirty) { 150 for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) { 151 is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, driver_buffers.led_control_buffer[i]); 152 } 153 154 driver_buffers.led_control_buffer_dirty = false; 155 } 156 }