Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RGB matrix & LED Matrix support for IS31FL3729 #21944

Merged
merged 26 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3d17202
Added support IS31FL3729 LED Driver
HorrorTroll Aug 31, 2023
771e87a
Update driver code
HorrorTroll Sep 2, 2023
a9ee959
Fix up buggy PWM and delete unused functions
HorrorTroll Sep 3, 2023
e255ad0
Initial IS31FL3729 cleanup
Xelus22 Sep 4, 2023
3ff017b
Fixed some issues
HorrorTroll Sep 5, 2023
7434673
SImplify register declaration header for is31fl3729
dexter93 Sep 5, 2023
a3c2702
Clean up and fixed pwm_buffer
HorrorTroll Sep 6, 2023
719896f
Added support for LED Matrix
HorrorTroll Sep 6, 2023
2e4b955
Added docs for RGB Matrix & LED Matrix
HorrorTroll Sep 6, 2023
a02bb7a
Drivers name cleanup
HorrorTroll Sep 7, 2023
21ea867
Formatting lint error
HorrorTroll Sep 7, 2023
3e18101
Use define for I2C Address
HorrorTroll Sep 16, 2023
af82d20
Added missing Spread Spectrum register for noise reduction
HorrorTroll Sep 17, 2023
bd8d828
Add define for noise reduction
HorrorTroll Sep 17, 2023
7330e31
Add define to change matrix mode on Configuration register
HorrorTroll Sep 19, 2023
071b6b9
Resolved fauxpark suggest changes
HorrorTroll Sep 23, 2023
b5cf6bf
Resolved conflict again
HorrorTroll Nov 6, 2023
d3ab72f
Resolved changes again
HorrorTroll Dec 13, 2023
050038a
Another suggest change resolved
HorrorTroll Dec 29, 2023
10ae2ec
Revert docs change back to original state
HorrorTroll Dec 29, 2023
6dd473f
Resolved changes again
HorrorTroll Jan 6, 2024
2f5e08e
Resolve changes
HorrorTroll Jan 25, 2024
bfd8c4d
Resolved
HorrorTroll Feb 8, 2024
96ce46d
Resolved
HorrorTroll Feb 13, 2024
52394b2
update PWM register defines
HorrorTroll Feb 13, 2024
b2c9fa5
Resolved
HorrorTroll Feb 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions builddefs/common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ LED_MATRIX_DRIVER := snled27351
endif

LED_MATRIX_ENABLE ?= no
VALID_LED_MATRIX_TYPES := is31fl3218 is31fl3731 is31fl3733 is31fl3736 is31fl3737 is31fl3741 is31fl3742a is31fl3743a is31fl3745 is31fl3746a snled27351 custom
VALID_LED_MATRIX_TYPES := is31fl3218 is31fl3729 is31fl3731 is31fl3733 is31fl3736 is31fl3737 is31fl3741 is31fl3742a is31fl3743a is31fl3745 is31fl3746a snled27351 custom

ifeq ($(strip $(LED_MATRIX_ENABLE)), yes)
ifeq ($(filter $(LED_MATRIX_DRIVER),$(VALID_LED_MATRIX_TYPES)),)
Expand All @@ -365,6 +365,12 @@ ifeq ($(strip $(LED_MATRIX_ENABLE)), yes)
SRC += is31fl3218-mono.c
endif

ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3729)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3729-mono.c
endif

ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3731)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
Expand Down Expand Up @@ -437,7 +443,7 @@ endif

RGB_MATRIX_ENABLE ?= no

