mirror of
https://github.com/mon/PocketVoltex.git
synced 2026-09-22 22:57:58 +03:00
Firmware support for rev5 LEDs
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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;
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user