/* * Created on: Jul 29, 2024 * * not sure how well the ambient light sensor will work, being surrounded by other LEDs. * I guess I could make the programs black out and read then. maybe I'll do that. */ #include #include "adc.h" static const uint8_t led_brightness_map[] = { 63, 60, 53, 48, 47, 46, 45, 43, 42, 41, 40, 39, 38, 36, 35, 34, 33, 31, 30, 28, // indoors normal brightness 26, 24, 22, 21, 20, 20, 19, 19, 18, 18, 17, 17 }; static GPIO_InitTypeDef lsens_a = { .GPIO_Mode = GPIO_Mode_Out_PP, .GPIO_Pin = LSENS_A_PIN, .GPIO_Speed = GPIO_Speed_2MHz }; static GPIO_InitTypeDef lsens_k = { .GPIO_Mode = GPIO_Mode_Out_PP, .GPIO_Pin = LSENS_K_PIN, .GPIO_Speed = GPIO_Speed_2MHz }; volatile uint16_t lsens_limits[2] = {LSENS_COARSE_UP, LSENS_COARSE_DOWN}; static uint8_t lsens_mode = LSENS_READING_IDLE; uint16_t lsens_val; uint8_t lsens_wait; uint8_t lsens_coarse = 1; void adc_init() { ADC_InitTypeDef adc = {0}; RCC_ADCCLKConfig(RCC_PCLK2_Div4); ADC_DeInit(ADC1); adc.ADC_Mode = ADC_Mode_Independent; adc.ADC_ScanConvMode = DISABLE; adc.ADC_ContinuousConvMode = DISABLE; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; adc.ADC_DataAlign = ADC_DataAlign_Right; adc.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &adc); ADC_RegularChannelConfig(ADC1, LSENS_ADC_CH, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); } void adc_convert() { ADC_SoftwareStartConvCmd(ADC1, ENABLE); } void adc_read() { 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; if (mode == LSENS_OUTPUT) { lsens_a.GPIO_Mode = GPIO_Mode_Out_PP; lsens_k.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(LSENS_A_PORT, &lsens_a); GPIO_Init(LSENS_K_PORT, &lsens_k); } } uint8_t adc_get_mode_lsens() { return lsens_mode; } static void lsens_start() { // set anode and cathode low LSENS_A_PORT->BCR = LSENS_A_PIN; LSENS_K_PORT->BCR = LSENS_K_PIN; adc_set_mode_lsens(LSENS_READING_START); // set cathode high, let it charge LSENS_K_PORT->BSHR = LSENS_K_PIN; __asm("nop"); __asm("nop"); __asm("nop"); __asm("nop"); // set cathode as analog input lsens_k.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(LSENS_K_PORT, &lsens_k); } static void lsens_stop() { lsens_a.GPIO_Mode = GPIO_Mode_Out_PP; lsens_k.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(LSENS_A_PORT, &lsens_a); GPIO_Init(LSENS_K_PORT, &lsens_k); lsens_mode = LSENS_READING_IDLE; } 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_limits[0]) { lsens_coarse++; if (lsens_coarse > 0x3f) lsens_coarse = 0x3f; } else if (lsens_val < lsens_limits[1]) { 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--; } } } } uint16_t adc_get_lsens() { return lsens_val; } uint8_t adc_get_lsens_coarse() { return lsens_coarse; } uint8_t adc_get_brightness(uint8_t level) { if (!level) { // 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() < 1800) { // yup, outside or in a spotlight at 3ft away or something return 0; } } if (level >= sizeof(led_brightness_map)) { return led_brightness_map[sizeof(led_brightness_map) - 1]; } return led_brightness_map[level]; }