qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

is31fl3741.c (10369B)


      1 /* Copyright 2017 Jason Williams
      2  * Copyright 2018 Jack Humbert
      3  * Copyright 2018 Yiancar
      4  * Copyright 2020 MelGeek
      5  *
      6  * This program is free software: you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include "is31fl3741.h"
     21 #include "i2c_master.h"
     22 #include "gpio.h"
     23 #include "wait.h"
     24 
     25 #define IS31FL3741_PWM_0_REGISTER_COUNT 180
     26 #define IS31FL3741_PWM_1_REGISTER_COUNT 171
     27 #define IS31FL3741_SCALING_0_REGISTER_COUNT 180
     28 #define IS31FL3741_SCALING_1_REGISTER_COUNT 171
     29 
     30 #ifndef IS31FL3741_I2C_TIMEOUT
     31 #    define IS31FL3741_I2C_TIMEOUT 100
     32 #endif
     33 
     34 #ifndef IS31FL3741_I2C_PERSISTENCE
     35 #    define IS31FL3741_I2C_PERSISTENCE 0
     36 #endif
     37 
     38 #ifndef IS31FL3741_CONFIGURATION
     39 #    define IS31FL3741_CONFIGURATION 0x01
     40 #endif
     41 
     42 #ifndef IS31FL3741_PWM_FREQUENCY
     43 #    define IS31FL3741_PWM_FREQUENCY IS31FL3741_PWM_FREQUENCY_29K_HZ
     44 #endif
     45 
     46 #ifndef IS31FL3741_SW_PULLUP
     47 #    define IS31FL3741_SW_PULLUP IS31FL3741_PUR_32K_OHM
     48 #endif
     49 
     50 #ifndef IS31FL3741_CS_PULLDOWN
     51 #    define IS31FL3741_CS_PULLDOWN IS31FL3741_PDR_32K_OHM
     52 #endif
     53 
     54 #ifndef IS31FL3741_GLOBAL_CURRENT
     55 #    define IS31FL3741_GLOBAL_CURRENT 0xFF
     56 #endif
     57 
     58 const uint8_t i2c_addresses[IS31FL3741_DRIVER_COUNT] = {
     59     IS31FL3741_I2C_ADDRESS_1,
     60 #ifdef IS31FL3741_I2C_ADDRESS_2
     61     IS31FL3741_I2C_ADDRESS_2,
     62 #    ifdef IS31FL3741_I2C_ADDRESS_3
     63     IS31FL3741_I2C_ADDRESS_3,
     64 #        ifdef IS31FL3741_I2C_ADDRESS_4
     65     IS31FL3741_I2C_ADDRESS_4,
     66 #        endif
     67 #    endif
     68 #endif
     69 };
     70 
     71 // These buffers match the IS31FL3741 and IS31FL3741A PWM registers.
     72 // The scaling buffers match the page 2 and 3 LED On/Off registers.
     73 // Storing them like this is optimal for I2C transfers to the registers.
     74 // We could optimize this and take out the unused registers from these
     75 // buffers and the transfers in is31fl3741_write_pwm_buffer() but it's
     76 // probably not worth the extra complexity.
     77 typedef struct is31fl3741_driver_t {
     78     uint8_t pwm_buffer_0[IS31FL3741_PWM_0_REGISTER_COUNT];
     79     uint8_t pwm_buffer_1[IS31FL3741_PWM_1_REGISTER_COUNT];
     80     bool    pwm_buffer_dirty;
     81     uint8_t scaling_buffer_0[IS31FL3741_SCALING_0_REGISTER_COUNT];
     82     uint8_t scaling_buffer_1[IS31FL3741_SCALING_1_REGISTER_COUNT];
     83     bool    scaling_buffer_dirty;
     84 } PACKED is31fl3741_driver_t;
     85 
     86 is31fl3741_driver_t driver_buffers[IS31FL3741_DRIVER_COUNT] = {{
     87     .pwm_buffer_0         = {0},
     88     .pwm_buffer_1         = {0},
     89     .pwm_buffer_dirty     = false,
     90     .scaling_buffer_0     = {0},
     91     .scaling_buffer_1     = {0},
     92     .scaling_buffer_dirty = false,
     93 }};
     94 
     95 void is31fl3741_write_register(uint8_t index, uint8_t reg, uint8_t data) {
     96 #if IS31FL3741_I2C_PERSISTENCE > 0
     97     for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
     98         if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
     99     }
    100 #else
    101     i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT);
    102 #endif
    103 }
    104 
    105 void is31fl3741_select_page(uint8_t index, uint8_t page) {
    106     is31fl3741_write_register(index, IS31FL3741_REG_COMMAND_WRITE_LOCK, IS31FL3741_COMMAND_WRITE_LOCK_MAGIC);
    107     is31fl3741_write_register(index, IS31FL3741_REG_COMMAND, page);
    108 }
    109 
    110 void is31fl3741_write_pwm_buffer(uint8_t index) {
    111     is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_0);
    112 
    113     // Transmit PWM0 registers in 6 transfers of 30 bytes.
    114 
    115     // Iterate over the pwm_buffer_0 contents at 30 byte intervals.
    116     for (uint8_t i = 0; i < IS31FL3741_PWM_0_REGISTER_COUNT; i += 30) {
    117 #if IS31FL3741_I2C_PERSISTENCE > 0
    118         for (uint8_t j = 0; j < IS31FL3741_I2C_PERSISTENCE; j++) {
    119             if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
    120         }
    121 #else
    122         i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT);
    123 #endif
    124     }
    125 
    126     is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_1);
    127 
    128     // Transmit PWM1 registers in 9 transfers of 19 bytes.
    129 
    130     // Iterate over the pwm_buffer_1 contents at 19 byte intervals.
    131     for (uint8_t i = 0; i < IS31FL3741_PWM_1_REGISTER_COUNT; i += 19) {
    132 #if IS31FL3741_I2C_PERSISTENCE > 0
    133         for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
    134             if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
    135         }
    136 #else
    137         i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT);
    138 #endif
    139     }
    140 }
    141 
    142 void is31fl3741_init_drivers(void) {
    143     i2c_init();
    144 
    145 #if defined(IS31FL3741_SDB_PIN)
    146     gpio_set_pin_output(IS31FL3741_SDB_PIN);
    147     gpio_write_pin_high(IS31FL3741_SDB_PIN);
    148 #endif
    149 
    150     for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
    151         is31fl3741_init(i);
    152     }
    153 
    154     for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
    155         is31fl3741_set_led_control_register(i, true, true, true);
    156     }
    157 
    158     for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
    159         is31fl3741_update_led_control_registers(i);
    160     }
    161 }
    162 
    163 void is31fl3741_init(uint8_t index) {
    164     // In order to avoid the LEDs being driven with garbage data
    165     // in the LED driver's PWM registers, shutdown is enabled last.
    166     // Set up the mode and other settings, clear the PWM registers,
    167     // then disable software shutdown.
    168     // Unlock the command register.
    169 
    170     is31fl3741_select_page(index, IS31FL3741_COMMAND_FUNCTION);
    171 
    172     // Set to Normal operation
    173     is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
    174 
    175     // Set Golbal Current Control Register
    176     is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3741_GLOBAL_CURRENT);
    177     // Set Pull up & Down for SWx CSy
    178     is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PULLDOWNUP, ((IS31FL3741_CS_PULLDOWN << 4) | IS31FL3741_SW_PULLUP));
    179     // Set PWM frequency
    180     is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
    181 
    182     // is31fl3741_update_led_scaling_registers(index, 0xFF, 0xFF, 0xFF);
    183 
    184     // Wait 10ms to ensure the device has woken up.
    185     wait_ms(10);
    186 }
    187 
    188 uint8_t get_pwm_value(uint8_t driver, uint16_t reg) {
    189     if (reg & 0x100) {
    190         return driver_buffers[driver].pwm_buffer_1[reg & 0xFF];
    191     } else {
    192         return driver_buffers[driver].pwm_buffer_0[reg];
    193     }
    194 }
    195 
    196 void set_pwm_value(uint8_t driver, uint16_t reg, uint8_t value) {
    197     if (reg & 0x100) {
    198         driver_buffers[driver].pwm_buffer_1[reg & 0xFF] = value;
    199     } else {
    200         driver_buffers[driver].pwm_buffer_0[reg] = value;
    201     }
    202 }
    203 
    204 void is31fl3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
    205     is31fl3741_led_t led;
    206 
    207     if (index >= 0 && index < IS31FL3741_LED_COUNT) {
    208         memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
    209 
    210         if (get_pwm_value(led.driver, led.r) == red && get_pwm_value(led.driver, led.g) == green && get_pwm_value(led.driver, led.b) == blue) {
    211             return;
    212         }
    213 
    214         set_pwm_value(led.driver, led.r, red);
    215         set_pwm_value(led.driver, led.g, green);
    216         set_pwm_value(led.driver, led.b, blue);
    217         driver_buffers[led.driver].pwm_buffer_dirty = true;
    218     }
    219 }
    220 
    221 void is31fl3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
    222     for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
    223         is31fl3741_set_color(i, red, green, blue);
    224     }
    225 }
    226 
    227 void set_scaling_value(uint8_t driver, uint16_t reg, uint8_t value) {
    228     if (reg & 0x100) {
    229         driver_buffers[driver].scaling_buffer_1[reg & 0xFF] = value;
    230     } else {
    231         driver_buffers[driver].scaling_buffer_0[reg] = value;
    232     }
    233 }
    234 
    235 void is31fl3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue) {
    236     is31fl3741_led_t led;
    237     memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
    238 
    239     set_scaling_value(led.driver, led.r, red ? 0xFF : 0x00);
    240     set_scaling_value(led.driver, led.g, green ? 0xFF : 0x00);
    241     set_scaling_value(led.driver, led.b, blue ? 0xFF : 0x00);
    242 
    243     driver_buffers[led.driver].scaling_buffer_dirty = true;
    244 }
    245 
    246 void is31fl3741_update_pwm_buffers(uint8_t index) {
    247     if (driver_buffers[index].pwm_buffer_dirty) {
    248         is31fl3741_write_pwm_buffer(index);
    249 
    250         driver_buffers[index].pwm_buffer_dirty = false;
    251     }
    252 }
    253 
    254 void is31fl3741_set_pwm_buffer(const is31fl3741_led_t *pled, uint8_t red, uint8_t green, uint8_t blue) {
    255     set_pwm_value(pled->driver, pled->r, red);
    256     set_pwm_value(pled->driver, pled->g, green);
    257     set_pwm_value(pled->driver, pled->b, blue);
    258     driver_buffers[pled->driver].pwm_buffer_dirty = true;
    259 }
    260 
    261 void is31fl3741_update_led_control_registers(uint8_t index) {
    262     if (driver_buffers[index].scaling_buffer_dirty) {
    263         is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_0);
    264 
    265         for (uint8_t i = 0; i < IS31FL3741_SCALING_0_REGISTER_COUNT; i++) {
    266             is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_0[i]);
    267         }
    268 
    269         is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_1);
    270 
    271         for (uint8_t i = 0; i < IS31FL3741_SCALING_1_REGISTER_COUNT; i++) {
    272             is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_1[i]);
    273         }
    274 
    275         driver_buffers[index].scaling_buffer_dirty = false;
    276     }
    277 }
    278 
    279 void is31fl3741_set_scaling_registers(const is31fl3741_led_t *pled, uint8_t red, uint8_t green, uint8_t blue) {
    280     set_scaling_value(pled->driver, pled->r, red);
    281     set_scaling_value(pled->driver, pled->g, green);
    282     set_scaling_value(pled->driver, pled->b, blue);
    283     driver_buffers[pled->driver].scaling_buffer_dirty = true;
    284 }
    285 
    286 void is31fl3741_flush(void) {
    287     for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
    288         is31fl3741_update_pwm_buffers(i);
    289     }
    290 }