commit
c7436e667d
@ -0,0 +1,150 @@ |
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/* This library is only valid for STM32 processors.
|
||||
* This library follows the convention of the AVR i2c_master library. |
||||
* As a result addresses are expected to be already shifted (addr << 1). |
||||
* I2CD1 is the default driver which corresponds to pins B6 and B7. This |
||||
* can be changed. |
||||
* Please ensure that HAL_USE_I2C is TRUE in the halconf.h file and that |
||||
* STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file. Pins B6 and B7 are used |
||||
* but using any other I2C pins should be trivial. |
||||
*/ |
||||
|
||||
#ifdef RGB_MATRIX_ENABLE |
||||
|
||||
|
||||
#include "quantum.h" |
||||
#include "i2c_master.h" |
||||
#include <string.h> |
||||
#include <hal.h> |
||||
|
||||
static uint8_t i2c_address; |
||||
|
||||
I2CDriver *drivers[I2C_COUNT]; |
||||
|
||||
static const I2CConfig i2cconfig = { |
||||
#if defined(USE_I2CV1_CONTRIB) |
||||
I2C1_CLOCK_SPEED, |
||||
#elif defined(USE_I2CV1) |
||||
I2C1_OPMODE, |
||||
I2C1_CLOCK_SPEED, |
||||
I2C1_DUTY_CYCLE, |
||||
#else |
||||
// This configures the I2C clock to 400khz assuming a 72Mhz clock
|
||||
// For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html
|
||||
STM32_TIMINGR_PRESC(I2C1_TIMINGR_PRESC) | STM32_TIMINGR_SCLDEL(I2C1_TIMINGR_SCLDEL) | STM32_TIMINGR_SDADEL(I2C1_TIMINGR_SDADEL) | STM32_TIMINGR_SCLH(I2C1_TIMINGR_SCLH) | STM32_TIMINGR_SCLL(I2C1_TIMINGR_SCLL), 0, 0 |
||||
#endif |
||||
}; |
||||
|
||||
static i2c_status_t chibios_to_qmk(const msg_t* status) { |
||||
switch (*status) { |
||||
case I2C_NO_ERROR: |
||||
return I2C_STATUS_SUCCESS; |
||||
case I2C_TIMEOUT: |
||||
return I2C_STATUS_TIMEOUT; |
||||
// I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
|
||||
default: |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
} |
||||
|
||||
__attribute__((weak)) void i2c_init(I2CDriver *driver, ioportid_t scl_port, ioportid_t sda_port, iopadid_t scl_pad, iopadid_t sda_pad) { |
||||
static uint8_t index = 0; |
||||
if (index < I2C_COUNT) { |
||||
|
||||
// Try releasing special pins for a short time
|
||||
palSetPadMode(scl_port, scl_pad, PAL_MODE_INPUT); |
||||
palSetPadMode(sda_port, sda_pad, PAL_MODE_INPUT); |
||||
|
||||
chThdSleepMilliseconds(10); |
||||
|
||||
#if defined(USE_GPIOV1) |
||||
palSetPadMode(scl_port, scl_pad, I2C1_SCL_PAL_MODE); |
||||
palSetPadMode(sda_port, sda_pad, I2C1_SDA_PAL_MODE); |
||||
#else |
||||
palSetPadMode(scl_port, scl_pad, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); |
||||
palSetPadMode(sda_port, sda_pad, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); |
||||
#endif |
||||
|
||||
drivers[index++] = driver; |
||||
} |
||||
} |
||||
|
||||
i2c_status_t i2c_start(uint8_t index, uint8_t address) { |
||||
if(index >= I2C_COUNT) { |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
i2c_address = address; |
||||
i2cStart(drivers[index], &i2cconfig); |
||||
return I2C_STATUS_SUCCESS; |
||||
} |
||||
|
||||
i2c_status_t i2c_transmit(uint8_t index, uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) { |
||||
if(index >= I2C_COUNT) { |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
i2c_address = address; |
||||
i2cStart(drivers[index], &i2cconfig); |
||||
msg_t status = i2cMasterTransmitTimeout(drivers[index], (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout)); |
||||
return chibios_to_qmk(&status); |
||||
} |
||||
|
||||
i2c_status_t i2c_receive(uint8_t index, uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) { |
||||
if(index >= I2C_COUNT) { |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
i2c_address = address; |
||||
i2cStart(drivers[index], &i2cconfig); |
||||
msg_t status = i2cMasterReceiveTimeout(drivers[index], (i2c_address >> 1), data, length, TIME_MS2I(timeout)); |
||||
return chibios_to_qmk(&status); |
||||
} |
||||
|
||||
i2c_status_t i2c_writeReg(uint8_t index, uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { |
||||
if(index >= I2C_COUNT) { |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
i2c_address = devaddr; |
||||
i2cStart(drivers[index], &i2cconfig); |
||||
|
||||
uint8_t complete_packet[length + 1]; |
||||
for (uint8_t i = 0; i < length; i++) { |
||||
complete_packet[i + 1] = data[i]; |
||||
} |
||||
complete_packet[0] = regaddr; |
||||
|
||||
msg_t status = i2cMasterTransmitTimeout(drivers[index], (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout)); |
||||
return chibios_to_qmk(&status); |
||||
} |
||||
|
||||
i2c_status_t i2c_readReg(uint8_t index, uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { |
||||
if(index >= I2C_COUNT) { |
||||
return I2C_STATUS_ERROR; |
||||
} |
||||
i2c_address = devaddr; |
||||
i2cStart(drivers[index], &i2cconfig); |
||||
msg_t status = i2cMasterTransmitTimeout(drivers[index], (i2c_address >> 1), ®addr, 1, data, length, TIME_MS2I(timeout)); |
||||
return chibios_to_qmk(&status); |
||||
} |
||||
|
||||
void i2c_stop(uint8_t index) { |
||||
if(index < I2C_COUNT) { |
||||
i2cStop(drivers[index]); |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,127 @@ |
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/* This library follows the convention of the AVR i2c_master library.
|
||||
* As a result addresses are expected to be already shifted (addr << 1). |
||||
* I2CD1 is the default driver which corresponds to pins B6 and B7. This |
||||
* can be changed. |
||||
* Please ensure that HAL_USE_I2C is TRUE in the halconf.h file and that |
||||
* STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file. |
||||
*/ |
||||
#pragma once |
||||
|
||||
#include <ch.h> |
||||
#include <hal.h> |
||||
|
||||
#ifndef I2C_COUNT |
||||
# define I2C_COUNT 1 |
||||
#endif |
||||
|
||||
#ifdef I2C1_BANK |
||||
# define I2C1_SCL_BANK I2C1_BANK |
||||
# define I2C1_SDA_BANK I2C1_BANK |
||||
#endif |
||||
|
||||
#ifndef I2C1_SCL_BANK |
||||
# define I2C1_SCL_BANK GPIOB |
||||
#endif |
||||
|
||||
#ifndef I2C1_SDA_BANK |
||||
# define I2C1_SDA_BANK GPIOB |
||||
#endif |
||||
|
||||
|
||||
#ifdef USE_I2C2 |
||||
# ifdef I2C2_BANK |
||||
# define I2C2_SCL_BANK I2C2_BANK |
||||
# define I2C2_SDA_BANK I2C2_BANK |
||||
# endif |
||||
# ifndef I2C2_SCL_BANK |
||||
# define I2C2_SCL_BANK GPIOC |
||||
# endif |
||||
# ifndef I2C2_SDA_BANK |
||||
# define I2C2_SDA_BANK GPIOC |
||||
# endif |
||||
#endif |
||||
|
||||
#ifndef I2C1_SCL |
||||
# define I2C1_SCL 6 |
||||
#endif |
||||
#ifndef I2C1_SDA |
||||
# define I2C1_SDA 7 |
||||
#endif |
||||
|
||||
#ifdef USE_I2CV1 |
||||
# ifndef I2C1_OPMODE |
||||
# define I2C1_OPMODE OPMODE_I2C |
||||
# endif |
||||
# ifndef I2C1_CLOCK_SPEED |
||||
# define I2C1_CLOCK_SPEED 100000 /* 400000 */ |
||||
# endif |
||||
# ifndef I2C1_DUTY_CYCLE |
||||
# define I2C1_DUTY_CYCLE STD_DUTY_CYCLE /* FAST_DUTY_CYCLE_2 */ |
||||
# endif |
||||
#else |
||||
// The default timing values below configures the I2C clock to 400khz assuming a 72Mhz clock
|
||||
// For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html
|
||||
# ifndef I2C1_TIMINGR_PRESC |
||||
# define I2C1_TIMINGR_PRESC 0U |
||||
# endif |
||||
# ifndef I2C1_TIMINGR_SCLDEL |
||||
# define I2C1_TIMINGR_SCLDEL 7U |
||||
# endif |
||||
# ifndef I2C1_TIMINGR_SDADEL |
||||
# define I2C1_TIMINGR_SDADEL 0U |
||||
# endif |
||||
# ifndef I2C1_TIMINGR_SCLH |
||||
# define I2C1_TIMINGR_SCLH 38U |
||||
# endif |
||||
# ifndef I2C1_TIMINGR_SCLL |
||||
# define I2C1_TIMINGR_SCLL 129U |
||||
# endif |
||||
#endif |
||||
|
||||
#ifdef USE_GPIOV1 |
||||
# ifndef I2C1_SCL_PAL_MODE |
||||
# define I2C1_SCL_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN |
||||
# endif |
||||
# ifndef I2C1_SDA_PAL_MODE |
||||
# define I2C1_SDA_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN |
||||
# endif |
||||
#else |
||||
// The default PAL alternate modes are used to signal that the pins are used for I2C
|
||||
# ifndef I2C1_SCL_PAL_MODE |
||||
# define I2C1_SCL_PAL_MODE 4 |
||||
# endif |
||||
# ifndef I2C1_SDA_PAL_MODE |
||||
# define I2C1_SDA_PAL_MODE 4 |
||||
# endif |
||||
#endif |
||||
|
||||
typedef int16_t i2c_status_t; |
||||
|
||||
#define I2C_STATUS_SUCCESS (0) |
||||
#define I2C_STATUS_ERROR (-1) |
||||
#define I2C_STATUS_TIMEOUT (-2) |
||||
|
||||
void i2c_init(I2CDriver *driver, ioportid_t scl_port, ioportid_t sda_port, iopadid_t scl_pad, iopadid_t sda_pad); |
||||
i2c_status_t i2c_start(uint8_t index, uint8_t address); |
||||
i2c_status_t i2c_transmit(uint8_t index, uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); |
||||
i2c_status_t i2c_receive(uint8_t index, uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); |
||||
i2c_status_t i2c_writeReg(uint8_t index, uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); |
||||
i2c_status_t i2c_readReg(uint8_t index, uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); |
||||
void i2c_stop(uint8_t index); |
@ -0,0 +1,236 @@ |
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#ifdef RGB_MATRIX_ENABLE |
||||
|
||||
#include "is31fl3733-dual.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}, {0}}; |
||||
bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; |
||||
|
||||
bool IS31FL3733_write_register(uint8_t index, 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(index, addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) { |
||||
return false; |
||||
} |
||||
} |
||||
#else |
||||
if (i2c_transmit(index, addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) { |
||||
return false; |
||||
} |
||||
#endif |
||||
return true; |
||||
} |
||||
|
||||
bool IS31FL3733_write_pwm_buffer(uint8_t index, 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(index, addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) { |
||||
return false; |
||||
} |
||||
} |
||||
#else |
||||
if (i2c_transmit(index, addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) { |
||||
return false; |
||||
} |
||||
#endif |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void IS31FL3733_init(uint8_t bus, 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(bus, addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); |
||||
// Select PG0
|
||||
IS31FL3733_write_register(bus, addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); |
||||
// Turn off all LEDs.
|
||||
for (int i = 0x00; i <= 0x17; i++) { |
||||
IS31FL3733_write_register(bus, addr, i, 0x00); |
||||
} |
||||
// Unlock the command register.
|
||||
IS31FL3733_write_register(bus, addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); |
||||
// Select PG1
|
||||
IS31FL3733_write_register(bus, 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(bus, addr, i, 0x00); |
||||
} |
||||
// Unlock the command register.
|
||||
IS31FL3733_write_register(bus, addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); |
||||
// Select PG3
|
||||
IS31FL3733_write_register(bus, addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); |
||||
// Set global current to maximum.
|
||||
IS31FL3733_write_register(bus, addr, ISSI_REG_GLOBALCURRENT, 0xFF); |
||||
// Disable software shutdown.
|
||||
IS31FL3733_write_register(bus, 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(index, addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); |
||||
IS31FL3733_write_register(index, 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(index, 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(index, addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); |
||||
IS31FL3733_write_register(index, addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); |
||||
for (int i = 0; i < 24; i++) { |
||||
IS31FL3733_write_register(index, addr, i, g_led_control_registers[index][i]); |
||||
} |
||||
} |
||||
g_led_control_registers_update_required[index] = false; |
||||
} |
||||
|
||||
|
||||
#endif |
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
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 bus, uint8_t addr, uint8_t sync); |
||||
bool IS31FL3733_write_register(uint8_t index, uint8_t addr, uint8_t reg, uint8_t data); |
||||
bool IS31FL3733_write_pwm_buffer(uint8_t index, 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); // index is the driver 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 |
@ -0,0 +1,57 @@ |
||||
/* Copyright 2021 Andrew Fahmy
|
||||
* |
||||
* 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 RGB_MATRIX_ENABLE |
||||
|
||||
#include "rgb_matrix.h" |
||||
#include "i2c_master.h" |
||||
#include "is31fl3733-dual.h" |
||||
|
||||
|
||||
|
||||
static void init(void) { |
||||
i2c_init(&I2CD1, I2C1_SCL_BANK, I2C1_SDA_BANK, I2C1_SCL, I2C1_SDA); |
||||
IS31FL3733_init(0, DRIVER_ADDR_1, 0); |
||||
# ifdef USE_I2C2 |
||||
i2c_init(&I2CD2, I2C2_SCL_BANK, I2C2_SDA_BANK, I2C2_SCL, I2C2_SDA); |
||||
IS31FL3733_init(1, DRIVER_ADDR_2, 0); |
||||
# endif |
||||
for (int index = 0; index < DRIVER_LED_TOTAL; index++) { |
||||
bool enabled = true; |
||||
// This only caches it for later
|
||||
IS31FL3733_set_led_control_register(index, enabled, enabled, enabled); |
||||
} |
||||
IS31FL3733_update_led_control_registers(DRIVER_ADDR_1, 0); |
||||
# ifdef USE_I2C2 |
||||
IS31FL3733_update_led_control_registers(DRIVER_ADDR_2, 1); |
||||
# endif |
||||
} |
||||
|
||||
static void flush(void) { |
||||
IS31FL3733_update_pwm_buffers(DRIVER_ADDR_1, 0); |
||||
# ifdef USE_I2C2 |
||||
IS31FL3733_update_pwm_buffers(DRIVER_ADDR_2, 1); |
||||
# endif |
||||
} |
||||
|
||||
const rgb_matrix_driver_t rgb_matrix_driver = { |
||||
.init = init, |
||||
.flush = flush, |
||||
.set_color = IS31FL3733_set_color, |
||||
.set_color_all = IS31FL3733_set_color_all, |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,52 @@ |
||||
/* Copyright 2021 Andrew Fahmy
|
||||
* |
||||
* 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/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
|
||||
#ifdef RGB_MATRIX_ENABLE |
||||
// # define RGB_MATRIX_FRAMEBUFFER_EFFECTS
|
||||
// # define RGB_MATRIX_KEYPRESSES
|
||||
# define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_RAINDROPS |
||||
|
||||
// # define DEBUG_MATRIX_SCAN_RATE
|
||||
|
||||
# define RGB_MATRIX_LED_FLUSH_LIMIT 100 |
||||
// # define RGB_MATRIX_LED_PROCESS_LIMIT 2
|
||||
|
||||
// i2c_master defines
|
||||
# define I2C_COUNT 2 |
||||
|
||||
# define I2C1_BANK GPIOB |
||||
# define I2C1_SCL 0 // A2 on pinout = B0
|
||||
# define I2C1_SDA 1 // A2 on pinout = B1
|
||||
# define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATIVE_2 |
||||
# define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATIVE_2 |
||||
|
||||
# define USE_I2C2 |
||||
# define I2C2_BANK GPIOC |
||||
# define I2C2_SCL 10 // A2 on pinout = C10
|
||||
# define I2C2_SDA 11 // A2 on pinout = C11
|
||||
# define I2C2_SCL_PAL_MODE PAL_MODE_ALTERNATIVE_2 |
||||
# define I2C2_SDA_PAL_MODE PAL_MODE_ALTERNATIVE_2 |
||||
|
||||
# define DRIVER_ADDR_1 0b1010000 |
||||
# define DRIVER_ADDR_2 0b1010000 |
||||
# define DRIVER_COUNT 2 |
||||
# define DRIVER_1_LED_TOTAL 64 |
||||
# define DRIVER_2_LED_TOTAL 55 |
||||
# define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL) |
||||
#endif |
@ -0,0 +1,60 @@ |
||||
/* Copyright 2021 Andrew Fahmy
|
||||
* |
||||
* 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/>.
|
||||
*/ |
||||
|
||||
#include QMK_KEYBOARD_H |
||||
|
||||
enum layer_names { |
||||
_MAIN, |
||||
_L1 |
||||
}; |
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { |
||||
[_MAIN] = LAYOUT_tkl_ansi( |
||||
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SLCK, KC_PAUS, |
||||
|
||||
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS, KC_HOME, KC_PGUP, |
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END, KC_PGDN, |
||||
MO(_L1), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, |
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, |
||||
KC_LCTL, _______, KC_LALT, KC_SPC, KC_RALT, MO(_L1), KC_APP, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT |
||||
), |
||||
[_L1] = LAYOUT_tkl_ansi( |
||||
RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_TOG, RGB_MOD, _______, |
||||
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_SPD, RGB_SPI, _______, RGB_HUI, RGB_SAI, RGB_VAI, |
||||
_______, KC_MPRV, KC_MPLY, KC_MNXT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_HUD, RGB_SAD, RGB_VAD, |
||||
_______, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______, _______, _______, |
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, |
||||
_______, KC_LGUI, _______, _______, _______, _______, _______, _______, _______, _______, _______ |
||||
) |
||||
}; |
||||
|
||||
void keyboard_post_init_user(void) { |
||||
// Customise these values to desired behaviour
|
||||
// debug_enable=true;
|
||||
// debug_matrix=true;
|
||||
// debug_keyboard=true;
|
||||
// debug_mouse=true;
|
||||
} |
||||
|
||||
#ifdef RGB_MATRIX_ENABLE |
||||
// Turn off SDB
|
||||
void keyboard_pre_init_user() { |
||||
palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL); |
||||
palSetPad(GPIOB, 16); |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1 @@ |
||||
RGB_MATRIX_ENABLE = yes
|
Loading…
Reference in new issue