diff options
| author | HorrorTroll <sonicvipduc@gmail.com> | 2024-02-16 21:41:35 +0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-17 01:41:35 +1100 |
| commit | f6709e65ebfd385a9963348d41c19abe9b91e8ad (patch) | |
| tree | e61190504d666a8535f5e41bed90d8b5cdb7b9dc /drivers/led | |
| parent | 9b0b3d7b25a845bd1af2152ab1259a6522d5590f (diff) | |
Add RGB matrix & LED Matrix support for IS31FL3729 (#21944)
Co-authored-by: Xelus22 <preyas22@gmail.com>
Co-authored-by: dexter93 <d3xter93@gmail.com>
Diffstat (limited to 'drivers/led')
| -rw-r--r-- | drivers/led/issi/is31fl3729-mono.c | 220 | ||||
| -rw-r--r-- | drivers/led/issi/is31fl3729-mono.h | 265 | ||||
| -rw-r--r-- | drivers/led/issi/is31fl3729.c | 226 | ||||
| -rw-r--r-- | drivers/led/issi/is31fl3729.h | 267 |
4 files changed, 978 insertions, 0 deletions
diff --git a/drivers/led/issi/is31fl3729-mono.c b/drivers/led/issi/is31fl3729-mono.c new file mode 100644 index 0000000000..1617dd40a7 --- /dev/null +++ b/drivers/led/issi/is31fl3729-mono.c | |||
| @@ -0,0 +1,220 @@ | |||
| 1 | /* Copyright 2024 HorrorTroll <https://github.com/HorrorTroll> | ||
| 2 | * Copyright 2024 Harrison Chan (Xelus) | ||
| 3 | * Copyright 2024 Dimitris Mantzouranis <d3xter93@gmail.com> | ||
| 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 | |||
| 19 | #include "is31fl3729-mono.h" | ||
| 20 | #include "i2c_master.h" | ||
| 21 | #include "wait.h" | ||
| 22 | |||
| 23 | #define IS31FL3729_PWM_REGISTER_COUNT 143 | ||
| 24 | #define IS31FL3729_SCALING_REGISTER_COUNT 16 | ||
| 25 | |||
| 26 | #ifndef IS31FL3729_I2C_TIMEOUT | ||
| 27 | # define IS31FL3729_I2C_TIMEOUT 100 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #ifndef IS31FL3729_I2C_PERSISTENCE | ||
| 31 | # define IS31FL3729_I2C_PERSISTENCE 0 | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #ifndef IS31FL3729_CONFIGURATION | ||
| 35 | # define IS31FL3729_CONFIGURATION IS31FL3729_CONFIG_SWS_15_9 | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #ifndef IS31FL3729_GLOBAL_CURRENT | ||
| 39 | # define IS31FL3729_GLOBAL_CURRENT 0x40 | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #ifndef IS31FL3729_PULLDOWNUP | ||
| 43 | # define IS31FL3729_PULLDOWNUP 0x33 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifndef IS31FL3729_SPREAD_SPECTRUM | ||
| 47 | # define IS31FL3729_SPREAD_SPECTRUM IS31FL3729_SSP_DISABLE | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifndef IS31FL3729_SPREAD_SPECTRUM_RANGE | ||
| 51 | # define IS31FL3729_SPREAD_SPECTRUM_RANGE IS31FL3729_RNG_5_PERCENT | ||
| 52 | #endif | ||
| 53 | |||
| 54 | #ifndef IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME | ||
| 55 | # define IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME IS31FL3729_CLT_1980_US | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #ifndef IS31FL3729_PWM_FREQUENCY | ||
| 59 | # define IS31FL3729_PWM_FREQUENCY IS31FL3729_PWM_FREQUENCY_32K_HZ | ||
| 60 | #endif | ||
| 61 | |||
| 62 | // These buffers match the PWM & scaling registers. | ||
| 63 | // Storing them like this is optimal for I2C transfers to the registers. | ||
| 64 | typedef struct is31fl3729_driver_t { | ||
| 65 | uint8_t pwm_buffer[IS31FL3729_PWM_REGISTER_COUNT]; | ||
| 66 | bool pwm_buffer_dirty; | ||
| 67 | uint8_t scaling_buffer[IS31FL3729_SCALING_REGISTER_COUNT]; | ||
| 68 | bool scaling_buffer_dirty; | ||
| 69 | } PACKED is31fl3729_driver_t; | ||
| 70 | |||
| 71 | is31fl3729_driver_t driver_buffers[IS31FL3729_DRIVER_COUNT] = {{ | ||
| 72 | .pwm_buffer = {0}, | ||
| 73 | .pwm_buffer_dirty = false, | ||
| 74 | .scaling_buffer = {0}, | ||
| 75 | .scaling_buffer_dirty = false, | ||
| 76 | }}; | ||
| 77 | |||
| 78 | void is31fl3729_write_register(uint8_t addr, uint8_t reg, uint8_t data) { | ||
| 79 | #if IS31FL3729_I2C_PERSISTENCE > 0 | ||
| 80 | for (uint8_t i = 0; i < IS31FL3729_I2C_PERSISTENCE; i++) { | ||
| 81 | if (i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
| 82 | } | ||
| 83 | #else | ||
| 84 | i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT); | ||
| 85 | #endif | ||
| 86 | } | ||
| 87 | |||
| 88 | void is31fl3729_write_pwm_buffer(uint8_t addr, uint8_t index) { | ||
| 89 | // Transmit PWM registers in 9 transfers of 16 bytes. | ||
| 90 | |||
| 91 | // Iterate over the pwm_buffer contents at 16 byte intervals. | ||
| 92 | for (uint8_t i = 0; i <= IS31FL3729_PWM_REGISTER_COUNT; i += 16) { | ||
| 93 | #if IS31FL3729_I2C_PERSISTENCE > 0 | ||
| 94 | for (uint8_t j = 0; j < IS31FL3729_I2C_PERSISTENCE; j++) { | ||
| 95 | if (i2c_write_register(addr << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
| 96 | } | ||
| 97 | #else | ||
| 98 | i2c_write_register(addr << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3729_I2C_TIMEOUT); | ||
| 99 | #endif | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | void is31fl3729_init_drivers(void) { | ||
| 104 | i2c_init(); | ||
| 105 | |||
| 106 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_1); | ||
| 107 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 108 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_2); | ||
| 109 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 110 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_3); | ||
| 111 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 112 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_4); | ||
| 113 | # endif | ||
| 114 | # endif | ||
| 115 | #endif | ||
| 116 | |||
| 117 | for (int i = 0; i < IS31FL3729_LED_COUNT; i++) { | ||
| 118 | is31fl3729_set_scaling_register(i, 0xFF); | ||
| 119 | } | ||
| 120 | |||
| 121 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_1, 0); | ||
| 122 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 123 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_2, 1); | ||
| 124 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 125 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_3, 2); | ||
| 126 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 127 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_4, 3); | ||
| 128 | # endif | ||
| 129 | # endif | ||
| 130 | #endif | ||
| 131 | } | ||
| 132 | |||
| 133 | void is31fl3729_init(uint8_t addr) { | ||
| 134 | // In order to avoid the LEDs being driven with garbage data | ||
| 135 | // in the LED driver's PWM registers, shutdown is enabled last. | ||
| 136 | // Set up the mode and other settings, clear the PWM registers, | ||
| 137 | // then disable software shutdown. | ||
| 138 | |||
| 139 | // Set Pull up & Down for SWx CSy | ||
| 140 | is31fl3729_write_register(addr, IS31FL3729_REG_PULLDOWNUP, IS31FL3729_PULLDOWNUP); | ||
| 141 | |||
| 142 | // Set Spread Spectrum Register if applicable | ||
| 143 | is31fl3729_write_register(addr, IS31FL3729_REG_SPREAD_SPECTRUM, ((IS31FL3729_SPREAD_SPECTRUM & 0b1) << 4) | ((IS31FL3729_SPREAD_SPECTRUM_RANGE & 0b11) << 2) | (IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME & 0b11)); | ||
| 144 | |||
| 145 | // Set PWM Frequency Register if applicable | ||
| 146 | is31fl3729_write_register(addr, IS31FL3729_REG_PWM_FREQUENCY, IS31FL3729_PWM_FREQUENCY); | ||
| 147 | |||
| 148 | // Set Golbal Current Control Register | ||
| 149 | is31fl3729_write_register(addr, IS31FL3729_REG_GLOBAL_CURRENT, IS31FL3729_GLOBAL_CURRENT); | ||
| 150 | |||
| 151 | // Set to Normal operation | ||
| 152 | is31fl3729_write_register(addr, IS31FL3729_REG_CONFIGURATION, IS31FL3729_CONFIGURATION); | ||
| 153 | |||
| 154 | // Wait 10ms to ensure the device has woken up. | ||
| 155 | wait_ms(10); | ||
| 156 | } | ||
| 157 | |||
| 158 | void is31fl3729_set_value(int index, uint8_t value) { | ||
| 159 | is31fl3729_led_t led; | ||
| 160 | if (index >= 0 && index < IS31FL3729_LED_COUNT) { | ||
| 161 | memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led)); | ||
| 162 | |||
| 163 | if (driver_buffers[led.driver].pwm_buffer[led.v] == value) { | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 167 | driver_buffers[led.driver].pwm_buffer[led.v] = value; | ||
| 168 | driver_buffers[led.driver].pwm_buffer_dirty = true; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | void is31fl3729_set_value_all(uint8_t value) { | ||
| 173 | for (int i = 0; i < IS31FL3729_LED_COUNT; i++) { | ||
| 174 | is31fl3729_set_value(i, value); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | void is31fl3729_set_scaling_register(uint8_t index, uint8_t value) { | ||
| 179 | is31fl3729_led_t led; | ||
| 180 | memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led)); | ||
| 181 | |||
| 182 | // need to do a bit of checking here since 3729 scaling is per CS pin. | ||
| 183 | // not the usual per single LED key as per other ISSI drivers | ||
| 184 | // only enable them, since they should be default disabled | ||
| 185 | int cs_value = (led.v & 0x0F) - 1; | ||
| 186 | |||
| 187 | driver_buffers[led.driver].scaling_buffer[cs_value] = value; | ||
| 188 | driver_buffers[led.driver].scaling_buffer_dirty = true; | ||
| 189 | } | ||
| 190 | |||
| 191 | void is31fl3729_update_pwm_buffers(uint8_t addr, uint8_t index) { | ||
| 192 | if (driver_buffers[index].pwm_buffer_dirty) { | ||
| 193 | is31fl3729_write_pwm_buffer(addr, index); | ||
| 194 | |||
| 195 | driver_buffers[index].pwm_buffer_dirty = false; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | void is31fl3729_update_scaling_registers(uint8_t addr, uint8_t index) { | ||
| 200 | if (driver_buffers[index].scaling_buffer_dirty) { | ||
| 201 | for (uint8_t i = 0; i < IS31FL3729_SCALING_REGISTER_COUNT; i++) { | ||
| 202 | is31fl3729_write_register(addr, IS31FL3729_REG_SCALING + i, driver_buffers[index].scaling_buffer[i]); | ||
| 203 | } | ||
| 204 | |||
| 205 | driver_buffers[index].scaling_buffer_dirty = false; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | void is31fl3729_flush(void) { | ||
| 210 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_1, 0); | ||
| 211 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 212 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_2, 1); | ||
| 213 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 214 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_3, 2); | ||
| 215 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 216 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_4, 3); | ||
| 217 | # endif | ||
| 218 | # endif | ||
| 219 | #endif | ||
| 220 | } | ||
diff --git a/drivers/led/issi/is31fl3729-mono.h b/drivers/led/issi/is31fl3729-mono.h new file mode 100644 index 0000000000..815c200fd9 --- /dev/null +++ b/drivers/led/issi/is31fl3729-mono.h | |||
| @@ -0,0 +1,265 @@ | |||
| 1 | /* Copyright 2024 HorrorTroll <https://github.com/HorrorTroll> | ||
| 2 | * Copyright 2024 Harrison Chan (Xelus) | ||
| 3 | * Copyright 2024 Dimitris Mantzouranis <d3xter93@gmail.com> | ||
| 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 | |||
| 19 | #pragma once | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | #include <stdbool.h> | ||
| 23 | #include "progmem.h" | ||
| 24 | #include "util.h" | ||
| 25 | |||
| 26 | #define IS31FL3729_REG_SCALING 0x90 | ||
| 27 | #define IS31FL3729_REG_CONFIGURATION 0xA0 | ||
| 28 | #define IS31FL3729_REG_GLOBAL_CURRENT 0xA1 | ||
| 29 | #define IS31FL3729_REG_PULLDOWNUP 0xB0 | ||
| 30 | #define IS31FL3729_REG_SPREAD_SPECTRUM 0xB1 | ||
| 31 | #define IS31FL3729_REG_PWM_FREQUENCY 0xB2 | ||
| 32 | #define IS31FL3729_REG_RESET 0xCF | ||
| 33 | |||
| 34 | #define IS31FL3729_I2C_ADDRESS_GND 0x34 | ||
| 35 | #define IS31FL3729_I2C_ADDRESS_SCL 0x35 | ||
| 36 | #define IS31FL3729_I2C_ADDRESS_SDA 0x36 | ||
| 37 | #define IS31FL3729_I2C_ADDRESS_VCC 0x37 | ||
| 38 | |||
| 39 | #if defined(LED_MATRIX_IS31FL3729) | ||
| 40 | # define IS31FL3729_LED_COUNT LED_MATRIX_LED_COUNT | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 44 | # define IS31FL3729_DRIVER_COUNT 4 | ||
| 45 | #elif defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 46 | # define IS31FL3729_DRIVER_COUNT 3 | ||
| 47 | #elif defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 48 | # define IS31FL3729_DRIVER_COUNT 2 | ||
| 49 | #elif defined(IS31FL3729_I2C_ADDRESS_1) | ||
| 50 | # define IS31FL3729_DRIVER_COUNT 1 | ||
| 51 | #endif | ||
| 52 | |||
| 53 | typedef struct is31fl3729_led_t { | ||
| 54 | uint8_t driver : 2; | ||
| 55 | uint8_t v; | ||
| 56 | } PACKED is31fl3729_led_t; | ||
| 57 | |||
| 58 | extern const is31fl3729_led_t PROGMEM g_is31fl3729_leds[IS31FL3729_LED_COUNT]; | ||
| 59 | |||
| 60 | void is31fl3729_init_drivers(void); | ||
| 61 | void is31fl3729_init(uint8_t addr); | ||
| 62 | void is31fl3729_write_register(uint8_t addr, uint8_t reg, uint8_t data); | ||
| 63 | |||
| 64 | void is31fl3729_set_value(int index, uint8_t value); | ||
| 65 | void is31fl3729_set_value_all(uint8_t value); | ||
| 66 | |||
| 67 | void is31fl3729_set_scaling_register(uint8_t index, uint8_t value); | ||
| 68 | |||
| 69 | // This should not be called from an interrupt | ||
| 70 | // (eg. from a timer interrupt). | ||
| 71 | // Call this while idle (in between matrix scans). | ||
| 72 | // If the buffer is dirty, it will update the driver with the buffer. | ||
| 73 | void is31fl3729_update_pwm_buffers(uint8_t addr, uint8_t index); | ||
| 74 | void is31fl3729_update_scaling_registers(uint8_t addr, uint8_t index); | ||
| 75 | |||
| 76 | void is31fl3729_flush(void); | ||
| 77 | |||
| 78 | // Noise reduction using Spread Spectrum register | ||
| 79 | #define IS31FL3729_SSP_DISABLE 0b0 | ||
| 80 | #define IS31FL3729_SSP_ENABLE 0b1 | ||
| 81 | |||
| 82 | #define IS31FL3729_RNG_5_PERCENT 0b00 | ||
| 83 | #define IS31FL3729_RNG_15_PERCENT 0b01 | ||
| 84 | #define IS31FL3729_RNG_24_PERCENT 0b10 | ||
| 85 | #define IS31FL3729_RNG_34_PERCENT 0b11 | ||
| 86 | |||
| 87 | #define IS31FL3729_CLT_1980_US 0b00 | ||
| 88 | #define IS31FL3729_CLT_1200_US 0b01 | ||
| 89 | #define IS31FL3729_CLT_820_US 0b10 | ||
| 90 | #define IS31FL3729_CLT_660_US 0b11 | ||
| 91 | |||
| 92 | // Noise reduction using PWM Frequency register | ||
| 93 | #define IS31FL3729_PWM_FREQUENCY_55K_HZ 0b000 | ||
| 94 | #define IS31FL3729_PWM_FREQUENCY_32K_HZ 0b001 | ||
| 95 | #define IS31FL3729_PWM_FREQUENCY_4K_HZ 0b010 | ||
| 96 | #define IS31FL3729_PWM_FREQUENCY_2K_HZ 0b011 | ||
| 97 | #define IS31FL3729_PWM_FREQUENCY_1K_HZ 0b100 | ||
| 98 | #define IS31FL3729_PWM_FREQUENCY_500_HZ 0b101 | ||
| 99 | #define IS31FL3729_PWM_FREQUENCY_250_HZ 0b110 | ||
| 100 | #define IS31FL3729_PWM_FREQUENCY_80K_HZ 0b111 | ||
| 101 | |||
| 102 | // Change SWx Setting using Configuration register | ||
| 103 | #define IS31FL3729_CONFIG_SWS_15_9 0x01 // 15 CS x 9 SW matrix | ||
| 104 | #define IS31FL3729_CONFIG_SWS_16_8 0x11 // 16 CS x 8 SW matrix | ||
| 105 | #define IS31FL3729_CONFIG_SWS_16_7 0x21 // 16 CS x 7 SW matrix | ||
| 106 | #define IS31FL3729_CONFIG_SWS_16_6 0x31 // 16 CS x 6 SW matrix | ||
| 107 | #define IS31FL3729_CONFIG_SWS_16_5 0x41 // 16 CS x 5 SW matrix | ||
| 108 | #define IS31FL3729_CONFIG_SWS_16_4 0x51 // 16 CS x 4 SW matrix | ||
| 109 | #define IS31FL3729_CONFIG_SWS_16_3 0x61 // 16 CS x 3 SW matrix | ||
| 110 | #define IS31FL3729_CONFIG_SWS_16_2 0x71 // 16 CS x 2 SW matrix | ||
| 111 | |||
| 112 | // Map CS SW locations to order in PWM / Scaling buffers | ||
| 113 | // This matches the ORDER in the Datasheet Register not the POSITION | ||
| 114 | // It will always count from 0x01 to (ISSI_MAX_LEDS - 1) | ||
| 115 | #define SW1_CS1 0x01 | ||
| 116 | #define SW1_CS2 0x02 | ||
| 117 | #define SW1_CS3 0x03 | ||
| 118 | #define SW1_CS4 0x04 | ||
| 119 | #define SW1_CS5 0x05 | ||
| 120 | #define SW1_CS6 0x06 | ||
| 121 | #define SW1_CS7 0x07 | ||
| 122 | #define SW1_CS8 0x08 | ||
| 123 | #define SW1_CS9 0x09 | ||
| 124 | #define SW1_CS10 0x0A | ||
| 125 | #define SW1_CS11 0x0B | ||
| 126 | #define SW1_CS12 0x0C | ||
| 127 | #define SW1_CS13 0x0D | ||
| 128 | #define SW1_CS14 0x0E | ||
| 129 | #define SW1_CS15 0x0F | ||
| 130 | #define SW1_CS16 0x10 | ||
| 131 | |||
| 132 | #define SW2_CS1 0x11 | ||
| 133 | #define SW2_CS2 0x12 | ||
| 134 | #define SW2_CS3 0x13 | ||
| 135 | #define SW2_CS4 0x14 | ||
| 136 | #define SW2_CS5 0x15 | ||
| 137 | #define SW2_CS6 0x16 | ||
| 138 | #define SW2_CS7 0x17 | ||
| 139 | #define SW2_CS8 0x18 | ||
| 140 | #define SW2_CS9 0x19 | ||
| 141 | #define SW2_CS10 0x1A | ||
| 142 | #define SW2_CS11 0x1B | ||
| 143 | #define SW2_CS12 0x1C | ||
| 144 | #define SW2_CS13 0x1D | ||
| 145 | #define SW2_CS14 0x1E | ||
| 146 | #define SW2_CS15 0x1F | ||
| 147 | #define SW2_CS16 0x20 | ||
| 148 | |||
| 149 | #define SW3_CS1 0x21 | ||
| 150 | #define SW3_CS2 0x22 | ||
| 151 | #define SW3_CS3 0x23 | ||
| 152 | #define SW3_CS4 0x24 | ||
| 153 | #define SW3_CS5 0x25 | ||
| 154 | #define SW3_CS6 0x26 | ||
| 155 | #define SW3_CS7 0x27 | ||
| 156 | #define SW3_CS8 0x28 | ||
| 157 | #define SW3_CS9 0x29 | ||
| 158 | #define SW3_CS10 0x2A | ||
| 159 | #define SW3_CS11 0x2B | ||
| 160 | #define SW3_CS12 0x2C | ||
| 161 | #define SW3_CS13 0x2D | ||
| 162 | #define SW3_CS14 0x2E | ||
| 163 | #define SW3_CS15 0x2F | ||
| 164 | #define SW3_CS16 0x30 | ||
| 165 | |||
| 166 | #define SW4_CS1 0x31 | ||
| 167 | #define SW4_CS2 0x32 | ||
| 168 | #define SW4_CS3 0x33 | ||
| 169 | #define SW4_CS4 0x34 | ||
| 170 | #define SW4_CS5 0x35 | ||
| 171 | #define SW4_CS6 0x36 | ||
| 172 | #define SW4_CS7 0x37 | ||
| 173 | #define SW4_CS8 0x38 | ||
| 174 | #define SW4_CS9 0x39 | ||
| 175 | #define SW4_CS10 0x3A | ||
| 176 | #define SW4_CS11 0x3B | ||
| 177 | #define SW4_CS12 0x3C | ||
| 178 | #define SW4_CS13 0x3D | ||
| 179 | #define SW4_CS14 0x3E | ||
| 180 | #define SW4_CS15 0x3F | ||
| 181 | #define SW4_CS16 0x40 | ||
| 182 | |||
| 183 | #define SW5_CS1 0x41 | ||
| 184 | #define SW5_CS2 0x42 | ||
| 185 | #define SW5_CS3 0x43 | ||
| 186 | #define SW5_CS4 0x44 | ||
| 187 | #define SW5_CS5 0x45 | ||
| 188 | #define SW5_CS6 0x46 | ||
| 189 | #define SW5_CS7 0x47 | ||
| 190 | #define SW5_CS8 0x48 | ||
| 191 | #define SW5_CS9 0x49 | ||
| 192 | #define SW5_CS10 0x4A | ||
| 193 | #define SW5_CS11 0x4B | ||
| 194 | #define SW5_CS12 0x4C | ||
| 195 | #define SW5_CS13 0x4D | ||
| 196 | #define SW5_CS14 0x4E | ||
| 197 | #define SW5_CS15 0x4F | ||
| 198 | #define SW5_CS16 0x50 | ||
| 199 | |||
| 200 | #define SW6_CS1 0x51 | ||
| 201 | #define SW6_CS2 0x52 | ||
| 202 | #define SW6_CS3 0x53 | ||
| 203 | #define SW6_CS4 0x54 | ||
| 204 | #define SW6_CS5 0x55 | ||
| 205 | #define SW6_CS6 0x56 | ||
| 206 | #define SW6_CS7 0x57 | ||
| 207 | #define SW6_CS8 0x58 | ||
| 208 | #define SW6_CS9 0x59 | ||
| 209 | #define SW6_CS10 0x5A | ||
| 210 | #define SW6_CS11 0x5B | ||
| 211 | #define SW6_CS12 0x5C | ||
| 212 | #define SW6_CS13 0x5D | ||
| 213 | #define SW6_CS14 0x5E | ||
| 214 | #define SW6_CS15 0x5F | ||
| 215 | #define SW6_CS16 0x60 | ||
| 216 | |||
| 217 | #define SW7_CS1 0x61 | ||
| 218 | #define SW7_CS2 0x62 | ||
| 219 | #define SW7_CS3 0x63 | ||
| 220 | #define SW7_CS4 0x64 | ||
| 221 | #define SW7_CS5 0x65 | ||
| 222 | #define SW7_CS6 0x66 | ||
| 223 | #define SW7_CS7 0x67 | ||
| 224 | #define SW7_CS8 0x68 | ||
| 225 | #define SW7_CS9 0x69 | ||
| 226 | #define SW7_CS10 0x6A | ||
| 227 | #define SW7_CS11 0x6B | ||
| 228 | #define SW7_CS12 0x6C | ||
| 229 | #define SW7_CS13 0x6D | ||
| 230 | #define SW7_CS14 0x6E | ||
| 231 | #define SW7_CS15 0x6F | ||
| 232 | #define SW7_CS16 0x70 | ||
| 233 | |||
| 234 | #define SW8_CS1 0x71 | ||
| 235 | #define SW8_CS2 0x72 | ||
| 236 | #define SW8_CS3 0x73 | ||
| 237 | #define SW8_CS4 0x74 | ||
| 238 | #define SW8_CS5 0x75 | ||
| 239 | #define SW8_CS6 0x76 | ||
| 240 | #define SW8_CS7 0x77 | ||
| 241 | #define SW8_CS8 0x78 | ||
| 242 | #define SW8_CS9 0x79 | ||
| 243 | #define SW8_CS10 0x7A | ||
| 244 | #define SW8_CS11 0x7B | ||
| 245 | #define SW8_CS12 0x7C | ||
| 246 | #define SW8_CS13 0x7D | ||
| 247 | #define SW8_CS14 0x7E | ||
| 248 | #define SW8_CS15 0x7F | ||
| 249 | #define SW8_CS16 0x80 | ||
| 250 | |||
| 251 | #define SW9_CS1 0x81 | ||
| 252 | #define SW9_CS2 0x82 | ||
| 253 | #define SW9_CS3 0x83 | ||
| 254 | #define SW9_CS4 0x84 | ||
| 255 | #define SW9_CS5 0x85 | ||
| 256 | #define SW9_CS6 0x86 | ||
| 257 | #define SW9_CS7 0x87 | ||
| 258 | #define SW9_CS8 0x88 | ||
| 259 | #define SW9_CS9 0x89 | ||
| 260 | #define SW9_CS10 0x8A | ||
| 261 | #define SW9_CS11 0x8B | ||
| 262 | #define SW9_CS12 0x8C | ||
| 263 | #define SW9_CS13 0x8D | ||
| 264 | #define SW9_CS14 0x8E | ||
| 265 | #define SW9_CS15 0x8F | ||
diff --git a/drivers/led/issi/is31fl3729.c b/drivers/led/issi/is31fl3729.c new file mode 100644 index 0000000000..06f2d168d0 --- /dev/null +++ b/drivers/led/issi/is31fl3729.c | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | /* Copyright 2024 HorrorTroll <https://github.com/HorrorTroll> | ||
| 2 | * Copyright 2024 Harrison Chan (Xelus) | ||
| 3 | * Copyright 2024 Dimitris Mantzouranis <d3xter93@gmail.com> | ||
| 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 | |||
| 19 | #include "is31fl3729.h" | ||
| 20 | #include "i2c_master.h" | ||
| 21 | #include "wait.h" | ||
| 22 | |||
| 23 | #define IS31FL3729_PWM_REGISTER_COUNT 143 | ||
| 24 | #define IS31FL3729_SCALING_REGISTER_COUNT 16 | ||
| 25 | |||
| 26 | #ifndef IS31FL3729_I2C_TIMEOUT | ||
| 27 | # define IS31FL3729_I2C_TIMEOUT 100 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #ifndef IS31FL3729_I2C_PERSISTENCE | ||
| 31 | # define IS31FL3729_I2C_PERSISTENCE 0 | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #ifndef IS31FL3729_CONFIGURATION | ||
| 35 | # define IS31FL3729_CONFIGURATION IS31FL3729_CONFIG_SWS_15_9 | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #ifndef IS31FL3729_GLOBAL_CURRENT | ||
| 39 | # define IS31FL3729_GLOBAL_CURRENT 0x40 | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #ifndef IS31FL3729_PULLDOWNUP | ||
| 43 | # define IS31FL3729_PULLDOWNUP 0x33 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifndef IS31FL3729_SPREAD_SPECTRUM | ||
| 47 | # define IS31FL3729_SPREAD_SPECTRUM IS31FL3729_SSP_DISABLE | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifndef IS31FL3729_SPREAD_SPECTRUM_RANGE | ||
| 51 | # define IS31FL3729_SPREAD_SPECTRUM_RANGE IS31FL3729_RNG_5_PERCENT | ||
| 52 | #endif | ||
| 53 | |||
| 54 | #ifndef IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME | ||
| 55 | # define IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME IS31FL3729_CLT_1980_US | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #ifndef IS31FL3729_PWM_FREQUENCY | ||
| 59 | # define IS31FL3729_PWM_FREQUENCY IS31FL3729_PWM_FREQUENCY_32K_HZ | ||
| 60 | #endif | ||
| 61 | |||
| 62 | // These buffers match the PWM & scaling registers. | ||
| 63 | // Storing them like this is optimal for I2C transfers to the registers. | ||
| 64 | typedef struct is31fl3729_driver_t { | ||
| 65 | uint8_t pwm_buffer[IS31FL3729_PWM_REGISTER_COUNT]; | ||
| 66 | bool pwm_buffer_dirty; | ||
| 67 | uint8_t scaling_buffer[IS31FL3729_SCALING_REGISTER_COUNT]; | ||
| 68 | bool scaling_buffer_dirty; | ||
| 69 | } PACKED is31fl3729_driver_t; | ||
| 70 | |||
| 71 | is31fl3729_driver_t driver_buffers[IS31FL3729_DRIVER_COUNT] = {{ | ||
| 72 | .pwm_buffer = {0}, | ||
| 73 | .pwm_buffer_dirty = false, | ||
| 74 | .scaling_buffer = {0}, | ||
| 75 | .scaling_buffer_dirty = false, | ||
| 76 | }}; | ||
| 77 | |||
| 78 | void is31fl3729_write_register(uint8_t addr, uint8_t reg, uint8_t data) { | ||
| 79 | #if IS31FL3729_I2C_PERSISTENCE > 0 | ||
| 80 | for (uint8_t i = 0; i < IS31FL3729_I2C_PERSISTENCE; i++) { | ||
| 81 | if (i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
| 82 | } | ||
| 83 | #else | ||
| 84 | i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT); | ||
| 85 | #endif | ||
| 86 | } | ||
| 87 | |||
| 88 | void is31fl3729_write_pwm_buffer(uint8_t addr, uint8_t index) { | ||
| 89 | // Transmit PWM registers in 9 transfers of 16 bytes. | ||
| 90 | |||
| 91 | // Iterate over the pwm_buffer contents at 16 byte intervals. | ||
| 92 | for (uint8_t i = 0; i <= IS31FL3729_PWM_REGISTER_COUNT; i += 16) { | ||
| 93 | #if IS31FL3729_I2C_PERSISTENCE > 0 | ||
| 94 | for (uint8_t j = 0; j < IS31FL3729_I2C_PERSISTENCE; j++) { | ||
| 95 | if (i2c_write_register(addr << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break; | ||
| 96 | } | ||
| 97 | #else | ||
| 98 | i2c_write_register(addr << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3729_I2C_TIMEOUT); | ||
| 99 | #endif | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | void is31fl3729_init_drivers(void) { | ||
| 104 | i2c_init(); | ||
| 105 | |||
| 106 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_1); | ||
| 107 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 108 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_2); | ||
| 109 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 110 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_3); | ||
| 111 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 112 | is31fl3729_init(IS31FL3729_I2C_ADDRESS_4); | ||
| 113 | # endif | ||
| 114 | # endif | ||
| 115 | #endif | ||
| 116 | |||
| 117 | for (int i = 0; i < IS31FL3729_LED_COUNT; i++) { | ||
| 118 | is31fl3729_set_scaling_register(i, 0xFF, 0xFF, 0xFF); | ||
| 119 | } | ||
| 120 | |||
| 121 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_1, 0); | ||
| 122 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 123 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_2, 1); | ||
| 124 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 125 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_3, 2); | ||
| 126 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 127 | is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_4, 3); | ||
| 128 | # endif | ||
| 129 | # endif | ||
| 130 | #endif | ||
| 131 | } | ||
| 132 | |||
| 133 | void is31fl3729_init(uint8_t addr) { | ||
| 134 | // In order to avoid the LEDs being driven with garbage data | ||
| 135 | // in the LED driver's PWM registers, shutdown is enabled last. | ||
| 136 | // Set up the mode and other settings, clear the PWM registers, | ||
| 137 | // then disable software shutdown. | ||
| 138 | |||
| 139 | // Set Pull up & Down for SWx CSy | ||
| 140 | is31fl3729_write_register(addr, IS31FL3729_REG_PULLDOWNUP, IS31FL3729_PULLDOWNUP); | ||
| 141 | |||
| 142 | // Set Spread Spectrum Register if applicable | ||
| 143 | is31fl3729_write_register(addr, IS31FL3729_REG_SPREAD_SPECTRUM, ((IS31FL3729_SPREAD_SPECTRUM & 0b1) << 4) | ((IS31FL3729_SPREAD_SPECTRUM_RANGE & 0b11) << 2) | (IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME & 0b11)); | ||
| 144 | |||
| 145 | // Set PWM Frequency Register if applicable | ||
| 146 | is31fl3729_write_register(addr, IS31FL3729_REG_PWM_FREQUENCY, IS31FL3729_PWM_FREQUENCY); | ||
| 147 | |||
| 148 | // Set Golbal Current Control Register | ||
| 149 | is31fl3729_write_register(addr, IS31FL3729_REG_GLOBAL_CURRENT, IS31FL3729_GLOBAL_CURRENT); | ||
| 150 | |||
| 151 | // Set to Normal operation | ||
| 152 | is31fl3729_write_register(addr, IS31FL3729_REG_CONFIGURATION, IS31FL3729_CONFIGURATION); | ||
| 153 | |||
| 154 | // Wait 10ms to ensure the device has woken up. | ||
| 155 | wait_ms(10); | ||
| 156 | } | ||
| 157 | |||
| 158 | void is31fl3729_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { | ||
| 159 | is31fl3729_led_t led; | ||
| 160 | if (index >= 0 && index < IS31FL3729_LED_COUNT) { | ||
| 161 | memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led)); | ||
| 162 | |||
| 163 | 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) { | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 167 | driver_buffers[led.driver].pwm_buffer[led.r] = red; | ||
| 168 | driver_buffers[led.driver].pwm_buffer[led.g] = green; | ||
| 169 | driver_buffers[led.driver].pwm_buffer[led.b] = blue; | ||
| 170 | driver_buffers[led.driver].pwm_buffer_dirty = true; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | void is31fl3729_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { | ||
| 175 | for (int i = 0; i < IS31FL3729_LED_COUNT; i++) { | ||
| 176 | is31fl3729_set_color(i, red, green, blue); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | void is31fl3729_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) { | ||
| 181 | is31fl3729_led_t led; | ||
| 182 | memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led)); | ||
| 183 | |||
| 184 | // need to do a bit of checking here since 3729 scaling is per CS pin. | ||
| 185 | // not the usual per RGB key as per other ISSI drivers | ||
| 186 | // only enable them, since they should be default disabled | ||
| 187 | int cs_red = (led.r & 0x0F) - 1; | ||
| 188 | int cs_green = (led.g & 0x0F) - 1; | ||
| 189 | int cs_blue = (led.b & 0x0F) - 1; | ||
| 190 | |||
| 191 | driver_buffers[led.driver].scaling_buffer[cs_red] = red; | ||
| 192 | driver_buffers[led.driver].scaling_buffer[cs_green] = green; | ||
| 193 | driver_buffers[led.driver].scaling_buffer[cs_blue] = blue; | ||
| 194 | driver_buffers[led.driver].scaling_buffer_dirty = true; | ||
| 195 | } | ||
| 196 | |||
| 197 | void is31fl3729_update_pwm_buffers(uint8_t addr, uint8_t index) { | ||
| 198 | if (driver_buffers[index].pwm_buffer_dirty) { | ||
| 199 | is31fl3729_write_pwm_buffer(addr, index); | ||
| 200 | |||
| 201 | driver_buffers[index].pwm_buffer_dirty = false; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | void is31fl3729_update_scaling_registers(uint8_t addr, uint8_t index) { | ||
| 206 | if (driver_buffers[index].scaling_buffer_dirty) { | ||
| 207 | for (uint8_t i = 0; i < IS31FL3729_SCALING_REGISTER_COUNT; i++) { | ||
| 208 | is31fl3729_write_register(addr, IS31FL3729_REG_SCALING + i, driver_buffers[index].scaling_buffer[i]); | ||
| 209 | } | ||
| 210 | |||
| 211 | driver_buffers[index].scaling_buffer_dirty = false; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | void is31fl3729_flush(void) { | ||
| 216 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_1, 0); | ||
| 217 | #if defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 218 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_2, 1); | ||
| 219 | # if defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 220 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_3, 2); | ||
| 221 | # if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 222 | is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_4, 3); | ||
| 223 | # endif | ||
| 224 | # endif | ||
| 225 | #endif | ||
| 226 | } | ||
diff --git a/drivers/led/issi/is31fl3729.h b/drivers/led/issi/is31fl3729.h new file mode 100644 index 0000000000..6f2672b6a3 --- /dev/null +++ b/drivers/led/issi/is31fl3729.h | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | /* Copyright 2024 HorrorTroll <https://github.com/HorrorTroll> | ||
| 2 | * Copyright 2024 Harrison Chan (Xelus) | ||
| 3 | * Copyright 2024 Dimitris Mantzouranis <d3xter93@gmail.com> | ||
| 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 | |||
| 19 | #pragma once | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | #include <stdbool.h> | ||
| 23 | #include "progmem.h" | ||
| 24 | #include "util.h" | ||
| 25 | |||
| 26 | #define IS31FL3729_REG_SCALING 0x90 | ||
| 27 | #define IS31FL3729_REG_CONFIGURATION 0xA0 | ||
| 28 | #define IS31FL3729_REG_GLOBAL_CURRENT 0xA1 | ||
| 29 | #define IS31FL3729_REG_PULLDOWNUP 0xB0 | ||
| 30 | #define IS31FL3729_REG_SPREAD_SPECTRUM 0xB1 | ||
| 31 | #define IS31FL3729_REG_PWM_FREQUENCY 0xB2 | ||
| 32 | #define IS31FL3729_REG_RESET 0xCF | ||
| 33 | |||
| 34 | #define IS31FL3729_I2C_ADDRESS_GND 0x34 | ||
| 35 | #define IS31FL3729_I2C_ADDRESS_SCL 0x35 | ||
| 36 | #define IS31FL3729_I2C_ADDRESS_SDA 0x36 | ||
| 37 | #define IS31FL3729_I2C_ADDRESS_VCC 0x37 | ||
| 38 | |||
| 39 | #if defined(RGB_MATRIX_IS31FL3729) | ||
| 40 | # define IS31FL3729_LED_COUNT RGB_MATRIX_LED_COUNT | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if defined(IS31FL3729_I2C_ADDRESS_4) | ||
| 44 | # define IS31FL3729_DRIVER_COUNT 4 | ||
| 45 | #elif defined(IS31FL3729_I2C_ADDRESS_3) | ||
| 46 | # define IS31FL3729_DRIVER_COUNT 3 | ||
| 47 | #elif defined(IS31FL3729_I2C_ADDRESS_2) | ||
| 48 | # define IS31FL3729_DRIVER_COUNT 2 | ||
| 49 | #elif defined(IS31FL3729_I2C_ADDRESS_1) | ||
| 50 | # define IS31FL3729_DRIVER_COUNT 1 | ||
| 51 | #endif | ||
| 52 | |||
| 53 | typedef struct is31fl3729_led_t { | ||
| 54 | uint8_t driver : 2; | ||
| 55 | uint8_t r; | ||
| 56 | uint8_t g; | ||
| 57 | uint8_t b; | ||
| 58 | } PACKED is31fl3729_led_t; | ||
| 59 | |||
| 60 | extern const is31fl3729_led_t PROGMEM g_is31fl3729_leds[IS31FL3729_LED_COUNT]; | ||
| 61 | |||
| 62 | void is31fl3729_init_drivers(void); | ||
| 63 | void is31fl3729_init(uint8_t addr); | ||
| 64 | void is31fl3729_write_register(uint8_t addr, uint8_t reg, uint8_t data); | ||
| 65 | |||
| 66 | void is31fl3729_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); | ||
| 67 | void is31fl3729_set_color_all(uint8_t red, uint8_t green, uint8_t blue); | ||
| 68 | |||
| 69 | void is31fl3729_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue); | ||
| 70 | |||
| 71 | // This should not be called from an interrupt | ||
| 72 | // (eg. from a timer interrupt). | ||
| 73 | // Call this while idle (in between matrix scans). | ||
| 74 | // If the buffer is dirty, it will update the driver with the buffer. | ||
| 75 | void is31fl3729_update_pwm_buffers(uint8_t addr, uint8_t index); | ||
| 76 | void is31fl3729_update_scaling_registers(uint8_t addr, uint8_t index); | ||
| 77 | |||
| 78 | void is31fl3729_flush(void); | ||
| 79 | |||
| 80 | // Noise reduction using Spread Spectrum register | ||
| 81 | #define IS31FL3729_SSP_DISABLE 0b0 | ||
| 82 | #define IS31FL3729_SSP_ENABLE 0b1 | ||
| 83 | |||
| 84 | #define IS31FL3729_RNG_5_PERCENT 0b00 | ||
| 85 | #define IS31FL3729_RNG_15_PERCENT 0b01 | ||
| 86 | #define IS31FL3729_RNG_24_PERCENT 0b10 | ||
| 87 | #define IS31FL3729_RNG_34_PERCENT 0b11 | ||
| 88 | |||
| 89 | #define IS31FL3729_CLT_1980_US 0b00 | ||
| 90 | #define IS31FL3729_CLT_1200_US 0b01 | ||
| 91 | #define IS31FL3729_CLT_820_US 0b10 | ||
| 92 | #define IS31FL3729_CLT_660_US 0b11 | ||
| 93 | |||
| 94 | // Noise reduction using PWM Frequency register | ||
| 95 | #define IS31FL3729_PWM_FREQUENCY_55K_HZ 0b000 | ||
| 96 | #define IS31FL3729_PWM_FREQUENCY_32K_HZ 0b001 | ||
| 97 | #define IS31FL3729_PWM_FREQUENCY_4K_HZ 0b010 | ||
| 98 | #define IS31FL3729_PWM_FREQUENCY_2K_HZ 0b011 | ||
| 99 | #define IS31FL3729_PWM_FREQUENCY_1K_HZ 0b100 | ||
| 100 | #define IS31FL3729_PWM_FREQUENCY_500_HZ 0b101 | ||
| 101 | #define IS31FL3729_PWM_FREQUENCY_250_HZ 0b110 | ||
| 102 | #define IS31FL3729_PWM_FREQUENCY_80K_HZ 0b111 | ||
| 103 | |||
| 104 | // Change SWx Setting using Configuration register | ||
| 105 | #define IS31FL3729_CONFIG_SWS_15_9 0x01 // 15 CS x 9 SW matrix | ||
| 106 | #define IS31FL3729_CONFIG_SWS_16_8 0x11 // 16 CS x 8 SW matrix | ||
| 107 | #define IS31FL3729_CONFIG_SWS_16_7 0x21 // 16 CS x 7 SW matrix | ||
| 108 | #define IS31FL3729_CONFIG_SWS_16_6 0x31 // 16 CS x 6 SW matrix | ||
| 109 | #define IS31FL3729_CONFIG_SWS_16_5 0x41 // 16 CS x 5 SW matrix | ||
| 110 | #define IS31FL3729_CONFIG_SWS_16_4 0x51 // 16 CS x 4 SW matrix | ||
| 111 | #define IS31FL3729_CONFIG_SWS_16_3 0x61 // 16 CS x 3 SW matrix | ||
| 112 | #define IS31FL3729_CONFIG_SWS_16_2 0x71 // 16 CS x 2 SW matrix | ||
| 113 | |||
| 114 | // Map CS SW locations to order in PWM / Scaling buffers | ||
| 115 | // This matches the ORDER in the Datasheet Register not the POSITION | ||
| 116 | // It will always count from 0x01 to (ISSI_MAX_LEDS - 1) | ||
| 117 | #define SW1_CS1 0x01 | ||
| 118 | #define SW1_CS2 0x02 | ||
| 119 | #define SW1_CS3 0x03 | ||
| 120 | #define SW1_CS4 0x04 | ||
| 121 | #define SW1_CS5 0x05 | ||
| 122 | #define SW1_CS6 0x06 | ||
| 123 | #define SW1_CS7 0x07 | ||
| 124 | #define SW1_CS8 0x08 | ||
| 125 | #define SW1_CS9 0x09 | ||
| 126 | #define SW1_CS10 0x0A | ||
| 127 | #define SW1_CS11 0x0B | ||
| 128 | #define SW1_CS12 0x0C | ||
| 129 | #define SW1_CS13 0x0D | ||
| 130 | #define SW1_CS14 0x0E | ||
| 131 | #define SW1_CS15 0x0F | ||
| 132 | #define SW1_CS16 0x10 | ||
| 133 | |||
| 134 | #define SW2_CS1 0x11 | ||
| 135 | #define SW2_CS2 0x12 | ||
| 136 | #define SW2_CS3 0x13 | ||
| 137 | #define SW2_CS4 0x14 | ||
| 138 | #define SW2_CS5 0x15 | ||
| 139 | #define SW2_CS6 0x16 | ||
| 140 | #define SW2_CS7 0x17 | ||
| 141 | #define SW2_CS8 0x18 | ||
| 142 | #define SW2_CS9 0x19 | ||
| 143 | #define SW2_CS10 0x1A | ||
| 144 | #define SW2_CS11 0x1B | ||
| 145 | #define SW2_CS12 0x1C | ||
| 146 | #define SW2_CS13 0x1D | ||
| 147 | #define SW2_CS14 0x1E | ||
| 148 | #define SW2_CS15 0x1F | ||
| 149 | #define SW2_CS16 0x20 | ||
| 150 | |||
| 151 | #define SW3_CS1 0x21 | ||
| 152 | #define SW3_CS2 0x22 | ||
| 153 | #define SW3_CS3 0x23 | ||
| 154 | #define SW3_CS4 0x24 | ||
| 155 | #define SW3_CS5 0x25 | ||
| 156 | #define SW3_CS6 0x26 | ||
| 157 | #define SW3_CS7 0x27 | ||
| 158 | #define SW3_CS8 0x28 | ||
| 159 | #define SW3_CS9 0x29 | ||
| 160 | #define SW3_CS10 0x2A | ||
| 161 | #define SW3_CS11 0x2B | ||
| 162 | #define SW3_CS12 0x2C | ||
| 163 | #define SW3_CS13 0x2D | ||
| 164 | #define SW3_CS14 0x2E | ||
| 165 | #define SW3_CS15 0x2F | ||
| 166 | #define SW3_CS16 0x30 | ||
| 167 | |||
| 168 | #define SW4_CS1 0x31 | ||
| 169 | #define SW4_CS2 0x32 | ||
| 170 | #define SW4_CS3 0x33 | ||
| 171 | #define SW4_CS4 0x34 | ||
| 172 | #define SW4_CS5 0x35 | ||
| 173 | #define SW4_CS6 0x36 | ||
| 174 | #define SW4_CS7 0x37 | ||
| 175 | #define SW4_CS8 0x38 | ||
| 176 | #define SW4_CS9 0x39 | ||
| 177 | #define SW4_CS10 0x3A | ||
| 178 | #define SW4_CS11 0x3B | ||
| 179 | #define SW4_CS12 0x3C | ||
| 180 | #define SW4_CS13 0x3D | ||
| 181 | #define SW4_CS14 0x3E | ||
| 182 | #define SW4_CS15 0x3F | ||
| 183 | #define SW4_CS16 0x40 | ||
| 184 | |||
| 185 | #define SW5_CS1 0x41 | ||
| 186 | #define SW5_CS2 0x42 | ||
| 187 | #define SW5_CS3 0x43 | ||
| 188 | #define SW5_CS4 0x44 | ||
| 189 | #define SW5_CS5 0x45 | ||
| 190 | #define SW5_CS6 0x46 | ||
| 191 | #define SW5_CS7 0x47 | ||
| 192 | #define SW5_CS8 0x48 | ||
| 193 | #define SW5_CS9 0x49 | ||
| 194 | #define SW5_CS10 0x4A | ||
| 195 | #define SW5_CS11 0x4B | ||
| 196 | #define SW5_CS12 0x4C | ||
| 197 | #define SW5_CS13 0x4D | ||
| 198 | #define SW5_CS14 0x4E | ||
| 199 | #define SW5_CS15 0x4F | ||
| 200 | #define SW5_CS16 0x50 | ||
| 201 | |||
| 202 | #define SW6_CS1 0x51 | ||
| 203 | #define SW6_CS2 0x52 | ||
| 204 | #define SW6_CS3 0x53 | ||
| 205 | #define SW6_CS4 0x54 | ||
| 206 | #define SW6_CS5 0x55 | ||
| 207 | #define SW6_CS6 0x56 | ||
| 208 | #define SW6_CS7 0x57 | ||
| 209 | #define SW6_CS8 0x58 | ||
| 210 | #define SW6_CS9 0x59 | ||
| 211 | #define SW6_CS10 0x5A | ||
| 212 | #define SW6_CS11 0x5B | ||
| 213 | #define SW6_CS12 0x5C | ||
| 214 | #define SW6_CS13 0x5D | ||
| 215 | #define SW6_CS14 0x5E | ||
| 216 | #define SW6_CS15 0x5F | ||
| 217 | #define SW6_CS16 0x60 | ||
| 218 | |||
| 219 | #define SW7_CS1 0x61 | ||
| 220 | #define SW7_CS2 0x62 | ||
| 221 | #define SW7_CS3 0x63 | ||
| 222 | #define SW7_CS4 0x64 | ||
| 223 | #define SW7_CS5 0x65 | ||
| 224 | #define SW7_CS6 0x66 | ||
| 225 | #define SW7_CS7 0x67 | ||
| 226 | #define SW7_CS8 0x68 | ||
| 227 | #define SW7_CS9 0x69 | ||
| 228 | #define SW7_CS10 0x6A | ||
| 229 | #define SW7_CS11 0x6B | ||
| 230 | #define SW7_CS12 0x6C | ||
| 231 | #define SW7_CS13 0x6D | ||
| 232 | #define SW7_CS14 0x6E | ||
| 233 | #define SW7_CS15 0x6F | ||
| 234 | #define SW7_CS16 0x70 | ||
| 235 | |||
| 236 | #define SW8_CS1 0x71 | ||
| 237 | #define SW8_CS2 0x72 | ||
| 238 | #define SW8_CS3 0x73 | ||
| 239 | #define SW8_CS4 0x74 | ||
| 240 | #define SW8_CS5 0x75 | ||
| 241 | #define SW8_CS6 0x76 | ||
| 242 | #define SW8_CS7 0x77 | ||
| 243 | #define SW8_CS8 0x78 | ||
| 244 | #define SW8_CS9 0x79 | ||
| 245 | #define SW8_CS10 0x7A | ||
| 246 | #define SW8_CS11 0x7B | ||
| 247 | #define SW8_CS12 0x7C | ||
| 248 | #define SW8_CS13 0x7D | ||
| 249 | #define SW8_CS14 0x7E | ||
| 250 | #define SW8_CS15 0x7F | ||
| 251 | #define SW8_CS16 0x80 | ||
| 252 | |||
| 253 | #define SW9_CS1 0x81 | ||
| 254 | #define SW9_CS2 0x82 | ||
| 255 | #define SW9_CS3 0x83 | ||
| 256 | #define SW9_CS4 0x84 | ||
| 257 | #define SW9_CS5 0x85 | ||
| 258 | #define SW9_CS6 0x86 | ||
| 259 | #define SW9_CS7 0x87 | ||
| 260 | #define SW9_CS8 0x88 | ||
| 261 | #define SW9_CS9 0x89 | ||
| 262 | #define SW9_CS10 0x8A | ||
| 263 | #define SW9_CS11 0x8B | ||
| 264 | #define SW9_CS12 0x8C | ||
| 265 | #define SW9_CS13 0x8D | ||
| 266 | #define SW9_CS14 0x8E | ||
| 267 | #define SW9_CS15 0x8F | ||
