From a6966fc32f437a283f0bd06000a66aac56cae64b Mon Sep 17 00:00:00 2001 From: true Date: Sat, 3 Aug 2024 19:55:04 -0700 Subject: [PATCH] added light level setting based on ambient light detection this required increasing the main interrupt rate again. need to actually test during the daytime to see if it works ok. it's a little bit jumpy when it's dark but oh well, that's fine. --- firmware/user/ch32v20x_it.c | 20 ++++----- firmware/user/main.c | 5 ++- firmware/user/src/adc.c | 83 ++++++++++++++++++++++++++++++++----- firmware/user/src/adc.h | 13 ++++-- firmware/user/src/ui.c | 25 +++++++++++ 5 files changed, 119 insertions(+), 27 deletions(-) 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);