WS2812 Overhaul (#210)

* ARM - ws2812 bitbang (#7173)

* Initial ARM bitbang ws2812 driver

* Unify chibios platform to run rgblight_task

* Remove 'avr only' comments from ws2812 docs

* Remove 'avr only' comments from ws2812 docs

* Unify chibios platform to run rgblight_task - review comments

* Remove debug flags from keymap

* Add comments from review

* Add defines for STM32L0XX

* Attempt to get arm ws2812 working on multiple gcc versions

* Support RGBLIGHT_SLEEP when ChibiOS boards suspend (#7280)

Copypasta from the AVR suspend implementation with a Teensy-specific
hack removed

* Unify RGB and RGBW commands (#7297)

* Fix unicode in comments

Co-Authored-By: fauxpark <fauxpark@gmail.com>

* Remove separate RGBW implementation for a unified function

* Set White to 0 in RGBW LEDs

This is just to get this working, later, proper brightness can be handled elsewhere.

* Use us instead of nanoseconds(?) since it renders correctly on web

* Remove RGBW function from arm/ws2812.h

* Remove RGBW function from arm/ws2812.c

* Formatting changes

* Add doc info

* Remove force of debug on within rgblight - causes lockups waiting for hid_listen (#7330)

* Move Ergodox EZ RGB Light code to custom driver  (#7309)

* Move Ergodox EZ RGB code to custom driver

Also implements full addressing of Ergodox EZ's LED Strip, as written by seebs
Co-authored-by: Seebs <seebs@seebs.net>

* Make Clipping range accessible for custom drivers

* Remove RGBW_BB_TWI from driver and docs

* Revert changes to clipping range support

* Use just rgblight_set instead of full custom driver

* Convert to i2c_master commands

* Rename rgblight driver and clean up includes

* Use White channel on RGBW LEDs

* SPI DMA based RGB Underglow for STM32 (#7674)

* Initial stash of ws2812 spi driver

* Update comment, add sync backup plan

* Add testing notes to spi ws2812 driver

* Align RGBW error messages

Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Jonathan Rascher <jon@bcat.name>
Co-authored-by: Florian Didron <fdidron@users.noreply.github.com>
This commit is contained in:
Drashna Jaelre
2020-01-05 19:04:55 -08:00
committed by Florian Didron
parent 81126b6673
commit df91396be9
17 changed files with 426 additions and 164 deletions

View File

@@ -1 +1,95 @@
#error("NOT SUPPORTED") #include "quantum.h"
#include "ws2812.h"
#include "ch.h"
#include "hal.h"
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
#ifndef NOP_FUDGE
# if defined(STM32F1XX) || defined(STM32F1xx) || defined(STM32F0XX) || defined(STM32F0xx) || defined(STM32F3XX) || defined(STM32F3xx) || defined(STM32L0XX) || defined(STM32L0xx)
# define NOP_FUDGE 0.4
# else
# error("NOP_FUDGE configuration required")
# define NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
# endif
#endif
#define NUMBER_NOPS 6
#define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE)
#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
#define wait_ns(x) \
do { \
for (int i = 0; i < NS_TO_CYCLES(x); i++) { \
__asm__ volatile("nop\n\t" \
"nop\n\t" \
"nop\n\t" \
"nop\n\t" \
"nop\n\t" \
"nop\n\t"); \
} \
} while (0)
// These are the timing constraints taken mostly from the WS2812 datasheets
// These are chosen to be conservative and avoid problems rather than for maximum throughput
#define T1H 900 // Width of a 1 bit in ns
#define T1L (1250 - T1H) // Width of a 1 bit in ns
#define T0H 350 // Width of a 0 bit in ns
#define T0L (1250 - T0H) // Width of a 0 bit in ns
// The reset gap can be 6000 ns, but depending on the LED strip it may have to be increased
// to values like 600000 ns. If it is too small, the pixels will show nothing most of the time.
#define RES 10000 // Width of the low gap between bits to cause a frame to latch
void sendByte(uint8_t byte) {
// WS2812 protocol wants most significant bits first
for (unsigned char bit = 0; bit < 8; bit++) {
bool is_one = byte & (1 << (7 - bit));
// using something like wait_ns(is_one ? T1L : T0L) here throws off timings
if (is_one) {
// 1
writePinHigh(RGB_DI_PIN);
wait_ns(T1H);
writePinLow(RGB_DI_PIN);
wait_ns(T1L);
} else {
// 0
writePinHigh(RGB_DI_PIN);
wait_ns(T0H);
writePinLow(RGB_DI_PIN);
wait_ns(T0L);
}
}
}
void ws2812_init(void) { setPinOutput(RGB_DI_PIN); }
// Setleds for standard RGB
void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
static bool s_init = false;
if (!s_init) {
ws2812_init();
s_init = true;
}
// this code is very time dependent, so we need to disable interrupts
chSysLock();
for (uint8_t i = 0; i < leds; i++) {
// WS2812 protocol dictates grb order
sendByte(ledarray[i].g);
sendByte(ledarray[i].r);
sendByte(ledarray[i].b);
#ifdef RGBW
sendByte(ledarray[i].w);
#endif
}
wait_ns(RES);
chSysUnlock();
}

16
drivers/arm/ws2812.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "quantum/color.h"
/* User Interface
*
* Input:
* ledarray: An array of GRB data describing the LED colors
* number_of_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
* - Wait 50us to reset the LEDs
*/
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds);

View File

@@ -1 +1,90 @@
#error("NOT SUPPORTED") #include "quantum.h"
#include "ws2812.h"
/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */
#ifdef RGBW
# error "RGBW not supported"
#endif
// Define the spi your LEDs are plugged to here
#ifndef WS2812_SPI
# define WS2812_SPI SPID1
#endif
#ifndef WS2812_SPI_MOSI_PAL_MODE
# define WS2812_SPI_MOSI_PAL_MODE 5
#endif
#define BYTES_FOR_LED_BYTE 4
#define NB_COLORS 3
#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM)
#define RESET_SIZE 200
#define PREAMBLE_SIZE 4
static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE] = {0};
/*
* As the trick here is to use the SPI to send a huge pattern of 0 and 1 to
* the ws2812b protocol, we use this helper function to translate bytes into
* 0s and 1s for the LED (with the appropriate timing).
*/
static uint8_t get_protocol_eq(uint8_t data, int pos) {
uint8_t eq = 0;
if (data & (1 << (2 * (3 - pos))))
eq = 0b1110;
else
eq = 0b1000;
if (data & (2 << (2 * (3 - pos))))
eq += 0b11100000;
else
eq += 0b10000000;
return eq;
}
static void set_led_color_rgb(LED_TYPE color, int pos) {
uint8_t* tx_start = &txbuf[PREAMBLE_SIZE];
for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j);
for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j);
for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
}
void ws2812_init(void) {
#if defined(USE_GPIOV1)
palSetLineMode(RGB_DI_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
#else
palSetLineMode(RGB_DI_PIN, PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL);
#endif
// TODO: more dynamic baudrate
static const SPIConfig spicfg = {
NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
SPI_CR1_BR_1 | SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
};
spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
spiSelect(&WS2812_SPI); /* Slave Select assertion. */
}
void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
static bool s_init = false;
if (!s_init) {
ws2812_init();
s_init = true;
}
for (uint8_t i = 0; i < leds; i++) {
set_led_color_rgb(ledarray[i], i);
}
// Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
// Instead spiSend can be used to send synchronously (or the thread logic can be added back).
#ifdef WS2812_SPI_SYNC
spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
#else
spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
#endif
}

View File

@@ -36,109 +36,6 @@
void ws2812_sendarray(uint8_t *array, uint16_t length); void ws2812_sendarray(uint8_t *array, uint16_t length);
void ws2812_sendarray_mask(uint8_t *array, uint16_t length, uint8_t pinmask); void ws2812_sendarray_mask(uint8_t *array, uint16_t length, uint8_t pinmask);
#ifdef RGBW_BB_TWI
// Port for the I2C
# define I2C_DDR DDRD
# define I2C_PIN PIND
# define I2C_PORT PORTD
// Pins to be used in the bit banging
# define I2C_CLK 0
# define I2C_DAT 1
# define I2C_DATA_HI() \
I2C_DDR &= ~(1 << I2C_DAT); \
I2C_PORT |= (1 << I2C_DAT);
# define I2C_DATA_LO() \
I2C_DDR |= (1 << I2C_DAT); \
I2C_PORT &= ~(1 << I2C_DAT);
# define I2C_CLOCK_HI() \
I2C_DDR &= ~(1 << I2C_CLK); \
I2C_PORT |= (1 << I2C_CLK);
# define I2C_CLOCK_LO() \
I2C_DDR |= (1 << I2C_CLK); \
I2C_PORT &= ~(1 << I2C_CLK);
# define I2C_DELAY 1
void I2C_WriteBit(unsigned char c) {
if (c > 0) {
I2C_DATA_HI();
} else {
I2C_DATA_LO();
}
I2C_CLOCK_HI();
_delay_us(I2C_DELAY);
I2C_CLOCK_LO();
_delay_us(I2C_DELAY);
if (c > 0) {
I2C_DATA_LO();
}
_delay_us(I2C_DELAY);
}
// Inits bitbanging port, must be called before using the functions below
//
void I2C_Init(void) {
I2C_PORT &= ~((1 << I2C_DAT) | (1 << I2C_CLK));
I2C_CLOCK_HI();
I2C_DATA_HI();
_delay_us(I2C_DELAY);
}
// Send a START Condition
//
void I2C_Start(void) {
// set both to high at the same time
I2C_DDR &= ~((1 << I2C_DAT) | (1 << I2C_CLK));
_delay_us(I2C_DELAY);
I2C_DATA_LO();
_delay_us(I2C_DELAY);
I2C_CLOCK_LO();
_delay_us(I2C_DELAY);
}
// Send a STOP Condition
//
void I2C_Stop(void) {
I2C_CLOCK_HI();
_delay_us(I2C_DELAY);
I2C_DATA_HI();
_delay_us(I2C_DELAY);
}
// write a byte to the I2C slave device
//
unsigned char I2C_Write(unsigned char c) {
for (char i = 0; i < 8; i++) {
I2C_WriteBit(c & 128);
c <<= 1;
}
I2C_WriteBit(0);
_delay_us(I2C_DELAY);
_delay_us(I2C_DELAY);
// _delay_us(I2C_DELAY);
// return I2C_ReadBit();
return 0;
}
#endif
// Setleds for standard RGB // Setleds for standard RGB
void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) { void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
// ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
@@ -146,45 +43,15 @@ void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
} }
void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) { void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) {
// ws2812_DDRREG |= pinmask; // Enable DDR
// new universal format (DDR) // new universal format (DDR)
_SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask; _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
ws2812_sendarray_mask((uint8_t *)ledarray, leds + leds + leds, pinmask); ws2812_sendarray_mask((uint8_t *)ledarray, leds * sizeof(LED_TYPE), pinmask);
_delay_us(50);
}
// Setleds for SK6812RGBW #ifdef RGBW
void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) {
#ifdef RGBW_BB_TWI
uint8_t sreg_prev, twcr_prev;
sreg_prev = SREG;
twcr_prev = TWCR;
cli();
TWCR &= ~(1 << TWEN);
I2C_Init();
I2C_Start();
I2C_Write(0x84);
uint16_t datlen = leds << 2;
uint8_t curbyte;
uint8_t *data = (uint8_t *)ledarray;
while (datlen--) {
curbyte = *data++;
I2C_Write(curbyte);
}
I2C_Stop();
SREG = sreg_prev;
TWCR = twcr_prev;
#endif
// ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
// new universal format (DDR)
_SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
ws2812_sendarray_mask((uint8_t *)ledarray, leds << 2, _BV(RGB_DI_PIN & 0xF));
#ifndef RGBW_BB_TWI
_delay_us(80); _delay_us(80);
#else
_delay_us(50);
#endif #endif
} }

