#include "cp.h" #include "tim.h" #define CP_CAPTURE_TARGET_CLK_HZ 1000000U #define CP_INPUT_SIGNAL_INVERTED 1U typedef enum { CP_WAIT_RISING_1 = 0, CP_WAIT_FALLING, CP_WAIT_RISING_2 } CP_CaptureState_t; static volatile CP_CaptureState_t cp_capture_state = CP_WAIT_RISING_1; static volatile uint32_t cp_rise_1 = 0; static volatile uint32_t cp_fall = 0; static volatile uint32_t cp_rise_2 = 0; static volatile uint32_t cp_last_update_ms = 0; static volatile CP_Measurement_t cp_measurement = {0, 0, 0}; static uint32_t CP_TicksDiff(uint32_t now, uint32_t prev, uint32_t arr); static uint32_t CP_GetTimerClockHz(void); static void CP_ApplyStateOutputs(void); static uint32_t CP_GetTim3InputClockHz(void); void CP_Init(void) { TIM_IC_InitTypeDef sConfigIC = {0}; uint32_t tim3_input_clk = CP_GetTim3InputClockHz(); uint32_t target_prescaler = 0U; if (tim3_input_clk > CP_CAPTURE_TARGET_CLK_HZ) { target_prescaler = (tim3_input_clk / CP_CAPTURE_TARGET_CLK_HZ) - 1U; } if (target_prescaler > 0xFFFFU) { target_prescaler = 0xFFFFU; } __HAL_TIM_SET_PRESCALER(&htim3, (uint16_t)target_prescaler); __HAL_TIM_SET_COUNTER(&htim3, 0U); sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 2; HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2); cp_capture_state = CP_WAIT_RISING_1; cp_measurement.valid = 0; cp_last_update_ms = HAL_GetTick(); CP_ApplyStateOutputs(); HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2); } void CP_Task(void) { CP_ApplyStateOutputs(); if ((HAL_GetTick() - cp_last_update_ms) > 200U) { cp_measurement.valid = 0; cp_measurement.frequency_hz = 0; cp_measurement.duty_percent = 0; } } CP_Measurement_t CP_GetMeasurement(void) { CP_Measurement_t snapshot; __disable_irq(); snapshot = cp_measurement; __enable_irq(); return snapshot; } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if ((htim->Instance != TIM3) || (htim->Channel != HAL_TIM_ACTIVE_CHANNEL_2)) { return; } uint32_t captured = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); uint32_t arr = __HAL_TIM_GET_AUTORELOAD(htim); TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2); if (cp_capture_state == CP_WAIT_RISING_1) { cp_rise_1 = captured; cp_capture_state = CP_WAIT_FALLING; TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); return; } if (cp_capture_state == CP_WAIT_FALLING) { cp_fall = captured; cp_capture_state = CP_WAIT_RISING_2; TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); return; } cp_rise_2 = captured; cp_capture_state = CP_WAIT_RISING_1; TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); uint32_t period_ticks = CP_TicksDiff(cp_rise_2, cp_rise_1, arr); uint32_t high_ticks = CP_TicksDiff(cp_fall, cp_rise_1, arr); uint32_t timer_clk = CP_GetTimerClockHz(); if ((period_ticks == 0U) || (high_ticks > period_ticks) || (timer_clk == 0U)) { cp_measurement.valid = 0; return; } cp_measurement.frequency_hz = timer_clk / period_ticks; uint32_t duty_high = (high_ticks * 100U + (period_ticks / 2U)) / period_ticks; /* rounded */ if (duty_high > 100U) { duty_high = 100U; } uint32_t duty = duty_high; #if CP_INPUT_SIGNAL_INVERTED duty = 100U - duty_high; #endif cp_measurement.duty_percent = (uint8_t)duty; cp_measurement.valid = 1; cp_last_update_ms = HAL_GetTick(); } static uint32_t CP_TicksDiff(uint32_t now, uint32_t prev, uint32_t arr) { if (now >= prev) { return now - prev; } return (arr - prev + 1U) + now; } static uint32_t CP_GetTimerClockHz(void) { uint32_t timclk = CP_GetTim3InputClockHz(); uint32_t prescaler = htim3.Instance->PSC; return timclk / (prescaler + 1U); } static uint32_t CP_GetTim3InputClockHz(void) { RCC_ClkInitTypeDef clk_init = {0}; uint32_t flash_latency = 0U; uint32_t pclk1 = HAL_RCC_GetPCLK1Freq(); HAL_RCC_GetClockConfig(&clk_init, &flash_latency); if (clk_init.APB1CLKDivider == RCC_HCLK_DIV1) { return pclk1; } return pclk1 * 2U; } static void CP_ApplyStateOutputs(void) { static CP_State_t last_state = (CP_State_t)0xFF; if (last_state == cp_state) { return; } switch (cp_state) { case EV_STATE_A_IDLE: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET); break; case EV_STATE_B_CONN_PREP: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET); break; case EV_STATE_C_CONN_ACTIVE: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET); break; case EV_STATE_F_ERROR: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_SET); break; case EV_STATE_D_CONN_ACT_VENT: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET); break; case EV_STATE_E_NO_POWER: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_SET); break; case EV_STATE_ACQUIRING: default: HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET); break; } last_state = cp_state; }