sc8-gat-stand/gat_stand_fw/user/src/adc.c

212 lines
4.7 KiB
C
Raw Normal View History

/*
* lightsense.c
*
* Created on: Oct 18, 2024
* Author: true
*/
#include <ch32v20x.h>
#include <stdint.h>
#include "adc.h"
static const uint8_t led_brightness_map[] = {
47, 44, 42, 41,
40, 38, 36, 34,
32, 31, 30, 29,
27, 25, 21, 19,
17, 16, 15, 15, // indoors normal brightness
14, 14, 13, 13,
12, 12, 12, 11,
11, 11, 10, 10,
10, 9, 9, 9,
8, 8, 8, 8,
7, 7, 7, 7,
7, 6, 6, 6
};
static GPIO_InitTypeDef lsens_gpio = {
.GPIO_Mode = GPIO_Mode_Out_PP,
.GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN,
.GPIO_Speed = GPIO_Speed_2MHz
};
uint16_t lsens_val;
static uint8_t lsens_mode = LSENS_READING_IDLE;
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_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()
{
return lsens_mode;
}
static void lsens_start()
{
// set anode and cathode low
LSENS_PORT->BCR = LSENS_A_PIN | LSENS_K_PIN;
adc_set_mode_lsens(LSENS_READING_START);
// set cathode high, let it charge
LSENS_PORT->BSHR = LSENS_K_PIN;
// set anode low
lsens_gpio.GPIO_Pin = LSENS_A_PIN;
lsens_gpio.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(LSENS_PORT, &lsens_gpio);
// set cathode as analog input
lsens_gpio.GPIO_Pin = LSENS_K_PIN;
lsens_gpio.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(LSENS_PORT, &lsens_gpio);
}
static void lsens_stop()
{
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()
{
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 > 0x3f) lsens_coarse = 0x3f;
} 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--;
}
}
}
}
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() < 400) {
// 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];
}