213 lines
4.9 KiB
C
213 lines
4.9 KiB
C
|
/*
|
||
|
* 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 <ch32v20x.h>
|
||
|
|
||
|
#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];
|
||
|
}
|