From 206a995ccd53b0843e72da606abebe06f39c9c28 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sat, 31 Jul 2021 14:31:09 +0100 Subject: Move some led drivers to common folder (#13749) * Move some led drivers to common folder --- drivers/led/apa102.c | 151 +++++++++++++ drivers/led/apa102.h | 41 ++++ drivers/led/aw20216.c | 141 ++++++++++++ drivers/led/aw20216.h | 252 +++++++++++++++++++++ drivers/led/issi/is31fl3218.c | 96 ++++++++ drivers/led/issi/is31fl3218.h | 25 +++ drivers/led/issi/is31fl3731-simple.c | 233 +++++++++++++++++++ drivers/led/issi/is31fl3731-simple.h | 207 +++++++++++++++++ drivers/led/issi/is31fl3731.c | 237 ++++++++++++++++++++ drivers/led/issi/is31fl3731.h | 208 +++++++++++++++++ drivers/led/issi/is31fl3733.c | 237 ++++++++++++++++++++ drivers/led/issi/is31fl3733.h | 251 +++++++++++++++++++++ drivers/led/issi/is31fl3736.c | 269 ++++++++++++++++++++++ drivers/led/issi/is31fl3736.h | 168 ++++++++++++++ drivers/led/issi/is31fl3737.c | 227 +++++++++++++++++++ drivers/led/issi/is31fl3737.h | 203 +++++++++++++++++ drivers/led/issi/is31fl3741.c | 255 +++++++++++++++++++++ drivers/led/issi/is31fl3741.h | 420 +++++++++++++++++++++++++++++++++++ 18 files changed, 3621 insertions(+) create mode 100644 drivers/led/apa102.c create mode 100644 drivers/led/apa102.h create mode 100644 drivers/led/aw20216.c create mode 100644 drivers/led/aw20216.h create mode 100644 drivers/led/issi/is31fl3218.c create mode 100644 drivers/led/issi/is31fl3218.h create mode 100644 drivers/led/issi/is31fl3731-simple.c create mode 100644 drivers/led/issi/is31fl3731-simple.h create mode 100644 drivers/led/issi/is31fl3731.c create mode 100644 drivers/led/issi/is31fl3731.h create mode 100644 drivers/led/issi/is31fl3733.c create mode 100644 drivers/led/issi/is31fl3733.h create mode 100644 drivers/led/issi/is31fl3736.c create mode 100644 drivers/led/issi/is31fl3736.h create mode 100644 drivers/led/issi/is31fl3737.c create mode 100644 drivers/led/issi/is31fl3737.h create mode 100644 drivers/led/issi/is31fl3741.c create mode 100644 drivers/led/issi/is31fl3741.h (limited to 'drivers/led') diff --git a/drivers/led/apa102.c b/drivers/led/apa102.c new file mode 100644 index 0000000000..7396dc3c55 --- /dev/null +++ b/drivers/led/apa102.c @@ -0,0 +1,151 @@ +/* Copyright 2020 Aldehir Rojas + * Copyright 2017 Mikkel (Duckle29) + * + * 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 . + */ + +#include "apa102.h" +#include "quantum.h" + +#ifndef APA102_NOPS +# if defined(__AVR__) +# define APA102_NOPS 0 // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed +# elif defined(PROTOCOL_CHIBIOS) + +# include "hal.h" +# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) +# define APA102_NOPS (100 / (1000000000L / (STM32_SYSCLK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns +# else +# error("APA102_NOPS configuration required") +# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot +# endif +# endif +#endif + +#define io_wait \ + do { \ + for (int i = 0; i < APA102_NOPS; i++) { \ + __asm__ volatile("nop\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "nop\n\t"); \ + } \ + } while (0) + +#define APA102_SEND_BIT(byte, bit) \ + do { \ + writePin(RGB_DI_PIN, (byte >> bit) & 1); \ + io_wait; \ + writePinHigh(RGB_CI_PIN); \ + io_wait; \ + writePinLow(RGB_CI_PIN); \ + io_wait; \ + } while (0) + +uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS; + +void static apa102_start_frame(void); +void static apa102_end_frame(uint16_t num_leds); + +void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness); +void static apa102_send_byte(uint8_t byte); + +void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds) { + LED_TYPE *end = start_led + num_leds; + + apa102_start_frame(); + for (LED_TYPE *led = start_led; led < end; led++) { + apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness); + } + apa102_end_frame(num_leds); +} + +// Overwrite the default rgblight_call_driver to use apa102 driver +void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { apa102_setleds(start_led, num_leds); } + +void static apa102_init(void) { + setPinOutput(RGB_DI_PIN); + setPinOutput(RGB_CI_PIN); + + writePinLow(RGB_DI_PIN); + writePinLow(RGB_CI_PIN); +} + +void apa102_set_brightness(uint8_t brightness) { + if (brightness > APA102_MAX_BRIGHTNESS) { + apa102_led_brightness = APA102_MAX_BRIGHTNESS; + } else if (brightness < 0) { + apa102_led_brightness = 0; + } else { + apa102_led_brightness = brightness; + } +} + +void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness) { + apa102_send_byte(0b11100000 | brightness); + apa102_send_byte(blue); + apa102_send_byte(green); + apa102_send_byte(red); +} + +void static apa102_start_frame(void) { + apa102_init(); + for (uint16_t i = 0; i < 4; i++) { + apa102_send_byte(0); + } +} + +void static apa102_end_frame(uint16_t num_leds) { + // This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h + // and adapted. The code is MIT licensed. I think thats compatible? + // + // The data stream seen by the last LED in the chain will be delayed by + // (count - 1) clock edges, because each LED before it inverts the clock + // line and delays the data by one clock edge. Therefore, to make sure + // the last LED actually receives the data we wrote, the number of extra + // edges we send at the end of the frame must be at least (count - 1). + // + // Assuming we only want to send these edges in groups of size K, the + // C/C++ expression for the minimum number of groups to send is: + // + // ((count - 1) + (K - 1)) / K + // + // The C/C++ expression above is just (count - 1) divided by K, + // rounded up to the nearest whole number if there is a remainder. + // + // We set K to 16 and use the formula above as the number of frame-end + // bytes to transfer. Each byte has 16 clock edges. + // + // We are ignoring the specification for the end frame in the APA102 + // datasheet, which says to send 0xFF four times, because it does not work + // when you have 66 LEDs or more, and also it results in unwanted white + // pixels if you try to update fewer LEDs than are on your LED strip. + uint16_t iterations = (num_leds + 14) / 16; + for (uint16_t i = 0; i < iterations; i++) { + apa102_send_byte(0); + } + + apa102_init(); +} + +void static apa102_send_byte(uint8_t byte) { + APA102_SEND_BIT(byte, 7); + APA102_SEND_BIT(byte, 6); + APA102_SEND_BIT(byte, 5); + APA102_SEND_BIT(byte, 4); + APA102_SEND_BIT(byte, 3); + APA102_SEND_BIT(byte, 2); + APA102_SEND_BIT(byte, 1); + APA102_SEND_BIT(byte, 0); +} diff --git a/drivers/led/apa102.h b/drivers/led/apa102.h new file mode 100644 index 0000000000..58cf020c1e --- /dev/null +++ b/drivers/led/apa102.h @@ -0,0 +1,41 @@ +/* Copyright 2020 Aldehir Rojas + * Copyright 2017 Mikkel (Duckle29) + * + * 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 . + */ + +#pragma once + +#include "color.h" + +#ifndef APA102_DEFAULT_BRIGHTNESS +# define APA102_DEFAULT_BRIGHTNESS 31 +#endif + +#define APA102_MAX_BRIGHTNESS 31 + +extern uint8_t apa102_led_brightness; + +/* User Interface + * + * Input: + * start_led: An array of GRB data describing the LED colors + * num_leds: The number of LEDs to write + * + * The functions will perform the following actions: + * - Set the data-out pin as output + * - Send out the LED data + */ +void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds); +void apa102_set_brightness(uint8_t brightness); diff --git a/drivers/led/aw20216.c b/drivers/led/aw20216.c new file mode 100644 index 0000000000..c608c0ab44 --- /dev/null +++ b/drivers/led/aw20216.c @@ -0,0 +1,141 @@ +/* Copyright 2021 Jasper Chan + * + * 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 . + */ + +#include "aw20216.h" +#include "spi_master.h" + +/* The AW20216 appears to be somewhat similar to the IS31FL743, although quite + * a few things are different, such as the command byte format and page ordering. + * The LED addresses start from 0x00 instead of 0x01. + */ +#define AWINIC_ID 0b1010 << 4 + +#define AW_PAGE_FUNCTION 0x00 << 1 // PG0, Function registers +#define AW_PAGE_PWM 0x01 << 1 // PG1, LED PWM control +#define AW_PAGE_SCALING 0x02 << 1 // PG2, LED current scaling control +#define AW_PAGE_PATCHOICE 0x03 << 1 // PG3, Pattern choice? +#define AW_PAGE_PWMSCALING 0x04 << 1 // PG4, LED PWM + Scaling control? + +#define AW_WRITE 0 +#define AW_READ 1 + +#define AW_REG_CONFIGURATION 0x00 // PG0 +#define AW_REG_GLOBALCURRENT 0x01 // PG0 + +// Default value of AW_REG_CONFIGURATION +// D7:D4 = 1011, SWSEL (SW1~SW12 active) +// D3 = 0?, reserved (apparently this should be 1 but it doesn't seem to matter) +// D2:D1 = 00, OSDE (open/short detection enable) +// D0 = 0, CHIPEN (write 1 to enable LEDs when hardware enable pulled high) +#define AW_CONFIG_DEFAULT 0b10110000 +#define AW_CHIPEN 1 + +#define AW_PWM_REGISTER_COUNT 216 + +#ifndef AW_SCALING_MAX +# define AW_SCALING_MAX 150 +#endif + +#ifndef AW_GLOBAL_CURRENT_MAX +# define AW_GLOBAL_CURRENT_MAX 150 +#endif + +#ifndef AW_SPI_DIVISOR +# define AW_SPI_DIVISOR 4 +#endif + +uint8_t g_pwm_buffer[DRIVER_COUNT][AW_PWM_REGISTER_COUNT]; +bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +bool AW20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8_t len) { + static uint8_t s_spi_transfer_buffer[2] = {0}; + + if (!spi_start(cs_pin, false, 0, AW_SPI_DIVISOR)) { + spi_stop(); + return false; + } + + s_spi_transfer_buffer[0] = (AWINIC_ID | page | AW_WRITE); + s_spi_transfer_buffer[1] = reg; + + if (spi_transmit(s_spi_transfer_buffer, 2) != SPI_STATUS_SUCCESS) { + spi_stop(); + return false; + } + + if (spi_transmit(data, len) != SPI_STATUS_SUCCESS) { + spi_stop(); + return false; + } + + spi_stop(); + return true; +} + +static inline bool AW20216_write_register(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t value) { + // Little wrapper so callers need not care about sending a buffer + return AW20216_write(cs_pin, page, reg, &value, 1); +} + +static void AW20216_init_scaling(pin_t cs_pin) { + // Set constant current to the max, control brightness with PWM + for (uint8_t i = 0; i < AW_PWM_REGISTER_COUNT; i++) { + AW20216_write_register(cs_pin, AW_PAGE_SCALING, i, AW_SCALING_MAX); + } +} + +static inline void AW20216_init_current_limit(pin_t cs_pin) { + // Push config + AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_GLOBALCURRENT, AW_GLOBAL_CURRENT_MAX); +} + +static inline void AW20216_soft_enable(pin_t cs_pin) { + // Push config + AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN); +} + +void AW20216_init(pin_t cs_pin, pin_t en_pin) { + setPinOutput(en_pin); + writePinHigh(en_pin); + + // Drivers should start with all scaling and PWM registers as off + AW20216_init_current_limit(cs_pin); + AW20216_init_scaling(cs_pin); + + AW20216_soft_enable(cs_pin); +} + +void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + aw_led led = g_aw_leds[index]; + + g_pwm_buffer[led.driver][led.r] = red; + g_pwm_buffer[led.driver][led.g] = green; + g_pwm_buffer[led.driver][led.b] = blue; + g_pwm_buffer_update_required[led.driver] = true; +} + +void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) { + AW20216_set_color(i, red, green, blue); + } +} + +void AW20216_update_pwm_buffers(pin_t cs_pin, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + AW20216_write(cs_pin, AW_PAGE_PWM, 0, g_pwm_buffer[index], AW_PWM_REGISTER_COUNT); + } + g_pwm_buffer_update_required[index] = false; +} diff --git a/drivers/led/aw20216.h b/drivers/led/aw20216.h new file mode 100644 index 0000000000..c55d9605fc --- /dev/null +++ b/drivers/led/aw20216.h @@ -0,0 +1,252 @@ +/* Copyright 2021 Jasper Chan (Gigahawk) + * + * 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 . + */ + +#pragma once + +#include +#include +#include "gpio.h" + +typedef struct aw_led { + uint8_t driver : 2; + uint8_t r; + uint8_t g; + uint8_t b; +} aw_led; + +extern const aw_led g_aw_leds[DRIVER_LED_TOTAL]; + +void AW20216_init(pin_t cs_pin, pin_t en_pin); +void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void AW20216_update_pwm_buffers(pin_t cs_pin, uint8_t index); + +#define CS1_SW1 0x00 +#define CS2_SW1 0x01 +#define CS3_SW1 0x02 +#define CS4_SW1 0x03 +#define CS5_SW1 0x04 +#define CS6_SW1 0x05 +#define CS7_SW1 0x06 +#define CS8_SW1 0x07 +#define CS9_SW1 0x08 +#define CS10_SW1 0x09 +#define CS11_SW1 0x0A +#define CS12_SW1 0x0B +#define CS13_SW1 0x0C +#define CS14_SW1 0x0D +#define CS15_SW1 0x0E +#define CS16_SW1 0x0F +#define CS17_SW1 0x10 +#define CS18_SW1 0x11 +#define CS1_SW2 0x12 +#define CS2_SW2 0x13 +#define CS3_SW2 0x14 +#define CS4_SW2 0x15 +#define CS5_SW2 0x16 +#define CS6_SW2 0x17 +#define CS7_SW2 0x18 +#define CS8_SW2 0x19 +#define CS9_SW2 0x1A +#define CS10_SW2 0x1B +#define CS11_SW2 0x1C +#define CS12_SW2 0x1D +#define CS13_SW2 0x1E +#define CS14_SW2 0x1F +#define CS15_SW2 0x20 +#define CS16_SW2 0x21 +#define CS17_SW2 0x22 +#define CS18_SW2 0x23 +#define CS1_SW3 0x24 +#define CS2_SW3 0x25 +#define CS3_SW3 0x26 +#define CS4_SW3 0x27 +#define CS5_SW3 0x28 +#define CS6_SW3 0x29 +#define CS7_SW3 0x2A +#define CS8_SW3 0x2B +#define CS9_SW3 0x2C +#define CS10_SW3 0x2D +#define CS11_SW3 0x2E +#define CS12_SW3 0x2F +#define CS13_SW3 0x30 +#define CS14_SW3 0x31 +#define CS15_SW3 0x32 +#define CS16_SW3 0x33 +#define CS17_SW3 0x34 +#define CS18_SW3 0x35 +#define CS1_SW4 0x36 +#define CS2_SW4 0x37 +#define CS3_SW4 0x38 +#define CS4_SW4 0x39 +#define CS5_SW4 0x3A +#define CS6_SW4 0x3B +#define CS7_SW4 0x3C +#define CS8_SW4 0x3D +#define CS9_SW4 0x3E +#define CS10_SW4 0x3F +#define CS11_SW4 0x40 +#define CS12_SW4 0x41 +#define CS13_SW4 0x42 +#define CS14_SW4 0x43 +#define CS15_SW4 0x44 +#define CS16_SW4 0x45 +#define CS17_SW4 0x46 +#define CS18_SW4 0x47 +#define CS1_SW5 0x48 +#define CS2_SW5 0x49 +#define CS3_SW5 0x4A +#define CS4_SW5 0x4B +#define CS5_SW5 0x4C +#define CS6_SW5 0x4D +#define CS7_SW5 0x4E +#define CS8_SW5 0x4F +#define CS9_SW5 0x50 +#define CS10_SW5 0x51 +#define CS11_SW5 0x52 +#define CS12_SW5 0x53 +#define CS13_SW5 0x54 +#define CS14_SW5 0x55 +#define CS15_SW5 0x56 +#define CS16_SW5 0x57 +#define CS17_SW5 0x58 +#define CS18_SW5 0x59 +#define CS1_SW6 0x5A +#define CS2_SW6 0x5B +#define CS3_SW6 0x5C +#define CS4_SW6 0x5D +#define CS5_SW6 0x5E +#define CS6_SW6 0x5F +#define CS7_SW6 0x60 +#define CS8_SW6 0x61 +#define CS9_SW6 0x62 +#define CS10_SW6 0x63 +#define CS11_SW6 0x64 +#define CS12_SW6 0x65 +#define CS13_SW6 0x66 +#define CS14_SW6 0x67 +#define CS15_SW6 0x68 +#define CS16_SW6 0x69 +#define CS17_SW6 0x6A +#define CS18_SW6 0x6B +#define CS1_SW7 0x6C +#define CS2_SW7 0x6D +#define CS3_SW7 0x6E +#define CS4_SW7 0x6F +#define CS5_SW7 0x70 +#define CS6_SW7 0x71 +#define CS7_SW7 0x72 +#define CS8_SW7 0x73 +#define CS9_SW7 0x74 +#define CS10_SW7 0x75 +#define CS11_SW7 0x76 +#define CS12_SW7 0x77 +#define CS13_SW7 0x78 +#define CS14_SW7 0x79 +#define CS15_SW7 0x7A +#define CS16_SW7 0x7B +#define CS17_SW7 0x7C +#define CS18_SW7 0x7D +#define CS1_SW8 0x7E +#define CS2_SW8 0x7F +#define CS3_SW8 0x80 +#define CS4_SW8 0x81 +#define CS5_SW8 0x82 +#define CS6_SW8 0x83 +#define CS7_SW8 0x84 +#define CS8_SW8 0x85 +#define CS9_SW8 0x86 +#define CS10_SW8 0x87 +#define CS11_SW8 0x88 +#define CS12_SW8 0x89 +#define CS13_SW8 0x8A +#define CS14_SW8 0x8B +#define CS15_SW8 0x8C +#define CS16_SW8 0x8D +#define CS17_SW8 0x8E +#define CS18_SW8 0x8F +#define CS1_SW9 0x90 +#define CS2_SW9 0x91 +#define CS3_SW9 0x92 +#define CS4_SW9 0x93 +#define CS5_SW9 0x94 +#define CS6_SW9 0x95 +#define CS7_SW9 0x96 +#define CS8_SW9 0x97 +#define CS9_SW9 0x98 +#define CS10_SW9 0x99 +#define CS11_SW9 0x9A +#define CS12_SW9 0x9B +#define CS13_SW9 0x9C +#define CS14_SW9 0x9D +#define CS15_SW9 0x9E +#define CS16_SW9 0x9F +#define CS17_SW9 0xA0 +#define CS18_SW9 0xA1 +#define CS1_SW10 0xA2 +#define CS2_SW10 0xA3 +#define CS3_SW10 0xA4 +#define CS4_SW10 0xA5 +#define CS5_SW10 0xA6 +#define CS6_SW10 0xA7 +#define CS7_SW10 0xA8 +#define CS8_SW10 0xA9 +#define CS9_SW10 0xAA +#define CS10_SW10 0xAB +#define CS11_SW10 0xAC +#define CS12_SW10 0xAD +#define CS13_SW10 0xAE +#define CS14_SW10 0xAF +#define CS15_SW10 0xB0 +#define CS16_SW10 0xB1 +#define CS17_SW10 0xB2 +#define CS18_SW10 0xB3 +#define CS1_SW11 0xB4 +#define CS2_SW11 0xB5 +#define CS3_SW11 0xB6 +#define CS4_SW11 0xB7 +#define CS5_SW11 0xB8 +#define CS6_SW11 0xB9 +#define CS7_SW11 0xBA +#define CS8_SW11 0xBB +#define CS9_SW11 0xBC +#define CS10_SW11 0xBD +#define CS11_SW11 0xBE +#define CS12_SW11 0xBF +#define CS13_SW11 0xC0 +#define CS14_SW11 0xC1 +#define CS15_SW11 0xC2 +#define CS16_SW11 0xC3 +#define CS17_SW11 0xC4 +#define CS18_SW11 0xC5 +#define CS1_SW12 0xC6 +#define CS2_SW12 0xC7 +#define CS3_SW12 0xC8 +#define CS4_SW12 0xC9 +#define CS5_SW12 0xCA +#define CS6_SW12 0xCB +#define CS7_SW12 0xCC +#define CS8_SW12 0xCD +#define CS9_SW12 0xCE +#define CS10_SW12 0xCF +#define CS11_SW12 0xD0 +#define CS12_SW12 0xD1 +#define CS13_SW12 0xD2 +#define CS14_SW12 0xD3 +#define CS15_SW12 0xD4 +#define CS16_SW12 0xD5 +#define CS17_SW12 0xD6 +#define CS18_SW12 0xD7 diff --git a/drivers/led/issi/is31fl3218.c b/drivers/led/issi/is31fl3218.c new file mode 100644 index 0000000000..d43863ac4b --- /dev/null +++ b/drivers/led/issi/is31fl3218.c @@ -0,0 +1,96 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 . + */ +#include "is31fl3218.h" +#include "i2c_master.h" + +// This is the full 8-bit address +#define ISSI_ADDRESS 0b10101000 + +// These are the register addresses +#define ISSI_REG_SHUTDOWN 0x00 +#define ISSI_REG_PWM 0x01 +#define ISSI_REG_CONTROL 0x13 +#define ISSI_REG_UPDATE 0x16 +#define ISSI_REG_RESET 0x17 + +// Default timeout if no I2C response +#define ISSI_TIMEOUT 100 + +// Reusable buffer for transfers +uint8_t g_twi_transfer_buffer[20]; + +// IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining. +// If used as RGB LED driver, LEDs are assigned RGB,RGB,RGB,RGB,RGB,RGB +uint8_t g_pwm_buffer[18]; +bool g_pwm_buffer_update_required = false; + +void IS31FL3218_write_register(uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + i2c_transmit(ISSI_ADDRESS, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +} + +void IS31FL3218_write_pwm_buffer(uint8_t *pwm_buffer) { + g_twi_transfer_buffer[0] = ISSI_REG_PWM; + for (int i = 0; i < 18; i++) { + g_twi_transfer_buffer[1 + i] = pwm_buffer[i]; + } + + i2c_transmit(ISSI_ADDRESS, g_twi_transfer_buffer, 19, ISSI_TIMEOUT); +} + +void IS31FL3218_init(void) { + // In case we ever want to reinitialize (?) + IS31FL3218_write_register(ISSI_REG_RESET, 0x00); + + // Turn off software shutdown + IS31FL3218_write_register(ISSI_REG_SHUTDOWN, 0x01); + + // Set all PWM values to zero + for (uint8_t i = 0; i < 18; i++) { + IS31FL3218_write_register(ISSI_REG_PWM + i, 0x00); + } + + // Enable all channels + for (uint8_t i = 0; i < 3; i++) { + IS31FL3218_write_register(ISSI_REG_CONTROL + i, 0b00111111); + } + + // Load PWM registers and LED Control register data + IS31FL3218_write_register(ISSI_REG_UPDATE, 0x01); +} + +void IS31FL3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + g_pwm_buffer[index * 3 + 0] = red; + g_pwm_buffer[index * 3 + 1] = green; + g_pwm_buffer[index * 3 + 2] = blue; + g_pwm_buffer_update_required = true; +} + +void IS31FL3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < 6; i++) { + IS31FL3218_set_color(i, red, green, blue); + } +} + +void IS31FL3218_update_pwm_buffers(void) { + if (g_pwm_buffer_update_required) { + IS31FL3218_write_pwm_buffer(g_pwm_buffer); + // Load PWM registers and LED Control register data + IS31FL3218_write_register(ISSI_REG_UPDATE, 0x01); + } + g_pwm_buffer_update_required = false; +} diff --git a/drivers/led/issi/is31fl3218.h b/drivers/led/issi/is31fl3218.h new file mode 100644 index 0000000000..fa760da191 --- /dev/null +++ b/drivers/led/issi/is31fl3218.h @@ -0,0 +1,25 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 . + */ + +#pragma once + +#include +#include + +void IS31FL3218_init(void); +void IS31FL3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3218_update_pwm_buffers(void); diff --git a/drivers/led/issi/is31fl3731-simple.c b/drivers/led/issi/is31fl3731-simple.c new file mode 100644 index 0000000000..d295772f5e --- /dev/null +++ b/drivers/led/issi/is31fl3731-simple.c @@ -0,0 +1,233 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2019 Clueboard + * + * 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 . + */ + +#include "is31fl3731-simple.h" +#include "i2c_master.h" +#include "wait.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 0b1110100 AD <-> GND +// 0b1110111 AD <-> VCC +// 0b1110101 AD <-> SCL +// 0b1110110 AD <-> SDA +#define ISSI_ADDR_DEFAULT 0x74 + +#define ISSI_REG_CONFIG 0x00 +#define ISSI_REG_CONFIG_PICTUREMODE 0x00 +#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08 +#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18 + +#define ISSI_CONF_PICTUREMODE 0x00 +#define ISSI_CONF_AUTOFRAMEMODE 0x04 +#define ISSI_CONF_AUDIOMODE 0x08 + +#define ISSI_REG_PICTUREFRAME 0x01 + +#define ISSI_REG_SHUTDOWN 0x0A +#define ISSI_REG_AUDIOSYNC 0x06 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine' + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// 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 +// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[LED_DRIVER_COUNT][144]; +bool g_pwm_buffer_update_required[LED_DRIVER_COUNT] = {false}; + +/* There's probably a better way to init this... */ +#if LED_DRIVER_COUNT == 1 +uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}}; +#elif LED_DRIVER_COUNT == 2 +uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}}; +#elif LED_DRIVER_COUNT == 3 +uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}, {0}}; +#elif LED_DRIVER_COUNT == 4 +uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}, {0}, {0}}; +#endif +bool g_led_control_registers_update_required[LED_DRIVER_COUNT] = {false}; + +// This is the bit pattern in the LED control registers +// (for matrix A, add one to register for matrix B) +// +// reg - b7 b6 b5 b4 b3 b2 b1 b0 +// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01 +// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00 +// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00 +// 0x06 - - , - , - , - , - ,B02,B01,B00 +// 0x08 - - , - , - , - , - , - , - , - +// 0x0A - B17,B16,B15, - , - , - , - , - +// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09 +// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09 +// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09 + +void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) { + break; + } + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // assumes bank is already selected + + // transmit PWM registers in 9 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // iterate over the pwm_buffer contents at 16 byte intervals + for (int i = 0; i < 144; i += 16) { + // set the first register, e.g. 0x24, 0x34, 0x44, etc. + g_twi_transfer_buffer[0] = 0x24 + i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT); +#endif + } +} + +void IS31FL3731_init(uint8_t addr) { + // 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. + + // select "function register" bank + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + + // enable software shutdown + IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); + + // this delay was copied from other drivers, might not be needed + wait_ms(10); + + // picture mode + IS31FL3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); + // display frame 0 + IS31FL3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); + // audio sync off + IS31FL3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); + + // select bank 0 + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + + // turn off all LEDs in the LED control register + for (int i = 0x00; i <= 0x11; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // turn off all LEDs in the blink control register (not really needed) + for (int i = 0x12; i <= 0x23; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // set PWM on all LEDs to 0 + for (int i = 0x24; i <= 0xB3; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // select "function register" bank + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + + // disable software shutdown + IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); + + // select bank 0 and leave it selected. + // most usage after initialization is just writing PWM buffers in bank 0 + // as there's not much point in double-buffering + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); +} + +void IS31FL3731_set_value(int index, uint8_t value) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + is31_led led = g_is31_leds[index]; + + // Subtract 0x24 to get the second index of g_pwm_buffer + g_pwm_buffer[led.driver][led.v - 0x24] = value; + g_pwm_buffer_update_required[led.driver] = true; + } +} + +void IS31FL3731_set_value_all(uint8_t value) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3731_set_value(i, value); + } +} + +void IS31FL3731_set_led_control_register(uint8_t index, bool value) { + is31_led led = g_is31_leds[index]; + + uint8_t control_register = (led.v - 0x24) / 8; + uint8_t bit_value = (led.v - 0x24) % 8; + + if (value) { + g_led_control_registers[led.driver][control_register] |= (1 << bit_value); + } else { + g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value); + } + + g_led_control_registers_update_required[led.driver] = true; +} + +void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + IS31FL3731_write_pwm_buffer(addr, g_pwm_buffer[index]); + g_pwm_buffer_update_required[index] = false; + } +} + +void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_led_control_registers_update_required[index]) { + for (int i = 0; i < 18; i++) { + IS31FL3731_write_register(addr, i, g_led_control_registers[index][i]); + } + g_led_control_registers_update_required[index] = false; + } +} diff --git a/drivers/led/issi/is31fl3731-simple.h b/drivers/led/issi/is31fl3731-simple.h new file mode 100644 index 0000000000..9665d6ed35 --- /dev/null +++ b/drivers/led/issi/is31fl3731-simple.h @@ -0,0 +1,207 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2019 Clueboard + * + * 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 . + */ + +#pragma once + +#include +#include + +typedef struct is31_led { + uint8_t driver : 2; + uint8_t v; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3731_init(uint8_t addr); +void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3731_set_value(int index, uint8_t value); +void IS31FL3731_set_value_all(uint8_t value); + +void IS31FL3731_set_led_control_register(uint8_t index, bool value); + +// This should not be called from an interrupt +// (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); + +#define C1_1 0x24 +#define C1_2 0x25 +#define C1_3 0x26 +#define C1_4 0x27 +#define C1_5 0x28 +#define C1_6 0x29 +#define C1_7 0x2A +#define C1_8 0x2B + +#define C1_9 0x2C +#define C1_10 0x2D +#define C1_11 0x2E +#define C1_12 0x2F +#define C1_13 0x30 +#define C1_14 0x31 +#define C1_15 0x32 +#define C1_16 0x33 + +#define C2_1 0x34 +#define C2_2 0x35 +#define C2_3 0x36 +#define C2_4 0x37 +#define C2_5 0x38 +#define C2_6 0x39 +#define C2_7 0x3A +#define C2_8 0x3B + +#define C2_9 0x3C +#define C2_10 0x3D +#define C2_11 0x3E +#define C2_12 0x3F +#define C2_13 0x40 +#define C2_14 0x41 +#define C2_15 0x42 +#define C2_16 0x43 + +#define C3_1 0x44 +#define C3_2 0x45 +#define C3_3 0x46 +#define C3_4 0x47 +#define C3_5 0x48 +#define C3_6 0x49 +#define C3_7 0x4A +#define C3_8 0x4B + +#define C3_9 0x4C +#define C3_10 0x4D +#define C3_11 0x4E +#define C3_12 0x4F +#define C3_13 0x50 +#define C3_14 0x51 +#define C3_15 0x52 +#define C3_16 0x53 + +#define C4_1 0x54 +#define C4_2 0x55 +#define C4_3 0x56 +#define C4_4 0x57 +#define C4_5 0x58 +#define C4_6 0x59 +#define C4_7 0x5A +#define C4_8 0x5B + +#define C4_9 0x5C +#define C4_10 0x5D +#define C4_11 0x5E +#define C4_12 0x5F +#define C4_13 0x60 +#define C4_14 0x61 +#define C4_15 0x62 +#define C4_16 0x63 + +#define C5_1 0x64 +#define C5_2 0x65 +#define C5_3 0x66 +#define C5_4 0x67 +#define C5_5 0x68 +#define C5_6 0x69 +#define C5_7 0x6A +#define C5_8 0x6B + +#define C5_9 0x6C +#define C5_10 0x6D +#define C5_11 0x6E +#define C5_12 0x6F +#define C5_13 0x70 +#define C5_14 0x71 +#define C5_15 0x72 +#define C5_16 0x73 + +#define C6_1 0x74 +#define C6_2 0x75 +#define C6_3 0x76 +#define C6_4 0x77 +#define C6_5 0x78 +#define C6_6 0x79 +#define C6_7 0x7A +#define C6_8 0x7B + +#define C6_9 0x7C +#define C6_10 0x7D +#define C6_11 0x7E +#define C6_12 0x7F +#define C6_13 0x80 +#define C6_14 0x81 +#define C6_15 0x82 +#define C6_16 0x83 + +#define C7_1 0x84 +#define C7_2 0x85 +#define C7_3 0x86 +#define C7_4 0x87 +#define C7_5 0x88 +#define C7_6 0x89 +#define C7_7 0x8A +#define C7_8 0x8B + +#define C7_9 0x8C +#define C7_10 0x8D +#define C7_11 0x8E +#define C7_12 0x8F +#define C7_13 0x90 +#define C7_14 0x91 +#define C7_15 0x92 +#define C7_16 0x93 + +#define C8_1 0x94 +#define C8_2 0x95 +#define C8_3 0x96 +#define C8_4 0x97 +#define C8_5 0x98 +#define C8_6 0x99 +#define C8_7 0x9A +#define C8_8 0x9B + +#define C8_9 0x9C +#define C8_10 0x9D +#define C8_11 0x9E +#define C8_12 0x9F +#define C8_13 0xA0 +#define C8_14 0xA1 +#define C8_15 0xA2 +#define C8_16 0xA3 + +#define C9_1 0xA4 +#define C9_2 0xA5 +#define C9_3 0xA6 +#define C9_4 0xA7 +#define C9_5 0xA8 +#define C9_6 0xA9 +#define C9_7 0xAA +#define C9_8 0xAB + +#define C9_9 0xAC +#define C9_10 0xAD +#define C9_11 0xAE +#define C9_12 0xAF +#define C9_13 0xB0 +#define C9_14 0xB1 +#define C9_15 0xB2 +#define C9_16 0xB3 diff --git a/drivers/led/issi/is31fl3731.c b/drivers/led/issi/is31fl3731.c new file mode 100644 index 0000000000..110bdc1be4 --- /dev/null +++ b/drivers/led/issi/is31fl3731.c @@ -0,0 +1,237 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * + * 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 . + */ + +#include "is31fl3731.h" +#include "i2c_master.h" +#include "wait.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 0b1110100 AD <-> GND +// 0b1110111 AD <-> VCC +// 0b1110101 AD <-> SCL +// 0b1110110 AD <-> SDA +#define ISSI_ADDR_DEFAULT 0x74 + +#define ISSI_REG_CONFIG 0x00 +#define ISSI_REG_CONFIG_PICTUREMODE 0x00 +#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08 +#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18 + +#define ISSI_CONF_PICTUREMODE 0x00 +#define ISSI_CONF_AUTOFRAMEMODE 0x04 +#define ISSI_CONF_AUDIOMODE 0x08 + +#define ISSI_REG_PICTUREFRAME 0x01 + +#define ISSI_REG_SHUTDOWN 0x0A +#define ISSI_REG_AUDIOSYNC 0x06 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine' + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// 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 +// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][144]; +bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_led_control_registers[DRIVER_COUNT][18] = {{0}}; +bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; + +// This is the bit pattern in the LED control registers +// (for matrix A, add one to register for matrix B) +// +// reg - b7 b6 b5 b4 b3 b2 b1 b0 +// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01 +// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00 +// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00 +// 0x06 - - , - , - , - , - ,B02,B01,B00 +// 0x08 - - , - , - , - , - , - , - , - +// 0x0A - B17,B16,B15, - , - , - , - , - +// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09 +// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09 +// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09 + +void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // assumes bank is already selected + + // transmit PWM registers in 9 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // iterate over the pwm_buffer contents at 16 byte intervals + for (int i = 0; i < 144; i += 16) { + // set the first register, e.g. 0x24, 0x34, 0x44, etc. + g_twi_transfer_buffer[0] = 0x24 + i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT); +#endif + } +} + +void IS31FL3731_init(uint8_t addr) { + // 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. + + // select "function register" bank + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + + // enable software shutdown + IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); + + // this delay was copied from other drivers, might not be needed + wait_ms(10); + + // picture mode + IS31FL3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); + // display frame 0 + IS31FL3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); + // audio sync off + IS31FL3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); + + // select bank 0 + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + + // turn off all LEDs in the LED control register + for (int i = 0x00; i <= 0x11; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // turn off all LEDs in the blink control register (not really needed) + for (int i = 0x12; i <= 0x23; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // set PWM on all LEDs to 0 + for (int i = 0x24; i <= 0xB3; i++) { + IS31FL3731_write_register(addr, i, 0x00); + } + + // select "function register" bank + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + + // disable software shutdown + IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); + + // select bank 0 and leave it selected. + // most usage after initialization is just writing PWM buffers in bank 0 + // as there's not much point in double-buffering + IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); +} + +void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + is31_led led = g_is31_leds[index]; + + // Subtract 0x24 to get the second index of g_pwm_buffer + g_pwm_buffer[led.driver][led.r - 0x24] = red; + g_pwm_buffer[led.driver][led.g - 0x24] = green; + g_pwm_buffer[led.driver][led.b - 0x24] = blue; + g_pwm_buffer_update_required[led.driver] = true; + } +} + +void IS31FL3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3731_set_color(i, red, green, blue); + } +} + +void IS31FL3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { + is31_led led = g_is31_leds[index]; + + uint8_t control_register_r = (led.r - 0x24) / 8; + uint8_t control_register_g = (led.g - 0x24) / 8; + uint8_t control_register_b = (led.b - 0x24) / 8; + uint8_t bit_r = (led.r - 0x24) % 8; + uint8_t bit_g = (led.g - 0x24) % 8; + uint8_t bit_b = (led.b - 0x24) % 8; + + if (red) { + g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r); + } else { + g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r); + } + if (green) { + g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g); + } else { + g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g); + } + if (blue) { + g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b); + } else { + g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b); + } + + g_led_control_registers_update_required[led.driver] = true; +} + +void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + IS31FL3731_write_pwm_buffer(addr, g_pwm_buffer[index]); + } + g_pwm_buffer_update_required[index] = false; +} + +void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_led_control_registers_update_required[index]) { + for (int i = 0; i < 18; i++) { + IS31FL3731_write_register(addr, i, g_led_control_registers[index][i]); + } + } + g_led_control_registers_update_required[index] = false; +} diff --git a/drivers/led/issi/is31fl3731.h b/drivers/led/issi/is31fl3731.h new file mode 100644 index 0000000000..19e8e6251f --- /dev/null +++ b/drivers/led/issi/is31fl3731.h @@ -0,0 +1,208 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * + * 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 . + */ + +#pragma once + +#include +#include + +typedef struct is31_led { + uint8_t driver : 2; + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3731_init(uint8_t addr); +void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue); + +// This should not be called from an interrupt +// (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); + +#define C1_1 0x24 +#define C1_2 0x25 +#define C1_3 0x26 +#define C1_4 0x27 +#define C1_5 0x28 +#define C1_6 0x29 +#define C1_7 0x2A +#define C1_8 0x2B + +#define C1_9 0x2C +#define C1_10 0x2D +#define C1_11 0x2E +#define C1_12 0x2F +#define C1_13 0x30 +#define C1_14 0x31 +#define C1_15 0x32 +#define C1_16 0x33 + +#define C2_1 0x34 +#define C2_2 0x35 +#define C2_3 0x36 +#define C2_4 0x37 +#define C2_5 0x38 +#define C2_6 0x39 +#define C2_7 0x3A +#define C2_8 0x3B + +#define C2_9 0x3C +#define C2_10 0x3D +#define C2_11 0x3E +#define C2_12 0x3F +#define C2_13 0x40 +#define C2_14 0x41 +#define C2_15 0x42 +#define C2_16 0x43 + +#define C3_1 0x44 +#define C3_2 0x45 +#define C3_3 0x46 +#define C3_4 0x47 +#define C3_5 0x48 +#define C3_6 0x49 +#define C3_7 0x4A +#define C3_8 0x4B + +#define C3_9 0x4C +#define C3_10 0x4D +#define C3_11 0x4E +#define C3_12 0x4F +#define C3_13 0x50 +#define C3_14 0x51 +#define C3_15 0x52 +#define C3_16 0x53 + +#define C4_1 0x54 +#define C4_2 0x55 +#define C4_3 0x56 +#define C4_4 0x57 +#define C4_5 0x58 +#define C4_6 0x59 +#define C4_7 0x5A +#define C4_8 0x5B + +#define C4_9 0x5C +#define C4_10 0x5D +#define C4_11 0x5E +#define C4_12 0x5F +#define C4_13 0x60 +#define C4_14 0x61 +#define C4_15 0x62 +#define C4_16 0x63 + +#define C5_1 0x64 +#define C5_2 0x65 +#define C5_3 0x66 +#define C5_4 0x67 +#define C5_5 0x68 +#define C5_6 0x69 +#define C5_7 0x6A +#define C5_8 0x6B + +#define C5_9 0x6C +#define C5_10 0x6D +#define C5_11 0x6E +#define C5_12 0x6F +#define C5_13 0x70 +#define C5_14 0x71 +#define C5_15 0x72 +#define C5_16 0x73 + +#define C6_1 0x74 +#define C6_2 0x75 +#define C6_3 0x76 +#define C6_4 0x77 +#define C6_5 0x78 +#define C6_6 0x79 +#define C6_7 0x7A +#define C6_8 0x7B + +#define C6_9 0x7C +#define C6_10 0x7D +#define C6_11 0x7E +#define C6_12 0x7F +#define C6_13 0x80 +#define C6_14 0x81 +#define C6_15 0x82 +#define C6_16 0x83 + +#define C7_1 0x84 +#define C7_2 0x85 +#define C7_3 0x86 +#define C7_4 0x87 +#define C7_5 0x88 +#define C7_6 0x89 +#define C7_7 0x8A +#define C7_8 0x8B + +#define C7_9 0x8C +#define C7_10 0x8D +#define C7_11 0x8E +#define C7_12 0x8F +#define C7_13 0x90 +#define C7_14 0x91 +#define C7_15 0x92 +#define C7_16 0x93 + +#define C8_1 0x94 +#define C8_2 0x95 +#define C8_3 0x96 +#define C8_4 0x97 +#define C8_5 0x98 +#define C8_6 0x99 +#define C8_7 0x9A +#define C8_8 0x9B + +#define C8_9 0x9C +#define C8_10 0x9D +#define C8_11 0x9E +#define C8_12 0x9F +#define C8_13 0xA0 +#define C8_14 0xA1 +#define C8_15 0xA2 +#define C8_16 0xA3 + +#define C9_1 0xA4 +#define C9_2 0xA5 +#define C9_3 0xA6 +#define C9_4 0xA7 +#define C9_5 0xA8 +#define C9_6 0xA9 +#define C9_7 0xAA +#define C9_8 0xAB + +#define C9_9 0xAC +#define C9_10 0xAD +#define C9_11 0xAE +#define C9_12 0xAF +#define C9_13 0xB0 +#define C9_14 0xB1 +#define C9_15 0xB2 +#define C9_16 0xB3 diff --git a/drivers/led/issi/is31fl3733.c b/drivers/led/issi/is31fl3733.c new file mode 100644 index 0000000000..d99e5339c9 --- /dev/null +++ b/drivers/led/issi/is31fl3733.c @@ -0,0 +1,237 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * + * 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 . + */ + +#include "is31fl3733.h" +#include "i2c_master.h" +#include "wait.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 00 <-> GND +// 01 <-> SCL +// 10 <-> SDA +// 11 <-> VCC +// ADDR1 represents A1:A0 of the 7-bit address. +// ADDR2 represents A3:A2 of the 7-bit address. +// The result is: 0b101(ADDR2)(ADDR1) +#define ISSI_ADDR_DEFAULT 0x50 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE +#define ISSI_INTERRUPTMASKREGISTER 0xF0 +#define ISSI_INTERRUPTSTATUSREGISTER 0xF1 + +#define ISSI_PAGE_LEDCONTROL 0x00 // PG0 +#define ISSI_PAGE_PWM 0x01 // PG1 +#define ISSI_PAGE_AUTOBREATH 0x02 // PG2 +#define ISSI_PAGE_FUNCTION 0x03 // PG3 + +#define ISSI_REG_CONFIGURATION 0x00 // PG3 +#define ISSI_REG_GLOBALCURRENT 0x01 // PG3 +#define ISSI_REG_RESET 0x11 // PG3 +#define ISSI_REG_SWPULLUP 0x0F // PG3 +#define ISSI_REG_CSPULLUP 0x10 // PG3 + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the IS31FL3733 PWM registers. +// The control buffers match the PG0 LED On/Off registers. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in IS31FL3733_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][192]; +bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; +bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; + +bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + // If the transaction fails function returns false. + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) { + return false; + } +#endif + return true; +} + +bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // Assumes PG1 is already selected. + // If any of the transactions fails function returns false. + // Transmit PWM registers in 12 transfers of 16 bytes. + // g_twi_transfer_buffer[] is 20 bytes + + // Iterate over the pwm_buffer contents at 16 byte intervals. + for (int i = 0; i < 192; i += 16) { + g_twi_transfer_buffer[0] = i; + // Copy the data from i to i+15. + // Device will auto-increment register for data after the first byte + // Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer. + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) { + return false; + } +#endif + } + return true; +} + +void IS31FL3733_init(uint8_t addr, uint8_t sync) { + // 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. + // Sync is passed so set it according to the datasheet. + + // Unlock the command register. + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG0 + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + // Turn off all LEDs. + for (int i = 0x00; i <= 0x17; i++) { + IS31FL3733_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG1 + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + // Set PWM on all LEDs to 0 + // No need to setup Breath registers to PWM as that is the default. + for (int i = 0x00; i <= 0xBF; i++) { + IS31FL3733_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG3 + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + // Set global current to maximum. + IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); + // Disable software shutdown. + IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, (sync << 6) | 0x01); + + // Wait 10ms to ensure the device has woken up. + wait_ms(10); +} + +void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + is31_led led = g_is31_leds[index]; + + g_pwm_buffer[led.driver][led.r] = red; + g_pwm_buffer[led.driver][led.g] = green; + g_pwm_buffer[led.driver][led.b] = blue; + g_pwm_buffer_update_required[led.driver] = true; + } +} + +void IS31FL3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3733_set_color(i, red, green, blue); + } +} + +void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { + is31_led led = g_is31_leds[index]; + + 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) { + g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r); + } else { + g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r); + } + if (green) { + g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g); + } else { + g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g); + } + if (blue) { + g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b); + } else { + g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b); + } + + g_led_control_registers_update_required[led.driver] = true; +} + +void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + // Firstly we need to unlock the command register and select PG1. + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + + // If any of the transactions fail we risk writing dirty PG0, + // refresh page 0 just in case. + if (!IS31FL3733_write_pwm_buffer(addr, g_pwm_buffer[index])) { + g_led_control_registers_update_required[index] = true; + } + } + g_pwm_buffer_update_required[index] = false; +} + +void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_led_control_registers_update_required[index]) { + // Firstly we need to unlock the command register and select PG0 + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + for (int i = 0; i < 24; i++) { + IS31FL3733_write_register(addr, i, g_led_control_registers[index][i]); + } + } + g_led_control_registers_update_required[index] = false; +} diff --git a/drivers/led/issi/is31fl3733.h b/drivers/led/issi/is31fl3733.h new file mode 100644 index 0000000000..603d505a13 --- /dev/null +++ b/drivers/led/issi/is31fl3733.h @@ -0,0 +1,251 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * + * 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 . + */ + +#pragma once + +#include +#include + +typedef struct is31_led { + uint8_t driver : 2; + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3733_init(uint8_t addr, uint8_t sync); +bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue); + +// This should not be called from an interrupt +// (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 IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index); +void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index); + +#define A_1 0x00 +#define A_2 0x01 +#define A_3 0x02 +#define A_4 0x03 +#define A_5 0x04 +#define A_6 0x05 +#define A_7 0x06 +#define A_8 0x07 +#define A_9 0x08 +#define A_10 0x09 +#define A_11 0x0A +#define A_12 0x0B +#define A_13 0x0C +#define A_14 0x0D +#define A_15 0x0E +#define A_16 0x0F + +#define B_1 0x10 +#define B_2 0x11 +#define B_3 0x12 +#define B_4 0x13 +#define B_5 0x14 +#define B_6 0x15 +#define B_7 0x16 +#define B_8 0x17 +#define B_9 0x18 +#define B_10 0x19 +#define B_11 0x1A +#define B_12 0x1B +#define B_13 0x1C +#define B_14 0x1D +#define B_15 0x1E +#define B_16 0x1F + +#define C_1 0x20 +#define C_2 0x21 +#define C_3 0x22 +#define C_4 0x23 +#define C_5 0x24 +#define C_6 0x25 +#define C_7 0x26 +#define C_8 0x27 +#define C_9 0x28 +#define C_10 0x29 +#define C_11 0x2A +#define C_12 0x2B +#define C_13 0x2C +#define C_14 0x2D +#define C_15 0x2E +#define C_16 0x2F + +#define D_1 0x30 +#define D_2 0x31 +#define D_3 0x32 +#define D_4 0x33 +#define D_5 0x34 +#define D_6 0x35 +#define D_7 0x36 +#define D_8 0x37 +#define D_9 0x38 +#define D_10 0x39 +#define D_11 0x3A +#define D_12 0x3B +#define D_13 0x3C +#define D_14 0x3D +#define D_15 0x3E +#define D_16 0x3F + +#define E_1 0x40 +#define E_2 0x41 +#define E_3 0x42 +#define E_4 0x43 +#define E_5 0x44 +#define E_6 0x45 +#define E_7 0x46 +#define E_8 0x47 +#define E_9 0x48 +#define E_10 0x49 +#define E_11 0x4A +#define E_12 0x4B +#define E_13 0x4C +#define E_14 0x4D +#define E_15 0x4E +#define E_16 0x4F + +#define F_1 0x50 +#define F_2 0x51 +#define F_3 0x52 +#define F_4 0x53 +#define F_5 0x54 +#define F_6 0x55 +#define F_7 0x56 +#define F_8 0x57 +#define F_9 0x58 +#define F_10 0x59 +#define F_11 0x5A +#define F_12 0x5B +#define F_13 0x5C +#define F_14 0x5D +#define F_15 0x5E +#define F_16 0x5F + +#define G_1 0x60 +#define G_2 0x61 +#define G_3 0x62 +#define G_4 0x63 +#define G_5 0x64 +#define G_6 0x65 +#define G_7 0x66 +#define G_8 0x67 +#define G_9 0x68 +#define G_10 0x69 +#define G_11 0x6A +#define G_12 0x6B +#define G_13 0x6C +#define G_14 0x6D +#define G_15 0x6E +#define G_16 0x6F + +#define H_1 0x70 +#define H_2 0x71 +#define H_3 0x72 +#define H_4 0x73 +#define H_5 0x74 +#define H_6 0x75 +#define H_7 0x76 +#define H_8 0x77 +#define H_9 0x78 +#define H_10 0x79 +#define H_11 0x7A +#define H_12 0x7B +#define H_13 0x7C +#define H_14 0x7D +#define H_15 0x7E +#define H_16 0x7F + +#define I_1 0x80 +#define I_2 0x81 +#define I_3 0x82 +#define I_4 0x83 +#define I_5 0x84 +#define I_6 0x85 +#define I_7 0x86 +#define I_8 0x87 +#define I_9 0x88 +#define I_10 0x89 +#define I_11 0x8A +#define I_12 0x8B +#define I_13 0x8C +#define I_14 0x8D +#define I_15 0x8E +#define I_16 0x8F + +#define J_1 0x90 +#define J_2 0x91 +#define J_3 0x92 +#define J_4 0x93 +#define J_5 0x94 +#define J_6 0x95 +#define J_7 0x96 +#define J_8 0x97 +#define J_9 0x98 +#define J_10 0x99 +#define J_11 0x9A +#define J_12 0x9B +#define J_13 0x9C +#define J_14 0x9D +#define J_15 0x9E +#define J_16 0x9F + +#define K_1 0xA0 +#define K_2 0xA1 +#define K_3 0xA2 +#define K_4 0xA3 +#define K_5 0xA4 +#define K_6 0xA5 +#define K_7 0xA6 +#define K_8 0xA7 +#define K_9 0xA8 +#define K_10 0xA9 +#define K_11 0xAA +#define K_12 0xAB +#define K_13 0xAC +#define K_14 0xAD +#define K_15 0xAE +#define K_16 0xAF + +#define L_1 0xB0 +#define L_2 0xB1 +#define L_3 0xB2 +#define L_4 0xB3 +#define L_5 0xB4 +#define L_6 0xB5 +#define L_7 0xB6 +#define L_8 0xB7 +#define L_9 0xB8 +#define L_10 0xB9 +#define L_11 0xBA +#define L_12 0xBB +#define L_13 0xBC +#define L_14 0xBD +#define L_15 0xBE +#define L_16 0xBF diff --git a/drivers/led/issi/is31fl3736.c b/drivers/led/issi/is31fl3736.c new file mode 100644 index 0000000000..7dece1b1eb --- /dev/null +++ b/drivers/led/issi/is31fl3736.c @@ -0,0 +1,269 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 . + */ + +#include "is31fl3736.h" +#include "i2c_master.h" +#include "wait.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 00 <-> GND +// 01 <-> SCL +// 10 <-> SDA +// 11 <-> VCC +// ADDR1 represents A1:A0 of the 7-bit address. +// ADDR2 represents A3:A2 of the 7-bit address. +// The result is: 0b101(ADDR2)(ADDR1) +#define ISSI_ADDR_DEFAULT 0x50 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE +#define ISSI_INTERRUPTMASKREGISTER 0xF0 +#define ISSI_INTERRUPTSTATUSREGISTER 0xF1 + +#define ISSI_PAGE_LEDCONTROL 0x00 // PG0 +#define ISSI_PAGE_PWM 0x01 // PG1 +#define ISSI_PAGE_AUTOBREATH 0x02 // PG2 +#define ISSI_PAGE_FUNCTION 0x03 // PG3 + +#define ISSI_REG_CONFIGURATION 0x00 // PG3 +#define ISSI_REG_GLOBALCURRENT 0x01 // PG3 +#define ISSI_REG_RESET 0x11 // PG3 +#define ISSI_REG_SWPULLUP 0x0F // PG3 +#define ISSI_REG_CSPULLUP 0x10 // PG3 + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the IS31FL3736 PWM registers. +// The control buffers match the PG0 LED On/Off registers. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in IS31FL3736_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][192]; +bool g_pwm_buffer_update_required = false; + +uint8_t g_led_control_registers[DRIVER_COUNT][24] = {{0}, {0}}; +bool g_led_control_registers_update_required = false; + +void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +void IS31FL3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // assumes PG1 is already selected + + // transmit PWM registers in 12 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // iterate over the pwm_buffer contents at 16 byte intervals + for (int i = 0; i < 192; i += 16) { + g_twi_transfer_buffer[0] = i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT); +#endif + } +} + +void IS31FL3736_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. + + // Unlock the command register. + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG0 + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + // Turn off all LEDs. + for (int i = 0x00; i <= 0x17; i++) { + IS31FL3736_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG1 + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + // Set PWM on all LEDs to 0 + // No need to setup Breath registers to PWM as that is the default. + for (int i = 0x00; i <= 0xBF; i++) { + IS31FL3736_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG3 + IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + // Set global current to maximum. + IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); + // Disable software shutdown. + IS31FL3736_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); + + // Wait 10ms to ensure the device has woken up. + wait_ms(10); +} + +void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + is31_led led = g_is31_leds[index]; + + g_pwm_buffer[led.driver][led.r] = red; + g_pwm_buffer[led.driver][led.g] = green; + g_pwm_buffer[led.driver][led.b] = blue; + g_pwm_buffer_update_required = true; + } +} + +void IS31FL3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3736_set_color(i, red, green, blue); + } +} + +void IS31FL3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { + is31_led led = g_is31_leds[index]; + + // IS31FL3733 + // The PWM register for a matrix position (0x00 to 0xBF) can be + // divided by 8 to get the LED control register (0x00 to 0x17), + // then mod 8 to get the bit position within that register. + + // IS31FL3736 + // The PWM register for a matrix position (0x00 to 0xBF) is interleaved, so: + // A1=0x00 A2=0x02 A3=0x04 A4=0x06 A5=0x08 A6=0x0A A7=0x0C A8=0x0E + // B1=0x10 B2=0x12 B3=0x14 + // But also, the LED control registers (0x00 to 0x17) are also interleaved, so: + // A1-A4=0x00 A5-A8=0x01 + // So, the same math applies. + + 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) { + g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r); + } else { + g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r); + } + if (green) { + g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g); + } else { + g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g); + } + if (blue) { + g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b); + } else { + g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b); + } + + g_led_control_registers_update_required = true; +} + +void IS31FL3736_mono_set_brightness(int index, uint8_t value) { + if (index >= 0 && index < 96) { + // Index in range 0..95 -> A1..A8, B1..B8, etc. + // Map index 0..95 to registers 0x00..0xBE (interleaved) + uint8_t pwm_register = index * 2; + g_pwm_buffer[0][pwm_register] = value; + g_pwm_buffer_update_required = true; + } +} + +void IS31FL3736_mono_set_brightness_all(uint8_t value) { + for (int i = 0; i < 96; i++) { + IS31FL3736_mono_set_brightness(i, value); + } +} + +void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled) { + // Index in range 0..95 -> A1..A8, B1..B8, etc. + + // Map index 0..95 to registers 0x00..0xBE (interleaved) + uint8_t pwm_register = index * 2; + // Map register 0x00..0xBE (interleaved) into control register and bit + uint8_t control_register = pwm_register / 8; + uint8_t bit = pwm_register % 8; + + if (enabled) { + g_led_control_registers[0][control_register] |= (1 << bit); + } else { + g_led_control_registers[0][control_register] &= ~(1 << bit); + } + + g_led_control_registers_update_required = true; +} + +void IS31FL3736_update_pwm_buffers(uint8_t addr1, uint8_t addr2) { + if (g_pwm_buffer_update_required) { + // Firstly we need to unlock the command register and select PG1 + IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + + IS31FL3736_write_pwm_buffer(addr1, g_pwm_buffer[0]); + // IS31FL3736_write_pwm_buffer(addr2, g_pwm_buffer[1]); + } + g_pwm_buffer_update_required = false; +} + +void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2) { + if (g_led_control_registers_update_required) { + // Firstly we need to unlock the command register and select PG0 + IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + for (int i = 0; i < 24; i++) { + IS31FL3736_write_register(addr1, i, g_led_control_registers[0][i]); + // IS31FL3736_write_register(addr2, i, g_led_control_registers[1][i]); + } + g_led_control_registers_update_required = false; + } +} diff --git a/drivers/led/issi/is31fl3736.h b/drivers/led/issi/is31fl3736.h new file mode 100644 index 0000000000..e48e31c279 --- /dev/null +++ b/drivers/led/issi/is31fl3736.h @@ -0,0 +1,168 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 . + */ + +#pragma once + +#include +#include + +// Simple interface option. +// If these aren't defined, just define them to make it compile + +#ifndef DRIVER_COUNT +# define DRIVER_COUNT 2 +#endif + +#ifndef DRIVER_LED_TOTAL +# define DRIVER_LED_TOTAL 96 +#endif + +typedef struct is31_led { + uint8_t driver : 2; + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3736_init(uint8_t addr); +void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void IS31FL3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue); + +void IS31FL3736_mono_set_brightness(int index, uint8_t value); +void IS31FL3736_mono_set_brightness_all(uint8_t value); +void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled); + +// This should not be called from an interrupt +// (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 IS31FL3736_update_pwm_buffers(uint8_t addr1, uint8_t addr2); +void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2); + +#define A_1 0x00 +#define A_2 0x02 +#define A_3 0x04 +#define A_4 0x06 +#define A_5 0x08 +#define A_6 0x0A +#define A_7 0x0C +#define A_8 0x0E + +#define B_1 0x10 +#define B_2 0x12 +#define B_3 0x14 +#define B_4 0x16 +#define B_5 0x18 +#define B_6 0x1A +#define B_7 0x1C +#define B_8 0x1E + +#define C_1 0x20 +#define C_2 0x22 +#define C_3 0x24 +#define C_4 0x26 +#define C_5 0x28 +#define C_6 0x2A +#define C_7 0x2C +#define C_8 0x2E + +#define D_1 0x30 +#define D_2 0x32 +#define D_3 0x34 +#define D_4 0x36 +#define D_5 0x38 +#define D_6 0x3A +#define D_7 0x3C +#define D_8 0x3E + +#define E_1 0x40 +#define E_2 0x42 +#define E_3 0x44 +#define E_4 0x46 +#define E_5 0x48 +#define E_6 0x4A +#define E_7 0x4C +#define E_8 0x4E + +#define F_1 0x50 +#define F_2 0x52 +#define F_3 0x54 +#define F_4 0x56 +#define F_5 0x58 +#define F_6 0x5A +#define F_7 0x5C +#define F_8 0x5E + +#define G_1 0x60 +#define G_2 0x62 +#define G_3 0x64 +#define G_4 0x66 +#define G_5 0x68 +#define G_6 0x6A +#define G_7 0x6C +#define G_8 0x6E + +#define H_1 0x70 +#define H_2 0x72 +#define H_3 0x74 +#define H_4 0x76 +#define H_5 0x78 +#define H_6 0x7A +#define H_7 0x7C +#define H_8 0x7E + +#define I_1 0x80 +#define I_2 0x82 +#define I_3 0x84 +#define I_4 0x86 +#define I_5 0x88 +#define I_6 0x8A +#define I_7 0x8C +#define I_8 0x8E + +#define J_1 0x90 +#define J_2 0x92 +#define J_3 0x94 +#define J_4 0x96 +#define J_5 0x98 +#define J_6 0x9A +#define J_7 0x9C +#define J_8 0x9E + +#define K_1 0xA0 +#define K_2 0xA2 +#define K_3 0xA4 +#define K_4 0xA6 +#define K_5 0xA8 +#define K_6 0xAA +#define K_7 0xAC +#define K_8 0xAE + +#define L_1 0xB0 +#define L_2 0xB2 +#define L_3 0xB4 +#define L_4 0xB6 +#define L_5 0xB8 +#define L_6 0xBA +#define L_7 0xBC +#define L_8 0xBE diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c new file mode 100644 index 0000000000..30906b4840 --- /dev/null +++ b/drivers/led/issi/is31fl3737.c @@ -0,0 +1,227 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * + * 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 . + */ + +#include "is31fl3737.h" +#include "i2c_master.h" +#include "wait.h" +#include "progmem.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 00 <-> GND +// 01 <-> SCL +// 10 <-> SDA +// 11 <-> VCC +// ADDR1 represents A1:A0 of the 7-bit address. +// ADDR2 represents A3:A2 of the 7-bit address. +// The result is: 0b101(ADDR2)(ADDR1) +#define ISSI_ADDR_DEFAULT 0x50 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE +#define ISSI_INTERRUPTMASKREGISTER 0xF0 +#define ISSI_INTERRUPTSTATUSREGISTER 0xF1 + +#define ISSI_PAGE_LEDCONTROL 0x00 // PG0 +#define ISSI_PAGE_PWM 0x01 // PG1 +#define ISSI_PAGE_AUTOBREATH 0x02 // PG2 +#define ISSI_PAGE_FUNCTION 0x03 // PG3 + +#define ISSI_REG_CONFIGURATION 0x00 // PG3 +#define ISSI_REG_GLOBALCURRENT 0x01 // PG3 +#define ISSI_REG_RESET 0x11 // PG3 +#define ISSI_REG_SWPULLUP 0x0F // PG3 +#define ISSI_REG_CSPULLUP 0x10 // PG3 + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the IS31FL3737 PWM registers. +// The control buffers match the PG0 LED On/Off registers. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in IS31FL3737_write_pwm_buffer() but it's +// probably not worth the extra complexity. + +uint8_t g_pwm_buffer[DRIVER_COUNT][192]; +bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; +bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; + +void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +void IS31FL3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // assumes PG1 is already selected + + // transmit PWM registers in 12 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // iterate over the pwm_buffer contents at 16 byte intervals + for (int i = 0; i < 192; i += 16) { + g_twi_transfer_buffer[0] = i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer + for (int j = 0; j < 16; j++) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT); +#endif + } +} + +void IS31FL3737_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. + + // Unlock the command register. + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG0 + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + // Turn off all LEDs. + for (int i = 0x00; i <= 0x17; i++) { + IS31FL3737_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG1 + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + // Set PWM on all LEDs to 0 + // No need to setup Breath registers to PWM as that is the default. + for (int i = 0x00; i <= 0xBF; i++) { + IS31FL3737_write_register(addr, i, 0x00); + } + + // Unlock the command register. + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG3 + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + // Set global current to maximum. + IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); + // Disable software shutdown. + IS31FL3737_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); + + // Wait 10ms to ensure the device has woken up. + wait_ms(10); +} + +void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + // copy the led config from progmem to SRAM + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + + g_pwm_buffer[led.driver][led.r] = red; + g_pwm_buffer[led.driver][led.g] = green; + g_pwm_buffer[led.driver][led.b] = blue; + g_pwm_buffer_update_required[led.driver] = true; + } +} + +void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3737_set_color(i, red, green, blue); + } +} + +void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { + // copy the led config from progmem to SRAM + is31_led led; + memcpy_P(&led, (&g_is31_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) { + g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r); + } else { + g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r); + } + if (green) { + g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g); + } else { + g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g); + } + if (blue) { + g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b); + } else { + g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b); + } + + g_led_control_registers_update_required[led.driver] = true; +} + +void IS31FL3737_update_pwm_buffers(uint8_t addr, uint8_t index) { + if (g_pwm_buffer_update_required[index]) { + // Firstly we need to unlock the command register and select PG1 + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + + IS31FL3737_write_pwm_buffer(addr, g_pwm_buffer[index]); + } + g_pwm_buffer_update_required[index] = false; +} + +void IS31FL3737_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_led_control_registers_update_required[index]) { + // Firstly we need to unlock the command register and select PG0 + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + for (int i = 0; i < 24; i++) { + IS31FL3737_write_register(addr, i, g_led_control_registers[index][i]); + } + } + g_led_control_registers_update_required[index] = false; +} diff --git a/drivers/led/issi/is31fl3737.h b/drivers/led/issi/is31fl3737.h new file mode 100644 index 0000000000..a1d2281778 --- /dev/null +++ b/drivers/led/issi/is31fl3737.h @@ -0,0 +1,203 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * + * 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 . + */ + +#pragma once + +#include +#include + +typedef struct is31_led { + uint8_t driver : 2; + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3737_init(uint8_t addr); +void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void IS31FL3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue); + +// This should not be called from an interrupt +// (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 IS31FL3737_update_pwm_buffers(uint8_t addr1, uint8_t addr2); +void IS31FL3737_update_led_control_registers(uint8_t addr1, uint8_t addr2); + +#define A_1 0x00 +#define A_2 0x01 +#define A_3 0x02 +#define A_4 0x03 +#define A_5 0x04 +#define A_6 0x05 +#define A_7 0x08 +#define A_8 0x09 +#define A_9 0x0A +#define A_10 0x0B +#define A_11 0x0C +#define A_12 0x0D + +#define B_1 0x10 +#define B_2 0x11 +#define B_3 0x12 +#define B_4 0x13 +#define B_5 0x14 +#define B_6 0x15 +#define B_7 0x18 +#define B_8 0x19 +#define B_9 0x1A +#define B_10 0x1B +#define B_11 0x1C +#define B_12 0x1D + +#define C_1 0x20 +#define C_2 0x21 +#define C_3 0x22 +#define C_4 0x23 +#define C_5 0x24 +#define C_6 0x25 +#define C_7 0x28 +#define C_8 0x29 +#define C_9 0x2A +#define C_10 0x2B +#define C_11 0x2C +#define C_12 0x2D + +#define D_1 0x30 +#define D_2 0x31 +#define D_3 0x32 +#define D_4 0x33 +#define D_5 0x34 +#define D_6 0x35 +#define D_7 0x38 +#define D_8 0x39 +#define D_9 0x3A +#define D_10 0x3B +#define D_11 0x3C +#define D_12 0x3D + +#define E_1 0x40 +#define E_2 0x41 +#define E_3 0x42 +#define E_4 0x43 +#define E_5 0x44 +#define E_6 0x45 +#define E_7 0x48 +#define E_8 0x49 +#define E_9 0x4A +#define E_10 0x4B +#define E_11 0x4C +#define E_12 0x4D + +#define F_1 0x50 +#define F_2 0x51 +#define F_3 0x52 +#define F_4 0x53 +#define F_5 0x54 +#define F_6 0x55 +#define F_7 0x58 +#define F_8 0x59 +#define F_9 0x5A +#define F_10 0x5B +#define F_11 0x5C +#define F_12 0x5D + +#define G_1 0x60 +#define G_2 0x61 +#define G_3 0x62 +#define G_4 0x63 +#define G_5 0x64 +#define G_6 0x65 +#define G_7 0x68 +#define G_8 0x69 +#define G_9 0x6A +#define G_10 0x6B +#define G_11 0x6C +#define G_12 0x6D + +#define H_1 0x70 +#define H_2 0x71 +#define H_3 0x72 +#define H_4 0x73 +#define H_5 0x74 +#define H_6 0x75 +#define H_7 0x78 +#define H_8 0x79 +#define H_9 0x7A +#define H_10 0x7B +#define H_11 0x7C +#define H_12 0x7D + +#define I_1 0x80 +#define I_2 0x81 +#define I_3 0x82 +#define I_4 0x83 +#define I_5 0x84 +#define I_6 0x85 +#define I_7 0x88 +#define I_8 0x89 +#define I_9 0x8A +#define I_10 0x8B +#define I_11 0x8C +#define I_12 0x8D + +#define J_1 0x90 +#define J_2 0x91 +#define J_3 0x92 +#define J_4 0x93 +#define J_5 0x94 +#define J_6 0x95 +#define J_7 0x98 +#define J_8 0x99 +#define J_9 0x9A +#define J_10 0x9B +#define J_11 0x9C +#define J_12 0x9D + +#define K_1 0xA0 +#define K_2 0xA1 +#define K_3 0xA2 +#define K_4 0xA3 +#define K_5 0xA4 +#define K_6 0xA5 +#define K_7 0xA8 +#define K_8 0xA9 +#define K_9 0xAA +#define K_10 0xAB +#define K_11 0xAC +#define K_12 0xAD + +#define L_1 0xB0 +#define L_2 0xB1 +#define L_3 0xB2 +#define L_4 0xB3 +#define L_5 0xB4 +#define L_6 0xB5 +#define L_7 0xB8 +#define L_8 0xB9 +#define L_9 0xBA +#define L_10 0xBB +#define L_11 0xBC +#define L_12 0xBD diff --git a/drivers/led/issi/is31fl3741.c b/drivers/led/issi/is31fl3741.c new file mode 100644 index 0000000000..1b533c9b6a --- /dev/null +++ b/drivers/led/issi/is31fl3741.c @@ -0,0 +1,255 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * Copyright 2020 MelGeek + * + * 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 . + */ + +#include "wait.h" + +#include "is31fl3741.h" +#include +#include "i2c_master.h" +#include "progmem.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 00 <-> GND +// 01 <-> SCL +// 10 <-> SDA +// 11 <-> VCC +// ADDR1 represents A1:A0 of the 7-bit address. +// ADDR2 represents A3:A2 of the 7-bit address. +// The result is: 0b101(ADDR2)(ADDR1) +#define ISSI_ADDR_DEFAULT 0x60 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE +#define ISSI_INTERRUPTMASKREGISTER 0xF0 +#define ISSI_INTERRUPTSTATUSREGISTER 0xF1 +#define ISSI_IDREGISTER 0xFC + +#define ISSI_PAGE_PWM0 0x00 // PG0 +#define ISSI_PAGE_PWM1 0x01 // PG1 +#define ISSI_PAGE_SCALING_0 0x02 // PG2 +#define ISSI_PAGE_SCALING_1 0x03 // PG3 +#define ISSI_PAGE_FUNCTION 0x04 // PG4 + +#define ISSI_REG_CONFIGURATION 0x00 // PG4 +#define ISSI_REG_GLOBALCURRENT 0x01 // PG4 +#define ISSI_REG_PULLDOWNUP 0x02 // PG4 +#define ISSI_REG_RESET 0x3F // PG4 + +#ifndef ISSI_TIMEOUT +# define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE +# define ISSI_PERSISTENCE 0 +#endif + +#define ISSI_MAX_LEDS 351 + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20] = {0xFF}; + +// These buffers match the IS31FL3741 and IS31FL3741A PWM registers. +// The scaling buffers match the PG2 and PG3 LED On/Off registers. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in IS31FL3741_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][ISSI_MAX_LEDS]; +bool g_pwm_buffer_update_required = false; +bool g_scaling_registers_update_required[DRIVER_COUNT] = {false}; + +uint8_t g_scaling_registers[DRIVER_COUNT][ISSI_MAX_LEDS]; + +void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) { + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break; + } +#else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +#endif +} + +bool IS31FL3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { + // unlock the command register and select PG2 + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM0); + + for (int i = 0; i < 342; i += 18) { + if (i == 180) { + // unlock the command register and select PG2 + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM1); + } + + g_twi_transfer_buffer[0] = i % 180; + memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 18); + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 19, ISSI_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 19, ISSI_TIMEOUT) != 0) { + return false; + } +#endif + } + + // transfer the left cause the total number is 351 + g_twi_transfer_buffer[0] = 162; + memcpy(g_twi_transfer_buffer + 1, pwm_buffer + 342, 9); + +#if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 10, ISSI_TIMEOUT) != 0) { + return false; + } + } +#else + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 10, ISSI_TIMEOUT) != 0) { + return false; + } +#endif + + return true; +} + +void IS31FL3741_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. + // Unlock the command register. + + // Unlock the command register. + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + + // Select PG4 + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + + // Set to Normal operation + IS31FL3741_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); + + // Set Golbal Current Control Register + IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); + // Set Pull up & Down for SWx CSy + IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, 0x77); + + // IS31FL3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF); + + // Wait 10ms to ensure the device has woken up. + wait_ms(10); +} + +void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (index >= 0 && index < DRIVER_LED_TOTAL) { + is31_led led = g_is31_leds[index]; + + g_pwm_buffer[led.driver][led.r] = red; + g_pwm_buffer[led.driver][led.g] = green; + g_pwm_buffer[led.driver][led.b] = blue; + g_pwm_buffer_update_required = true; + } +} + +void IS31FL3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { + for (int i = 0; i < DRIVER_LED_TOTAL; i++) { + IS31FL3741_set_color(i, red, green, blue); + } +} + +void IS31FL3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { + is31_led led = g_is31_leds[index]; + + if (red) { + g_scaling_registers[led.driver][led.r] = 0xFF; + } else { + g_scaling_registers[led.driver][led.r] = 0x00; + } + + if (green) { + g_scaling_registers[led.driver][led.g] = 0xFF; + } else { + g_scaling_registers[led.driver][led.g] = 0x00; + } + + if (blue) { + g_scaling_registers[led.driver][led.b] = 0xFF; + } else { + g_scaling_registers[led.driver][led.b] = 0x00; + } + + g_scaling_registers_update_required[led.driver] = true; +} + +void IS31FL3741_update_pwm_buffers(uint8_t addr1, uint8_t addr2) { + if (g_pwm_buffer_update_required) { + IS31FL3741_write_pwm_buffer(addr1, g_pwm_buffer[0]); + } + + g_pwm_buffer_update_required = false; +} + +void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { + g_pwm_buffer[pled->driver][pled->r] = red; + g_pwm_buffer[pled->driver][pled->g] = green; + g_pwm_buffer[pled->driver][pled->b] = blue; + + g_pwm_buffer_update_required = true; +} + +void IS31FL3741_update_led_control_registers(uint8_t addr, uint8_t index) { + if (g_scaling_registers_update_required[index]) { + // unlock the command register and select PG2 + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_0); + + // CS1_SW1 to CS30_SW6 are on PG2 + for (int i = CS1_SW1; i <= CS30_SW6; ++i) { + IS31FL3741_write_register(addr, i, g_scaling_registers[0][i]); + } + + // unlock the command register and select PG3 + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_1); + + // CS1_SW7 to CS39_SW9 are on PG3 + for (int i = CS1_SW7; i <= CS39_SW9; ++i) { + IS31FL3741_write_register(addr, i - CS1_SW7, g_scaling_registers[0][i]); + } + + g_scaling_registers_update_required[index] = false; + } +} + +void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { + g_scaling_registers[pled->driver][pled->r] = red; + g_scaling_registers[pled->driver][pled->g] = green; + g_scaling_registers[pled->driver][pled->b] = blue; + + g_scaling_registers_update_required[pled->driver] = true; +} diff --git a/drivers/led/issi/is31fl3741.h b/drivers/led/issi/is31fl3741.h new file mode 100644 index 0000000000..2df0c5b1a7 --- /dev/null +++ b/drivers/led/issi/is31fl3741.h @@ -0,0 +1,420 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * Copyright 2018 Yiancar + * Copyright 2020 MelGeek + * + * 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 . + */ + +#pragma once + +#include +#include + +typedef struct is31_led { + uint32_t driver : 2; + uint32_t r : 10; + uint32_t g : 10; + uint32_t b : 10; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3741_init(uint8_t addr); +void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool IS31FL3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); + +void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void IS31FL3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue); + +// This should not be called from an interrupt +// (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 IS31FL3741_update_pwm_buffers(uint8_t addr1, uint8_t addr2); +void IS31FL3741_update_led_control_registers(uint8_t addr1, uint8_t addr2); +void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); + +void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); + +#define CS1_SW1 0x00 +#define CS2_SW1 0x01 +#define CS3_SW1 0x02 +#define CS4_SW1 0x03 +#define CS5_SW1 0x04 +#define CS6_SW1 0x05 +#define CS7_SW1 0x06 +#define CS8_SW1 0x07 +#define CS9_SW1 0x08 +#define CS10_SW1 0x09 +#define CS11_SW1 0x0A +#define CS12_SW1 0x0B +#define CS13_SW1 0x0C +#define CS14_SW1 0x0D +#define CS15_SW1 0x0E +#define CS16_SW1 0x0F +#define CS17_SW1 0x10 +#define CS18_SW1 0x11 +#define CS19_SW1 0x12 +#define CS20_SW1 0x13 +#define CS21_SW1 0x14 +#define CS22_SW1 0x15 +#define CS23_SW1 0x16 +#define CS24_SW1 0x17 +#define CS25_SW1 0x18 +#define CS26_SW1 0x19 +#define CS27_SW1 0x1A +#define CS28_SW1 0x1B +#define CS29_SW1 0x1C +#define CS30_SW1 0x1D + +#define CS1_SW2 0x1E +#define CS2_SW2 0x1F +#define CS3_SW2 0x20 +#define CS4_SW2 0x21 +#define CS5_SW2 0x22 +#define CS6_SW2 0x23 +#define CS7_SW2 0x24 +#define CS8_SW2 0x25 +#define CS9_SW2 0x26 +#define CS10_SW2 0x27 +#define CS11_SW2 0x28 +#define CS12_SW2 0x29 +#define CS13_SW2 0x2A +#define CS14_SW2 0x2B +#define CS15_SW2 0x2C +#define CS16_SW2 0x2D +#define CS17_SW2 0x2E +#define CS18_SW2 0x2F +#define CS19_SW2 0x30 +#define CS20_SW2 0x31 +#define CS21_SW2 0x32 +#define CS22_SW2 0x33 +#define CS23_SW2 0x34 +#define CS24_SW2 0x35 +#define CS25_SW2 0x36 +#define CS26_SW2 0x37 +#define CS27_SW2 0x38 +#define CS28_SW2 0x39 +#define CS29_SW2 0x3A +#define CS30_SW2 0x3B + +#define CS1_SW3 0x3C +#define CS2_SW3 0x3D +#define CS3_SW3 0x3E +#define CS4_SW3 0x3F +#define CS5_SW3 0x40 +#define CS6_SW3 0x41 +#define CS7_SW3 0x42 +#define CS8_SW3 0x43 +#define CS9_SW3 0x44 +#define CS10_SW3 0x45 +#define CS11_SW3 0x46 +#define CS12_SW3 0x47 +#define CS13_SW3 0x48 +#define CS14_SW3 0x49 +#define CS15_SW3 0x4A +#define CS16_SW3 0x4B +#define CS17_SW3 0x4C +#define CS18_SW3 0x4D +#define CS19_SW3 0x4E +#define CS20_SW3 0x4F +#define CS21_SW3 0x50 +#define CS22_SW3 0x51 +#define CS23_SW3 0x52 +#define CS24_SW3 0x53 +#define CS25_SW3 0x54 +#define CS26_SW3 0x55 +#define CS27_SW3 0x56 +#define CS28_SW3 0x57 +#define CS29_SW3 0x58 +#define CS30_SW3 0x59 + +#define CS1_SW4 0x5A +#define CS2_SW4 0x5B +#define CS3_SW4 0x5C +#define CS4_SW4 0x5D +#define CS5_SW4 0x5E +#define CS6_SW4 0x5F +#define CS7_SW4 0x60 +#define CS8_SW4 0x61 +#define CS9_SW4 0x62 +#define CS10_SW4 0x63 +#define CS11_SW4 0x64 +#define CS12_SW4 0x65 +#define CS13_SW4 0x66 +#define CS14_SW4 0x67 +#define CS15_SW4 0x68 +#define CS16_SW4 0x69 +#define CS17_SW4 0x6A +#define CS18_SW4 0x6B +#define CS19_SW4 0x6C +#define CS20_SW4 0x6D +#define CS21_SW4 0x6E +#define CS22_SW4 0x6F +#define CS23_SW4 0x70 +#define CS24_SW4 0x71 +#define CS25_SW4 0x72 +#define CS26_SW4 0x73 +#define CS27_SW4 0x74 +#define CS28_SW4 0x75 +#define CS29_SW4 0x76 +#define CS30_SW4 0x77 + +#define CS1_SW5 0x78 +#define CS2_SW5 0x79 +#define CS3_SW5 0x7A +#define CS4_SW5 0x7B +#define CS5_SW5 0x7C +#define CS6_SW5 0x7D +#define CS7_SW5 0x7E +#define CS8_SW5 0x7F +#define CS9_SW5 0x80 +#define CS10_SW5 0x81 +#define CS11_SW5 0x82 +#define CS12_SW5 0x83 +#define CS13_SW5 0x84 +#define CS14_SW5 0x85 +#define CS15_SW5 0x86 +#define CS16_SW5 0x87 +#define CS17_SW5 0x88 +#define CS18_SW5 0x89 +#define CS19_SW5 0x8A +#define CS20_SW5 0x8B +#define CS21_SW5 0x8C +#define CS22_SW5 0x8D +#define CS23_SW5 0x8E +#define CS24_SW5 0x8F +#define CS25_SW5 0x90 +#define CS26_SW5 0x91 +#define CS27_SW5 0x92 +#define CS28_SW5 0x93 +#define CS29_SW5 0x94 +#define CS30_SW5 0x95 + +#define CS1_SW6 0x96 +#define CS2_SW6 0x97 +#define CS3_SW6 0x98 +#define CS4_SW6 0x99 +#define CS5_SW6 0x9A +#define CS6_SW6 0x9B +#define CS7_SW6 0x9C +#define CS8_SW6 0x9D +#define CS9_SW6 0x9E +#define CS10_SW6 0x9F +#define CS11_SW6 0xA0 +#define CS12_SW6 0xA1 +#define CS13_SW6 0xA2 +#define CS14_SW6 0xA3 +#define CS15_SW6 0xA4 +#define CS16_SW6 0xA5 +#define CS17_SW6 0xA6 +#define CS18_SW6 0xA7 +#define CS19_SW6 0xA8 +#define CS20_SW6 0xA9 +#define CS21_SW6 0xAA +#define CS22_SW6 0xAB +#define CS23_SW6 0xAC +#define CS24_SW6 0xAD +#define CS25_SW6 0xAE +#define CS26_SW6 0xAF +#define CS27_SW6 0xB0 +#define CS28_SW6 0xB1 +#define CS29_SW6 0xB2 +#define CS30_SW6 0xB3 + +#define CS1_SW7 0xB4 +#define CS2_SW7 0xB5 +#define CS3_SW7 0xB6 +#define CS4_SW7 0xB7 +#define CS5_SW7 0xB8 +#define CS6_SW7 0xB9 +#define CS7_SW7 0xBA +#define CS8_SW7 0xBB +#define CS9_SW7 0xBC +#define CS10_SW7 0xBD +#define CS11_SW7 0xBE +#define CS12_SW7 0xBF +#define CS13_SW7 0xC0 +#define CS14_SW7 0xC1 +#define CS15_SW7 0xC2 +#define CS16_SW7 0xC3 +#define CS17_SW7 0xC4 +#define CS18_SW7 0xC5 +#define CS19_SW7 0xC6 +#define CS20_SW7 0xC7 +#define CS21_SW7 0xC8 +#define CS22_SW7 0xC9 +#define CS23_SW7 0xCA +#define CS24_SW7 0xCB +#define CS25_SW7 0xCC +#define CS26_SW7 0xCD +#define CS27_SW7 0xCE +#define CS28_SW7 0xCF +#define CS29_SW7 0xD0 +#define CS30_SW7 0xD1 + +#define CS1_SW8 0xD2 +#define CS2_SW8 0xD3 +#define CS3_SW8 0xD4 +#define CS4_SW8 0xD5 +#define CS5_SW8 0xD6 +#define CS6_SW8 0xD7 +#define CS7_SW8 0xD8 +#define CS8_SW8 0xD9 +#define CS9_SW8 0xDA +#define CS10_SW8 0xDB +#define CS11_SW8 0xDC +#define CS12_SW8 0xDD +#define CS13_SW8 0xDE +#define CS14_SW8 0xDF +#define CS15_SW8 0xE0 +#define CS16_SW8 0xE1 +#define CS17_SW8 0xE2 +#define CS18_SW8 0xE3 +#define CS19_SW8 0xE4 +#define CS20_SW8 0xE5 +#define CS21_SW8 0xE6 +#define CS22_SW8 0xE7 +#define CS23_SW8 0xE8 +#define CS24_SW8 0xE9 +#define CS25_SW8 0xEA +#define CS26_SW8 0xEB +#define CS27_SW8 0xEC +#define CS28_SW8 0xED +#define CS29_SW8 0xEE +#define CS30_SW8 0xEF + +#define CS1_SW9 0xF0 +#define CS2_SW9 0xF1 +#define CS3_SW9 0xF2 +#define CS4_SW9 0xF3 +#define CS5_SW9 0xF4 +#define CS6_SW9 0xF5 +#define CS7_SW9 0xF6 +#define CS8_SW9 0xF7 +#define CS9_SW9 0xF8 +#define CS10_SW9 0xF9 +#define CS11_SW9 0xFA +#define CS12_SW9 0xFB +#define CS13_SW9 0xFC +#define CS14_SW9 0xFD +#define CS15_SW9 0xFE +#define CS16_SW9 0xFF +#define CS17_SW9 0x100 +#define CS18_SW9 0x101 +#define CS19_SW9 0x102 +#define CS20_SW9 0x103 +#define CS21_SW9 0x104 +#define CS22_SW9 0x105 +#define CS23_SW9 0x106 +#define CS24_SW9 0x107 +#define CS25_SW9 0x108 +#define CS26_SW9 0x109 +#define CS27_SW9 0x10A +#define CS28_SW9 0x10B +#define CS29_SW9 0x10C +#define CS30_SW9 0x10D + +#define CS31_SW1 0x10E +#define CS32_SW1 0x10F +#define CS33_SW1 0x110 +#define CS34_SW1 0x111 +#define CS35_SW1 0x112 +#define CS36_SW1 0x113 +#define CS37_SW1 0x114 +#define CS38_SW1 0x115 +#define CS39_SW1 0x116 + +#define CS31_SW2 0x117 +#define CS32_SW2 0x118 +#define CS33_SW2 0x119 +#define CS34_SW2 0x11A +#define CS35_SW2 0x11B +#define CS36_SW2 0x11C +#define CS37_SW2 0x11D +#define CS38_SW2 0x11E +#define CS39_SW2 0x11F + +#define CS31_SW3 0x120 +#define CS32_SW3 0x121 +#define CS33_SW3 0x122 +#define CS34_SW3 0x123 +#define CS35_SW3 0x124 +#define CS36_SW3 0x125 +#define CS37_SW3 0x126 +#define CS38_SW3 0x127 +#define CS39_SW3 0x128 + +#define CS31_SW4 0x129 +#define CS32_SW4 0x12A +#define CS33_SW4 0x12B +#define CS34_SW4 0x12C +#define CS35_SW4 0x12D +#define CS36_SW4 0x12E +#define CS37_SW4 0x12F +#define CS38_SW4 0x130 +#define CS39_SW4 0x131 + +#define CS31_SW5 0x132 +#define CS32_SW5 0x133 +#define CS33_SW5 0x134 +#define CS34_SW5 0x135 +#define CS35_SW5 0x136 +#define CS36_SW5 0x137 +#define CS37_SW5 0x138 +#define CS38_SW5 0x139 +#define CS39_SW5 0x13A + +#define CS31_SW6 0x13B +#define CS32_SW6 0x13C +#define CS33_SW6 0x13D +#define CS34_SW6 0x13E +#define CS35_SW6 0x13F +#define CS36_SW6 0x140 +#define CS37_SW6 0x141 +#define CS38_SW6 0x142 +#define CS39_SW6 0x143 + +#define CS31_SW7 0x144 +#define CS32_SW7 0x145 +#define CS33_SW7 0x146 +#define CS34_SW7 0x147 +#define CS35_SW7 0x148 +#define CS36_SW7 0x149 +#define CS37_SW7 0x14A +#define CS38_SW7 0x14B +#define CS39_SW7 0x14C + +#define CS31_SW8 0x14D +#define CS32_SW8 0x14E +#define CS33_SW8 0x14F +#define CS34_SW8 0x150 +#define CS35_SW8 0x151 +#define CS36_SW8 0x152 +#define CS37_SW8 0x153 +#define CS38_SW8 0x154 +#define CS39_SW8 0x155 + +#define CS31_SW9 0x156 +#define CS32_SW9 0x157 +#define CS33_SW9 0x158 +#define CS34_SW9 0x159 +#define CS35_SW9 0x15A +#define CS36_SW9 0x15B +#define CS37_SW9 0x15C +#define CS38_SW9 0x15D +#define CS39_SW9 0x15E -- cgit v1.3.1 From 70fb3e1aaf406cbbd5137916a93ed814d6891ef2 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sat, 31 Jul 2021 14:35:30 +0100 Subject: __flash? (#13799) --- docs/feature_led_matrix.md | 2 +- docs/feature_rgb_matrix.md | 8 ++++---- docs/ja/feature_led_matrix.md | 2 +- drivers/led/aw20216.h | 3 ++- drivers/led/issi/is31fl3731-simple.h | 3 ++- drivers/led/issi/is31fl3731.h | 3 ++- drivers/led/issi/is31fl3733.h | 3 ++- drivers/led/issi/is31fl3736.h | 3 ++- drivers/led/issi/is31fl3737.c | 9 ++------- drivers/led/issi/is31fl3737.h | 3 ++- drivers/led/issi/is31fl3741.h | 3 ++- keyboards/clueboard/66_hotswap/gen1/gen1.c | 2 +- keyboards/dp60/dp60.c | 2 +- keyboards/durgod/dgk6x/galaxy/galaxy.c | 2 +- keyboards/durgod/dgk6x/hades/hades.c | 2 +- keyboards/durgod/dgk6x/venus/venus.c | 2 +- keyboards/dztech/dz60rgb/dz60rgb.c | 2 +- keyboards/dztech/dz60rgb_ansi/dz60rgb_ansi.c | 2 +- keyboards/dztech/dz60rgb_wkl/dz60rgb_wkl.c | 2 +- keyboards/dztech/dz65rgb/v1/v1.c | 2 +- keyboards/dztech/dz65rgb/v2/v2.c | 2 +- keyboards/dztech/dz65rgb/v3/v3.c | 2 +- keyboards/ergodox_ez/ergodox_ez.c | 2 +- keyboards/ergodox_infinity/ergodox_infinity.c | 2 +- keyboards/exclusive/e6_rgb/e6_rgb.c | 2 +- keyboards/fallacy/indicators.c | 2 +- keyboards/geekboards/tester/tester.c | 2 +- keyboards/hs60/v1/v1.c | 4 ++-- keyboards/inett_studio/sqx/hotswap/hotswap.c | 2 +- keyboards/inett_studio/sqx/universal/universal.c | 2 +- keyboards/k_type/is31fl3733-dual.h | 2 +- keyboards/k_type/k_type.c | 2 +- keyboards/kbdfans/bella/rgb/rgb.c | 2 +- keyboards/kbdfans/bella/rgb_iso/rgb_iso.c | 2 +- keyboards/kbdfans/kbd67/mkiirgb/mkiirgb.c | 2 +- keyboards/kbdfans/kbdmini/kbdmini.c | 2 +- keyboards/kbdfans/maja/maja.c | 2 +- keyboards/keychron/q1/q1.c | 2 +- keyboards/latin17rgb/latin17rgb.c | 2 +- keyboards/latin60rgb/latin60rgb.c | 2 +- keyboards/latin6rgb/latin6rgb.c | 2 +- keyboards/matrix/m20add/rgb_ring.c | 2 +- keyboards/matrix/noah/noah.c | 2 +- keyboards/mechlovin/adelais/rgb_led/rev2/rev2.c | 2 +- keyboards/mechlovin/delphine/rgb_led/rgb_led.c | 2 +- keyboards/mechlovin/hannah60rgb/rev2/rev2.c | 2 +- keyboards/mechlovin/infinity87/rgb_rev1/rgb_rev1.c | 2 +- keyboards/melgeek/mj61/rev1/rev1.c | 2 +- keyboards/melgeek/mj61/rev2/rev2.c | 2 +- keyboards/melgeek/mj63/rev1/rev1.c | 2 +- keyboards/melgeek/mj63/rev2/rev2.c | 2 +- keyboards/melgeek/mj64/rev1/rev1.c | 2 +- keyboards/melgeek/mj64/rev2/rev2.c | 2 +- keyboards/melgeek/mj64/rev3/rev3.c | 2 +- keyboards/melgeek/mj65/rev3/rev3.c | 2 +- keyboards/melgeek/mojo75/rev1/rev1.c | 2 +- keyboards/melgeek/z70ultra/z70ultra.c | 2 +- keyboards/miller/gm862/gm862.c | 2 +- keyboards/moonlander/moonlander.c | 2 +- keyboards/mt64rgb/mt64rgb.c | 2 +- keyboards/mt84/mt84.c | 2 +- keyboards/opendeck/32/rev1/rev1.c | 2 +- keyboards/planck/ez/ez.c | 2 +- keyboards/planck/light/light.c | 2 +- keyboards/terrazzo/terrazzo.c | 2 +- keyboards/tkc/portico/portico.c | 2 +- keyboards/whitefox/whitefox.c | 2 +- keyboards/wilba_tech/wt_rgb_backlight.c | 16 ++++++++-------- keyboards/xbows/knight/knight.c | 2 +- keyboards/xbows/knight_plus/knight_plus.c | 2 +- keyboards/xbows/nature/nature.c | 2 +- keyboards/xbows/numpad/numpad.c | 2 +- keyboards/xbows/woody/woody.c | 2 +- keyboards/xelus/dawn60/rev1_qmk/rev1_qmk.c | 2 +- keyboards/xelus/pachi/rgb/rgb.c | 2 +- tmk_core/common/progmem.h | 1 + 76 files changed, 95 insertions(+), 92 deletions(-) (limited to 'drivers/led') diff --git a/docs/feature_led_matrix.md b/docs/feature_led_matrix.md index afa11e7232..7d7971bbed 100644 --- a/docs/feature_led_matrix.md +++ b/docs/feature_led_matrix.md @@ -52,7 +52,7 @@ Here is an example using 2 drivers. Define these arrays listing all the LEDs in your `.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | LED address diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md index 18e38955ec..670d7e09bf 100644 --- a/docs/feature_rgb_matrix.md +++ b/docs/feature_rgb_matrix.md @@ -52,7 +52,7 @@ Here is an example using 2 drivers. Define these arrays listing all the LEDs in your `.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -122,7 +122,7 @@ Currently only 4 drivers are supported, but it would be trivial to support all 8 Define these arrays listing all the LEDs in your `.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -186,7 +186,7 @@ Currently only 2 drivers are supported, but it would be trivial to support all 4 Define these arrays listing all the LEDs in your `.c`: ```c -const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -287,7 +287,7 @@ Here is an example using 2 drivers. Define these arrays listing all the LEDs in your `.c`: ```c -const aw_led g_aw_leds[DRIVER_LED_TOTAL] = { +const aw_led __flash g_aw_leds[DRIVER_LED_TOTAL] = { /* Each AW20216 channel is controlled by a register at some offset between 0x00 * and 0xD7 inclusive. * See drivers/awinic/aw20216.h for the mapping between register offsets and diff --git a/docs/ja/feature_led_matrix.md b/docs/ja/feature_led_matrix.md index f132d716f6..6511b28249 100644 --- a/docs/ja/feature_led_matrix.md +++ b/docs/ja/feature_led_matrix.md @@ -52,7 +52,7 @@ I2C IS31FL3731 RGB コントローラを使ったアドレス指定可能な LED `.c` に全ての LED を列挙する配列を定義します: - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* これらの位置については IS31 マニュアルを参照してください * driver * | LED address diff --git a/drivers/led/aw20216.h b/drivers/led/aw20216.h index c55d9605fc..97ac6dc5bf 100644 --- a/drivers/led/aw20216.h +++ b/drivers/led/aw20216.h @@ -18,6 +18,7 @@ #include #include +#include "progmem.h" #include "gpio.h" typedef struct aw_led { @@ -27,7 +28,7 @@ typedef struct aw_led { uint8_t b; } aw_led; -extern const aw_led g_aw_leds[DRIVER_LED_TOTAL]; +extern const aw_led __flash g_aw_leds[DRIVER_LED_TOTAL]; void AW20216_init(pin_t cs_pin, pin_t en_pin); void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); diff --git a/drivers/led/issi/is31fl3731-simple.h b/drivers/led/issi/is31fl3731-simple.h index 9665d6ed35..ecde31eed5 100644 --- a/drivers/led/issi/is31fl3731-simple.h +++ b/drivers/led/issi/is31fl3731-simple.h @@ -20,13 +20,14 @@ #include #include +#include "progmem.h" typedef struct is31_led { uint8_t driver : 2; uint8_t v; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3731_init(uint8_t addr); void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3731.h b/drivers/led/issi/is31fl3731.h index 19e8e6251f..803ea3ea12 100644 --- a/drivers/led/issi/is31fl3731.h +++ b/drivers/led/issi/is31fl3731.h @@ -19,6 +19,7 @@ #include #include +#include "progmem.h" typedef struct is31_led { uint8_t driver : 2; @@ -27,7 +28,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3731_init(uint8_t addr); void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3733.h b/drivers/led/issi/is31fl3733.h index 603d505a13..64fd38eb19 100644 --- a/drivers/led/issi/is31fl3733.h +++ b/drivers/led/issi/is31fl3733.h @@ -20,6 +20,7 @@ #include #include +#include "progmem.h" typedef struct is31_led { uint8_t driver : 2; @@ -28,7 +29,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3733_init(uint8_t addr, uint8_t sync); bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3736.h b/drivers/led/issi/is31fl3736.h index e48e31c279..c956c87f7c 100644 --- a/drivers/led/issi/is31fl3736.h +++ b/drivers/led/issi/is31fl3736.h @@ -18,6 +18,7 @@ #include #include +#include "progmem.h" // Simple interface option. // If these aren't defined, just define them to make it compile @@ -37,7 +38,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3736_init(uint8_t addr); void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c index 30906b4840..0bb4ddd425 100644 --- a/drivers/led/issi/is31fl3737.c +++ b/drivers/led/issi/is31fl3737.c @@ -19,7 +19,6 @@ #include "is31fl3737.h" #include "i2c_master.h" #include "wait.h" -#include "progmem.h" // This is a 7-bit address, that gets left-shifted and bit 0 // set to 0 for write, 1 for read (as per I2C protocol) @@ -155,9 +154,7 @@ void IS31FL3737_init(uint8_t addr) { void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { if (index >= 0 && index < DRIVER_LED_TOTAL) { - // copy the led config from progmem to SRAM - is31_led led; - memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + is31_led led = g_is31_leds[index]; g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; @@ -173,9 +170,7 @@ void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { } void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { - // copy the led config from progmem to SRAM - is31_led led; - memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + is31_led led = g_is31_leds[index]; uint8_t control_register_r = led.r / 8; uint8_t control_register_g = led.g / 8; diff --git a/drivers/led/issi/is31fl3737.h b/drivers/led/issi/is31fl3737.h index a1d2281778..06886e9c9b 100644 --- a/drivers/led/issi/is31fl3737.h +++ b/drivers/led/issi/is31fl3737.h @@ -20,6 +20,7 @@ #include #include +#include "progmem.h" typedef struct is31_led { uint8_t driver : 2; @@ -28,7 +29,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3737_init(uint8_t addr); void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3741.h b/drivers/led/issi/is31fl3741.h index 2df0c5b1a7..cea6761ca8 100644 --- a/drivers/led/issi/is31fl3741.h +++ b/drivers/led/issi/is31fl3741.h @@ -21,6 +21,7 @@ #include #include +#include "progmem.h" typedef struct is31_led { uint32_t driver : 2; @@ -29,7 +30,7 @@ typedef struct is31_led { uint32_t b : 10; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3741_init(uint8_t addr); void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/keyboards/clueboard/66_hotswap/gen1/gen1.c b/keyboards/clueboard/66_hotswap/gen1/gen1.c index 339bd78d5a..8e3db70d07 100644 --- a/keyboards/clueboard/66_hotswap/gen1/gen1.c +++ b/keyboards/clueboard/66_hotswap/gen1/gen1.c @@ -16,7 +16,7 @@ #include "gen1.h" #ifdef LED_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | LED address diff --git a/keyboards/dp60/dp60.c b/keyboards/dp60/dp60.c index 475084b049..87543b2a1c 100644 --- a/keyboards/dp60/dp60.c +++ b/keyboards/dp60/dp60.c @@ -17,7 +17,7 @@ #include "dp60.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/durgod/dgk6x/galaxy/galaxy.c b/keyboards/durgod/dgk6x/galaxy/galaxy.c index d101533b16..5f793ed85b 100644 --- a/keyboards/durgod/dgk6x/galaxy/galaxy.c +++ b/keyboards/durgod/dgk6x/galaxy/galaxy.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/durgod/dgk6x/hades/hades.c b/keyboards/durgod/dgk6x/hades/hades.c index 21b2722913..3e235683f1 100644 --- a/keyboards/durgod/dgk6x/hades/hades.c +++ b/keyboards/durgod/dgk6x/hades/hades.c @@ -19,7 +19,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/durgod/dgk6x/venus/venus.c b/keyboards/durgod/dgk6x/venus/venus.c index 2d49b34daf..3398acb19d 100644 --- a/keyboards/durgod/dgk6x/venus/venus.c +++ b/keyboards/durgod/dgk6x/venus/venus.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/dztech/dz60rgb/dz60rgb.c b/keyboards/dztech/dz60rgb/dz60rgb.c index aa02fb902d..a7fc3dbc5c 100644 --- a/keyboards/dztech/dz60rgb/dz60rgb.c +++ b/keyboards/dztech/dz60rgb/dz60rgb.c @@ -1,7 +1,7 @@ #include "dz60rgb.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, K_14, J_14, L_14 }, { 0, K_13, J_13, L_13 }, { 0, K_12, J_12, L_12 }, diff --git a/keyboards/dztech/dz60rgb_ansi/dz60rgb_ansi.c b/keyboards/dztech/dz60rgb_ansi/dz60rgb_ansi.c index 4bb5938b66..ab24410912 100644 --- a/keyboards/dztech/dz60rgb_ansi/dz60rgb_ansi.c +++ b/keyboards/dztech/dz60rgb_ansi/dz60rgb_ansi.c @@ -1,7 +1,7 @@ #include "dz60rgb_ansi.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, K_14, J_14, L_14 }, { 0, K_13, J_13, L_13 }, { 0, K_12, J_12, L_12 }, diff --git a/keyboards/dztech/dz60rgb_wkl/dz60rgb_wkl.c b/keyboards/dztech/dz60rgb_wkl/dz60rgb_wkl.c index b57560bacd..455624471d 100644 --- a/keyboards/dztech/dz60rgb_wkl/dz60rgb_wkl.c +++ b/keyboards/dztech/dz60rgb_wkl/dz60rgb_wkl.c @@ -1,7 +1,7 @@ #include "dz60rgb_wkl.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, H_15, G_15, I_15 }, { 0, K_14, J_14, L_14 }, { 0, K_13, J_13, L_13 }, diff --git a/keyboards/dztech/dz65rgb/v1/v1.c b/keyboards/dztech/dz65rgb/v1/v1.c index 8a3f0e27bf..aabe41c313 100644 --- a/keyboards/dztech/dz65rgb/v1/v1.c +++ b/keyboards/dztech/dz65rgb/v1/v1.c @@ -16,7 +16,7 @@ #include "v1.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, C8_8, C7_8, C6_8 }, { 0, C9_8, C7_7, C6_7 }, { 0, C9_7, C8_7, C6_6 }, diff --git a/keyboards/dztech/dz65rgb/v2/v2.c b/keyboards/dztech/dz65rgb/v2/v2.c index 788709d989..dce167c73f 100644 --- a/keyboards/dztech/dz65rgb/v2/v2.c +++ b/keyboards/dztech/dz65rgb/v2/v2.c @@ -16,7 +16,7 @@ #include "v2.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, C8_8, C7_8, C6_8 }, { 0, C9_8, C7_7, C6_7 }, { 0, C9_7, C8_7, C6_6 }, diff --git a/keyboards/dztech/dz65rgb/v3/v3.c b/keyboards/dztech/dz65rgb/v3/v3.c index dec75814ca..c3719bfa51 100755 --- a/keyboards/dztech/dz65rgb/v3/v3.c +++ b/keyboards/dztech/dz65rgb/v3/v3.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS21_SW1, CS20_SW1, CS19_SW1}, {0, CS21_SW2, CS20_SW2, CS19_SW2}, {0, CS21_SW3, CS20_SW3, CS19_SW3}, diff --git a/keyboards/ergodox_ez/ergodox_ez.c b/keyboards/ergodox_ez/ergodox_ez.c index 47dd1b0cc9..7af76cb624 100644 --- a/keyboards/ergodox_ez/ergodox_ez.c +++ b/keyboards/ergodox_ez/ergodox_ez.c @@ -243,7 +243,7 @@ const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = { #ifdef RGB_MATRIX_ENABLE // clang-format off -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* driver * | R location * | | G location diff --git a/keyboards/ergodox_infinity/ergodox_infinity.c b/keyboards/ergodox_infinity/ergodox_infinity.c index 76cbca07f8..90aa522427 100644 --- a/keyboards/ergodox_infinity/ergodox_infinity.c +++ b/keyboards/ergodox_infinity/ergodox_infinity.c @@ -191,7 +191,7 @@ const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = { #endif #ifdef LED_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { // The numbers in the comments are the led numbers DXX on the PCB /* Refer to IS31 manual for these locations * driver diff --git a/keyboards/exclusive/e6_rgb/e6_rgb.c b/keyboards/exclusive/e6_rgb/e6_rgb.c index 0e248a2023..e0d313f835 100644 --- a/keyboards/exclusive/e6_rgb/e6_rgb.c +++ b/keyboards/exclusive/e6_rgb/e6_rgb.c @@ -11,7 +11,7 @@ void matrix_init_kb(void) { matrix_init_user(); } -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/fallacy/indicators.c b/keyboards/fallacy/indicators.c index 08c500064d..dcf1b4de07 100755 --- a/keyboards/fallacy/indicators.c +++ b/keyboards/fallacy/indicators.c @@ -54,7 +54,7 @@ void set_fallacy_led(int index, bool state) { /* define LED matrix */ -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C1_1}, {0, C2_1}, {0, C3_1}, diff --git a/keyboards/geekboards/tester/tester.c b/keyboards/geekboards/tester/tester.c index 4fab1a7012..0c5c056cc0 100644 --- a/keyboards/geekboards/tester/tester.c +++ b/keyboards/geekboards/tester/tester.c @@ -1,5 +1,5 @@ #include "tester.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/hs60/v1/v1.c b/keyboards/hs60/v1/v1.c index 70c1c2128e..58b19b6408 100644 --- a/keyboards/hs60/v1/v1.c +++ b/keyboards/hs60/v1/v1.c @@ -91,7 +91,7 @@ void raw_hid_receive( uint8_t *data, uint8_t length ) #ifdef HS60_ANSI -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -199,7 +199,7 @@ led_config_t g_led_config = { { #else -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/inett_studio/sqx/hotswap/hotswap.c b/keyboards/inett_studio/sqx/hotswap/hotswap.c index be8985c87e..5b3c8df822 100644 --- a/keyboards/inett_studio/sqx/hotswap/hotswap.c +++ b/keyboards/inett_studio/sqx/hotswap/hotswap.c @@ -20,7 +20,7 @@ #include "hotswap.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/inett_studio/sqx/universal/universal.c b/keyboards/inett_studio/sqx/universal/universal.c index 42d99330d5..dd431a7f45 100644 --- a/keyboards/inett_studio/sqx/universal/universal.c +++ b/keyboards/inett_studio/sqx/universal/universal.c @@ -20,7 +20,7 @@ #include "universal.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/k_type/is31fl3733-dual.h b/keyboards/k_type/is31fl3733-dual.h index 272bcdc417..aab170a3fd 100644 --- a/keyboards/k_type/is31fl3733-dual.h +++ b/keyboards/k_type/is31fl3733-dual.h @@ -28,7 +28,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; void IS31FL3733_init(uint8_t bus, uint8_t addr, uint8_t sync); bool IS31FL3733_write_register(uint8_t index, uint8_t addr, uint8_t reg, uint8_t data); diff --git a/keyboards/k_type/k_type.c b/keyboards/k_type/k_type.c index 61c5881454..924862277f 100644 --- a/keyboards/k_type/k_type.c +++ b/keyboards/k_type/k_type.c @@ -23,7 +23,7 @@ along with this program. If not, see . #include "is31fl3733-dual.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, B_1, A_1, C_1 }, { 0, B_2, A_2, C_2 }, { 0, B_3, A_3, C_3 }, diff --git a/keyboards/kbdfans/bella/rgb/rgb.c b/keyboards/kbdfans/bella/rgb/rgb.c index e197d9b538..17cf992146 100644 --- a/keyboards/kbdfans/bella/rgb/rgb.c +++ b/keyboards/kbdfans/bella/rgb/rgb.c @@ -15,7 +15,7 @@ */ #include "rgb.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS18_SW1, CS17_SW1, CS16_SW1}, /* RGB6 */ {0, CS18_SW3, CS17_SW3, CS16_SW3}, /* RGB32 */ {0, CS18_SW4, CS17_SW4, CS16_SW4}, /* RGB45 */ diff --git a/keyboards/kbdfans/bella/rgb_iso/rgb_iso.c b/keyboards/kbdfans/bella/rgb_iso/rgb_iso.c index 1a853ac8af..0c431b1543 100644 --- a/keyboards/kbdfans/bella/rgb_iso/rgb_iso.c +++ b/keyboards/kbdfans/bella/rgb_iso/rgb_iso.c @@ -15,7 +15,7 @@ */ #include "rgb_iso.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS18_SW1, CS17_SW1, CS16_SW1}, /* RGB6 */ {0, CS18_SW3, CS17_SW3, CS16_SW3}, /* RGB32 */ {0, CS18_SW4, CS17_SW4, CS16_SW4}, /* RGB45 */ diff --git a/keyboards/kbdfans/kbd67/mkiirgb/mkiirgb.c b/keyboards/kbdfans/kbd67/mkiirgb/mkiirgb.c index 323cb23848..2826c08988 100644 --- a/keyboards/kbdfans/kbd67/mkiirgb/mkiirgb.c +++ b/keyboards/kbdfans/kbd67/mkiirgb/mkiirgb.c @@ -1,6 +1,6 @@ #include "mkiirgb.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C8_8, C7_8, C6_8}, // LA17 {0, C9_8, C7_7, C6_7}, // LA16 diff --git a/keyboards/kbdfans/kbdmini/kbdmini.c b/keyboards/kbdfans/kbdmini/kbdmini.c index 0e0df2f9af..799803c6fa 100644 --- a/keyboards/kbdfans/kbdmini/kbdmini.c +++ b/keyboards/kbdfans/kbdmini/kbdmini.c @@ -1,6 +1,6 @@ #include "kbdmini.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, B_9, A_9, C_9 }, //LA33 { 0, B_10, A_10, C_10 }, //LA37 { 0, B_11, A_11, C_11 }, //LA41 diff --git a/keyboards/kbdfans/maja/maja.c b/keyboards/kbdfans/maja/maja.c index a0afcbda8a..9619a84b48 100755 --- a/keyboards/kbdfans/maja/maja.c +++ b/keyboards/kbdfans/maja/maja.c @@ -1,6 +1,6 @@ #include "maja.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C2_1, C3_1, C4_1}, // LA0 {0, C1_1, C3_2, C4_2}, // LA1 {0, C1_2, C2_2, C4_3}, // LA2 diff --git a/keyboards/keychron/q1/q1.c b/keyboards/keychron/q1/q1.c index 520e6e4c57..6beb96e7eb 100644 --- a/keyboards/keychron/q1/q1.c +++ b/keyboards/keychron/q1/q1.c @@ -33,7 +33,7 @@ bool dip_switch_update_kb(uint8_t index, bool active) { return true; } -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/latin17rgb/latin17rgb.c b/keyboards/latin17rgb/latin17rgb.c index 8d9eaae8ae..f7bbe125c2 100644 --- a/keyboards/latin17rgb/latin17rgb.c +++ b/keyboards/latin17rgb/latin17rgb.c @@ -17,7 +17,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/latin60rgb/latin60rgb.c b/keyboards/latin60rgb/latin60rgb.c index cdd6fed44d..fe5d2eea8f 100644 --- a/keyboards/latin60rgb/latin60rgb.c +++ b/keyboards/latin60rgb/latin60rgb.c @@ -16,7 +16,7 @@ #include "latin60rgb.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, K_13, J_13, L_13 }, { 0, K_12, J_12, L_12 }, { 0, K_11, J_11, L_11 }, diff --git a/keyboards/latin6rgb/latin6rgb.c b/keyboards/latin6rgb/latin6rgb.c index 76b39c86bb..9ea4721ecb 100644 --- a/keyboards/latin6rgb/latin6rgb.c +++ b/keyboards/latin6rgb/latin6rgb.c @@ -17,7 +17,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/matrix/m20add/rgb_ring.c b/keyboards/matrix/m20add/rgb_ring.c index fa70dea7eb..3a8af7cd3b 100644 --- a/keyboards/matrix/m20add/rgb_ring.c +++ b/keyboards/matrix/m20add/rgb_ring.c @@ -30,7 +30,7 @@ #endif // rgb ring leds setting -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/matrix/noah/noah.c b/keyboards/matrix/noah/noah.c index 1e2f4bb7d9..6b624b9e09 100644 --- a/keyboards/matrix/noah/noah.c +++ b/keyboards/matrix/noah/noah.c @@ -66,7 +66,7 @@ __attribute__((weak)) void matrix_scan_user(void) { } #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/mechlovin/adelais/rgb_led/rev2/rev2.c b/keyboards/mechlovin/adelais/rgb_led/rev2/rev2.c index 5087174b96..fe946169a7 100644 --- a/keyboards/mechlovin/adelais/rgb_led/rev2/rev2.c +++ b/keyboards/mechlovin/adelais/rgb_led/rev2/rev2.c @@ -17,7 +17,7 @@ #include "adelais.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C2_1, C3_1, C4_1}, //D102-A0-0 {0, C5_1, C6_1, C7_1}, //D108-A1-1 diff --git a/keyboards/mechlovin/delphine/rgb_led/rgb_led.c b/keyboards/mechlovin/delphine/rgb_led/rgb_led.c index 6f3e3ec731..29b6d1f783 100644 --- a/keyboards/mechlovin/delphine/rgb_led/rgb_led.c +++ b/keyboards/mechlovin/delphine/rgb_led/rgb_led.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { // left CA {0, C5_2, C6_2, C7_2}, //D2-0 {0, C1_1, C3_2, C4_2}, //D20-1 diff --git a/keyboards/mechlovin/hannah60rgb/rev2/rev2.c b/keyboards/mechlovin/hannah60rgb/rev2/rev2.c index 05469a1bbe..8b30538cc2 100644 --- a/keyboards/mechlovin/hannah60rgb/rev2/rev2.c +++ b/keyboards/mechlovin/hannah60rgb/rev2/rev2.c @@ -17,7 +17,7 @@ #include "rev2.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/mechlovin/infinity87/rgb_rev1/rgb_rev1.c b/keyboards/mechlovin/infinity87/rgb_rev1/rgb_rev1.c index f13fee8add..bd1fd8abf7 100644 --- a/keyboards/mechlovin/infinity87/rgb_rev1/rgb_rev1.c +++ b/keyboards/mechlovin/infinity87/rgb_rev1/rgb_rev1.c @@ -17,7 +17,7 @@ #include "rgb_rev1.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS34_SW1, CS35_SW1, CS36_SW1}, //D92-K00-0 {0, CS37_SW1, CS38_SW1, CS39_SW1}, //D94-K01-1 {0, CS31_SW1, CS32_SW1, CS33_SW1}, //D96-K02-2 diff --git a/keyboards/melgeek/mj61/rev1/rev1.c b/keyboards/melgeek/mj61/rev1/rev1.c index be58f57a95..e51c57548f 100644 --- a/keyboards/melgeek/mj61/rev1/rev1.c +++ b/keyboards/melgeek/mj61/rev1/rev1.c @@ -17,7 +17,7 @@ #include "mj61.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS12_SW1, CS11_SW1, CS10_SW1}, /* RGB1 */ {0, CS12_SW2, CS11_SW2, CS10_SW2}, /* RGB2 */ {0, CS12_SW3, CS11_SW3, CS10_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/mj61/rev2/rev2.c b/keyboards/melgeek/mj61/rev2/rev2.c index 236b003972..3f6b1bff77 100644 --- a/keyboards/melgeek/mj61/rev2/rev2.c +++ b/keyboards/melgeek/mj61/rev2/rev2.c @@ -19,7 +19,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB3 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB4 */ diff --git a/keyboards/melgeek/mj63/rev1/rev1.c b/keyboards/melgeek/mj63/rev1/rev1.c index 34ff28d25f..a6ee8859b0 100644 --- a/keyboards/melgeek/mj63/rev1/rev1.c +++ b/keyboards/melgeek/mj63/rev1/rev1.c @@ -19,7 +19,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB2 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/mj63/rev2/rev2.c b/keyboards/melgeek/mj63/rev2/rev2.c index c2379dabe9..8cacc689ae 100644 --- a/keyboards/melgeek/mj63/rev2/rev2.c +++ b/keyboards/melgeek/mj63/rev2/rev2.c @@ -19,7 +19,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB3 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB4 */ diff --git a/keyboards/melgeek/mj64/rev1/rev1.c b/keyboards/melgeek/mj64/rev1/rev1.c index e01765b694..446ba779d0 100644 --- a/keyboards/melgeek/mj64/rev1/rev1.c +++ b/keyboards/melgeek/mj64/rev1/rev1.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB2 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/mj64/rev2/rev2.c b/keyboards/melgeek/mj64/rev2/rev2.c index d5486b9086..444e8f60ac 100644 --- a/keyboards/melgeek/mj64/rev2/rev2.c +++ b/keyboards/melgeek/mj64/rev2/rev2.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB2 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/mj64/rev3/rev3.c b/keyboards/melgeek/mj64/rev3/rev3.c index 03ed9fe007..2a1283ec70 100644 --- a/keyboards/melgeek/mj64/rev3/rev3.c +++ b/keyboards/melgeek/mj64/rev3/rev3.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB3 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB4 */ diff --git a/keyboards/melgeek/mj65/rev3/rev3.c b/keyboards/melgeek/mj65/rev3/rev3.c index 43fae53a36..6335edd796 100644 --- a/keyboards/melgeek/mj65/rev3/rev3.c +++ b/keyboards/melgeek/mj65/rev3/rev3.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS9_SW1, CS8_SW1, CS7_SW1}, /* RGB1 */ {0, CS9_SW2, CS8_SW2, CS7_SW2}, /* RGB2 */ {0, CS9_SW3, CS8_SW3, CS7_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/mojo75/rev1/rev1.c b/keyboards/melgeek/mojo75/rev1/rev1.c index 670116fcd6..07ae916da2 100644 --- a/keyboards/melgeek/mojo75/rev1/rev1.c +++ b/keyboards/melgeek/mojo75/rev1/rev1.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS6_SW1, CS5_SW1, CS4_SW1}, /* RGB1 */ {0, CS6_SW2, CS5_SW2, CS4_SW2}, /* RGB2 */ {0, CS6_SW3, CS5_SW3, CS4_SW3}, /* RGB3 */ diff --git a/keyboards/melgeek/z70ultra/z70ultra.c b/keyboards/melgeek/z70ultra/z70ultra.c index 740720681a..552576cd7c 100644 --- a/keyboards/melgeek/z70ultra/z70ultra.c +++ b/keyboards/melgeek/z70ultra/z70ultra.c @@ -18,7 +18,7 @@ #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, CS28_SW1, CS30_SW1, CS29_SW1}, /* RGB10 */ {0, CS28_SW2, CS30_SW2, CS29_SW2}, /* RGB11 */ {0, CS28_SW3, CS30_SW3, CS29_SW3}, /* RGB12 */ diff --git a/keyboards/miller/gm862/gm862.c b/keyboards/miller/gm862/gm862.c index 5af66dd398..d67104838b 100644 --- a/keyboards/miller/gm862/gm862.c +++ b/keyboards/miller/gm862/gm862.c @@ -1,7 +1,7 @@ #include "gm862.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, B_1, A_1, C_1}, {0, B_2, A_2, C_2}, {0, B_3, A_3, C_3}, diff --git a/keyboards/moonlander/moonlander.c b/keyboards/moonlander/moonlander.c index d66b74d973..8688b9efa4 100644 --- a/keyboards/moonlander/moonlander.c +++ b/keyboards/moonlander/moonlander.c @@ -203,7 +203,7 @@ layer_state_t layer_state_set_kb(layer_state_t state) { #ifdef RGB_MATRIX_ENABLE // clang-format off -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/mt64rgb/mt64rgb.c b/keyboards/mt64rgb/mt64rgb.c index 73f0e562e7..a0b8e8da71 100644 --- a/keyboards/mt64rgb/mt64rgb.c +++ b/keyboards/mt64rgb/mt64rgb.c @@ -16,7 +16,7 @@ #include "mt64rgb.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/mt84/mt84.c b/keyboards/mt84/mt84.c index e15a1ff951..9b00aa635e 100644 --- a/keyboards/mt84/mt84.c +++ b/keyboards/mt84/mt84.c @@ -16,7 +16,7 @@ #include "mt84.h" #ifdef RGB_MATRIX_ENABLE -const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/opendeck/32/rev1/rev1.c b/keyboards/opendeck/32/rev1/rev1.c index 297af907e2..91f59a60b7 100644 --- a/keyboards/opendeck/32/rev1/rev1.c +++ b/keyboards/opendeck/32/rev1/rev1.c @@ -17,7 +17,7 @@ #include "rev1.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/planck/ez/ez.c b/keyboards/planck/ez/ez.c index 5c68726a01..27cb2a1d1d 100644 --- a/keyboards/planck/ez/ez.c +++ b/keyboards/planck/ez/ez.c @@ -21,7 +21,7 @@ keyboard_config_t keyboard_config; #ifdef RGB_MATRIX_ENABLE -const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/planck/light/light.c b/keyboards/planck/light/light.c index 896ec44587..3a53e39985 100644 --- a/keyboards/planck/light/light.c +++ b/keyboards/planck/light/light.c @@ -16,7 +16,7 @@ #include "light.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/terrazzo/terrazzo.c b/keyboards/terrazzo/terrazzo.c index e6ba1f6c39..19ac6be491 100644 --- a/keyboards/terrazzo/terrazzo.c +++ b/keyboards/terrazzo/terrazzo.c @@ -21,7 +21,7 @@ #include "print.h" #include "quantum.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * https://cdn-learn.adafruit.com/downloads/pdf/adafruit-15x7-7x15-charlieplex-led-matrix-charliewing-featherwing.pdf */ diff --git a/keyboards/tkc/portico/portico.c b/keyboards/tkc/portico/portico.c index a65a85d242..e3d3a14880 100644 --- a/keyboards/tkc/portico/portico.c +++ b/keyboards/tkc/portico/portico.c @@ -19,7 +19,7 @@ along with this program. If not, see . #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { { 0, C2_1, C3_1, C4_1 }, { 0, C1_1, C3_2, C4_2 }, { 0, C1_2, C2_2, C4_3 }, diff --git a/keyboards/whitefox/whitefox.c b/keyboards/whitefox/whitefox.c index f10f0fd5c4..b17af15127 100644 --- a/keyboards/whitefox/whitefox.c +++ b/keyboards/whitefox/whitefox.c @@ -18,7 +18,7 @@ along with this program. If not, see . #include "whitefox.h" #ifdef LED_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { // The numbers in the comments are the led numbers DXX on the PCB /* Refer to IS31 manual for these locations * driver diff --git a/keyboards/wilba_tech/wt_rgb_backlight.c b/keyboards/wilba_tech/wt_rgb_backlight.c index e0359daab4..77613a3338 100644 --- a/keyboards/wilba_tech/wt_rgb_backlight.c +++ b/keyboards/wilba_tech/wt_rgb_backlight.c @@ -158,7 +158,7 @@ uint32_t g_any_key_hit = 0; // ADDR_2 is not needed. it is here as a dummy #define ISSI_ADDR_1 0x50 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -239,7 +239,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_1 0x50 #define ISSI_ADDR_2 0x52 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -382,7 +382,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { // set to 0 for write, 1 for read (as per I2C protocol) #define ISSI_ADDR_1 0x74 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -414,7 +414,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_2 0x76 // 11101[10] <- SDA #define ISSI_ADDR_3 0x75 // 11101[01] <- SCL -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -541,7 +541,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_1 0x74 #define ISSI_ADDR_2 0x76 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -622,7 +622,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_1 0x74 #define ISSI_ADDR_2 0x77 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -709,7 +709,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_1 0x74 #define ISSI_ADDR_2 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C1_9, C3_10, C4_10}, // LB1 {0, C1_10, C2_10, C4_11}, // LB2 {0, C1_11, C2_11, C3_11}, // LB3 @@ -729,7 +729,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { #define ISSI_ADDR_1 0x74 #define ISSI_ADDR_2 0x76 -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/xbows/knight/knight.c b/keyboards/xbows/knight/knight.c index 1a1aebf18f..539ecb653e 100644 --- a/keyboards/xbows/knight/knight.c +++ b/keyboards/xbows/knight/knight.c @@ -15,7 +15,7 @@ */ #include "knight.h" #ifdef RGB_MATRIX_ENABLE - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C1_3, C2_3, C3_3}, // L01 {0, C1_4, C2_4, C3_4}, // L02 diff --git a/keyboards/xbows/knight_plus/knight_plus.c b/keyboards/xbows/knight_plus/knight_plus.c index f2cf5399b6..c5dd1a5fd6 100644 --- a/keyboards/xbows/knight_plus/knight_plus.c +++ b/keyboards/xbows/knight_plus/knight_plus.c @@ -15,7 +15,7 @@ */ #include "knight_plus.h" #ifdef RGB_MATRIX_ENABLE - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C1_3, C2_3, C3_3}, // L01 {0, C1_4, C2_4, C3_4}, // L02 diff --git a/keyboards/xbows/nature/nature.c b/keyboards/xbows/nature/nature.c index f1b0615845..b7b10d5abb 100644 --- a/keyboards/xbows/nature/nature.c +++ b/keyboards/xbows/nature/nature.c @@ -15,7 +15,7 @@ */ #include "nature.h" #ifdef RGB_MATRIX_ENABLE - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C1_3, C2_3, C3_3}, // L01 {0, C1_4, C2_4, C3_4}, // L02 diff --git a/keyboards/xbows/numpad/numpad.c b/keyboards/xbows/numpad/numpad.c index 0ab677c769..4e05473b67 100644 --- a/keyboards/xbows/numpad/numpad.c +++ b/keyboards/xbows/numpad/numpad.c @@ -15,7 +15,7 @@ */ #include "numpad.h" #ifdef RGB_MATRIX_ENABLE - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C3_3, C2_3, C1_3}, // L01 {0, C3_4, C2_4, C1_4}, // L02 diff --git a/keyboards/xbows/woody/woody.c b/keyboards/xbows/woody/woody.c index 9821f5f655..1027e3ca37 100644 --- a/keyboards/xbows/woody/woody.c +++ b/keyboards/xbows/woody/woody.c @@ -1,6 +1,6 @@ #include "woody.h" #ifdef RGB_MATRIX_ENABLE -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { {0, C8_8, C7_8, C6_8}, // LA17 {0, C9_8, C7_7, C6_7}, // LA16 diff --git a/keyboards/xelus/dawn60/rev1_qmk/rev1_qmk.c b/keyboards/xelus/dawn60/rev1_qmk/rev1_qmk.c index c305ecae14..c6ddef0931 100644 --- a/keyboards/xelus/dawn60/rev1_qmk/rev1_qmk.c +++ b/keyboards/xelus/dawn60/rev1_qmk/rev1_qmk.c @@ -25,7 +25,7 @@ #ifdef RGB_MATRIX_ENABLE LED_TYPE rgb_matrix_ws2812_array[WS2812_LED_TOTAL]; -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/keyboards/xelus/pachi/rgb/rgb.c b/keyboards/xelus/pachi/rgb/rgb.c index ea9812d6b1..6f44b13e12 100644 --- a/keyboards/xelus/pachi/rgb/rgb.c +++ b/keyboards/xelus/pachi/rgb/rgb.c @@ -24,7 +24,7 @@ void matrix_io_delay(void) { __asm__ volatile("nop\nnop\nnop\n"); } #ifdef RGB_MATRIX_ENABLE #include #include "drivers/led/issi/is31fl3741.h" -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location diff --git a/tmk_core/common/progmem.h b/tmk_core/common/progmem.h index 3a7a169682..a70d8e299f 100644 --- a/tmk_core/common/progmem.h +++ b/tmk_core/common/progmem.h @@ -5,6 +5,7 @@ #else # include # define PROGMEM +# define __flash # define PSTR(x) x # define PGM_P const char* # define memcpy_P(dest, src, n) memcpy(dest, src, n) -- cgit v1.3.1