Skip to content
Draft
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
53 changes: 32 additions & 21 deletions docs/drivers/sled1734x.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,40 +51,51 @@ Depending on the ChibiOS board configuration, you may need to [enable and config

## LED Mapping {#led-mapping}

In order to use this driver, each output must be mapped to an LED index, by adding the following to your `<keyboardname>.c`:
In order to use this driver, each PWM register must be mapped to an LED index and color channel, by adding the following to your `<keyboardname>.c`:

```c
const sled1734x_led PROGMEM g_sled1734x_leds[SLED1734X_LED_COUNT] = {
/* Driver
* | R G B */
{0, CA3_D, CA1_D, CA2_D},
// etc...
const sled1734x_register_t PROGMEM g_sled1734x_registers[SLED1734X_DRIVER_COUNT][SLED1734X_PWM_REGISTER_COUNT] = {
[0] = {
// default value: NO_LED
[0 ... SLED1734X_PWM_REGISTER_COUNT - 1] = {.led_index = NO_LED, .color_channel = RED},

[CA3_D] = {.led_index = 0, .color_channel = RED},
[CA1_D] = {.led_index = 0, .color_channel = GREEN},
[CA2_D] = {.led_index = 0, .color_channel = BLUE},
// etc...
},
};
```

Each entry specifies which LED index that register drives, and which color channel (`RED`, `GREEN` or `BLUE`) it corresponds to. Registers that aren't wired to an LED should be left at their default value of `NO_LED` — the sparse initializer above sets this default for every register before the specific mappings are applied.

In this example, the red, green and blue channels for the first LED index on driver 0 all have their anodes connected to the `D` pin, and their cathodes on the `CA1`, `CA2` and `CA3` pins respectively.

These values correspond to the register indices as shown in the datasheet on page 64.
At the moment, the driver supports MATRIX TYPE 3 only.

## API {#api}

### `struct sled1734x_led_t` {#api-sled1734x-led-t}
### `enum sled1734x_color_channel_t` {#api-sled1734x-color-channel-t}

Lists out the color channels, which a register can control.

#### Values {#api-sled1734x-color-channel-t-values}

- `RED`
- `GREEN`
- `BLUE`

### `struct sled1734x_register_t` {#api-sled1734x-register-t}

Contains the PWM register addresses for a single RGB LED.
Describes which LED index and color channel a single PWM register is wired to. One entry exists for every register in the `g_sled1734x_registers` table.

#### Members {#api-sled1734x-led-t-members}
#### Members {#api-sled1734x-register-t-members}

- `uint8_t driver`
The driver index of the LED, from 0 to 3.
- `uint8_t r`
The output PWM register address for the LED's red channel (RGB driver only).
- `uint8_t g`
The output PWM register address for the LED's green channel (RGB driver only).
- `uint8_t b`
The output PWM register address for the LED's blue channel (RGB driver only).
- `uint8_t v`
The output PWM register address for the LED (single-color driver only).
- `uint8_t led_index`
The index of the LED that this register drives, or `NO_LED` if the register isn't connected to an LED.
- `sled1734x_color_channel_t color`
The color channel that this register drives: `RED`, `GREEN` or `BLUE`.

---

Expand Down Expand Up @@ -134,7 +145,7 @@ Set the color of a single LED (RGB driver only). This function does not immediat
#### Arguments {#api-sled1734x-set-color-arguments}

- `int index`
The LED index (ie. the index into the `g_sled1734x_leds` array).
The LED index, as referenced by the `led_index` field of entries in the `g_sled1734x_registers` table.
- `uint8_t red`
The red value to set.
- `uint8_t green`
Expand Down Expand Up @@ -166,7 +177,7 @@ Configure the LED control registers for a single LED (RGB driver only). This fun
#### Arguments {#api-sled1734x-set-led-control-register-rgb-arguments}

- `uint8_t index`
The LED index (ie. the index into the `g_sled1734x_leds` array).
The LED index, as referenced by the `led_index` field of entries in the `g_sled1734x_registers` table.
- `bool red`
Enable or disable the red channel.
- `bool green`
Expand Down
157 changes: 105 additions & 52 deletions drivers/led/sled1734x.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#include "i2c_master.h"
#include "gpio.h"
#include "wait.h"
#include "rgb_matrix.h"

#define SLED1734X_PWM_REGISTER_COUNT 256
#define SLED1734X_LED_CONTROL_REGISTER_COUNT 32

#ifndef SLED1734X_I2C_TIMEOUT
Expand Down Expand Up @@ -49,19 +49,17 @@ const uint8_t i2c_addresses[SLED1734X_DRIVER_COUNT] = {
// buffers and the transfers in sled1734x_write_pwm_buffer() but it's
// probably not worth the extra complexity.
typedef struct sled1734x_driver_t {
uint8_t pwm_buffer[SLED1734X_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[SLED1734X_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED sled1734x_driver_t;

sled1734x_driver_t driver_buffers[SLED1734X_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};

rgb_t pwm_buffer[SLED1734X_LED_COUNT] = {};

// This is the bit pattern in the LED control registers
// (for matrix type 3, using split frames)
//
Expand Down Expand Up @@ -107,12 +105,34 @@ void sled1734x_write_pwm_buffer(uint8_t index) {

// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < SLED1734X_FRAME_OFFSET; i += 16) {
uint8_t buf[16] = {0};
for (uint8_t j = 0; j < 16; j++) {
sled1734x_register_t reg_cfg;
memcpy_P(&reg_cfg, (&g_sled1734x_registers[index][i + j]), sizeof(reg_cfg));

if (reg_cfg.led_index == NO_LED) {
continue;
}

switch (reg_cfg.color_channel) {
case RED:
buf[j] = pwm_buffer[reg_cfg.led_index].r;
break;
case GREEN:
buf[j] = pwm_buffer[reg_cfg.led_index].g;
break;
case BLUE:
buf[j] = pwm_buffer[reg_cfg.led_index].b;
break;
}
}

#if SLED1734X_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < SLED1734X_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, driver_buffers[index].pwm_buffer + i, 16, SLED1734X_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
if (i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, buf, 16, SLED1734X_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, driver_buffers[index].pwm_buffer + i, 16, SLED1734X_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, buf, 16, SLED1734X_I2C_TIMEOUT);
#endif
}
// select the second frame
Expand All @@ -121,12 +141,34 @@ void sled1734x_write_pwm_buffer(uint8_t index) {

// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < SLED1734X_FRAME_OFFSET; i += 16) {
uint8_t buf[16] = {0};
for (uint8_t j = 0; j < 16; j++) {
sled1734x_register_t reg_cfg;
memcpy_P(&reg_cfg, (&g_sled1734x_registers[index][SLED1734X_FRAME_OFFSET + i + j]), sizeof(reg_cfg));

if (reg_cfg.led_index == NO_LED) {
continue;
}

switch (reg_cfg.color_channel) {
case RED:
buf[j] = pwm_buffer[reg_cfg.led_index].r;
break;
case GREEN:
buf[j] = pwm_buffer[reg_cfg.led_index].g;
break;
case BLUE:
buf[j] = pwm_buffer[reg_cfg.led_index].b;
break;
}
}

#if SLED1734X_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < SLED1734X_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, driver_buffers[index].pwm_buffer + SLED1734X_FRAME_OFFSET + i, 16, SLED1734X_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
if (i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, buf, 16, SLED1734X_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, driver_buffers[index].pwm_buffer + SLED1734X_FRAME_OFFSET + i, 16, SLED1734X_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, SLED1734X_OFFSET + i, buf, 16, SLED1734X_I2C_TIMEOUT);
#endif
}
}
Expand Down Expand Up @@ -225,18 +267,9 @@ void sled1734x_init(uint8_t index) {
}

void sled1734x_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
sled1734x_led_t led;
if (index >= 0 && index < SLED1734X_LED_COUNT) {
memcpy_P(&led, (&g_sled1734x_leds[index]), sizeof(led));

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) {
return;
}
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;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
pwm_buffer[index].r = red;
pwm_buffer[index].g = green;
pwm_buffer[index].b = blue;
}

void sled1734x_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
Expand All @@ -246,41 +279,61 @@ void sled1734x_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
}

void sled1734x_set_led_control_register(uint8_t index, bool red, bool green, bool blue) {
sled1734x_led_t led;
memcpy_P(&led, (&g_sled1734x_leds[index]), sizeof(led));

uint8_t control_register_r = (led.r) / 8;
uint8_t control_register_g = (led.g) / 8;
uint8_t control_register_b = (led.b) / 8;

uint8_t bit_r = (led.r) % 8;
uint8_t bit_g = (led.g) % 8;
uint8_t bit_b = (led.b) % 8;

if (red) {
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
bool red_set = false;
bool green_set = false;
bool blue_set = false;

for (uint8_t driver = 0; driver < SLED1734X_DRIVER_COUNT; driver++) {
uint8_t reg = CA1_A;
do {
sled1734x_register_t reg_cfg;
memcpy_P(&reg_cfg, (&g_sled1734x_registers[driver][reg]), sizeof(reg_cfg));

if (reg_cfg.led_index == index) {
uint8_t control_register = reg / 8;
uint8_t bit = reg % 8;

switch (reg_cfg.color_channel) {
case RED:
if (red) {
driver_buffers[driver].led_control_buffer[control_register] |= (1 << bit);
} else {
driver_buffers[driver].led_control_buffer[control_register] &= ~(1 << bit);
}
red_set = true;
break;
case GREEN:
if (green) {
driver_buffers[driver].led_control_buffer[control_register] |= (1 << bit);
} else {
driver_buffers[driver].led_control_buffer[control_register] &= ~(1 << bit);
}
green_set = true;
break;
case BLUE:
if (blue) {
driver_buffers[driver].led_control_buffer[control_register] |= (1 << bit);
} else {
driver_buffers[driver].led_control_buffer[control_register] &= ~(1 << bit);
}
blue_set = true;
break;
}

driver_buffers[driver].led_control_buffer_dirty = true;

if (red_set && green_set && blue_set) {
return;
}
}

reg++;
} while (reg != CA1_A);
}
if (blue) {
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}

driver_buffers[led.driver].led_control_buffer_dirty = true;
}

void sled1734x_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
sled1734x_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
sled1734x_write_pwm_buffer(index);
}

void sled1734x_update_led_control_registers(uint8_t index) {
Expand Down
22 changes: 14 additions & 8 deletions drivers/led/sled1734x.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,20 @@
# define SLED1734X_DRIVER_COUNT 1
#endif

typedef struct sled1734x_led_t {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED sled1734x_led_t;

extern const sled1734x_led_t PROGMEM g_sled1734x_leds[SLED1734X_LED_COUNT];
#define SLED1734X_PWM_REGISTER_COUNT 256

typedef enum sled1734x_color_channel_t {
RED,
GREEN,
BLUE,
} sled1734x_color_channel_t;

typedef struct sled1734x_register_t {
uint8_t led_index;
sled1734x_color_channel_t color_channel;
} PACKED sled1734x_register_t;

extern const sled1734x_register_t PROGMEM g_sled1734x_registers[SLED1734X_DRIVER_COUNT][SLED1734X_PWM_REGISTER_COUNT];

void sled1734x_init_drivers(void);
void sled1734x_init(uint8_t index);
Expand Down