diff --git a/badge_firmware/code/inc/adxl.h b/badge_firmware/code/inc/adxl.h index 4e1a041..38ffc64 100644 --- a/badge_firmware/code/inc/adxl.h +++ b/badge_firmware/code/inc/adxl.h @@ -155,6 +155,7 @@ typedef struct adxl345_axes { extern adxl345_axes adxl; +extern adxl345_axes adxl_summing; extern uint16_t movement_worst; diff --git a/badge_firmware/code/src/adxl.c b/badge_firmware/code/src/adxl.c index 06021ef..225a1eb 100644 --- a/badge_firmware/code/src/adxl.c +++ b/badge_firmware/code/src/adxl.c @@ -14,8 +14,9 @@ adxl345_axes adxl; -adxl345_axes adxl_last[4]; +adxl345_axes adxl_last[8]; adxl345_axes adxl_smoothing; +adxl345_axes adxl_summing; uint8_t buf[7]; @@ -43,10 +44,12 @@ void adxl345_init() void adxl345_tick() { + uint8_t i; + adxl_last[last_idx].x = adxl.x; adxl_last[last_idx].y = adxl.y; adxl_last[last_idx++].z = adxl.z; - last_idx &= 0x3; + last_idx &= 0x7; adxl345_get_axes(&adxl_smoothing); adxl.x += adxl_smoothing.x; adxl.x >>= 1; @@ -54,6 +57,13 @@ void adxl345_tick() adxl.z += adxl_smoothing.z; adxl.z >>= 1; 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; 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); diff --git a/badge_firmware/code/src/led_prog.c b/badge_firmware/code/src/led_prog.c index ad62d4c..fceeec4 100644 --- a/badge_firmware/code/src/led_prog.c +++ b/badge_firmware/code/src/led_prog.c @@ -8,7 +8,9 @@ #include +#include +#include "adxl.h" #include "btn.h" #include "hsv2rgb.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 ledprog1_twinkle_rgb_rand(); -void ledprog2_twinkle_rgb_set(); -void ledprog3_rainbow(); -void ledprog4_flicker_same(); -void ledprog5_flicker_all(); -void ledprog6_ramper(); +void ledprog00_twinkle_white(); +void ledprog01_twinkle_rgb_rand(); +void ledprog02_twinkle_rgb_set(); +void ledprog03_rainbow(); +void ledprog04_flicker_same(); +void ledprog05_flicker_all(); +void ledprog06_ramper(); +void ledprog07_toggles(); +void ledprog08_accel_x_solid(); +void ledprog09_accel_y_rainbow_shift(); const void (*led_prog_list[])() = { - ledprog0_twinkle_white, - ledprog1_twinkle_rgb_rand, - ledprog2_twinkle_rgb_set, - ledprog3_rainbow, - ledprog4_flicker_same, - ledprog5_flicker_all, - ledprog6_ramper + ledprog00_twinkle_white, + ledprog01_twinkle_rgb_rand, + ledprog02_twinkle_rgb_set, + ledprog03_rainbow, + ledprog04_flicker_same, + ledprog05_flicker_all, + ledprog06_ramper, + ledprog07_toggles, + ledprog08_accel_x_solid, + ledprog09_accel_y_rainbow_shift, }; static uint8_t led_prog_active = 0; static uint32_t work[4]; +static uint8_t dwell; static uint8_t r, g, b; @@ -61,16 +70,51 @@ static uint8_t prog_idx = 0; void ledprog_default() { - uconf.led[3][2] = 2; - uconf.led[3][3] = 30; + uconf.led[0][0] = 3; // dwell + uconf.led[0][1] = 240; // threshold - uconf.led[4][1] = 248; - uconf.led[4][2] = 170; - uconf.led[4][3] = 16; + uconf.led[1][0] = 3; // dwell + uconf.led[1][1] = 230; // threshold - uconf.led[6][1] = 192; - uconf.led[6][2] = 30; - uconf.led[6][3] = 6; + uconf.led[2][0] = 2; // dwell + uconf.led[2][1] = 220; // threshold + 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) @@ -78,6 +122,7 @@ void ledprog_change(uint8_t idx) uint8_t i; led_prog_active = idx; + dwell = 0; for (i = 0; i < 4; i++) { work[i] = 0; @@ -110,8 +155,12 @@ void ledprog_btn_held_cb(uint8_t idx) prog_mode ^= 1; 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) { + // make sure user LED is off + userled_set(0); + + // save settings to flash uconf.led_prog_idx = led_prog_active; uconf_save(); } @@ -243,10 +292,15 @@ void ledprog_run() } // 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; @@ -254,7 +308,7 @@ void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b) led_sk6x_set_all(0, 0, 0); - if (x > 240) { + if (x > thresh) { x = prng_get32() & 0x7; 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 * 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 * 1 threshold */ -void ledprog1_twinkle_rgb_rand() +void ledprog01_twinkle_rgb_rand() { 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 * 1 threshold * 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: * 0 dwell - * 1 threshold * 2 speed - * 3 skip + * 3 offset * * work: * 0 base hue */ -void ledprog3_rainbow() +void ledprog03_rainbow() { uint8_t i; uint16_t w; @@ -344,6 +397,12 @@ void ledprog3_rainbow() for (i = 0; i < 8; i++) { 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); 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; uint8_t x; - h = uconf.led[4][2] * 6; + h = uconf.led[idx][2] * 6; x = prng_get8(); - if (x > uconf.led[4][1]) { + if (x > uconf.led[idx][1]) { x = 255; } else { - x = uconf.led[4][3]; + x = uconf.led[idx][3]; } x &= ~0x07; @@ -379,25 +438,25 @@ void ledprogi_flicker() * 2 hue * 3 base */ -void ledprog4_flicker_same() +void ledprog04_flicker_same() { - ledprogi_flicker(); + ledprogi_flicker(4); led_sk6x_set_all(r, g, b); } /* - * uconf.led (uses ledprog4) + * uconf.led * 0 dwell * 1 threshold * 2 hue - * 3 val + * 3 base */ -void ledprog5_flicker_all() +void ledprog05_flicker_all() { uint8_t i; for (i = 0; i < 8; i++) { - ledprogi_flicker(); + ledprogi_flicker(5); led_sk6x_set(i, r, g, b); } } @@ -412,7 +471,7 @@ void ledprog5_flicker_all() * work: * 0 ramper state */ -void ledprog6_ramper() +void ledprog06_ramper() { uint8_t i; @@ -473,3 +532,241 @@ void ledprog6_ramper() 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); + } + } +} diff --git a/badge_firmware/code/src/main.c b/badge_firmware/code/src/main.c index 3588ba7..24b4650 100644 --- a/badge_firmware/code/src/main.c +++ b/badge_firmware/code/src/main.c @@ -26,7 +26,7 @@ #define GPIO_RCC_AHB_GPIO_ALL RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | \ 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); } +// 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 int main(void) { @@ -176,31 +202,11 @@ int main(void) #endif tim6_init(); - // do nothing - 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(); - } + // run non-timing-constrained code + app_loop(); } -// main code loop +// 1KHz main logic loop __attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler() { // clear interrupt @@ -216,8 +222,8 @@ __attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler() btn_tick(); } - // accelerometer: tick 32Hz - if ((cnt & 0x1f) == 0x1e) { + // accelerometer: tick 128Hz + if ((cnt & 0x7) == 0x6) { adxl345_tick(); // should we sleep? diff --git a/badge_firmware/code/src/userconf.c b/badge_firmware/code/src/userconf.c index 0012955..01fabd5 100644 --- a/badge_firmware/code/src/userconf.c +++ b/badge_firmware/code/src/userconf.c @@ -31,6 +31,8 @@ void uconf_save() uint8_t i; UserConf_t usave; + FLASH_Status status; + uint8_t *eeprom = (uint8_t *)EEPROM_BASE_ADDR; uint8_t *u8save = (uint8_t *)&usave; @@ -39,19 +41,35 @@ void uconf_save() // never save brightness as minimum value if (!usave.led_bright) usave.led_bright++; + // while saving data, disable interrupts + __disable_irq(); + // commit bytes to eeprom only if they differ + FLASH_Unlock(); for (i = 0; i < sizeof(uconf); i++) { if (*eeprom != *u8save) { // erase byte - EEPROM_EraseByte((uint32_t)eeprom); + while (*eeprom) { + status = EEPROM_EraseByte((uint32_t)eeprom); + if (status != FLASH_COMPLETE) { + while(1); + } + } // write new byte - EEPROM_ProgramByte((uint32_t)eeprom, *u8save); + status = EEPROM_ProgramByte((uint32_t)eeprom, *u8save); + if (status != FLASH_COMPLETE) { + while(1); + } } eeprom++; u8save++; } + FLASH_Lock(); + + // re-enable interrupts + __enable_irq(); } void uconf_restore(uint8_t force_defaults) @@ -63,7 +81,7 @@ void uconf_restore(uint8_t force_defaults) uconf.magic = UCONF_MAGIC; 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 ledprog_default(); diff --git a/badge_firmware/driver/HK32F030M_Driver/src/hk32f030m_flash.c b/badge_firmware/driver/HK32F030M_Driver/src/hk32f030m_flash.c index 2c1aeeb..3b609d6 100644 --- a/badge_firmware/driver/HK32F030M_Driver/src/hk32f030m_flash.c +++ b/badge_firmware/driver/HK32F030M_Driver/src/hk32f030m_flash.c @@ -1017,7 +1017,7 @@ FLASH_Status EEPROM_EraseByte(uint32_t Address) { /* If the previous operation is completed, proceed to program the new data */ FLASH->ECR |= FLASH_ECR_EEPROM_ER; - FLASH->AR = Address; + FLASH->AR = Address; FLASH->CR |= FLASH_CR_STRT; /* Wait for last operation to be completed */