Compare commits
	
		
			10 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 471722f495 | ||
|   | 5e66140fbc | ||
|   | ef8de0e6f0 | ||
|   | d495b26d2d | ||
|   | e992079e08 | ||
|   | 0aa30138ff | ||
|   | aa11627383 | ||
|   | 5c132afbf5 | ||
|   | b4feae42b4 | ||
|   | b867398408 | 
| @@ -65,11 +65,13 @@ uint8_t i2c_start(uint8_t address) | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) | ||||
| int8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) | ||||
| { | ||||
|   //xprintf("i2c_transmit(0x%x, 0x%x, %d, 0x%x) address:0x%x\n", address, data, length, timeout, address >> 1); | ||||
|   i2c_address = address; | ||||
|   i2cStart(&I2C_DRIVER, &i2cconfig); | ||||
|   return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout)); | ||||
|   int8_t result = i2cMasterTransmitTimeout(&I2C_DRIVER, i2c_address, data, length, 0, 0, MS2ST(timeout)); | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) | ||||
|   | ||||
| @@ -42,7 +42,7 @@ | ||||
|  | ||||
| void i2c_init(void); | ||||
| uint8_t i2c_start(uint8_t address); | ||||
| uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | ||||
| int8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | ||||
| uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | ||||
| uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length); | ||||
| uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | ||||
|   | ||||
							
								
								
									
										227
									
								
								drivers/issi/is31fl3235a.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								drivers/issi/is31fl3235a.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| /* 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 <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #ifdef __AVR__ | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/io.h> | ||||
| #include <util/delay.h> | ||||
| #else | ||||
| #include "wait.h" | ||||
| #endif | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include "is31fl3235a.h" | ||||
| #include "i2c_master.h" | ||||
| #include "progmem.h" | ||||
| #include "print.h" | ||||
|  | ||||
|  | ||||
| #define ISSI_REG_CONFIG  0x00  // FIXME: Not on 3235? | ||||
| #define ISSI_REG_CONFIG_PICTUREMODE 0x00  // FIXME: Not on 3235? | ||||
|  | ||||
| //#define ISSI_REG_AUDIOSYNC 0x06  // FIXME: Not on 3235? | ||||
|  | ||||
| #define ISSI_COMMANDREGISTER 0xFD  // FIXME: Not on 3235? | ||||
| #define ISSI_BANK_FUNCTIONREG 0x0B    // FIXME: Not on 3235? | ||||
|  | ||||
| #ifndef ISSI_TIMEOUT | ||||
|   #define ISSI_TIMEOUT 100 | ||||
| #endif | ||||
|  | ||||
| #ifndef ISSI_PERSISTENCE | ||||
|   #define ISSI_PERSISTENCE 0 | ||||
| #endif | ||||
|  | ||||
| // Transfer buffer for TWITransmitData() | ||||
| uint8_t g_3235a_transfer_buffer[20]; | ||||
|  | ||||
| // These buffers match the IS31FL3235A PWM registers 0x05-0x20. | ||||
| // 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 IS31FL3235A_write_pwm_buffer() but it's | ||||
| // probably not worth the extra complexity. | ||||
| uint8_t g_rgb7seg_buffer[IS31FL3235A_COUNT][IS31FL3235A_LED_MAX]; | ||||
| bool g_rgb7seg_buffer_update_required = false; | ||||
|  | ||||
| /* There's probably a better way to init this... */ | ||||
| #if IS31FL3235A_COUNT == 1 | ||||
|     uint8_t g_3235a_control_registers[IS31FL3235A_COUNT][18] = {{0}}; | ||||
| #elif IS31FL3235A_COUNT == 2 | ||||
|     uint8_t g_3235a_control_registers[IS31FL3235A_COUNT][18] = {{0}, {0}}; | ||||
| #elif IS31FL3235A_COUNT == 3 | ||||
|     uint8_t g_3235a_control_registers[IS31FL3235A_COUNT][18] = {{0}, {0}, {0}}; | ||||
| #elif IS31FL3235A_COUNT == 4 | ||||
|     uint8_t g_3235a_control_registers[IS31FL3235A_COUNT][18] = {{0}, {0}, {0}, {0}}; | ||||
| #endif | ||||
| bool g_rgb7seg_control_registers_update_required = false; | ||||
|  | ||||
| void IS31FL3235A_write_register(uint8_t addr, uint8_t reg, uint8_t data) { | ||||
|     g_3235a_transfer_buffer[0] = reg; | ||||
|     g_3235a_transfer_buffer[1] = data; | ||||
|     xprintf("IS31FL3235A_write_register(0x%x, 0x%x, 0x%x); g_3235a_transfer_buffer:0x%x\n", addr, reg, data, g_3235a_transfer_buffer); | ||||
|  | ||||
|     #if ISSI_PERSISTENCE > 0 | ||||
|         for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { | ||||
|             if (i2c_transmit(addr, g_3235a_transfer_buffer, 2, ISSI_TIMEOUT) == 0) { | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|     #else | ||||
|         if (i2c_transmit(addr, g_3235a_transfer_buffer, 2, ISSI_TIMEOUT) == -1) { | ||||
|             // When we encounter a timeout ChibiOS says the bus must be reset as it's in an unknown state | ||||
|             xprintf("i2c transmit timeout, resetting i2c bus!\n"); | ||||
|             i2c_stop(ISSI_TIMEOUT); | ||||
|             wait_ms(5); | ||||
|             i2c_start(ISSI_TIMEOUT); | ||||
|         } | ||||
|     #endif | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_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_3235a_transfer_buffer[] is 20 bytes | ||||
|  | ||||
|     // iterate over the pwm_buffer contents at 16 byte intervals | ||||
|     for (int i = 0; i < IS31FL3235A_LED_MAX; i += 16) { | ||||
|         // set the first register, e.g. 0x24, 0x34, 0x44, etc. | ||||
|         g_3235a_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_3235a_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_3235a_transfer_buffer, 17, ISSI_TIMEOUT) == 0) | ||||
|           break; | ||||
|       } | ||||
|     #else | ||||
|         if (i2c_transmit(addr << 1, g_3235a_transfer_buffer, 17, ISSI_TIMEOUT) == -1) { | ||||
|             // When we encounter a timeout ChibiOS says the bus must be reset as it's in an unknown state | ||||
|             xprintf("i2c transmit timeout, resetting i2c bus!\n"); | ||||
|             i2c_stop(ISSI_TIMEOUT); | ||||
|             wait_ms(5); | ||||
|             i2c_start(ISSI_TIMEOUT); | ||||
|         } | ||||
|     #endif | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_init(uint8_t addr) { | ||||
|     wait_ms(2000); // Give QMK Toolbox time to attach | ||||
|     xprintf("IS31FS3235A_init(0x%x)\n", 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. | ||||
|  | ||||
|     // Reset settings to default | ||||
|     //IS31FL3235A_write_register(addr, ISSI_REG_RESET_REG, 0); | ||||
|  | ||||
|     // this delay was copied from other drivers, might not be needed | ||||
|     wait_ms(10); | ||||
|  | ||||
|     // This is how the Arduino code does init... | ||||
|     uint8_t i = 0; | ||||
|  | ||||
|     for (i=0x2A; i<=0x45; i++) { | ||||
|         IS31FL3235A_write_register(addr, i, 0xFF);  // Turn off all LEDs | ||||
|     } | ||||
|  | ||||
|     for (i=0x05; i<=0x20; i++) { | ||||
|         IS31FL3235A_write_register(addr, i, 0x00);  // Write all PWM set 0x00 | ||||
|     } | ||||
|  | ||||
|     IS31FL3235A_write_register(addr, 0x25, 0x00);   //update PWM&Control registers | ||||
|     IS31FL3235A_write_register(addr, 0x4B, 0x01);   //frequency setting 22KHz | ||||
|     IS31FL3235A_write_register(addr, 0x00, 0x01);   //normal operation | ||||
|  | ||||
|     // This is how the Arduino code does LED turn on | ||||
|     IS31FL3235A_write_register(addr, 0x05, 0xFF);   // set PWM | ||||
|     IS31FL3235A_write_register(addr, 0x25, 0x00);   // update PWM&Control registers | ||||
|     IS31FL3235A_write_register(addr, 0x08, 0xFF);   // set PWM | ||||
|     IS31FL3235A_write_register(addr, 0x25, 0x00);   // update PWM&Control registers | ||||
|     IS31FL3235A_write_register(addr, 0x12, 0xFF);   // set PWM | ||||
|     IS31FL3235A_write_register(addr, 0x25, 0x00);   // update PWM&Control registers | ||||
|  | ||||
|     // FIXME: This is for testing, turn on OUT1 at full brightness | ||||
|     //IS31FL3235A_write_register(addr, 0x2A, 0xFF); | ||||
|     //IS31FL3235A_write_register(addr, 0x05, 0x00); | ||||
|  | ||||
|     // I think this finally turns it on? | ||||
|     //IS31FL3235A_write_register(addr, 0x25, 0x00);    //update PWM&Control registers | ||||
|     //IS31FL3235A_write_register(addr, 0x4B, 0x01);  //frequency setting 22KHz | ||||
|     //IS31FL3235A_write_register(addr, 0x00, 0x01);    //normal operation | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_set_value(int index, uint8_t value) { | ||||
| /* | ||||
|     if (index >= 0 && index < IS31FL3235A_LED_COUNT) { | ||||
|         is31_led led = g_is31_leds[index]; | ||||
|  | ||||
|         // Subtract 0x24 to get the second index of g_rgb7seg_buffer | ||||
|         g_rgb7seg_buffer[led.driver][led.v - 0x24] = value; | ||||
|         g_rgb7seg_buffer_update_required = true; | ||||
|     } | ||||
| */ | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_set_value_all(uint8_t value) { | ||||
|     for (int i = 0; i < IS31FL3235A_LED_COUNT; i++) { | ||||
|         IS31FL3235A_set_value(i, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_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_3235a_control_registers[led.driver][control_register] |= (1 << bit_value); | ||||
|     } else { | ||||
|         g_3235a_control_registers[led.driver][control_register] &= ~(1 << bit_value); | ||||
|     } | ||||
|  | ||||
|     g_rgb7seg_control_registers_update_required = true; | ||||
| */ | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_update_pwm_buffers(uint8_t addr, uint8_t index) { | ||||
|     //xprintf("IS31FS3235A_update_pwm_buffers(0x%x, %d)\n", addr, index); | ||||
|     if (g_rgb7seg_buffer_update_required) { | ||||
|         IS31FL3235A_write_pwm_buffer(addr, g_rgb7seg_buffer[index]); | ||||
|         g_rgb7seg_buffer_update_required = false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IS31FL3235A_update_led_control_registers(uint8_t addr, uint8_t index) { | ||||
|     if (g_rgb7seg_control_registers_update_required) { | ||||
|         for (int i=0; i<18; i++) { | ||||
|             IS31FL3235A_write_register(addr, i, g_3235a_control_registers[index][i]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										141
									
								
								drivers/issi/is31fl3235a.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								drivers/issi/is31fl3235a.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| /* 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 <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #ifndef IS31FL3235A_DRIVER_H | ||||
| #define IS31FL3235A_DRIVER_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: | ||||
| // 0b0111111 AD <-> VCC | ||||
| // 0b0111110 AD <-> SDA | ||||
| // 0b0111101 AD <-> SCL | ||||
| // 0b0111100 AD <-> GND | ||||
| #ifndef IS31FL3235A_COUNT | ||||
|     #define IS31FL3235A_COUNT 1 | ||||
| #endif | ||||
| #ifndef IS31FL3235A_DRIVER_ADDR_1 | ||||
|     #define IS31FL3235A_DRIVER_ADDR_1 0b0111111 | ||||
|     //#define IS31FL3235A_DRIVER_ADDR_1 0x7E | ||||
| #endif | ||||
| #ifndef IS31FL3235A_DRIVER_ADDR_2 | ||||
|     #define IS31FL3235A_DRIVER_ADDR_2 0b0111110 | ||||
| #endif | ||||
| #ifndef IS31FL3235A_DRIVER_ADDR_3 | ||||
|     #define IS31FL3235A_DRIVER_ADDR_3 0b0111101 | ||||
| #endif | ||||
| #ifndef IS31FL3235A_DRIVER_ADDR_4 | ||||
|     #define IS31FL3235A_DRIVER_ADDR_4 0b0111100 | ||||
| #endif | ||||
|  | ||||
| // This is the max number of LEDs this driver supports per IC | ||||
| #define IS31FL3235A_LED_MAX 28 | ||||
| #ifndef IS31FL3235A_LED_COUNT | ||||
|     #define IS31FL3235A_LED_COUNT IS31FL3235A_LED_MAX | ||||
| #endif | ||||
|  | ||||
| // Registers we will need to write to | ||||
| #define ISSI_REG_SHUTDOWN 0x00        // Control the software shutdown state of the controller | ||||
| #define ISSI_REG_GLOBAL_CONTROL 0x4A  // Write 0 for normal operation, 1 to shutdown all LEDs | ||||
| #define ISSI_REG_OUTPUT_FREQ 0x4B     // Write 0 for 3kHz PWM, 1 for 22kHz | ||||
| #define ISSI_REG_RESET_REG 0x4F       // Write 0 to reset all registers to default value | ||||
|  | ||||
|  | ||||
| void IS31FL3235A_init(uint8_t addr); | ||||
| void IS31FL3235A_write_register(uint8_t addr, uint8_t reg, uint8_t data); | ||||
| void IS31FL3235A_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); | ||||
|  | ||||
| void IS31FL3235A_set_value(int index, uint8_t value); | ||||
| void IS31FL3235A_set_value_all(uint8_t value); | ||||
|  | ||||
| void IS31FL3235A_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 IS31FL3235A_update_pwm_buffers(uint8_t addr, uint8_t index); | ||||
| void IS31FL3235A_update_led_control_registers(uint8_t addr, uint8_t index); | ||||
|  | ||||
| // The address for each LED in the is31fl3235a's Control Register | ||||
| enum control_register { | ||||
|     CR_OUT1 = 0x2A, | ||||
|     CR_OUT2, | ||||
|     CR_OUT3, | ||||
|     CR_OUT4, | ||||
|     CR_OUT5, | ||||
|     CR_OUT6, | ||||
|     CR_OUT7, | ||||
|     CR_OUT8, | ||||
|     CR_OUT9, | ||||
|     CR_OUT10, | ||||
|     CR_OUT11, | ||||
|     CR_OUT12, | ||||
|     CR_OUT13, | ||||
|     CR_OUT14, | ||||
|     CR_OUT15, | ||||
|     CR_OUT16, | ||||
|     CR_OUT17, | ||||
|     CR_OUT18, | ||||
|     CR_OUT19, | ||||
|     CR_OUT20, | ||||
|     CR_OUT21, | ||||
|     CR_OUT22, | ||||
|     CR_OUT23, | ||||
|     CR_OUT24, | ||||
|     CR_OUT25, | ||||
|     CR_OUT26, | ||||
|     CR_OUT27, | ||||
|     CR_OUT28 | ||||
| }; | ||||
|  | ||||
| // The address for each LED in the is31fl3235a's PWM Register | ||||
| enum pwm_register { | ||||
|     OUT1 = 0x05, | ||||
|     OUT2, | ||||
|     OUT3, | ||||
|     OUT4, | ||||
|     OUT5, | ||||
|     OUT6, | ||||
|     OUT7, | ||||
|     OUT8, | ||||
|     OUT9, | ||||
|     OUT10, | ||||
|     OUT11, | ||||
|     OUT12, | ||||
|     OUT13, | ||||
|     OUT14, | ||||
|     OUT15, | ||||
|     OUT16, | ||||
|     OUT17, | ||||
|     OUT18, | ||||
|     OUT19, | ||||
|     OUT20, | ||||
|     OUT21, | ||||
|     OUT22, | ||||
|     OUT23, | ||||
|     OUT24, | ||||
|     OUT25, | ||||
|     OUT26, | ||||
|     OUT27, | ||||
|     OUT28 | ||||
| }; | ||||
|  | ||||
| #endif // IS31FL3235A_DRIVER_H | ||||
| @@ -22,10 +22,16 @@ void qwiic_init(void) { | ||||
|   #ifdef QWIIC_MICRO_OLED_ENABLE | ||||
|     micro_oled_init(); | ||||
|   #endif | ||||
|   #ifdef QWIIC_RGB7SEG_ENABLE | ||||
|     rgb7seg_init(); | ||||
|   #endif | ||||
| } | ||||
|  | ||||
| void qwiic_task(void) { | ||||
|   #ifdef QWIIC_JOYSTIIC_ENABLE | ||||
|     joystiic_task(); | ||||
|   #endif | ||||
|   #ifdef QWIIC_RGB7SEG_ENABLE | ||||
|     rgb7seg_task(); | ||||
|   #endif | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,9 @@ | ||||
| #ifdef QWIIC_MICRO_OLED_ENABLE | ||||
|   #include "micro_oled.h" | ||||
| #endif | ||||
| #ifdef QWIIC_RGB7SEG_ENABLE | ||||
|   #include "rgb7seg.h" | ||||
| #endif | ||||
|  | ||||
| void qwiic_init(void); | ||||
| void qwiic_task(void); | ||||
|   | ||||
| @@ -16,3 +16,9 @@ ifneq ($(filter MICRO_OLED, $(QWIIC_ENABLE)),) | ||||
|   OPT_DEFS += -DQWIIC_MICRO_OLED_ENABLE | ||||
|   SRC += micro_oled.c | ||||
| endif | ||||
|  | ||||
| ifneq ($(filter RGB7SEG, $(QWIIC_ENABLE)),) | ||||
|   COMMON_VPATH += $(DRIVER_PATH)/issi | ||||
|   OPT_DEFS += -DQWIIC_RGB7SEG_ENABLE | ||||
|   SRC += rgb7seg.c is31fl3235a.c | ||||
| endif | ||||
|   | ||||
							
								
								
									
										168
									
								
								drivers/qwiic/rgb7seg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								drivers/qwiic/rgb7seg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| /* Copyright 2017 Jason Williams | ||||
|  * Copyright 2017 Jack Humbert | ||||
|  * Copyright 2018 Yiancar | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "quantum.h" | ||||
| #include "rgb7seg.h" | ||||
| #include "is31fl3235a.h" | ||||
| #include "progmem.h" | ||||
| #include "config.h" | ||||
| #include "eeprom.h" | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
|  | ||||
| #ifndef MAX | ||||
|     #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) | ||||
| #endif | ||||
|  | ||||
| #ifndef MIN | ||||
|     #define MIN(a,b) ((a) < (b)? (a): (b)) | ||||
| #endif | ||||
|  | ||||
| // State variables | ||||
| uint32_t g7_tick = 0;      // Global tick at 20 Hz | ||||
| bool rgb7seg_enabled = 0;  // Whether or not the display is turned on | ||||
|  | ||||
| /* | ||||
| const rgb7seg_led g_rgb7seg_leds[IS31FL3235A_COUNT * 8][4] = { | ||||
| / * Refer to IS31 manual for these locations | ||||
|  *  driver | ||||
|  *  |   R LED address | ||||
|  *  |   |      G LED address | ||||
|  *  |   |      |      B LED address | ||||
|  *  |   |      |      | * / | ||||
|     {0, OUT17, OUT16, OUT15},  // A, top middle | ||||
|     {0, OUT22, OUT21, OUT20},  // B, top right | ||||
|     {0, OUT26, OUT27, OUT28},  // C, bottom right | ||||
|     {0, OUT1,  OUT2,  OUT3},   // D, bottom center | ||||
|     {0, OUT23, OUT24, OUT25},  // DP, dot | ||||
|     {0, OUT4,  OUT5,  OUT6},   // E, bottom left | ||||
|     {0, OUT9,  OUT7,  OUT8},   // F, top left | ||||
|     {0, OUT14, OUT13, OUT12},  // G, center | ||||
|     #if IS31FL3235A_COUNT > 1 | ||||
|     {1, OUT17, OUT16, OUT15},  // A, top middle | ||||
|     {1, OUT22, OUT21, OUT20},  // B, top right | ||||
|     {1, OUT26, OUT27, OUT28},  // C, bottom right | ||||
|     {1, OUT1,  OUT2,  OUT3},   // D, bottom center | ||||
|     {1, OUT23, OUT24, OUT25},  // DP, dot | ||||
|     {1, OUT4,  OUT5,  OUT6},   // E, bottom left | ||||
|     {1, OUT9,  OUT7,  OUT8},   // F, top left | ||||
|     {1, OUT14, OUT13, OUT12},  // G, center | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 2 | ||||
|     {2, OUT17, OUT16, OUT15},  // A, top middle | ||||
|     {2, OUT17, OUT16, OUT15},  // A, top middle | ||||
|     {2, OUT22, OUT21, OUT20},  // B, top right | ||||
|     {2, OUT26, OUT27, OUT28},  // C, bottom right | ||||
|     {2, OUT1,  OUT2,  OUT3},   // D, bottom center | ||||
|     {2, OUT23, OUT24, OUT25},  // DP, dot | ||||
|     {2, OUT4,  OUT5,  OUT6},   // E, bottom left | ||||
|     {2, OUT9,  OUT7,  OUT8},   // F, top left | ||||
|     {2, OUT14, OUT13, OUT12},  // G, center | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 3 | ||||
|     {3, OUT17, OUT16, OUT15},  // A, top middle | ||||
|     {3, OUT22, OUT21, OUT20},  // B, top right | ||||
|     {3, OUT26, OUT27, OUT28},  // C, bottom right | ||||
|     {3, OUT1,  OUT2,  OUT3},   // D, bottom center | ||||
|     {3, OUT23, OUT24, OUT25},  // DP, dot | ||||
|     {3, OUT4,  OUT5,  OUT6},   // E, bottom left | ||||
|     {3, OUT9,  OUT7,  OUT8},   // F, top left | ||||
|     {3, OUT14, OUT13, OUT12},  // G, center | ||||
|     {3, OUT22, OUT21, OUT20},  // B, top right | ||||
|     #endif | ||||
| }; | ||||
| */ | ||||
|  | ||||
| // API | ||||
| void rgb7seg_flush(void) { | ||||
|     IS31FL3235A_update_pwm_buffers(IS31FL3235A_DRIVER_ADDR_1, 0); | ||||
|     #if IS31FL3235A_COUNT > 1 | ||||
|         IS31FL3235A_update_pwm_buffers(IS31FL3235A_DRIVER_ADDR_2, 1); | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 2 | ||||
|         IS31FL3235A_update_pwm_buffers(IS31FL3235A_DRIVER_ADDR_3, 2); | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 3 | ||||
|         IS31FL3235A_update_pwm_buffers(IS31FL3235A_DRIVER_ADDR_4, 3); | ||||
|     #endif | ||||
| } | ||||
|  | ||||
| void rgb7seg_set_index_value(int index, uint8_t value) { | ||||
|     IS31FL3235A_set_value(index, value); | ||||
| } | ||||
|  | ||||
| void rgb7seg_set_index_value_all(uint8_t value) { | ||||
|     IS31FL3235A_set_value_all(value); | ||||
| } | ||||
|  | ||||
| // All LEDs off | ||||
| void rgb7seg_off(void) { | ||||
|     rgb7seg_set_index_value_all(0); | ||||
| } | ||||
|  | ||||
| void rgb7seg_task(void) { | ||||
|     g7_tick++; | ||||
|  | ||||
|     // Do something here? | ||||
|  | ||||
|     // Tell the LED driver to update its state | ||||
|     rgb7seg_flush(); | ||||
| } | ||||
|  | ||||
| void rgb7seg_init(void) { | ||||
|     IS31FL3235A_init(IS31FL3235A_DRIVER_ADDR_1); | ||||
|     #if IS31FL3235A_COUNT > 1 | ||||
|         IS31FL3235A_init(IS31FL3235A_DRIVER_ADDR_2); | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 2 | ||||
|         IS31FL3235A_init(IS31FL3235A_DRIVER_ADDR_3); | ||||
|     #endif | ||||
|     #if IS31FL3235A_COUNT > 3 | ||||
|         IS31FL3235A_init(IS31FL3235A_DRIVER_ADDR_4); | ||||
|     #endif | ||||
|  | ||||
|     // Wait half a second for the driver to finish initializing | ||||
|     wait_ms(500); | ||||
| } | ||||
|  | ||||
| uint32_t rgb7seg_get_tick(void) { | ||||
|     return g7_tick; | ||||
| } | ||||
|  | ||||
| void rgb7seg_toggle(void) { | ||||
|     rgb7seg_enabled ^= 1; | ||||
| } | ||||
|  | ||||
| void rgb7seg_enable(void) { | ||||
|     rgb7seg_enabled = 1; | ||||
| } | ||||
|  | ||||
| void rgb7seg_disable(void) { | ||||
|     rgb7seg_enabled = 0; | ||||
| } | ||||
|  | ||||
| void rgb7seg_increase_val(void) { | ||||
|     // FIXME: Implement | ||||
| } | ||||
|  | ||||
| void rgb7seg_decrease_val(void) { | ||||
|     // FIXME: Implement | ||||
| } | ||||
							
								
								
									
										60
									
								
								drivers/qwiic/rgb7seg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								drivers/qwiic/rgb7seg.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /* Copyright 2017 Jason Williams | ||||
|  * Copyright 2017 Jack Humbert | ||||
|  * Copyright 2018 Yiancar | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #ifndef LED_MATRIX_H | ||||
| #define LED_MATRIX_H | ||||
|  | ||||
| #include "is31fl3235a.h" | ||||
|  | ||||
| #ifndef BACKLIGHT_ENABLE | ||||
|   #error You must define BACKLIGHT_ENABLE with LED_MATRIX_ENABLE | ||||
| #endif | ||||
|  | ||||
|  | ||||
| void rgb7seg_task(void); | ||||
| void rgb7seg_init(void); | ||||
|  | ||||
| // 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 rgb7seg_flush(void); | ||||
|  | ||||
| uint32_t rgb7seg_get_tick(void); | ||||
|  | ||||
| void rgb7seg_off(void); | ||||
| void rgb7seg_set_index_value(int index, uint8_t value); | ||||
| void rgb7seg_set_index_value_all(uint8_t value); | ||||
|  | ||||
| void rgb7seg_toggle(void); | ||||
| void rgb7seg_enable(void); | ||||
| void rgb7seg_disable(void); | ||||
| void rgb7seg_increase_val(void); | ||||
| void rgb7seg_decrease_val(void); | ||||
|  | ||||
| typedef struct rgb7seg_led { | ||||
|   uint8_t driver; | ||||
|   uint8_t r; | ||||
|   uint8_t g; | ||||
|   uint8_t b; | ||||
| } __attribute__((packed)) rgb7seg_led; | ||||
|  | ||||
| extern const rgb7seg_led g_rgb7seg_leds[IS31FL3235A_COUNT * 8]; | ||||
|  | ||||
| #endif | ||||
| @@ -47,7 +47,7 @@ | ||||
|  * | ||||
| */ | ||||
| #define MATRIX_ROW_PINS { B0, B1, B2, A15, A10 } | ||||
| #define MATRIX_COL_PINS { A2, A3, A6, B14, B15, A8, A9, A7, B3, B4, C14, C15, C13, B5, B6 } | ||||
| #define MATRIX_COL_PINS { A2, A3, A6, B14, B15, A8, A9, A7, B3, B4, C15, C14, C13, B5, B6 } | ||||
| #define UNUSED_PINS { A0, A1, A9, B7, B8, B9, B10, B11, B12, B13 } | ||||
| #define DIODE_DIRECTION COL2ROW | ||||
|  | ||||
|   | ||||
| @@ -37,6 +37,17 @@ | ||||
| /* Locking resynchronize hack */ | ||||
| #define LOCKING_RESYNC_ENABLE | ||||
|  | ||||
| /* key combination for command */ | ||||
| #define IS_COMMAND() ( \ | ||||
|     keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | ||||
| ) | ||||
|  | ||||
| #define IS31FL3235A_COUNT 1 | ||||
| //#define I2C_DRIVER I2CD1 | ||||
| #define I2C1_BANK GPIOB | ||||
| #define I2C1_SCL 8 | ||||
| #define I2C1_SDA 9 | ||||
|  | ||||
| /* | ||||
|  * Feature disable options | ||||
|  *  These options are also useful to firmware size reduction. | ||||
|   | ||||
| @@ -76,7 +76,7 @@ | ||||
|  * @brief   Enables the I2C subsystem. | ||||
|  */ | ||||
| #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) | ||||
| #define HAL_USE_I2C                 FALSE | ||||
| #define HAL_USE_I2C                 TRUE | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -154,7 +154,7 @@ | ||||
| /* | ||||
|  * I2C driver system settings. | ||||
|  */ | ||||
| #define STM32_I2C_USE_I2C1                  FALSE | ||||
| #define STM32_I2C_USE_I2C1                  TRUE | ||||
| #define STM32_I2C_USE_I2C2                  FALSE | ||||
| #define STM32_I2C_BUSY_TIMEOUT              50 | ||||
| #define STM32_I2C_I2C1_IRQ_PRIORITY         10 | ||||
|   | ||||
| @@ -17,6 +17,8 @@ DFU_ARGS = -d 0483:df11 -a 0 -s 0x08000000:leave | ||||
| # Build Options | ||||
| #   comment out to disable the options. | ||||
| # | ||||
| QWIIC_ENABLE = RGB7SEG | ||||
|  | ||||
| BACKLIGHT_ENABLE = yes | ||||
| BOOTMAGIC_ENABLE = no   # Virtual DIP switch configuration(+1000) | ||||
| MOUSEKEY_ENABLE = yes   # Mouse keys(+4700) | ||||
|   | ||||
| @@ -130,6 +130,15 @@ | ||||
|  */ | ||||
| #define BACKLIGHT_LEVELS 10 | ||||
|  | ||||
| // For the rgb7seg | ||||
| #define IS31FL3235A_COUNT 1 | ||||
| /* | ||||
| #define I2C_DRIVER I2CD2 | ||||
| #define I2C1_BANK GPIOA | ||||
| #define I2C1_SCL 9 | ||||
| #define I2C1_SDA 10 | ||||
| */ | ||||
|  | ||||
| // 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: | ||||
| @@ -138,6 +147,9 @@ | ||||
| // 0b1110101 AD <-> SCL | ||||
| // 0b1110110 AD <-> SDA | ||||
| #define LED_DRIVER_ADDR_1 0b1110100 | ||||
|  | ||||
| /* For the LED driver | ||||
|  */ | ||||
| #define I2C1_BANK GPIOB | ||||
| #define I2C1_SCL 8 | ||||
| #define I2C1_SDA 9 | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| #include "gen1.h" | ||||
| #include "is31fl3731-simple.h" | ||||
|  | ||||
| void matrix_init_kb(void) { | ||||
| } | ||||
| @@ -23,6 +22,8 @@ void matrix_scan_kb(void) { | ||||
| } | ||||
|  | ||||
| #ifdef LED_MATRIX_ENABLE | ||||
| #include "is31fl3731-simple.h" | ||||
|  | ||||
| const is31_led g_is31_leds[LED_DRIVER_LED_COUNT] = { | ||||
| /* Refer to IS31 manual for these locations | ||||
|  *  driver | ||||
| @@ -102,7 +103,6 @@ const is31_led g_is31_leds[LED_DRIVER_LED_COUNT] = { | ||||
| }; | ||||
|  | ||||
| const led_matrix g_leds[LED_DRIVER_LED_COUNT] = { | ||||
|  | ||||
|     /*{row | col << 4} | ||||
|       |            LED_ROW_COL(row, col) | ||||
|       |             |            modifier | ||||
|   | ||||
| @@ -155,7 +155,7 @@ | ||||
|  * I2C driver system settings. | ||||
|  */ | ||||
| #define STM32_I2C_USE_I2C1                  TRUE | ||||
| #define STM32_I2C_USE_I2C2                  FALSE | ||||
| #define STM32_I2C_USE_I2C2                  TRUE | ||||
| #define STM32_I2C_BUSY_TIMEOUT              50 | ||||
| #define STM32_I2C_I2C1_IRQ_PRIORITY         10 | ||||
| #define STM32_I2C_I2C2_IRQ_PRIORITY         10 | ||||
|   | ||||
| @@ -41,6 +41,9 @@ DFU_ARGS = -d 0483:df11 -a 0 -s 0x08000000:leave | ||||
| # LED Configuration | ||||
| LED_MATRIX_ENABLE = IS31FL3731 | ||||
|  | ||||
| # QWIIC Devices | ||||
| #QWIIC_ENABLE = RGB7SEG | ||||
|  | ||||
| # Build Options | ||||
| #   comment out to disable the options. | ||||
| # | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
| // The first section contains all of the arguments | ||||
| // The second converts the arguments into a two-dimensional array | ||||
|  | ||||
| #define LAYOUT_all( \ | ||||
| #define LAYOUT( \ | ||||
|     k00, k01, k02, k03, k04, k05, k06, k07, k50, k51, k52, k53, k54,    k56,   k57, \ | ||||
|     k10, k11, k12, k13, k14, k15, k16, k17, k60, k61, k62, k63, k64, k65,      k67, \ | ||||
|     k20, k21, k22, k23, k24, k25, k26, k27, k70, k71, k72, k73,    k75, \ | ||||
| @@ -47,25 +47,6 @@ | ||||
|     { k90, KC_NO, k92, k93, k94, k95, k96, k97 }  \ | ||||
| } | ||||
|  | ||||
| #define LAYOUT( \ | ||||
|     k00, k01, k02, k03, k04, k05, k06, k07, k50, k51, k52, k53, k54,    k56,   k57, \ | ||||
|     k10, k11, k12, k13, k14, k15, k16, k17, k60, k61, k62, k63, k64, k65,      k67, \ | ||||
|     k20, k21, k22, k23, k24, k25, k26, k27, k70, k71, k72, k73,    k75, \ | ||||
|     k30,      k32, k33, k34, k35, k36, k37, k80, k81, k82, k83,      k85, k86, \ | ||||
|     k40, k41, k42,           k45, k46,      k90,      k92, k93, k94, k95, k96, k97 \ | ||||
| ) { \ | ||||
|     { k00, k01, k02, k03, k04, k05, k06, k07 }, \ | ||||
|     { k10, k11, k12, k13, k14, k15, k16, k17 }, \ | ||||
|     { k20, k21, k22, k23, k24, k25, k26, k27 }, \ | ||||
|     { k30, KC_NO, k32, k33, k34, k35, k36, k37 }, \ | ||||
|     { k40, k41, k42, KC_NO, KC_NO, k45, k46, KC_NO }, \ | ||||
|     { k50, k51, k52, k53, k54, KC_NO, k56, k57 }, \ | ||||
|     { k60, k61, k62, k63, k64, k65, KC_NO, k67 }, \ | ||||
|     { k70, k71, k72, k73, KC_NO, k75, KC_NO, KC_NO }, \ | ||||
|     { k80, k81, k82, k83, KC_NO, k85, k86, KC_NO }, \ | ||||
|     { k90, KC_NO, k92, k93, k94, k95, k96, k97 }  \ | ||||
| } | ||||
|  | ||||
| #define LAYOUT_66_ansi( \ | ||||
|     k00, k01, k02, k03, k04, k05, k06, k07, k50, k51, k52, k53, k54,    k56,   k57, \ | ||||
|     k10, k11, k12, k13, k14, k15, k16, k17, k60, k61, k62, k63, k64, k65,      k67, \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user