Firmware support for rev5 LEDs

This commit is contained in:
William Toohey
2017-10-06 15:45:06 +10:00
parent c4cea45b40
commit 0e5c25b4ac
6 changed files with 69 additions and 143 deletions
+10 -1
View File
@@ -50,6 +50,7 @@ uint16_t MagicBootKey ATTR_NO_INIT;
*/ */
void Application_Jump_Check(void) void Application_Jump_Check(void)
{ {
#ifdef SOFT_LEDS
/* Always boot bootloader if RESET held /* Always boot bootloader if RESET held
* NOTE: This makes the assumption that * NOTE: This makes the assumption that
* A) No code on the device uses RESET as an output * A) No code on the device uses RESET as an output
@@ -58,6 +59,14 @@ void Application_Jump_Check(void)
*/ */
if(!(PINC & _BV(1))) if(!(PINC & _BV(1)))
return; return;
#else
/* New board - enable pullup for MACRO switch on PB6 */
DDRB &= ~_BV(5);
PORTB |= _BV(5);
_delay_us(500);
if(!(PINB & _BV(5)))
return;
#endif
/* If power on boot or magic key set */ /* If power on boot or magic key set */
if ((MCUSR & _BV(PORF)) || MagicBootKey == MAGIC_BOOT_KEY) if ((MCUSR & _BV(PORF)) || MagicBootKey == MAGIC_BOOT_KEY)
{ {
@@ -104,7 +113,7 @@ static void SetupHardware(void)
/* Relocate the interrupt vector table to the bootloader section */ /* Relocate the interrupt vector table to the bootloader section */
MCUCR = (1 << IVCE); MCUCR = (1 << IVCE);
MCUCR = (1 << IVSEL); MCUCR = (1 << IVSEL);
/* Initialize USB subsystem */ /* Initialize USB subsystem */
USB_Init(); USB_Init();
} }
+2 -2
View File
@@ -49,5 +49,5 @@ include $(LUFA_PATH)/Build/lufa_doxygen.mk
include $(LUFA_PATH)/Build/lufa_avrdude.mk include $(LUFA_PATH)/Build/lufa_avrdude.mk
include $(LUFA_PATH)/Build/lufa_atprogram.mk include $(LUFA_PATH)/Build/lufa_atprogram.mk
flash: all rev4: CC_FLAGS += -DSOFT_LEDS
$(AVRDUDE) -U flash:w:Bootloader.hex:i rev4: clean all
+6 -124
View File
@@ -1,66 +1,13 @@
#include "LED.h" #include "LED.h"
#define GND_COUNT 4
// RGB * 2
#define LED_PINS 6
// LED gnd 0-3 are on PC7-4
#define GND_PORT PORTC
#define GND_DDR DDRC
#define GND_MASK 0xF0
#define GND_OFFSET 4 // in bits
// LED power BGR BGR PB2-7
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_MASK (0b111111 << 2)
#define BRIGHTNESS_INCREMENT (BRIGHTNESS_LEVELS / BRIGHTNESS_DOWNSCALE)
#define UPDATE_HZ 100
// prescaler is the div8
#define TIMER_COMPARE ((F_CPU / 8 / UPDATE_HZ / GND_COUNT / BRIGHTNESS_DOWNSCALE)-1)
#if TIMER_COMPARE > 255
#error timer compare too large for timer register
#endif
#define R 2
#define G 1
#define B 0
uint8_t leds[LED_PHYSICAL_COUNT]; uint8_t leds[LED_PHYSICAL_COUNT];
static volatile uint8_t leds_frontbuffer[LED_PHYSICAL_COUNT];
void led_init() { // I can't decide if this is disgusting or delightful
// all GNDs low level for high impedence or gnd #ifdef SOFT_LEDS
GND_PORT &= ~GND_MASK; #include "LED_Driver_Software.c"
// all GNDs input #else
GND_DDR &= ~GND_MASK; #include "LED_Driver_SK9822.c"
#endif
// all LEDs off
LED_PORT &= ~LED_MASK;
// all LEDs output
LED_DDR |= LED_MASK;
memset(leds, 0, LED_PHYSICAL_COUNT);
memset((uint8_t*)leds_frontbuffer, 0, LED_PHYSICAL_COUNT);
// 64 light levels * 60Hz update * 4 different GND pins = 15360Hz
// 520 clock cycles for our interrupt handler
// CTC mode
TCCR0A = _BV(WGM01);
// clk/8 prescaler
TCCR0B = _BV(CS01);
OCR0A = TIMER_COMPARE;
// Enable interrupt on OCR0A
TIMSK0 = _BV(OCIE0A);
// Clear interrupt
TIFR0 = _BV(OCF0A);
}
void led_commit(void) {
memcpy((uint8_t*)leds_frontbuffer, leds, LED_PHYSICAL_COUNT);
}
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) { void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
uint8_t offset = num * 3; uint8_t offset = num * 3;
@@ -147,69 +94,4 @@ void led_fade_all_rgb(RGB_t* colour, uint8_t strength) {
void led_set_all_rgb(RGB_t* colour) { void led_set_all_rgb(RGB_t* colour) {
led_set_all(colour->r, colour->g, colour->b); led_set_all(colour->r, colour->g, colour->b);
}
/* Straight voodoo magic, consult the Inline Assembler Cookbook
Equivalent to:
if(*led++ > brightness)
out |= _BV(outPin)
*/
#define LED_PIN_SET(led, outPin) \
__asm__ volatile( \
"ld __tmp_reg__, %a["#led"]+ \n\t\
cp %[bright], __tmp_reg__ \n\t\
brcc skip%= \n\t\
ori %[out], (1 << "#outPin") \n\t\
skip%=:" \
: [out] "+a" (out), [led] "+z" (led) /* outputs */ \
: [bright] "r" (brightness) /* inputs */ )
// This function once took about 279 clock cycles.
// Optimised GND accesses got it to 157
// Optimised variables to static, got it to 100
// Made LED setter assembly, got it to 90
ISR(TIMER0_COMPA_vect) {
/* Why are these static here instead of at the top of file?
The compiler won't optimise 2 consecutive operations to use a register,
and instead will perform a costly lds-sts every time. Making them
static here will cache them in a local register.
*/
// Because we roll over on each loop and want to start at 0 this starts at max
static uint8_t currentGnd = GND_COUNT - 1;
// This saves us doing a costly dynamic _BV()
static uint8_t currentGndMask = 0;
static uint8_t brightness = BRIGHTNESS_LEVELS - BRIGHTNESS_INCREMENT;
static volatile uint8_t* offset = &leds_frontbuffer[0];
uint8_t out = 0;
currentGnd++;
currentGndMask >>= 1;
if(currentGnd >= GND_COUNT) {
currentGnd = 0;
// Because we work backwards start at the high end and shift down
currentGndMask = _BV(7);
offset = &leds_frontbuffer[0];
brightness += BRIGHTNESS_INCREMENT;
// brightness rolls over cleanly due to being a multiple
#if BRIGHTNESS_LEVELS != 256
if(brightness > BRIGHTNESS_MAX)
brightness = 0;
#endif
}
// Faster than loops
// NOTE: ASM MACRO INCREMENTS OFFSET
LED_PIN_SET(offset, 2);
LED_PIN_SET(offset, 3);
LED_PIN_SET(offset, 4);
LED_PIN_SET(offset, 5);
LED_PIN_SET(offset, 6);
LED_PIN_SET(offset, 7);
// Turn off before switch
LED_PORT &= ~LED_MASK;
// Enable new ground
GND_DDR = (GND_DDR & ~GND_MASK) | currentGndMask;
LED_PORT |= out;
} }
+1 -4
View File
@@ -13,11 +13,8 @@
#define LED_VIRTUAL_COUNT 6 #define LED_VIRTUAL_COUNT 6
#define LED_TOTAL_COUNT (LED_PHYSICAL_COUNT + LED_VIRTUAL_COUNT) #define LED_TOTAL_COUNT (LED_PHYSICAL_COUNT + LED_VIRTUAL_COUNT)
// Internally how many brightness levels you can use - for higher res fades // Internally how many brightness levels you can use - for higher res fades
#define BRIGHTNESS_LEVELS 128 #define BRIGHTNESS_LEVELS 256
#define BRIGHTNESS_MAX (BRIGHTNESS_LEVELS-1) #define BRIGHTNESS_MAX (BRIGHTNESS_LEVELS-1)
// How many are actually PWM'd, because the chip isn't that quick
// MUST be a multiple of BRIGHTNESS_LEVELS
#define BRIGHTNESS_DOWNSCALE 128
typedef struct { typedef struct {
uint8_t r, g, b; uint8_t r, g, b;
+32 -10
View File
@@ -6,12 +6,22 @@
#include "Macro.h" #include "Macro.h"
#define LOAD_SWITCH(source, sourceBit, result, resultBit) result |= !((source) & _BV(sourceBit)) << resultBit #define LOAD_SWITCH(source, sourceBit, result, resultBit) result |= !((source) & _BV(sourceBit)) << resultBit
// B 0,1
#define SWITCH_MASKB 0b00000011 #ifdef SOFT_LEDS
// C 1,2 // B 0,1
#define SWITCH_MASKC 0b00000110 #define SWITCH_MASKB 0b00000011
// D 4,5,6,7 // C 1,2
#define SWITCH_MASKD 0b11110000 #define SWITCH_MASKC 0b00000110
// D 4,5,6,7
#define SWITCH_MASKD 0b11110000
#else
// B 0,4,5
#define SWITCH_MASKB 0b00110001
// C 2
#define SWITCH_MASKC 0b00000100
// D 4,5,6,7
#define SWITCH_MASKD 0b11110000
#endif
// How long to wait before moving to internal lighting // How long to wait before moving to internal lighting
#define HID_LED_TIMEOUT 2000 #define HID_LED_TIMEOUT 2000
@@ -104,12 +114,21 @@ uint8_t load_switches(void) {
uint8_t tmp; uint8_t tmp;
uint8_t result = 0; uint8_t result = 0;
#ifdef SOFT_LEDS
tmp = PINB; tmp = PINB;
LOAD_SWITCH(tmp, 1, result, 1); // PINB1, A LOAD_SWITCH(tmp, 1, result, 1); // PINB1, A
LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L
tmp = PINC; tmp = PINC;
LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START
LOAD_SWITCH(tmp, 1, result, 7); // PINC1, MACRO LOAD_SWITCH(tmp, 1, result, 7); // PINC1, MACRO
#else
tmp = PINB;
LOAD_SWITCH(tmp, 4, result, 1); // PINB4, A
LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L
LOAD_SWITCH(tmp, 5, result, 7); // PINB5, MACRO
tmp = PINC;
LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START
#endif
tmp = PIND; tmp = PIND;
LOAD_SWITCH(tmp, 7, result, 2); // PIND7, B LOAD_SWITCH(tmp, 7, result, 2); // PIND7, B
LOAD_SWITCH(tmp, 5, result, 3); // PIND5, C LOAD_SWITCH(tmp, 5, result, 3); // PIND5, C
@@ -208,9 +227,8 @@ int main(void)
void SetupHardware() void SetupHardware()
{ {
uint8_t i; uint8_t i;
/* Disable watchdog if enabled by bootloader/fuses */ /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~_BV(WDRF);
wdt_disable(); wdt_disable();
for(i = 0; i < SWITCH_COUNT; i++) { for(i = 0; i < SWITCH_COUNT; i++) {
@@ -225,7 +243,9 @@ void SetupHardware()
// Pullups // Pullups
PORTB |= SWITCH_MASKB; PORTB |= SWITCH_MASKB;
PORTC |= SWITCH_MASKC; PORTC |= SWITCH_MASKC;
#ifdef SOFT_LEDS
PORTC &= ~_BV(1); // RESET has its own pullup PORTC &= ~_BV(1); // RESET has its own pullup
#endif
PORTD |= SWITCH_MASKD; PORTD |= SWITCH_MASKD;
/* Hardware Initialization */ /* Hardware Initialization */
@@ -364,15 +384,17 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI
hidTimeout = 0; hidTimeout = 0;
LED_Report_t* LEDReport = (LED_Report_t*)ReportData; LED_Report_t* LEDReport = (LED_Report_t*)ReportData;
//memcpy((uint8_t*)leds, LEDReport->mainLights, LED_PHYSICAL_COUNT); #ifdef SOFT_LEDS
// Load the user set colours as R/G/B instead of B/G/R // Load the user set colours as R/G/B instead of B/G/R
for(uint8_t i = 0; i < LED_PHYSICAL_COUNT; ) { for(uint8_t i = 0; i < LED_PHYSICAL_COUNT; ) {
uint8_t offset = i+2; uint8_t offset = i+2;
for(uint8_t j = 0; j < 3; j++) { for(uint8_t j = 0; j < 3; j++) {
// cast away the volatile for faster ops
leds[i++] = LEDReport->mainLights[offset--]; leds[i++] = LEDReport->mainLights[offset--];
} }
} }
#else
memcpy((uint8_t*)leds, LEDReport->mainLights, LED_PHYSICAL_COUNT);
#endif
// Keep normal lights but override when we get flashes on BT or FX // Keep normal lights but override when we get flashes on BT or FX
// BT LEDs // BT LEDs
+18 -2
View File
@@ -23,7 +23,7 @@ LUFA_PATH = ../LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
LD_FLAGS = LD_FLAGS =
AVRDUDE = avrdude -B 8 -c usbasp -p $(MCU) AVRDUDE = avrdude -c usbasp -p $(MCU)
# Default target # Default target
@@ -40,12 +40,23 @@ include $(LUFA_PATH)/Build/lufa_hid.mk
include $(LUFA_PATH)/Build/lufa_avrdude.mk include $(LUFA_PATH)/Build/lufa_avrdude.mk
include $(LUFA_PATH)/Build/lufa_atprogram.mk include $(LUFA_PATH)/Build/lufa_atprogram.mk
# This does not work with variables as pre-requisites. Use `make test TARGET=TestingApp`
#test: TARGET = TestingApp
test: all
cat TestingApp.hex | grep -v '^:00000001FF' > TestFull.hex
cat DFU/BootloaderUSB.hex >> TestFull.hex
debug: CC_FLAGS += -DDEBUG debug: CC_FLAGS += -DDEBUG
debug: clean flash debug: clean flash
init: erase wfuse flashboot disablereset flash rev4: CC_FLAGS += -DSOFT_LEDS
rev4: clean all
initboot: erase wfuse flashboot initboot: erase wfuse flashboot
initboot_rev4: erase wfuse flashboot_rev4
init: initboot flash
init_rev4: initboot_rev4 disablereset flash
erase: erase:
$(AVRDUDE) -e $(AVRDUDE) -e
@@ -61,11 +72,16 @@ disablereset:
$(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0x9a:m -U efuse:w:0xfe:m $(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0x9a:m -U efuse:w:0xfe:m
# To make this hex, compile the bootloader up a level # To make this hex, compile the bootloader up a level
flashboot_rev4:
$(AVRDUDE) -U flash:w:DFU/BootloaderUSB_rev4.hex:i
flashboot: flashboot:
$(AVRDUDE) -U flash:w:DFU/BootloaderUSB.hex:i $(AVRDUDE) -U flash:w:DFU/BootloaderUSB.hex:i
flash: all flash: all
cd DFU && python control_bootloader.py atmega16u2 ../$(TARGET).hex cd DFU && python control_bootloader.py atmega16u2 ../$(TARGET).hex
testflash: test wfuse
$(AVRDUDE) -U flash:w:TestFull.hex:i
md5: all md5: all
md5sum $(TARGET).bin md5sum $(TARGET).bin