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)
|
||||
{
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+6
-124
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user