View File

@@ -34,8 +34,7 @@
* The functions will perform the following actions: * The functions will perform the following actions:
* - Set the data-out pin as output * - Set the data-out pin as output
* - Send out the LED data * - Send out the LED data
* - Wait 50<EFBFBD>s to reset the LEDs * - Wait 50us to reset the LEDs
*/ */
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds); void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds);
void ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t number_of_leds, uint8_t pinmask); void ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t number_of_leds, uint8_t pinmask);
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);

View File

@@ -1,6 +1,10 @@
#include "ws2812.h" #include "ws2812.h"
#include "i2c_master.h" #include "i2c_master.h"
#ifdef RGBW
# error "RGBW not supported"
#endif
#ifndef WS2812_ADDRESS #ifndef WS2812_ADDRESS
# define WS2812_ADDRESS 0xb0 # define WS2812_ADDRESS 0xb0
#endif #endif
@@ -21,11 +25,3 @@ void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
i2c_transmit(WS2812_ADDRESS, (uint8_t *)ledarray, sizeof(LED_TYPE) * leds, WS2812_TIMEOUT); i2c_transmit(WS2812_ADDRESS, (uint8_t *)ledarray, sizeof(LED_TYPE) * leds, WS2812_TIMEOUT);
} }
// Setleds for SK6812RGBW
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) {
// not supported - for now error out if its enabled
#ifdef RGBW
# error "RGBW not supported"
#endif
}