VALID_RGB_MATRIX_TYPES := aw20216s is31fl3218 is31fl3731 is31fl3733 is31fl3736 is31fl3737 is31fl3741 is31fl3742a is31fl3743a is31fl3745 is31fl3746a snled27351 ws2812 custom
VALID_RGB_MATRIX_TYPES := aw20216s is31fl3218 is31fl3729 is31fl3731 is31fl3733 is31fl3736 is31fl3737 is31fl3741 is31fl3742a is31fl3743a is31fl3745 is31fl3746a snled27351 ws2812 custom
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
ifeq ($(filter $(RGB_MATRIX_DRIVER),$(VALID_RGB_MATRIX_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid RGB_MATRIX_DRIVER,RGB_MATRIX_DRIVER="$(RGB_MATRIX_DRIVER)" is not a valid matrix type)
Expand Down Expand Up @@ -468,6 +474,12 @@ ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
SRC += is31fl3218.c
endif

ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3729)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3729.c
endif

ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3731)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
Expand Down
2 changes: 1 addition & 1 deletion docs/reference_info_json.md
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ Configures the [RGB Matrix](feature_rgb_matrix.md) feature.
* The default animation speed.
* Default: `128`
* `driver` (Required)
* The driver to use. Must be one of `aw20216s`, `custom`, `is31fl3218`, `is31fl3731`, `is31fl3733`, `is31fl3736`, `is31fl3737`, `is31fl3741`, `is31fl3742a`, `is31fl3743a`, `is31fl3745`, `is31fl3746a`, `snled27351`, `ws2812`.
* The driver to use. Must be one of `aw20216s`, `custom`, `is31fl3218`, `is31fl3729`, `is31fl3731`, `is31fl3733`, `is31fl3736`, `is31fl3737`, `is31fl3741`, `is31fl3742a`, `is31fl3743a`, `is31fl3745`, `is31fl3746a`, `snled27351`, `ws2812`.
* `hue_steps`
* The number of hue adjustment steps.
* Default: `8`
Expand Down
213 changes: 213 additions & 0 deletions drivers/led/issi/is31fl3729-mono.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/* Copyright 2024 HorrorTroll <https://github.com/HorrorTroll>
* Copyright 2024 Harrison Chan (Xelus)
* Copyright 2024 Dimitris Mantzouranis <d3xter93@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "is31fl3729-mono.h"
#include "i2c_master.h"
#include "wait.h"

#define IS31FL3729_PWM_REGISTER_COUNT 143
#define IS31FL3729_SCALING_REGISTER_COUNT 16

#ifndef IS31FL3729_I2C_TIMEOUT
# define IS31FL3729_I2C_TIMEOUT 100
#endif

#ifndef IS31FL3729_I2C_PERSISTENCE
# define IS31FL3729_I2C_PERSISTENCE 0
#endif

#ifndef IS31FL3729_CONFIGURATION
# define IS31FL3729_CONFIGURATION IS31FL3729_CONFIG_SWS_15_9
#endif

#ifndef IS31FL3729_GLOBAL_CURRENT
# define IS31FL3729_GLOBAL_CURRENT 0x40
#endif

#ifndef IS31FL3729_PULLDOWNUP
# define IS31FL3729_PULLDOWNUP 0x33
#endif

#ifndef IS31FL3729_SPREAD_SPECTRUM
# define IS31FL3729_SPREAD_SPECTRUM IS31FL3729_SSP_DISABLE
#endif
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved

#ifndef IS31FL3729_SPREAD_SPECTRUM_RANGE
# define IS31FL3729_SPREAD_SPECTRUM_RANGE IS31FL3729_RNG_5_PERCENT
#endif

#ifndef IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME
# define IS31FL3729_SPREAD_SPECTRUM_CYCLE_TIME IS31FL3729_CLT_1980_US
#endif

#ifndef IS31FL3729_PWM_FREQUENCY
# define IS31FL3729_PWM_FREQUENCY IS31FL3729_PWM_FREQUENCY_32K_HZ
#endif

// These buffers match the PWM & scaling registers.
// Storing them like this is optimal for I2C transfers to the registers.
uint8_t g_pwm_buffer[IS31FL3729_DRIVER_COUNT][IS31FL3729_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3729_DRIVER_COUNT] = {false};

uint8_t g_scaling_registers[IS31FL3729_DRIVER_COUNT][IS31FL3729_SCALING_REGISTER_COUNT];
bool g_scaling_registers_update_required[IS31FL3729_DRIVER_COUNT] = {false};
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved

void is31fl3729_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
#if IS31FL3729_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3729_I2C_PERSISTENCE; i++) {
if (i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(addr << 1, reg, &data, 1, IS31FL3729_I2C_TIMEOUT);
#endif
}

void is31fl3729_write_pwm_buffer(uint8_t addr, uint8_t index) {
// Transmit PWM registers in 9 transfers of 16 bytes.

// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i <= IS31FL3729_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3729_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3729_I2C_PERSISTENCE; j++) {
if (i2c_write_register(addr << 1, i, g_pwm_buffer[index] + i, 16, IS31FL3729_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
}
#else
i2c_write_register(addr << 1, i, g_pwm_buffer[index] + i, 16, IS31FL3729_I2C_TIMEOUT);
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
#endif
}
}

void is31fl3729_init_drivers(void) {
i2c_init();

is31fl3729_init(IS31FL3729_I2C_ADDRESS_1);
#if defined(IS31FL3729_I2C_ADDRESS_2)
is31fl3729_init(IS31FL3729_I2C_ADDRESS_2);
# if defined(IS31FL3729_I2C_ADDRESS_3)
is31fl3729_init(IS31FL3729_I2C_ADDRESS_3);
# if defined(IS31FL3729_I2C_ADDRESS_4)
is31fl3729_init(IS31FL3729_I2C_ADDRESS_4);
# endif
# endif
#endif

for (int i = 0; i < IS31FL3729_LED_COUNT; i++) {
is31fl3729_set_scaling_register(i, 0xFF);
}

is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_1, 0);
#if defined(IS31FL3729_I2C_ADDRESS_2)
is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_2, 1);
# if defined(IS31FL3729_I2C_ADDRESS_3)
is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_3, 2);
# if defined(IS31FL3729_I2C_ADDRESS_4)
is31fl3729_update_scaling_registers(IS31FL3729_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

void is31fl3729_init(uint8_t addr) {
// In order to avoid the LEDs being driven with garbage data
// in the LED driver's PWM registers, shutdown is enabled last.
// Set up the mode and other settings, clear the PWM registers,
// then disable software shutdown.

// Set Pull up & Down for SWx CSy
is31fl3729_write_register(addr, IS31FL3729_REG_PULLDOWNUP, IS31FL3729_PULLDOWNUP);

// Set Spread Spectrum Register if applicable
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));

// Set PWM Frequency Register if applicable
is31fl3729_write_register(addr, IS31FL3729_REG_PWM_FREQUENCY, IS31FL3729_PWM_FREQUENCY);

// Set Golbal Current Control Register
is31fl3729_write_register(addr, IS31FL3729_REG_GLOBAL_CURRENT, IS31FL3729_GLOBAL_CURRENT);

// Set to Normal operation
is31fl3729_write_register(addr, IS31FL3729_REG_CONFIGURATION, IS31FL3729_CONFIGURATION);

// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}

void is31fl3729_set_value(int index, uint8_t value) {
is31fl3729_led_t led;
if (index >= 0 && index < IS31FL3729_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led));

if (g_pwm_buffer[led.driver][led.v] == value) {
return;
}

g_pwm_buffer_update_required[led.driver] = true;
g_pwm_buffer[led.driver][led.v] = value;
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
}
}

void is31fl3729_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3729_LED_COUNT; i++) {
is31fl3729_set_value(i, value);
}
}

void is31fl3729_set_scaling_register(uint8_t index, uint8_t value) {
is31fl3729_led_t led;
memcpy_P(&led, (&g_is31fl3729_leds[index]), sizeof(led));

// need to do a bit of checking here since 3729 scaling is per CS pin.
// not the usual per single LED key as per other ISSI drivers
// only enable them, since they should be default disabled
int cs_value = (led.v & 0x0F) - 1;

g_scaling_registers[led.driver][cs_value] = value;

g_scaling_registers_update_required[led.driver] = true;
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
}

void is31fl3729_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3729_write_pwm_buffer(addr, index);

g_pwm_buffer_update_required[index] = false;
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
}
}

void is31fl3729_update_scaling_registers(uint8_t addr, uint8_t index) {
if (g_scaling_registers_update_required[index]) {
for (uint8_t i = 0; i < IS31FL3729_SCALING_REGISTER_COUNT; i++) {
is31fl3729_write_register(addr, IS31FL3729_REG_SCALING + i, g_scaling_registers[index][i]);
}

g_scaling_registers_update_required[index] = false;
HorrorTroll marked this conversation as resolved.
Show resolved Hide resolved
}
}

void is31fl3729_flush(void) {
is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_1, 0);
#if defined(IS31FL3729_I2C_ADDRESS_2)
is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_2, 1);
# if defined(IS31FL3729_I2C_ADDRESS_3)
is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_3, 2);
# if defined(IS31FL3729_I2C_ADDRESS_4)
is31fl3729_update_pwm_buffers(IS31FL3729_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
Loading
Loading