Much improved LEDs and persistant knob LEDs

This commit is contained in:
William Toohey
2017-02-10 03:54:17 +10:00
parent 0a3c53eea1
commit fcae815027
5 changed files with 67 additions and 20 deletions
+37 -3
View File
@@ -28,6 +28,8 @@
#define G 1
#define B 0
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;
@@ -39,7 +41,8 @@ void led_init() {
// all LEDs output
LED_DDR |= LED_MASK;
memset((uint8_t*)leds, 0, LED_PHYSICAL_COUNT);
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
@@ -54,6 +57,10 @@ void led_init() {
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) {
uint8_t offset = num * 3;
leds[offset+R] = r;
@@ -71,6 +78,33 @@ void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
leds[offset+B] = b;
}
// Applies a crossfade between the current colour and an overlay colour with a given strength
void led_fade_over(uint8_t num, uint8_t r, uint8_t g, uint8_t b, uint8_t strength) {
uint8_t offset = num * 3;
// going outside max val for a signed int8
int16_t scales[3];
// get colour distances
scales[R] = r - leds[offset+R];
scales[G] = g - leds[offset+G];
scales[B] = b - leds[offset+B];
for(uint8_t i = 0; i < 3; i++) {
// perform scaling with div0 check
if(scales[i] == 0) {
scales[i] = BRIGHTNESS_LEVELS;
} else {
// won't ever be 0, don't check later
scales[i] = BRIGHTNESS_LEVELS / scales[i];
}
int16_t new = leds[offset+i] + strength/scales[i];
// Integer division strikes again
if(new > BRIGHTNESS_MAX)
new = BRIGHTNESS_MAX;
if(new < 0)
new = 0;
leds[offset+i] = new;
}
}
void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
for(uint8_t i = 0; i < LED_COUNT; i++) {
led_set(i, r, g, b);
@@ -111,7 +145,7 @@ ISR(TIMER0_COMPA_vect) {
// 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[0];
static volatile uint8_t* offset = &leds_frontbuffer[0];
uint8_t out = 0;
@@ -121,7 +155,7 @@ ISR(TIMER0_COMPA_vect) {
currentGnd = 0;
// Because we work backwards start at the high end and shift down
currentGndMask = _BV(7);
offset = &leds[0];
offset = &leds_frontbuffer[0];
brightness += BRIGHTNESS_INCREMENT;
// brightness rolls over cleanly due to being a multiple
}
+3 -1
View File
@@ -25,7 +25,7 @@ typedef struct {
// Arranged left to right, top to bottom
// LED order is BGR...BGR
volatile uint8_t leds[LED_PHYSICAL_COUNT];
uint8_t leds[LED_PHYSICAL_COUNT];
// Maps BT/FX keys to their associated LED
// Order is BT-1-4, FX-L, FX-R
@@ -37,8 +37,10 @@ static const PROGMEM uint8_t ledLeftCircleMap[] = {0, 2, 4, 6};
static const PROGMEM uint8_t ledRightCircleMap[] = {7, 5, 3, 1};
void led_init(void);
void led_commit(void);
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
void led_fade_over(uint8_t num, uint8_t r, uint8_t g, uint8_t b, uint8_t strength);
void led_set_all(uint8_t r, uint8_t g, uint8_t b);
void led_set_indiv(uint8_t num, uint8_t val);
+11 -13
View File
@@ -41,19 +41,19 @@ typedef struct {
// OPTIONS SHOULD BE: blue, pink, green, yellow
static KnobLights knobs[2] = {
// Aqua, mid left LEDs
{{0,1,1}, {2,3}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}},
{{0,BRIGHTNESS_MAX,BRIGHTNESS_MAX}, {2,3}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}},
// Pink, mid right LEDs
{{1,0,1}, {0,1}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}}
{{BRIGHTNESS_MAX,0,BRIGHTNESS_MAX}, {0,1}, {BRIGHTNESS_LEVELS/2, BRIGHTNESS_LEVELS/2}}
};
void led_knob_light_indiv(KnobLights* knob, const uint8_t* map);
uint8_t led_on_frame(void) {
return ++frameCounter >= LED_MS_PER_FRAME;
}
// Called every 1ms
void led_frame(void) {
if(++frameCounter < LED_MS_PER_FRAME) {
return;
}
void led_animate(void) {
frameCounter = 0;
switch(animMode) {
@@ -113,19 +113,17 @@ void led_frame(void) {
break;
}
// Knob lights, what shall I do with you?
led_set_all(0,0,0);
led_knob_light_indiv(&knobs[0], ledLeftCircleMap);
led_knob_light_indiv(&knobs[1], ledRightCircleMap);
}
void led_knob_light_indiv(KnobLights* knob, const uint8_t* map) {
for(uint8_t led = 0; led < 2; led++) {
uint8_t r = knob->levels[led] * knob->rgb[0];
uint8_t g = knob->levels[led] * knob->rgb[1];
uint8_t b = knob->levels[led] * knob->rgb[2];
uint8_t r = knob->rgb[0];
uint8_t g = knob->rgb[1];
uint8_t b = knob->rgb[2];
//led_set_max(ledCircleMap[knobs[i].leds[led]], r, g, b);
led_set(pgm_read_byte(&map[knob->leds[led]]), r, g, b);
led_fade_over(pgm_read_byte(&map[knob->leds[led]]), r, g, b, knob->levels[led]);
}
}
+2 -1
View File
@@ -22,7 +22,8 @@ enum LEDMode {
BREATHE,
};
void led_frame(void);
uint8_t led_on_frame(void);
void led_animate(void);
void led_anim_flash(void);
void led_anim_follower(void);
void led_knobs_update(int8_t left, int8_t right);
+14 -2
View File
@@ -38,6 +38,7 @@ static uint8_t PrevInputsHIDReportBuffer[MAX(sizeof(Keyboard_Report_t), sizeof(U
static uint8_t PrevLEDHIDReportBuffer[sizeof(LED_Report_t)];
static uint8_t sendKeyboard = 0;
static uint8_t updateLEDs = 1;
/** LUFA HID Class driver interface configuration and state information. This structure is
* passed to all HID Class driver functions, so that multiple instances of the same class
@@ -181,6 +182,12 @@ int main(void)
break;
}
}
if(updateLEDs) {
updateLEDs = 0;
led_animate();
led_commit();
}
}
}
@@ -312,7 +319,7 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI
uint8_t offset = i+2;
for(uint8_t j = 0; j < 3; j++) {
// cast away the volatile for faster ops
((uint8_t*)leds)[i++] = LEDReport->mainLights[offset--];
leds[i++] = LEDReport->mainLights[offset--];
}
}
@@ -343,6 +350,7 @@ void EVENT_USB_Device_Connect(void)
void EVENT_USB_Device_Disconnect(void)
{
led_set_all(0,0,0);
led_commit();
}
/** Event handler for the library USB Configuration Changed event. */
@@ -371,7 +379,11 @@ void EVENT_USB_Device_StartOfFrame(void)
HID_Device_MillisecondElapsed(&LED_HID_Interface);
if(hidTimeout > HID_LED_TIMEOUT) {
led_frame();
// we use a sentinel since this is actually inside an interrupt!
// less LED flicker if ran outside
if(led_on_frame()) {
updateLEDs = 1;
}
} else {
hidTimeout++;
}