View File

@@ -74,17 +74,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* ws2812 RGB LED */ /* ws2812 RGB LED */
#define RGB_DI_PIN D7 #define RGB_DI_PIN D7
#define RGBLIGHT_ANIMATIONS #define RGBLIGHT_ANIMATIONS
#define RGBLED_NUM 15 // Number of LEDs
#define RGBLIGHT_HUE_STEP 12 #define RGBLIGHT_HUE_STEP 12
#define RGBLIGHT_SAT_STEP 255 #define RGBLIGHT_SAT_STEP 255
#define RGBLIGHT_VAL_STEP 12 #define RGBLIGHT_VAL_STEP 12
// Pick one of the modes
// Defaults to 15 mirror, for legacy behavior
// #define ERGODOX_LED_15 // Addresses 15 LEDs, but same position on both halves
// #define ERGODOX_LED_15_MIRROR // Addresses 15 LEDs, but are mirrored
// #define ERGODOX_LED_30 // Addresses all 30 LED individually
/* fix space cadet rollover issue */ /* fix space cadet rollover issue */
#define DISABLE_SPACE_CADET_ROLLOVER #define DISABLE_SPACE_CADET_ROLLOVER
#define RGBW_BB_TWI #define RGBW
#define RGBW 1
#define RGBLIGHT_SLEEP #define RGBLIGHT_SLEEP

