main firmware: fix eeprom reliability, add more LED programs

This commit is contained in:
true 2023-08-05 00:59:48 -07:00
parent f475596dcc
commit 60bd8d88b7
6 changed files with 413 additions and 81 deletions

View File

@ -155,6 +155,7 @@ typedef struct adxl345_axes {
extern adxl345_axes adxl; extern adxl345_axes adxl;
extern adxl345_axes adxl_summing;
extern uint16_t movement_worst; extern uint16_t movement_worst;

View File

@ -14,8 +14,9 @@
adxl345_axes adxl; adxl345_axes adxl;
adxl345_axes adxl_last[4]; adxl345_axes adxl_last[8];
adxl345_axes adxl_smoothing; adxl345_axes adxl_smoothing;
adxl345_axes adxl_summing;
uint8_t buf[7]; uint8_t buf[7];
@ -43,10 +44,12 @@ void adxl345_init()
void adxl345_tick() void adxl345_tick()
{ {
uint8_t i;
adxl_last[last_idx].x = adxl.x; adxl_last[last_idx].x = adxl.x;
adxl_last[last_idx].y = adxl.y; adxl_last[last_idx].y = adxl.y;
adxl_last[last_idx++].z = adxl.z; adxl_last[last_idx++].z = adxl.z;
last_idx &= 0x3; last_idx &= 0x7;
adxl345_get_axes(&adxl_smoothing); adxl345_get_axes(&adxl_smoothing);
adxl.x += adxl_smoothing.x; adxl.x >>= 1; adxl.x += adxl_smoothing.x; adxl.x >>= 1;
@ -54,6 +57,13 @@ void adxl345_tick()
adxl.z += adxl_smoothing.z; adxl.z >>= 1; adxl.z += adxl_smoothing.z; adxl.z >>= 1;
if (!last_idx) { if (!last_idx) {
adxl_summing.x = adxl_summing.y = adxl_summing.z = 0;
for (i = 0; i < 8; i++) {
adxl_summing.x += adxl_last[i].x;
adxl_summing.y += adxl_last[i].y;
adxl_summing.z += adxl_last[i].z;
}
movement = 0; movement = 0;
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
movement += (adxl_last[i].x - adxl.x) + (adxl_last[i].y - adxl.y) + (adxl_last[i].z - adxl.z); movement += (adxl_last[i].x - adxl.x) + (adxl_last[i].y - adxl.y) + (adxl_last[i].z - adxl.z);

View File

@ -8,7 +8,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include "adxl.h"
#include "btn.h" #include "btn.h"
#include "hsv2rgb.h" #include "hsv2rgb.h"
#include "led_sk6x_spi.h" #include "led_sk6x_spi.h"
@ -18,32 +20,39 @@
#define LEDPROG_MAX_PROGRAMS 7 #define LEDPROG_MAX_PROGRAMS 10
void ledprog0_twinkle_white(); void ledprog00_twinkle_white();
void ledprog1_twinkle_rgb_rand(); void ledprog01_twinkle_rgb_rand();
void ledprog2_twinkle_rgb_set(); void ledprog02_twinkle_rgb_set();
void ledprog3_rainbow(); void ledprog03_rainbow();
void ledprog4_flicker_same(); void ledprog04_flicker_same();
void ledprog5_flicker_all(); void ledprog05_flicker_all();
void ledprog6_ramper(); void ledprog06_ramper();
void ledprog07_toggles();
void ledprog08_accel_x_solid();
void ledprog09_accel_y_rainbow_shift();
const void (*led_prog_list[])() = { const void (*led_prog_list[])() = {
ledprog0_twinkle_white, ledprog00_twinkle_white,
ledprog1_twinkle_rgb_rand, ledprog01_twinkle_rgb_rand,
ledprog2_twinkle_rgb_set, ledprog02_twinkle_rgb_set,
ledprog3_rainbow, ledprog03_rainbow,
ledprog4_flicker_same, ledprog04_flicker_same,
ledprog5_flicker_all, ledprog05_flicker_all,
ledprog6_ramper ledprog06_ramper,
ledprog07_toggles,
ledprog08_accel_x_solid,
ledprog09_accel_y_rainbow_shift,
}; };
static uint8_t led_prog_active = 0; static uint8_t led_prog_active = 0;
static uint32_t work[4]; static uint32_t work[4];
static uint8_t dwell;
static uint8_t r, g, b; static uint8_t r, g, b;
@ -61,16 +70,51 @@ static uint8_t prog_idx = 0;
void ledprog_default() void ledprog_default()
{ {
uconf.led[3][2] = 2; uconf.led[0][0] = 3; // dwell
uconf.led[3][3] = 30; uconf.led[0][1] = 240; // threshold
uconf.led[4][1] = 248; uconf.led[1][0] = 3; // dwell
uconf.led[4][2] = 170; uconf.led[1][1] = 230; // threshold
uconf.led[4][3] = 16;
uconf.led[6][1] = 192; uconf.led[2][0] = 2; // dwell
uconf.led[6][2] = 30; uconf.led[2][1] = 220; // threshold
uconf.led[6][3] = 6; uconf.led[2][2] = 0; // hue
uconf.led[2][3] = 224; // sat
uconf.led[3][0] = 2; // dwell
uconf.led[3][1] = 0; // unused
uconf.led[3][2] = 2; // speed
uconf.led[3][3] = 30; // offset
uconf.led[4][0] = 5; // dwell
uconf.led[4][1] = 248; // threshold
uconf.led[4][2] = 170; // hue
uconf.led[4][3] = 32; // base
uconf.led[5][0] = 7; // dwell
uconf.led[5][1] = 240; // threshold
uconf.led[5][2] = 185; // hue
uconf.led[5][3] = 24; // base
uconf.led[6][0] = 0; // dwell
uconf.led[6][1] = 192; // speed
uconf.led[6][2] = 30; // hue
uconf.led[6][3] = 6; // faderate
uconf.led[7][0] = 1; // dwell
uconf.led[7][1] = 0x48; // 7-4: faderate, 3-0: linger
uconf.led[7][2] = 170; // hue1
uconf.led[7][3] = 0; // hue2
uconf.led[8][0] = 0; // dwell
uconf.led[8][1] = 6; // sensitivity
uconf.led[8][2] = 0; // hue offset
uconf.led[8][3] = 255; // saturation
uconf.led[9][0] = 0; // rgb or two-color mode (lowest bit)
uconf.led[9][1] = 6; // sensitivity
uconf.led[9][2] = 42; // base hue
uconf.led[9][3] = 40; // offset (rgb) or alt_hue-128offset (two-color)
} }
void ledprog_change(uint8_t idx) void ledprog_change(uint8_t idx)
@ -78,6 +122,7 @@ void ledprog_change(uint8_t idx)
uint8_t i; uint8_t i;
led_prog_active = idx; led_prog_active = idx;
dwell = 0;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
work[i] = 0; work[i] = 0;
@ -110,8 +155,12 @@ void ledprog_btn_held_cb(uint8_t idx)
prog_mode ^= 1; prog_mode ^= 1;
prog_idx = prog_tmr = 0; prog_idx = prog_tmr = 0;
// when leaving programming mode we need to commit settings to flash // when leaving programming mode we need to commit some things
if (!prog_mode) { if (!prog_mode) {
// make sure user LED is off
userled_set(0);
// save settings to flash
uconf.led_prog_idx = led_prog_active; uconf.led_prog_idx = led_prog_active;
uconf_save(); uconf_save();
} }
@ -243,10 +292,15 @@ void ledprog_run()
} }
// always run a program // always run a program
led_prog_list[led_prog_active](); if (!dwell || led_prog_active == 9) {
dwell = uconf.led[led_prog_active][0] & 0xf;
led_prog_list[led_prog_active]();
} else {
dwell--;
}
} }
void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b) void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b, uint8_t thresh)
{ {
uint8_t x; uint8_t x;
@ -254,7 +308,7 @@ void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b)
led_sk6x_set_all(0, 0, 0); led_sk6x_set_all(0, 0, 0);
if (x > 240) { if (x > thresh) {
x = prng_get32() & 0x7; x = prng_get32() & 0x7;
led_sk6x_set(x, r, g, b); led_sk6x_set(x, r, g, b);
} }
@ -265,9 +319,9 @@ void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b)
* 0 dwell * 0 dwell
* 1 threshold * 1 threshold
*/ */
void ledprog0_twinkle_white() void ledprog00_twinkle_white()
{ {
ledprogi_twinkle(0xff, 0xff, 0xff); ledprogi_twinkle(0xff, 0xff, 0xff, uconf.led[0][1]);
} }
/* /*
@ -275,7 +329,7 @@ void ledprog0_twinkle_white()
* 0 dwell * 0 dwell
* 1 threshold * 1 threshold
*/ */
void ledprog1_twinkle_rgb_rand() void ledprog01_twinkle_rgb_rand()
{ {
uint32_t x; uint32_t x;
@ -305,7 +359,7 @@ void ledprog1_twinkle_rgb_rand()
} }
} }
ledprogi_twinkle(r, g, b); ledprogi_twinkle(r, g, b, uconf.led[1][1]);
} }
@ -314,26 +368,25 @@ void ledprog1_twinkle_rgb_rand()
* 0 dwell * 0 dwell
* 1 threshold * 1 threshold
* 2 hue * 2 hue
* 3 val * 3 sat
*/ */
void ledprog2_twinkle_rgb_set() void ledprog02_twinkle_rgb_set()
{ {
hsv2rgb_8b(uconf.led[2][2] * 6, 255, uconf.led[2][3], &r, &g, &b); hsv2rgb_8b(uconf.led[2][2] * 6, uconf.led[2][3], 255, &r, &g, &b);
ledprogi_twinkle(r, g, b); ledprogi_twinkle(r, g, b, uconf.led[2][1]);
} }
/* /*
* uconf.led: * uconf.led:
* 0 dwell * 0 dwell
* 1 threshold
* 2 speed * 2 speed
* 3 skip * 3 offset
* *
* work: * work:
* 0 base hue * 0 base hue
*/ */
void ledprog3_rainbow() void ledprog03_rainbow()
{ {
uint8_t i; uint8_t i;
uint16_t w; uint16_t w;
@ -344,6 +397,12 @@ void ledprog3_rainbow()
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
hsv2rgb_8b(w, 255, 255, &r, &g, &b); hsv2rgb_8b(w, 255, 255, &r, &g, &b);
// knock off some bits of low values to make solid colors more vivid
if (r <= 3) r >>= 1;
if (g <= 3) g >>= 1;
if (b <= 3) b >>= 1;
led_sk6x_set(i, r, g, b); led_sk6x_set(i, r, g, b);
w += (uconf.led[3][3] * 6) + 1; w += (uconf.led[3][3] * 6) + 1;
@ -351,19 +410,19 @@ void ledprog3_rainbow()
} }
} }
void ledprogi_flicker() void ledprogi_flicker(uint8_t idx)
{ {
uint16_t h; uint16_t h;
uint8_t x; uint8_t x;
h = uconf.led[4][2] * 6; h = uconf.led[idx][2] * 6;
x = prng_get8(); x = prng_get8();
if (x > uconf.led[4][1]) { if (x > uconf.led[idx][1]) {
x = 255; x = 255;
} else { } else {
x = uconf.led[4][3]; x = uconf.led[idx][3];
} }
x &= ~0x07; x &= ~0x07;
@ -379,25 +438,25 @@ void ledprogi_flicker()
* 2 hue * 2 hue
* 3 base * 3 base
*/ */
void ledprog4_flicker_same() void ledprog04_flicker_same()
{ {
ledprogi_flicker(); ledprogi_flicker(4);
led_sk6x_set_all(r, g, b); led_sk6x_set_all(r, g, b);
} }
/* /*
* uconf.led (uses ledprog4) * uconf.led
* 0 dwell * 0 dwell
* 1 threshold * 1 threshold
* 2 hue * 2 hue
* 3 val * 3 base
*/ */
void ledprog5_flicker_all() void ledprog05_flicker_all()
{ {
uint8_t i; uint8_t i;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
ledprogi_flicker(); ledprogi_flicker(5);
led_sk6x_set(i, r, g, b); led_sk6x_set(i, r, g, b);
} }
} }
@ -412,7 +471,7 @@ void ledprog5_flicker_all()
* work: * work:
* 0 ramper state * 0 ramper state
*/ */
void ledprog6_ramper() void ledprog06_ramper()
{ {
uint8_t i; uint8_t i;
@ -473,3 +532,241 @@ void ledprog6_ramper()
work[3] |= v[4 + i] << (i * 8); work[3] |= v[4 + i] << (i * 8);
} }
} }
/*
* uconf.led
* 0 dwell
* 1 top half: fade rate, bottom half: linger
* 2 hue1
* 3 hue2
*
* work:
* 0 state machine
* 1 linger state
* 2 fade state
*/
void ledprog07_toggles()
{
uint8_t i;
uint8_t x, y;
uint8_t r2, g2, b2;
// int16_t e, f, h;
switch (work[0]) {
case 0: // color2 even, color3 odd
case 2: { // color2 odd, color3 even
x = work[0] ? 2 : 3;
y = x ^ 1;
hsv2rgb_8b((uconf.led[7][x] * 6), 255, 255, &r, &g, &b);
hsv2rgb_8b((uconf.led[7][y] * 6), 255, 255, &r2, &g2, &b2);
for (i = 0; i < 8; i += 2) {
led_sk6x_set(i + 0, r, g, b);
led_sk6x_set(i + 1, r2, g2, b2);
}
work[0]++;
work[1] = uconf.led[7][1] & 0xf;
work[2] = uconf.led[7][1] >> 4;
break;
}
case 1:
case 3: {
//linger
if (!work[1]) {
// fade
/* this ended up looking like shit, so nixed for now
if (!work[2]) {
work[0]++;
} else {
// calculate huefade step amount
e = uconf.led[7][2]; // set hue1
e -= uconf.led[7][3]; // subtract hue2
e = abs(e) * 6; // expanded full size
f = e / (uconf.led[7][1] >> 4);// only a step of this
f *= work[2];
// apply fade
x = (work[0] & 2) ? 3 : 2;
y = x ^ 1;
h = (uconf.led[7][x] * 6);
h += f;
h %= 1536;
hsv2rgb_8b(h, 255, 255, &r, &g, &b);
h = (uconf.led[7][y] * 6);
h += (e - f);
h %= 1536;
hsv2rgb_8b(h, 255, 255, &r2, &g2, &b2);
for (i = 0; i < 8; i += 2) {
led_sk6x_set(i + 0, r, g, b);
led_sk6x_set(i + 1, r2, g2, b2);
}
work[2]--;
}
*/
work[0]++;
} else work[1]--;
break;
}
}
if (work[0] > 3) work[0] = 0;
}
/*
* uconf.led
* 0 dwell
* 1 sensitivity
* 2 hue_offset
* 3 sat
*/
void ledprog08_accel_x_solid()
{
uint16_t h;
uint8_t z;
uint8_t s;
// get hue from axis
h = abs(adxl_summing.x);
h *= (uconf.led[8][1] & 0xf);
h += (uconf.led[8][2] * 6);
h %= 1536;
// get brightness from Z
if (abs(adxl_summing.z) > 224) {
z = 224;
} else z = abs(adxl_summing.z) & 0xff;
// get saturation with cap
s = uconf.led[8][3];
if (s < 128) s = 128;
hsv2rgb_8b(h, s, 255 - z, &r, &g, &b);
led_sk6x_set_all(r, g, b);
}
/*
* uconf.led
* 0 dwell
* 1 sensitivity
* 2 base_hue
* 3 expansion
*/
/*
void ledprog09_accel_y_rainbow_fade()
{
uint8_t i;
int16_t h;
int16_t hstep;
uint8_t z;
// get hue from axis
hstep = adxl_summing.y;
// cap
if (hstep > 255) hstep = 255;
if (hstep < -255) hstep = -255;
// set step size by expanding, then divide by number of LED "sections"
hstep *= 6;
hstep /= 7;
// expand by expansion amount
if (hstep > 0) hstep += (uconf.led[9][3] * 2);
else hstep -= (uconf.led[9][3] * 2);
// set initial hue to be 2 steps back (to center on center LED in badge)
h = uconf.led[9][2] * 6;
h -= hstep;
h -= hstep;
if (hstep < 0) hstep += 1536;
// get brightness from Z
if (abs(adxl_summing.z) > 224) {
z = 224;
} else z = abs(adxl_summing.z) & 0xff;
for (i = 0; i < 8; i++) {
hsv2rgb_8b(h, 255, 255 - z, &r, &g, &b);
led_sk6x_set(i, r, g, b);
// both sides of top LEDs match
if (i == 5) {
i++;
led_sk6x_set(i, r, g, b);
}
// move forward another step
h += hstep;
h += uconf.led[9][3];
h %= 1536;
}
}
*/
/*
* uconf.led
* 0 rgb or two-color (lowest bit)
* 1 sensitivity
* 2 base_hue
* 3 offset (rgb) or alt_hue-128offset (two-color)
*/
void ledprog09_accel_y_rainbow_shift()
{
uint8_t i;
uint16_t h;
int16_t y;
int16_t check;
int16_t m;
uint8_t z;
// get hue from axis
y = adxl_summing.y;
// cap
if (y > 255) y = 255;
if (y < -256) y = -256;
y = 0 - y;
// get brightness from Z
if (abs(adxl_summing.z) > 224) {
z = 224;
} else z = abs(adxl_summing.z) & 0xff;
check = -256;
for (i = 0; i < 8; i++) {
if (i != 7) {
m = abs(i - 3) * 45;
m = 150 - m;
} else {
m = 15;
}
if (y >= check && y < (check + m)) {
h = uconf.led[9][2];
} else {
h = uconf.led[9][3] + 128;
h &= 0xff;
}
h *= 6;
check += m;
hsv2rgb_8b(h, 255, 255 - z, &r, &g, &b);
led_sk6x_set(i, r, g, b);
// both sides of top LEDs match
if (i == 5) {
i++;
led_sk6x_set(i, r, g, b);
}
}
}

