#include "stm32g0xx_hal.h"
#include "config.h"
#include "sensors.h"
#include "led.h"
#include "power.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_LPTIM1_Init(void);
static void Error_Handler(void);
static ADC_HandleTypeDef hadc1;
static LPTIM_HandleTypeDef hlptim1;
/* LSI ~32 kHz, prescaler /32 -> ~1 kHz; 500 ms ~= 512 counts */
#ifndef APP_TICK_PERIOD_MS
#define APP_TICK_PERIOD_MS 500u
#endif
#define LPTIM_TICK_HZ 1024u
#define LPTIM_APP_PERIOD ((uint32_t)(APP_TICK_PERIOD_MS) * LPTIM_TICK_HZ / 1000u - 1u)
typedef enum {
APP_STATE_OFF = 0,
APP_STATE_ON = 1,
} app_state_t;
static volatile uint8_t s_appTickPending = 0;
static volatile uint32_t s_appTickCount = 0;
static uint32_t s_lastMotionTick = 0;
static app_state_t s_state = APP_STATE_OFF;
static void update_logic(void) {
sensors_data_t s = {0};
sensors_read_all(&s);
const uint8_t isNight = (s.ldr_adc < NIGHT_ADC_THRESHOLD) ? 1u : 0u;
const uint8_t motion = s.motion;
if (!isNight) {
if (s_state != APP_STATE_OFF) {
led_off();
s_state = APP_STATE_OFF;
}
return;
}
if (motion) {
s_lastMotionTick = s_appTickCount;
if (s_state != APP_STATE_ON) {
led_on();
sendColor(16, 16, 16);
s_state = APP_STATE_ON;
}
}
if (s_state == APP_STATE_ON) {
const uint32_t dt = s_appTickCount - s_lastMotionTick;
if (dt >= MOTION_THRESHOLD_TICKS) {
led_off();
s_state = APP_STATE_OFF;
}
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_LPTIM1_Init();
sensors_init(&hadc1);
led_init();
power_init();
if (HAL_LPTIM_Counter_Start_IT(&hlptim1, LPTIM_APP_PERIOD) != HAL_OK) {
Error_Handler();
}
while (1) {
if (s_appTickPending) {
s_appTickPending = 0;
update_logic();
}
power_enter_sleep();
}
}
void SysTick_Handler(void) {
HAL_IncTick();
}
void LPTIM1_IRQHandler(void) {
HAL_LPTIM_IRQHandler(&hlptim1);
}
void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim) {
(void)hlptim;
s_appTickCount++;
s_appTickPending = 1;
}
void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef *hlptim) {
if (hlptim->Instance != LPTIM1) {
return;
}
__HAL_RCC_LPTIM1_CLK_ENABLE();
HAL_NVIC_SetPriority(LPTIM1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
}
static void MX_LPTIM1_Init(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
PeriphClkInit.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
Error_Handler();
}
hlptim1.Instance = LPTIM1;
hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV32;
hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
hlptim1.Init.Trigger.ActiveEdge = LPTIM_ACTIVEEDGE_RISING;
hlptim1.Init.Trigger.SampleTime = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;
hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
hlptim1.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO;
hlptim1.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO;
if (HAL_LPTIM_Init(&hlptim1) != HAL_OK) {
Error_Handler();
}
}
static void MX_ADC1_Init(void) {
__HAL_RCC_ADC_CLK_ENABLE();
hadc1.Instance = LDR_ADC;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.LowPowerAutoPowerOff = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_39CYCLES_5;
hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_39CYCLES_5;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
Error_Handler();
}
}
static void MX_GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// PIR input
GPIO_InitStruct.Pin = PIR_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = PIR_GPIO_PULL;
HAL_GPIO_Init(PIR_GPIO_PORT, &GPIO_InitStruct);
// LED power output
GPIO_InitStruct.Pin = LED_PWR_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_PWR_GPIO_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(LED_PWR_GPIO_PORT, LED_PWR_GPIO_PIN, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = LDR_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(LDR_GPIO_PORT, &GPIO_InitStruct);
}
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
Error_Handler();
}
}
static void Error_Handler(void) {
__disable_irq();
while (1) {
}
}