View File

@@ -0,0 +1,91 @@
/*
* light weight WS2812 lib V2.0b
*
* Controls WS2811/WS2812/WS2812B RGB-LEDs
* Author: Tim (cpldcpu@gmail.com)
*
* Jan 18th, 2014 v2.0b Initial Version
* Nov 29th, 2015 v2.3 Added SK6812RGBW support
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef RGBLIGHT_ENABLE
# include "ws2812.c"
# include "ergodox_ez.h"
extern rgblight_config_t rgblight_config;
/*
* Forward declare internal functions
*
* The functions take a byte-array and send to the data output as WS2812 bitstream.
* The length is the number of bytes to send - three per LED.
*/
void ws2812_sendarray(uint8_t *array, uint16_t length);
void ws2812_sendarray_mask(uint8_t *array, uint16_t length, uint8_t pinmask);
void rgblight_set(void) {
if (!rgblight_config.enable) {
for (uint8_t i = 0; i < RGBLED_NUM; i++) {
led[i].r = 0;
led[i].g = 0;
led[i].b = 0;
#ifdef RGBW
led[i].w = 0;
#endif
}
}
#ifdef RGBW
for (uint8_t i = 0; i < RGBLED_NUM; i++) {
convert_rgb_to_rgbw(&led[i]);
}
#endif
uint8_t led_num = RGBLED_NUM;
i2c_init();
i2c_start(0x84, ERGODOX_EZ_I2C_TIMEOUT);
int i = 0;
# if defined(ERGODOX_LED_30)
// prevent right-half code from trying to bitbang all 30
// so with 30 LEDs, we count from 29 to 15 here, and the
// other half does 0 to 14.
led_num = RGBLED_NUM / 2;
for (i = led_num + led_num - 1; i >= led_num; --i)
# elif defined(ERGODOX_LED_15_MIRROR)
for (i = 0; i < led_num; ++i)
# else // ERGDOX_LED_15 non-mirrored
for (i = led_num - 1; i >= 0; --i)
# endif
{
uint8_t *data = (uint8_t *)(led + i);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
#ifdef RGBW
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
#endif
}
i2c_stop();
ws2812_setleds(led, RGBLED_NUM);
}
#endif // RGBLIGHT_ENABLE

