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

LED drivers: place I2C addresses into an array #22975

Merged
merged 3 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
104 changes: 48 additions & 56 deletions drivers/led/issi/is31fl3731-mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@
# define IS31FL3731_I2C_PERSISTENCE 0
#endif

const uint8_t i2c_addresses[IS31FL3731_DRIVER_COUNT] = {
IS31FL3731_I2C_ADDRESS_1,
#ifdef IS31FL3731_I2C_ADDRESS_2
IS31FL3731_I2C_ADDRESS_2,
# ifdef IS31FL3731_I2C_ADDRESS_3
IS31FL3731_I2C_ADDRESS_3,
# ifdef IS31FL3731_I2C_ADDRESS_4
IS31FL3731_I2C_ADDRESS_4,
# endif
# endif
#endif
};

// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
// Storing them like this is optimal for I2C transfers to the registers.
// We could optimize this and take out the unused registers from these
Expand All @@ -43,116 +56,102 @@ bool g_pwm_buffer_update_required[IS31FL3731_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3731_DRIVER_COUNT][IS31FL3731_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3731_DRIVER_COUNT] = {false};

void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_write_register(addr << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(addr << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT);
#endif
}

void is31fl3731_select_page(uint8_t addr, uint8_t page) {
is31fl3731_write_register(addr, IS31FL3731_REG_COMMAND, page);
void is31fl3731_select_page(uint8_t index, uint8_t page) {
is31fl3731_write_register(index, IS31FL3731_REG_COMMAND, page);
}

void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t index) {
void is31fl3731_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// 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 < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3731_I2C_PERSISTENCE; j++) {
if (i2c_write_register(addr << 1, IS31FL3731_FRAME_REG_PWM + i, g_pwm_buffer[index] + i, 16, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, g_pwm_buffer[index] + i, 16, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(addr << 1, IS31FL3731_FRAME_REG_PWM + i, g_pwm_buffer[index] + i, 16, IS31FL3731_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, g_pwm_buffer[index] + i, 16, IS31FL3731_I2C_TIMEOUT);
#endif
}
}

void is31fl3731_init_drivers(void) {
i2c_init();

is31fl3731_init(IS31FL3731_I2C_ADDRESS_1);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_2);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_3);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_init(i);
}

for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_led_control_register(i, true);
}

is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_led_control_registers(i);
}
}

void is31fl3731_init(uint8_t addr) {
void is31fl3731_init(uint8_t index) {
// In order to avoid the LEDs being driven with garbage data
// in the LED driver's PWM registers, first enable software shutdown,
// then set up the mode and other settings, clear the PWM registers,
// then disable software shutdown.

is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);

// enable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
#ifdef IS31FL3731_DEGHOST // set to enable de-ghosting of the array
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
#endif

// this delay was copied from other drivers, might not be needed
wait_ms(10);

// picture mode
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
// display frame 0
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
// audio sync off
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);

is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);

// turn off all LEDs in the LED control register
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, IS31FL3731_FRAME_REG_LED_CONTROL + i, 0x00);
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_LED_CONTROL + i, 0x00);
}

// turn off all LEDs in the blink control register (not really needed)
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, IS31FL3731_FRAME_REG_BLINK_CONTROL + i, 0x00);
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_BLINK_CONTROL + i, 0x00);
}

// set PWM on all LEDs to 0
for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, IS31FL3731_FRAME_REG_PWM + i, 0x00);
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_PWM + i, 0x00);
}

is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);

// disable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);

// select page 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in page 0
// as there's not much point in double-buffering
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
}

void is31fl3731_set_value(int index, uint8_t value) {
Expand Down Expand Up @@ -192,33 +191,26 @@ void is31fl3731_set_led_control_register(uint8_t index, bool value) {
g_led_control_registers_update_required[led.driver] = true;
}

void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index) {
void is31fl3731_update_pwm_buffers(uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3731_write_pwm_buffer(addr, index);
is31fl3731_write_pwm_buffer(index);

g_pwm_buffer_update_required[index] = false;
}
}

void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index) {
void is31fl3731_update_led_control_registers(uint8_t index) {
if (g_led_control_registers_update_required[index]) {
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, i, g_led_control_registers[index][i]);
is31fl3731_write_register(index, i, g_led_control_registers[index][i]);
}

g_led_control_registers_update_required[index] = false;
}
}

void is31fl3731_flush(void) {
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_pwm_buffers(i);
}
}
10 changes: 5 additions & 5 deletions drivers/led/issi/is31fl3731-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ typedef struct is31fl3731_led_t {
extern const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT];

void is31fl3731_init_drivers(void);
void is31fl3731_init(uint8_t addr);
void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t addr, uint8_t page);
void is31fl3731_init(uint8_t index);
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t index, uint8_t page);

void is31fl3731_set_value(int index, uint8_t value);
void is31fl3731_set_value_all(uint8_t value);
Expand All @@ -118,8 +118,8 @@ void is31fl3731_set_led_control_register(uint8_t index, bool value);
// (eg. from a timer interrupt).
// Call this while idle (in between matrix scans).
// If the buffer is dirty, it will update the driver with the buffer.
void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index);
void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index);
void is31fl3731_update_pwm_buffers(uint8_t index);
void is31fl3731_update_led_control_registers(uint8_t index);

void is31fl3731_flush(void);

Expand Down
Loading
Loading