From 0e5c25b4ac92693158f324aa8fd48d4e28e6523e Mon Sep 17 00:00:00 2001 From: William Toohey Date: Fri, 6 Oct 2017 15:45:06 +1000 Subject: [PATCH] Firmware support for rev5 LEDs --- Firmware/Bootloader/Bootloader.c | 11 ++- Firmware/Bootloader/makefile | 4 +- Firmware/PocketVoltex/LED.c | 130 ++------------------------- Firmware/PocketVoltex/LED.h | 5 +- Firmware/PocketVoltex/PocketVoltex.c | 42 ++++++--- Firmware/PocketVoltex/makefile | 20 ++++- 6 files changed, 69 insertions(+), 143 deletions(-) diff --git a/Firmware/Bootloader/Bootloader.c b/Firmware/Bootloader/Bootloader.c index 807e5b6..9dea901 100644 --- a/Firmware/Bootloader/Bootloader.c +++ b/Firmware/Bootloader/Bootloader.c @@ -50,6 +50,7 @@ uint16_t MagicBootKey ATTR_NO_INIT; */ void Application_Jump_Check(void) { +#ifdef SOFT_LEDS /* Always boot bootloader if RESET held * NOTE: This makes the assumption that * A) No code on the device uses RESET as an output @@ -58,6 +59,14 @@ void Application_Jump_Check(void) */ if(!(PINC & _BV(1))) 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 ((MCUSR & _BV(PORF)) || MagicBootKey == MAGIC_BOOT_KEY) { @@ -104,7 +113,7 @@ static void SetupHardware(void) /* Relocate the interrupt vector table to the bootloader section */ MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); - + /* Initialize USB subsystem */ USB_Init(); } diff --git a/Firmware/Bootloader/makefile b/Firmware/Bootloader/makefile index 494031a..e298738 100644 --- a/Firmware/Bootloader/makefile +++ b/Firmware/Bootloader/makefile @@ -49,5 +49,5 @@ include $(LUFA_PATH)/Build/lufa_doxygen.mk include $(LUFA_PATH)/Build/lufa_avrdude.mk include $(LUFA_PATH)/Build/lufa_atprogram.mk -flash: all - $(AVRDUDE) -U flash:w:Bootloader.hex:i +rev4: CC_FLAGS += -DSOFT_LEDS +rev4: clean all diff --git a/Firmware/PocketVoltex/LED.c b/Firmware/PocketVoltex/LED.c index 2e54c51..2b26441 100644 --- a/Firmware/PocketVoltex/LED.c +++ b/Firmware/PocketVoltex/LED.c @@ -1,66 +1,13 @@ #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]; -static volatile uint8_t leds_frontbuffer[LED_PHYSICAL_COUNT]; -void led_init() { - // all GNDs low level for high impedence or gnd - GND_PORT &= ~GND_MASK; - // all GNDs input - GND_DDR &= ~GND_MASK; - - // 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); -} +// I can't decide if this is disgusting or delightful +#ifdef SOFT_LEDS + #include "LED_Driver_Software.c" +#else + #include "LED_Driver_SK9822.c" +#endif void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) { 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) { 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; } \ No newline at end of file diff --git a/Firmware/PocketVoltex/LED.h b/Firmware/PocketVoltex/LED.h index c3c700e..5b6642e 100644 --- a/Firmware/PocketVoltex/LED.h +++ b/Firmware/PocketVoltex/LED.h @@ -13,11 +13,8 @@ #define LED_VIRTUAL_COUNT 6 #define LED_TOTAL_COUNT (LED_PHYSICAL_COUNT + LED_VIRTUAL_COUNT) // 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) -// 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 { uint8_t r, g, b; diff --git a/Firmware/PocketVoltex/PocketVoltex.c b/Firmware/PocketVoltex/PocketVoltex.c index 2a615e4..85076c6 100644 --- a/Firmware/PocketVoltex/PocketVoltex.c +++ b/Firmware/PocketVoltex/PocketVoltex.c @@ -6,12 +6,22 @@ #include "Macro.h" #define LOAD_SWITCH(source, sourceBit, result, resultBit) result |= !((source) & _BV(sourceBit)) << resultBit -// B 0,1 -#define SWITCH_MASKB 0b00000011 -// C 1,2 -#define SWITCH_MASKC 0b00000110 -// D 4,5,6,7 -#define SWITCH_MASKD 0b11110000 + +#ifdef SOFT_LEDS + // B 0,1 + #define SWITCH_MASKB 0b00000011 + // C 1,2 + #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 #define HID_LED_TIMEOUT 2000 @@ -104,12 +114,21 @@ uint8_t load_switches(void) { uint8_t tmp; uint8_t result = 0; +#ifdef SOFT_LEDS tmp = PINB; LOAD_SWITCH(tmp, 1, result, 1); // PINB1, A LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L tmp = PINC; LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START 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; LOAD_SWITCH(tmp, 7, result, 2); // PIND7, B LOAD_SWITCH(tmp, 5, result, 3); // PIND5, C @@ -208,9 +227,8 @@ int main(void) void SetupHardware() { uint8_t i; - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); + MCUSR &= ~_BV(WDRF); wdt_disable(); for(i = 0; i < SWITCH_COUNT; i++) { @@ -225,7 +243,9 @@ void SetupHardware() // Pullups PORTB |= SWITCH_MASKB; PORTC |= SWITCH_MASKC; +#ifdef SOFT_LEDS PORTC &= ~_BV(1); // RESET has its own pullup +#endif PORTD |= SWITCH_MASKD; /* Hardware Initialization */ @@ -364,15 +384,17 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI hidTimeout = 0; 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 for(uint8_t i = 0; i < LED_PHYSICAL_COUNT; ) { uint8_t offset = i+2; for(uint8_t j = 0; j < 3; j++) { - // cast away the volatile for faster ops 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 // BT LEDs diff --git a/Firmware/PocketVoltex/makefile b/Firmware/PocketVoltex/makefile index 4752a02..6ebcfb4 100644 --- a/Firmware/PocketVoltex/makefile +++ b/Firmware/PocketVoltex/makefile @@ -23,7 +23,7 @@ LUFA_PATH = ../LUFA CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ LD_FLAGS = -AVRDUDE = avrdude -B 8 -c usbasp -p $(MCU) +AVRDUDE = avrdude -c usbasp -p $(MCU) # 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_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: clean flash -init: erase wfuse flashboot disablereset flash +rev4: CC_FLAGS += -DSOFT_LEDS +rev4: clean all initboot: erase wfuse flashboot +initboot_rev4: erase wfuse flashboot_rev4 + +init: initboot flash +init_rev4: initboot_rev4 disablereset flash erase: $(AVRDUDE) -e @@ -61,11 +72,16 @@ disablereset: $(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 +flashboot_rev4: + $(AVRDUDE) -U flash:w:DFU/BootloaderUSB_rev4.hex:i flashboot: $(AVRDUDE) -U flash:w:DFU/BootloaderUSB.hex:i flash: all cd DFU && python control_bootloader.py atmega16u2 ../$(TARGET).hex +testflash: test wfuse + $(AVRDUDE) -U flash:w:TestFull.hex:i + md5: all md5sum $(TARGET).bin \ No newline at end of file