~ruther/qmk_firmware

1cf63a193be50b14ecd33ee1c6eb5e470640e084 — Drashna Jaelre 5 years ago 8dc9764
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
M drivers/avr/ws2812.c => drivers/avr/ws2812.c +2 -127
@@ 36,108 36,6 @@
void ws2812_sendarray(uint8_t *array, uint16_t length);
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
void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
    // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));


@@ 145,38 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) {
#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 |= pinmask; // Enable DDR
    // new universal format (DDR)
    _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;

    ws2812_sendarray_mask((uint8_t *)ledarray, leds * sizeof(LED_TYPE), pinmask);

#ifndef RGBW_BB_TWI
#    ifdef RGBW
#ifdef RGBW
    _delay_us(80);
#    else
#else
    _delay_us(50);
#    endif
#endif
}


M keyboards/ergodox_ez/config.h => keyboards/ergodox_ez/config.h +8 -4
@@ 75,17 75,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
/* ws2812 RGB LED */
#define RGB_DI_PIN D7
#define RGBLIGHT_ANIMATIONS
#define RGBLED_NUM 15     // Number of LEDs
#define RGBLIGHT_HUE_STEP 12
#define RGBLIGHT_SAT_STEP 255
#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 */
#define DISABLE_SPACE_CADET_ROLLOVER

#define RGBW_BB_TWI

#define RGBW 1
#define RGBW

#define RGBLIGHT_SLEEP


A keyboards/ergodox_ez/led_i2c.c => keyboards/ergodox_ez/led_i2c.c +86 -0
@@ 0,0 1,86 @@
/*
 * 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
        }
    }


    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

A keyboards/ergodox_ez/post_config.h => keyboards/ergodox_ez/post_config.h +20 -0
@@ 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

M keyboards/ergodox_ez/rules.mk => keyboards/ergodox_ez/rules.mk +4 -1
@@ 31,11 31,14 @@ SWAP_HANDS_ENABLE= yes # Allow swapping hands of keyboard
SLEEP_LED_ENABLE = no
API_SYSEX_ENABLE = no
RGBLIGHT_ENABLE = yes
RGBLIGHT_CUSTOM_DRIVER = yes

RGB_MATRIX_ENABLE = no # enable later
DEBOUNCE_TYPE = eager_pr

# project specific files
SRC += matrix.c
SRC += matrix.c \
	   led_i2c.c
QUANTUM_LIB_SRC += i2c_master.c

LAYOUTS = ergodox