View File

@@ -0,0 +1,20 @@
#pragma once
#if !defined(ERGODOX_LED_15) && !defined(ERGODOX_LED_30)
// if no value is defined, assume previous behavior
// # define ERGODOX_LED_15
// # define ERGODOX_LED_30
# define ERGODOX_LED_15_MIRROR
#endif
#if (defined(ERGODOX_LED_30) + defined(ERGODOX_LED_15) + defined(ERGODOX_LED_15_MIRROR)) != 1
# error "You must only define one of the ERGODOX_LED options."
#endif
#ifdef ERGODOX_LED_30
// If using 30 LEDs, then define that many
# define RGBLED_NUM 30 // Number of LEDs
#else
// If not, then only define 15
# define RGBLED_NUM 15 // Number of LEDs
#endif

View File

@@ -14,10 +14,6 @@
# #
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# # project specific files
SRC += matrix.c
QUANTUM_LIB_SRC += i2c_master.c
# MCU name # MCU name
MCU = atmega32u4 MCU = atmega32u4
@@ -83,7 +79,14 @@ SWAP_HANDS_ENABLE= yes # Allow swapping hands of keyboard
SLEEP_LED_ENABLE = no SLEEP_LED_ENABLE = no
API_SYSEX_ENABLE = no API_SYSEX_ENABLE = no
RGBLIGHT_ENABLE = yes RGBLIGHT_ENABLE = yes
RGBLIGHT_CUSTOM_DRIVER = yes
RGB_MATRIX_ENABLE = no # enable later RGB_MATRIX_ENABLE = no # enable later
DEBOUNCE_TYPE = eager_pr DEBOUNCE_TYPE = eager_pr
# project specific files
SRC += matrix.c \
led_i2c.c
QUANTUM_LIB_SRC += i2c_master.c
LAYOUTS = ergodox LAYOUTS = ergodox

View File

@@ -85,3 +85,18 @@ RGB hsv_to_rgb(HSV hsv) {
return rgb; return rgb;
} }
#ifdef RGBW
#ifndef MIN
# define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
void convert_rgb_to_rgbw(LED_TYPE *led) {
// Determine lowest value in all three colors, put that into
// the white channel and then shift all colors by that amount
led->w = MIN(led->r, MIN(led->g, led->b));
led->r -= led->w;
led->g -= led->w;
led->b -= led->w;
}
#endif

View File

