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.
This commit is contained in:
true 2024-08-03 19:55:04 -07:00
parent 83fb171fbf
commit a6966fc32f
5 changed files with 119 additions and 27 deletions

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#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);