Add basic time-based light sensor code
This commit is contained in:
parent
dc7bdb006c
commit
6d63b76a02
|
@ -1 +1 @@
|
||||||
137
|
213
|
||||||
|
|
119
src/light_sensor.c
Normal file
119
src/light_sensor.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "light_sensor.h"
|
||||||
|
|
||||||
|
volatile unsigned int LightSensor_Measurement;
|
||||||
|
volatile bool LightSensor_NewMeasurement = false;
|
||||||
|
|
||||||
|
// Rolling average of the brightness measurement
|
||||||
|
float LightSensor_AbsoluteBrightness = 0.5f;
|
||||||
|
|
||||||
|
// Maximum and minimum encountered so far
|
||||||
|
float LightSensor_MinimumBrightness = 1.0f;
|
||||||
|
float LightSensor_MaximumBrightness = 0.0f;
|
||||||
|
|
||||||
|
float 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 = 48000 * LIGHTSENSOR_INTERVAL / 65535;
|
||||||
|
TIM14->ARR = 65535;
|
||||||
|
TIM14->DIER = TIM_DIER_UIE;
|
||||||
|
NVIC_EnableIRQ(TIM14_IRQn);
|
||||||
|
|
||||||
|
LightSensor_Measure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSensor_Poll(void)
|
||||||
|
{
|
||||||
|
if(LightSensor_NewMeasurement)
|
||||||
|
{
|
||||||
|
unsigned int measurement = LightSensor_Measurement;
|
||||||
|
LightSensor_NewMeasurement = false;
|
||||||
|
float brightness = 1.0f - measurement / 65535.0f;
|
||||||
|
|
||||||
|
if(measurement != 65535 && brightness < LightSensor_MinimumBrightness)
|
||||||
|
{
|
||||||
|
LightSensor_MinimumBrightness = brightness;
|
||||||
|
}
|
||||||
|
if(brightness > LightSensor_MaximumBrightness)
|
||||||
|
{
|
||||||
|
LightSensor_MaximumBrightness = brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
LightSensor_AbsoluteBrightness = LIGHTSENSOR_LAMBDA * LightSensor_AbsoluteBrightness
|
||||||
|
+ (1.0f - LIGHTSENSOR_LAMBDA) * brightness;
|
||||||
|
|
||||||
|
// Slowly move maximum and minimum back to 0.0 and 1.0, respectively
|
||||||
|
LightSensor_MaximumBrightness *= LIGHTSENSOR_ALPHA;
|
||||||
|
LightSensor_MinimumBrightness = 1.0f - LightSensor_MinimumBrightness;
|
||||||
|
LightSensor_MinimumBrightness *= LIGHTSENSOR_ALPHA;
|
||||||
|
LightSensor_MinimumBrightness = 1.0f - LightSensor_MinimumBrightness;
|
||||||
|
|
||||||
|
// Scale and saturate to get relative brightness value
|
||||||
|
float range = LightSensor_MaximumBrightness
|
||||||
|
- LightSensor_MinimumBrightness;
|
||||||
|
float low = LightSensor_MinimumBrightness
|
||||||
|
+ range * LIGHTSENSOR_LOW_BOUND;
|
||||||
|
float high = LightSensor_MinimumBrightness
|
||||||
|
+ range * LIGHTSENSOR_HIGH_BOUND;
|
||||||
|
LightSensor_RelativeBrightness = (LightSensor_AbsoluteBrightness - low)
|
||||||
|
/ (high - low);
|
||||||
|
if(LightSensor_RelativeBrightness < 0.0f)
|
||||||
|
{
|
||||||
|
LightSensor_RelativeBrightness = 0.0f;
|
||||||
|
}
|
||||||
|
if(LightSensor_RelativeBrightness > 1.0f)
|
||||||
|
{
|
||||||
|
LightSensor_RelativeBrightness = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIM14_IRQHandler(void)
|
||||||
|
{
|
||||||
|
if(TIM14->SR & TIM_SR_CC1IF)
|
||||||
|
{
|
||||||
|
LightSensor_Measurement = TIM14->CCR1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LightSensor_Measurement = 65535;
|
||||||
|
}
|
||||||
|
LightSensor_NewMeasurement = true;
|
||||||
|
|
||||||
|
LightSensor_Measure();
|
||||||
|
}
|
25
src/light_sensor.h
Normal file
25
src/light_sensor.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "stm32f030x6.h"
|
||||||
|
#include "pinning.h"
|
||||||
|
|
||||||
|
// ADC polling interval in milliseconds
|
||||||
|
#define LIGHTSENSOR_INTERVAL 2000
|
||||||
|
|
||||||
|
// 'Forgetting factor' of the rolling brightness average
|
||||||
|
#define LIGHTSENSOR_LAMBDA 0.95f
|
||||||
|
|
||||||
|
// 'Forgetting factor' for maximum and minimum brightness
|
||||||
|
#define LIGHTSENSOR_ALPHA 0.999f
|
||||||
|
|
||||||
|
// Bounds for converting absolute to relative brightness: Consider everything
|
||||||
|
// near the minimum or maximum 0.0 or 1.0, respectively
|
||||||
|
#define LIGHTSENSOR_LOW_BOUND 0.1f
|
||||||
|
#define LIGHTSENSOR_HIGH_BOUND 0.9f
|
||||||
|
|
||||||
|
extern float LightSensor_RelativeBrightness;
|
||||||
|
|
||||||
|
void LightSensor_Init(void);
|
||||||
|
void LightSensor_Poll(void);
|
|
@ -8,19 +8,21 @@ int main(void)
|
||||||
__asm__ volatile("nop");
|
__asm__ volatile("nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LightSensor_Init();
|
||||||
LED_Init();
|
LED_Init();
|
||||||
|
|
||||||
int ct = 0;
|
int ct = 0;
|
||||||
uint8_t *data = (uint8_t*)LED_PixelData;
|
uint8_t *data = (uint8_t*)LED_PixelData;
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
LightSensor_Poll();
|
||||||
|
uint8_t brightness = LightSensor_RelativeBrightness * 255;
|
||||||
if(LED_FrameFlag)
|
if(LED_FrameFlag)
|
||||||
{
|
{
|
||||||
LED_FrameFlag = false;
|
LED_FrameFlag = false;
|
||||||
data[ct]++;
|
data[ct] = brightness;
|
||||||
LED_Commit();
|
LED_Commit();
|
||||||
if(data[ct] == 255)
|
|
||||||
{
|
|
||||||
ct += 3;
|
ct += 3;
|
||||||
if(ct >= LED_COLUMNS * LED_ROWS)
|
if(ct >= LED_COLUMNS * LED_ROWS)
|
||||||
{
|
{
|
||||||
|
@ -29,7 +31,6 @@ int main(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "stm32f030x6.h"
|
#include "stm32f030x6.h"
|
||||||
#include "buildid.h"
|
#include "buildid.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
#include "light_sensor.h"
|
||||||
|
|
||||||
int main(void);
|
int main(void);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#define PIN_LED_G_3 13
|
#define PIN_LED_G_3 13
|
||||||
#define PIN_LED_B_3 14
|
#define PIN_LED_B_3 14
|
||||||
|
|
||||||
|
// Port B
|
||||||
|
#define PIN_LIGHT_SENSOR 1 // ADC_IN9
|
||||||
|
|
||||||
// Port F
|
// Port F
|
||||||
#define PIN_ROW_DATA 0 // Shift register data in
|
#define PIN_ROW_DATA 0 // Shift register data in
|
||||||
#define PIN_ROW_SCK 1 // Shift register clock
|
#define PIN_ROW_SCK 1 // Shift register clock
|
||||||
|
|
Loading…
Reference in a new issue