@@ -65,4 +65,8 @@ typedef struct PACKED {
RGB hsv_to_rgb(HSV hsv); RGB hsv_to_rgb(HSV hsv);
#ifdef RGBW
void convert_rgb_to_rgbw(LED_TYPE *led);
#endif
#endif // COLOR_H #endif // COLOR_H

View File

@@ -112,6 +112,9 @@ static inline void setled(int i, uint8_t r, uint8_t g, uint8_t b) {
led[i].r = r; led[i].r = r;
led[i].g = g; led[i].g = g;
led[i].b = b; led[i].b = b;
# ifdef RGBW
convert_rgb_to_rgbw(led[i]);
# endif
} }
static void setled_all(uint8_t r, uint8_t g, uint8_t b) { static void setled_all(uint8_t r, uint8_t g, uint8_t b) {

View File

@@ -126,6 +126,9 @@ void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
(*led1).r = r; (*led1).r = r;
(*led1).g = g; (*led1).g = g;
(*led1).b = b; (*led1).b = b;
#ifdef RGBW
(*led1).w = 0;
#endif
} }
void rgblight_check_config(void) { void rgblight_check_config(void) {
@@ -186,7 +189,6 @@ void rgblight_init(void) {
return; return;
} }
debug_enable = 1; // Debug ON!
dprintf("rgblight_init called.\n"); dprintf("rgblight_init called.\n");
dprintf("rgblight_init start!\n"); dprintf("rgblight_init start!\n");
if (!eeconfig_is_enabled()) { if (!eeconfig_is_enabled()) {
@@ -514,6 +516,9 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
led[i].r = r; led[i].r = r;
led[i].g = g; led[i].g = g;
led[i].b = b; led[i].b = b;
#ifdef RGBW
led[i].w = 0;
#endif
} }
rgblight_set(); rgblight_set();
} }
@@ -526,6 +531,9 @@ void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
led[index].r = r; led[index].r = r;
led[index].g = g; led[index].g = g;
led[index].b = b; led[index].b = b;
#ifdef RGBW
led[index].w = 0;
#endif
rgblight_set(); rgblight_set();
} }
@@ -560,6 +568,9 @@ void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8
led[i].r = r; led[i].r = r;
led[i].g = g; led[i].g = g;
led[i].b = b; led[i].b = b;
#ifdef RGBW
led[i].w = 0;
#endif
} }
rgblight_set(); rgblight_set();
wait_ms(1); wait_ms(1);
@@ -595,6 +606,9 @@ void rgblight_set(void) {
led[i].r = 0; led[i].r = 0;
led[i].g = 0; led[i].g = 0;
led[i].b = 0; led[i].b = 0;
# ifdef RGBW
led[i].w = 0;
# endif
} }
} }
# ifdef RGBLIGHT_LED_MAP # ifdef RGBLIGHT_LED_MAP
@@ -606,11 +620,12 @@ void rgblight_set(void) {
# else # else
start_led = led + clipping_start_pos; start_led = led + clipping_start_pos;
# endif # endif
# ifdef RGBW #ifdef RGBW
ws2812_setleds_rgbw(start_led, num_leds); for (uint8_t i = 0; i < num_leds; i++) {
# else convert_rgb_to_rgbw(&start_led[i]);
}
#endif
ws2812_setleds(start_led, num_leds); ws2812_setleds(start_led, num_leds);
# endif
} }
#endif #endif
@@ -908,6 +923,9 @@ void rgblight_effect_snake(animation_status_t *anim) {
ledp->r = 0; ledp->r = 0;
ledp->g = 0; ledp->g = 0;
ledp->b = 0; ledp->b = 0;
# ifdef RGBW
ledp->w = 0;
# endif
for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
k = pos + j * increment; k = pos + j * increment;
if (k > RGBLED_NUM) { if (k > RGBLED_NUM) {
@@ -965,6 +983,9 @@ void rgblight_effect_knight(animation_status_t *anim) {
led[i].r = 0; led[i].r = 0;
led[i].g = 0; led[i].g = 0;
led[i].b = 0; led[i].b = 0;
# ifdef RGBW
led[i].w = 0;
# endif
} }
// Determine which LEDs should be lit up // Determine which LEDs should be lit up
for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) { for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
@@ -976,6 +997,9 @@ void rgblight_effect_knight(animation_status_t *anim) {
led[cur].r = 0; led[cur].r = 0;
led[cur].g = 0; led[cur].g = 0;
led[cur].b = 0; led[cur].b = 0;
# ifdef RGBW
led[cur].w = 0;
# endif
} }
} }
rgblight_set(); rgblight_set();