View File

@ -26,7 +26,7 @@
#define GPIO_RCC_AHB_GPIO_ALL RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | \ #define GPIO_RCC_AHB_GPIO_ALL RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | \
RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD
#define NO_MOVE_SLEEP_TIME (15 * 60) * 32 #define NO_MOVE_SLEEP_TIME (15 * 60) * 128
@ -144,6 +144,32 @@ static void gpio_init()
GPIO_Init(GPIOB, &gpio); GPIO_Init(GPIOB, &gpio);
} }
// timing insensitive loop
__attribute__ ((long_call, section(".ramfunc"))) void app_loop()
{
while(1) {
if (cnt2 != cnt) {
cnt2++;
if (cnt2 >= 1024) cnt2 = 0;
// button processing (512Hz)
if (cnt2 & 1) {
btn_callback();
}
// led programs (128Hz)
if ((cnt2 & 0x7) == 0) {
ledprog_run();
// stuff next LED bits
led_sk6x_process();
}
}
__WFI();
}
}
// startup // startup
int main(void) int main(void)
{ {
@ -176,31 +202,11 @@ int main(void)
#endif #endif
tim6_init(); tim6_init();
// do nothing // run non-timing-constrained code
while(1) { app_loop();
if (cnt2 != cnt) {
cnt2++;
if (cnt2 >= 1024) cnt2 = 0;
// button processing (512Hz)
if (cnt2 & 1) {
btn_callback();
}
// led programs (128Hz)
if ((cnt2 & 0x7) == 0) {
ledprog_run();
// stuff next LED bits
led_sk6x_process();
}
}
__WFI();
}
} }
// main code loop // 1KHz main logic loop
__attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler() __attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler()
{ {
// clear interrupt // clear interrupt
@ -216,8 +222,8 @@ __attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler()
btn_tick(); btn_tick();
} }
// accelerometer: tick 32Hz // accelerometer: tick 128Hz
if ((cnt & 0x1f) == 0x1e) { if ((cnt & 0x7) == 0x6) {
adxl345_tick(); adxl345_tick();
// should we sleep? // should we sleep?

View File

@ -31,6 +31,8 @@ void uconf_save()
uint8_t i; uint8_t i;
UserConf_t usave; UserConf_t usave;
FLASH_Status status;
uint8_t *eeprom = (uint8_t *)EEPROM_BASE_ADDR; uint8_t *eeprom = (uint8_t *)EEPROM_BASE_ADDR;
uint8_t *u8save = (uint8_t *)&usave; uint8_t *u8save = (uint8_t *)&usave;
@ -39,19 +41,35 @@ void uconf_save()
// never save brightness as minimum value // never save brightness as minimum value
if (!usave.led_bright) usave.led_bright++; if (!usave.led_bright) usave.led_bright++;
// while saving data, disable interrupts
__disable_irq();
// commit bytes to eeprom only if they differ // commit bytes to eeprom only if they differ
FLASH_Unlock();
for (i = 0; i < sizeof(uconf); i++) { for (i = 0; i < sizeof(uconf); i++) {
if (*eeprom != *u8save) { if (*eeprom != *u8save) {
// erase byte // erase byte
EEPROM_EraseByte((uint32_t)eeprom); while (*eeprom) {
status = EEPROM_EraseByte((uint32_t)eeprom);
if (status != FLASH_COMPLETE) {
while(1);
}
}
// write new byte // write new byte
EEPROM_ProgramByte((uint32_t)eeprom, *u8save); status = EEPROM_ProgramByte((uint32_t)eeprom, *u8save);
if (status != FLASH_COMPLETE) {
while(1);
}
} }
eeprom++; eeprom++;
u8save++; u8save++;
} }
FLASH_Lock();
// re-enable interrupts
__enable_irq();
} }
void uconf_restore(uint8_t force_defaults) void uconf_restore(uint8_t force_defaults)
@ -63,7 +81,7 @@ void uconf_restore(uint8_t force_defaults)
uconf.magic = UCONF_MAGIC; uconf.magic = UCONF_MAGIC;
uconf.led_prog_idx = 3; // rainbow uconf.led_prog_idx = 3; // rainbow
uconf.led_bright = 3; // 50% brightness uconf.led_bright = 4; // 50% brightness
uconf.led_zone = 7; // all zones active uconf.led_zone = 7; // all zones active
ledprog_default(); ledprog_default();

View File

@ -1017,7 +1017,7 @@ FLASH_Status EEPROM_EraseByte(uint32_t Address)
{ {
/* If the previous operation is completed, proceed to program the new data */ /* If the previous operation is completed, proceed to program the new data */
FLASH->ECR |= FLASH_ECR_EEPROM_ER; FLASH->ECR |= FLASH_ECR_EEPROM_ER;
FLASH->AR = Address; FLASH->AR = Address;
FLASH->CR |= FLASH_CR_STRT; FLASH->CR |= FLASH_CR_STRT;
/* Wait for last operation to be completed */ /* Wait for last operation to be completed */