diff --git a/firmware/user/ch32v20x_it.c b/firmware/user/ch32v20x_it.c index c54b50b..572066c 100644 --- a/firmware/user/ch32v20x_it.c +++ b/firmware/user/ch32v20x_it.c @@ -56,28 +56,24 @@ volatile uint32_t uptime; void SysTick_Handler(void) { - if (++ticnt > 0x1ff) { + if (++ticnt > 0x3ff) { ticnt = 0; uptime++; } - // all processes update at 1/128 duty - switch (ticnt & 0x3) { + // light sensor updates at ~1ms + adc_process_lsens(); + + // general processes update at 1/128 duty + switch (ticnt & 0x7) { case 0: { // send new LEDs led_rgb_update(); led_matrix_send(); break; } - case 1: { // process / initialize light sensor - adc_process_lsens(0); - break; - } - case 2: { // convert light sensor - adc_process_lsens(1); - break; - } - case 3: { // process buttons + case 1: { // process buttons btn_poll(); + break; } } diff --git a/firmware/user/main.c b/firmware/user/main.c index 1d055eb..443ac59 100644 --- a/firmware/user/main.c +++ b/firmware/user/main.c @@ -36,7 +36,7 @@ void systick_init(void) { - SysTick->CMP = (SystemCoreClock / 512) - 1; // we want a 512Hz interrupt + SysTick->CMP = (SystemCoreClock / 1024) - 1; // we want a 1024Hz interrupt SysTick->CNT = 0; // clear counter SysTick->CTLR = 0xF; // start counter in /1 mode, enable interrupts, auto-reset counter SysTick->SR = 0; // clear count comparison flag @@ -123,6 +123,9 @@ int main(void) lis2dw_init(); // looking at badge: Y+ up, X+ right, Z+ in front of badge led_init(); // configure matrix IC as well as RGB PWM + // by default, top LED is in light sense mode + adc_set_mode_lsens(LSENS_READING_IDLE); + // configure random tinymt32_init(&tinymt32_s, DBGMCU_GetCHIPID() | userconf.checksum); diff --git a/firmware/user/src/adc.c b/firmware/user/src/adc.c index 9de895d..a287a7f 100644 --- a/firmware/user/src/adc.c +++ b/firmware/user/src/adc.c @@ -18,8 +18,12 @@ static GPIO_InitTypeDef lsens_gpio = { }; uint16_t lsens_val; + static uint8_t lsens_mode = LSENS_READING_IDLE; +uint8_t lsens_wait; +uint8_t lsens_coarse = 1; + void adc_init() @@ -48,19 +52,16 @@ void adc_convert() void adc_read() { - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); - lsens_val = ADC_GetConversionValue(ADC1); + uint16_t timeout = 0xfff; + while((!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) && timeout) timeout--; + if (timeout) { + lsens_val = ADC_GetConversionValue(ADC1); + } } void adc_set_mode_lsens(uint8_t mode) { lsens_mode = mode; - - // always reconfigure the pins as outputs when calling this - lsens_gpio.GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN; - lsens_gpio.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_Init(LSENS_PORT, &lsens_gpio); - } uint8_t adc_get_mode_lsens() @@ -89,15 +90,70 @@ static void lsens_start() GPIO_Init(LSENS_PORT, &lsens_gpio); } -static void lsens_end() +static void lsens_stop() { - adc_set_mode_lsens(LSENS_READING_IDLE); + lsens_gpio.GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN; + lsens_gpio.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(LSENS_PORT, &lsens_gpio); + + lsens_mode = LSENS_READING_IDLE; } -void adc_process_lsens(uint8_t convert) +void adc_process_lsens() { if (lsens_mode != LSENS_OUTPUT) { // do what needs to be done by me to defeat the light enemys + switch (lsens_mode) { + case LSENS_READING_IDLE: { + // prepare LED, wait a little bit + lsens_start(); + adc_convert(); + lsens_wait = lsens_coarse; + + lsens_mode = LSENS_READING_START; + + break; + } + case LSENS_READING_START: { + if (!lsens_wait) { + // convert the LED + adc_convert(); + + lsens_mode = LSENS_READING_WAIT; + } + + lsens_wait--; + + break; + } + case LSENS_READING_WAIT: { + // read the light sensor value + adc_read(); + lsens_stop(); + + // calculate adjustments + if (lsens_val > LSENS_COARSE_UP) { + lsens_coarse++; + if (lsens_coarse > 0x7f) lsens_coarse = 0x7f; + } else if (lsens_val < LSENS_COARSE_DOWN) { + if (lsens_coarse) lsens_coarse--; + } + + lsens_wait = 255 - lsens_coarse; + + // wait a bit before doing it again + lsens_mode = LSENS_READING_TIMEOUT; + + break; + } + case LSENS_READING_TIMEOUT: { + if (!lsens_wait) { + // do it all again + lsens_mode = LSENS_READING_IDLE; + } + lsens_wait--; + } + } } } @@ -105,3 +161,8 @@ uint16_t adc_get_lsens() { return lsens_val; } + +uint8_t adc_get_lsens_coarse() +{ + return lsens_coarse; +} diff --git a/firmware/user/src/adc.h b/firmware/user/src/adc.h index a0e4422..f10c9b5 100644 --- a/firmware/user/src/adc.h +++ b/firmware/user/src/adc.h @@ -10,17 +10,21 @@ -#define LSENS_DARK_THRESHOLD 0x7ff // baseline minimum value reading achieved in darkness +#define LSENS_DARK_THRESHOLD 0x7ff // baseline minimum value reading achieved in darkness #define LSENS_PORT GPIOA #define LSENS_A_PIN GPIO_Pin_2 #define LSENS_K_PIN GPIO_Pin_3 #define LSENS_ADC_CH ADC_Channel_3 -enum { +#define LSENS_COARSE_UP 0x680 // counts higher than this increase lsens_coarse, maximum 64 +#define LSENS_COARSE_DOWN 0x580 // counts lower than this decrease lsens_coarse, minimum 1 + +enum lsens_mode { LSENS_READING_IDLE = 0, LSENS_READING_START, LSENS_READING_WAIT, + LSENS_READING_TIMEOUT, LSENS_OUTPUT = 0xff }; @@ -34,7 +38,10 @@ void adc_read(); void adc_set_mode_lsens(uint8_t mode); uint8_t adc_get_mode_lsens(); -void adc_process_lsens(uint8_t convert); +void adc_process_lsens(); + +uint16_t adc_get_lsens(); +uint8_t adc_get_lsens_coarse(); diff --git a/firmware/user/src/ui.c b/firmware/user/src/ui.c index 9324988..e17b5f6 100644 --- a/firmware/user/src/ui.c +++ b/firmware/user/src/ui.c @@ -4,6 +4,7 @@ #include +#include "adc.h" #include "btn.h" #include "led.h" #include "ledprog_pep.h" @@ -22,6 +23,15 @@ +static const uint8_t led_gc_map[] = { + 48, 40, 34, 32, // 0 = maybe outside, or really bright inside. 1-3 = indoors + 30, 28, 27, 25, // 4-7 = indoors + 23, 21, 19, 18, // 8-11 = indoors normal + 17, 16, 15, 13, // 12 = dimmest normal, 13 = darker, 14-15 darker still + 11, 9, 7, 5, // 16-19 = from night room light to computer light + 0 // 20 = outside mode turns off the LEDs +}; + static uint8_t mode = MODE_RUN; static uint8_t tick = 0; @@ -64,6 +74,8 @@ volatile uint8_t prog_run = 5; void ui_render() { + uint8_t w; + tick++; switch (mode) { @@ -80,6 +92,19 @@ void ui_render() } } + // set LED current based on brightness + w = adc_get_lsens_coarse(); + if (w > 19) w = 19; + if (!w) { + // are you outside? why? it's too fucking hot + // we'll shut down when in the presence of big nuclear fire + if (adc_get_lsens() < 400) { + // yup, outside or in a spotlight at 3ft away or something + w = 20; + } + } + is31fl3729_set_global_current(FL3729_ADDR, led_gc_map[w]); + // temporary: testing ledprog_pep[prog_run](tick);