View File

@@ -2,10 +2,12 @@
# These are defaults based on what has been implemented for ARM boards # These are defaults based on what has been implemented for ARM boards
AUDIO_ENABLE = yes AUDIO_ENABLE = yes
RGBLIGHT_ENABLE = no WS2812_DRIVER = bitbang
# Force task driven PWM until ARM can provide automatic configuration # Force task driven PWM until ARM can provide automatic configuration
BACKLIGHT_DRIVER = software ifneq ($(strip $(BACKLIGHT_ENABLE)), no)
BACKLIGHT_ENABLE = software
endif
# The rest of these settings shouldn't change # The rest of these settings shouldn't change

View File

@@ -15,6 +15,13 @@
# include "backlight.h" # include "backlight.h"
#endif #endif
#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
# include "rgblight.h"
extern rgblight_config_t rgblight_config;
static bool rgblight_enabled;
static bool is_suspended;
#endif
/** \brief suspend idle /** \brief suspend idle
* *
* FIXME: needs doc * FIXME: needs doc
@@ -43,6 +50,16 @@ void suspend_power_down(void) {
// TODO: figure out what to power down and how // TODO: figure out what to power down and how
// shouldn't power down TPM/FTM if we want a breathing LED // shouldn't power down TPM/FTM if we want a breathing LED
// also shouldn't power down USB // also shouldn't power down USB
#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
# ifdef RGBLIGHT_ANIMATIONS
rgblight_timer_disable();
# endif
if (!is_suspended) {
is_suspended = true;
rgblight_enabled = rgblight_config.enable;
rgblight_disable_noeeprom();
}
#endif
suspend_power_down_kb(); suspend_power_down_kb();
// on AVR, this enables the watchdog for 15ms (max), and goes to // on AVR, this enables the watchdog for 15ms (max), and goes to
@@ -104,5 +121,14 @@ void suspend_wakeup_init(void) {
#ifdef BACKLIGHT_ENABLE #ifdef BACKLIGHT_ENABLE
backlight_init(); backlight_init();
#endif /* BACKLIGHT_ENABLE */ #endif /* BACKLIGHT_ENABLE */
#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
is_suspended = false;
if (rgblight_enabled) {
rgblight_enable_noeeprom();
}
# ifdef RGBLIGHT_ANIMATIONS
rgblight_timer_enable();
# endif
#endif
suspend_wakeup_init_kb(); suspend_wakeup_init_kb();
} }

View File

@@ -32,6 +32,11 @@
#include "sendchar.h" #include "sendchar.h"
#include "debug.h" #include "debug.h"
#include "printf.h" #include "printf.h"
#include "rgblight_reconfig.h"
#if (defined(RGB_MIDI) || defined(RGBLIGHT_ANIMATIONS)) && defined(RGBLIGHT_ENABLE)
# include "rgblight.h"
#endif
#ifdef SLEEP_LED_ENABLE #ifdef SLEEP_LED_ENABLE
# include "sleep_led.h" # include "sleep_led.h"
#endif #endif
@@ -222,5 +227,9 @@ int main(void) {
#ifdef WEBUSB_ENABLE #ifdef WEBUSB_ENABLE
webusb_task(); webusb_task();
#endif #endif
#if defined(RGBLIGHT_ANIMATIONS) && defined(RGBLIGHT_ENABLE)
rgblight_task();
#endif
} }
} }