129 lines
3.9 KiB
C
129 lines
3.9 KiB
C
#include "light_sensor.h"
|
|
|
|
volatile unsigned int LightSensor_Measurement;
|
|
volatile bool LightSensor_NewMeasurement = false;
|
|
|
|
// Rolling average of the brightness measurement
|
|
unsigned int LightSensor_AbsoluteBrightness = LIGHTSENSOR_MAX / 2;
|
|
|
|
// Maximum and minimum encountered so far
|
|
unsigned int LightSensor_MinimumBrightness = LIGHTSENSOR_MAX;
|
|
unsigned int LightSensor_MaximumBrightness = 0;
|
|
|
|
int LightSensor_RelativeBrightness;
|
|
|
|
static void LightSensor_Measure(void)
|
|
{
|
|
// Use light sensor pin in output mode, drive high
|
|
GPIOB->MODER = (GPIOB->MODER & ~(0x03 << PIN_LIGHT_SENSOR * 2))
|
|
| (0x01 << PIN_LIGHT_SENSOR * 2);
|
|
|
|
// Disable timer
|
|
TIM14->SR = 0x0000;
|
|
TIM14->CR1 = 0x0000;
|
|
TIM14->CNT = 0;
|
|
|
|
// Delay a bit to ensure capacitor is charged
|
|
for(unsigned int i = 0; i < 100; i++)
|
|
{
|
|
__asm__ volatile("nop");
|
|
}
|
|
|
|
// Re-enable timer
|
|
TIM14->CR1 = TIM_CR1_CEN;
|
|
|
|
// Switch to alternate function mode
|
|
GPIOB->MODER = (GPIOB->MODER & ~(0x03 << PIN_LIGHT_SENSOR * 2))
|
|
| (0x02 << PIN_LIGHT_SENSOR * 2);
|
|
}
|
|
|
|
void LightSensor_Init(void)
|
|
{
|
|
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
|
|
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
|
|
|
|
GPIOB->ODR |= (1 << PIN_LIGHT_SENSOR);
|
|
GPIOB->AFR[0] &= ~(0x0f << (PIN_LIGHT_SENSOR * 4));
|
|
|
|
// Enable input capture for light sensor pin, trigger on falling edge
|
|
TIM14->CCMR1 = TIM_CCMR1_CC1S_0;
|
|
TIM14->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
|
|
// Set up TIM14 for an oveflow interrupt at the configured interval
|
|
TIM14->PSC = 8000 * LIGHTSENSOR_INTERVAL / 65535;
|
|
TIM14->ARR = 65535;
|
|
TIM14->DIER = TIM_DIER_UIE;
|
|
NVIC_EnableIRQ(TIM14_IRQn);
|
|
|
|
LightSensor_Measure();
|
|
|
|
while(!LightSensor_NewMeasurement);
|
|
LightSensor_Poll();
|
|
}
|
|
|
|
void LightSensor_Poll(void)
|
|
{
|
|
if(LightSensor_NewMeasurement)
|
|
{
|
|
unsigned int measurement = LightSensor_Measurement;
|
|
LightSensor_NewMeasurement = false;
|
|
unsigned int brightness = ((1 << 31)
|
|
/ (measurement + 1)) >> (31 - 16);
|
|
// LightSensor_AbsoluteBrightness = LIGHTSENSOR_LAMBDA * LightSensor_AbsoluteBrightness
|
|
// + (1.0f - LIGHTSENSOR_LAMBDA) * brightness;
|
|
LightSensor_AbsoluteBrightness -= LightSensor_AbsoluteBrightness >> LIGHTSENSOR_LAMBDA_BITS;
|
|
LightSensor_AbsoluteBrightness += brightness >> LIGHTSENSOR_LAMBDA_BITS;
|
|
|
|
if(brightness < LightSensor_MinimumBrightness)
|
|
{
|
|
LightSensor_MinimumBrightness = brightness;
|
|
}
|
|
if(brightness > LightSensor_MaximumBrightness)
|
|
{
|
|
LightSensor_MaximumBrightness = brightness;
|
|
}
|
|
|
|
// Scale and saturate to get relative brightness value
|
|
int range = LightSensor_MaximumBrightness
|
|
- LightSensor_MinimumBrightness;
|
|
int low = LightSensor_MinimumBrightness
|
|
+ LIGHTSENSOR_LOW_BOUND * range / LIGHTSENSOR_MAX;
|
|
int high = LightSensor_MinimumBrightness
|
|
+ LIGHTSENSOR_HIGH_BOUND * range / LIGHTSENSOR_MAX;
|
|
LightSensor_RelativeBrightness = ((int)LightSensor_AbsoluteBrightness - low)
|
|
* LIGHTSENSOR_MAX / (high - low);
|
|
if(LightSensor_RelativeBrightness < 0)
|
|
{
|
|
LightSensor_RelativeBrightness = 0;
|
|
}
|
|
if(LightSensor_RelativeBrightness > LIGHTSENSOR_MAX)
|
|
{
|
|
LightSensor_RelativeBrightness = LIGHTSENSOR_MAX;
|
|
}
|
|
|
|
// Slowly reset limit values
|
|
static int decay_counter = 0;
|
|
decay_counter++;
|
|
if(decay_counter == LIGHTSENSOR_LIMIT_RESET_TIME * 1000
|
|
/ LIGHTSENSOR_INTERVAL / LIGHTSENSOR_MAX)
|
|
{
|
|
decay_counter = 0;
|
|
LightSensor_MaximumBrightness -= 1;
|
|
LightSensor_MinimumBrightness += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TIM14_IRQHandler(void)
|
|
{
|
|
if(TIM14->SR & TIM_SR_CC1IF)
|
|
{
|
|
LightSensor_Measurement = TIM14->CCR1;
|
|
}
|
|
else
|
|
{
|
|
LightSensor_Measurement = 65535;
|
|
}
|
|
LightSensor_NewMeasurement = true;
|
|
|
|
LightSensor_Measure();
|
|
}
|