diff --git a/hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp b/hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp index e3287b480..3950b3a98 100644 --- a/hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp +++ b/hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp @@ -8,6 +8,12 @@ void HepaControlHardware::set_hepa_fan_speed(uint32_t duty_cycle) { set_hepa_fan_pwm(duty_cycle); } -uint32_t HepaControlHardware::get_hepa_fan_rpm() { - return get_hepa_fan_rpm(); -} \ No newline at end of file +uint16_t HepaControlHardware::get_hepa_fan_rpm() { return hepa_fan_rpm; } + +void HepaControlHardware::reset_hepa_fan_rpm() { hepa_fan_rpm = 0; } + +bool HepaControlHardware::enable_tachometer(bool enable) { + return enable_hepa_fan_tachometer(enable); +} + +void HepaControlHardware::hepa_fan_rpm_irq(uint16_t rpm) { hepa_fan_rpm = rpm; } \ No newline at end of file diff --git a/hepa-uv/firmware/hepa_hardware.c b/hepa-uv/firmware/hepa_hardware.c index 3d2923308..2ff2ec7b5 100644 --- a/hepa-uv/firmware/hepa_hardware.c +++ b/hepa-uv/firmware/hepa_hardware.c @@ -2,9 +2,16 @@ #include "hepa-uv/firmware/utility_gpio.h" #include "common/firmware/errors.h" #include "timer_hardware.h" +#include + +#include "stdio.h" + +#define TIMCLOCK 85000000 +#define PRESCALAR 85 TIM_HandleTypeDef htim2; TIM_MasterConfigTypeDef sMasterConfig = {0}; +TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; void tachometer_gpio_init(void) { @@ -26,18 +33,20 @@ void tachometer_gpio_init(void) { static void TIM2_Tachometer_Init(void) { htim2.Instance = TIM2; htim2.State = HAL_TIM_STATE_RESET; - htim2.Init.Prescaler = 2; + htim2.Init.Prescaler = PRESCALAR; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; - htim2.Init.Period = 4.294967295E9; + htim2.Init.Period = 0xFFFFFFFF - 1; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { + if (HAL_TIM_Base_Init(&htim2) != HAL_OK) Error_Handler(); + + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) Error_Handler(); - } + /* Initialize Input Capture mode */ - if (HAL_TIM_IC_Init(&htim2) != HAL_OK) { - Error_Handler(); - } + if (HAL_TIM_IC_Init(&htim2) != HAL_OK) Error_Handler(); + sMasterConfig.MasterOutputTrigger = TIM_TRGO_ENABLE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != @@ -47,18 +56,14 @@ static void TIM2_Tachometer_Init(void) { /* Initialize TIM2 input capture channel */ sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; - sConfigIC.ICPrescaler = TIM_ICPSC_DIV4; + sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } - /* The update event of the enable timer is interrupted */ - __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE); - /* Start the input capture measurement */ - HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // /* TIM2 interrupt Init */ - HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); + HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); } @@ -74,41 +79,42 @@ void set_hepa_fan_pwm(uint32_t duty_cycle) { htim3.Instance->CCR1 = clamped_dc; } -uint32_t val1 = 0; -uint32_t val2 = 0; -uint32_t tach_period = 0; -uint8_t captured_val1 = 0; - -uint32_t get_hepa_fan_rpm(void) { - if (tach_period == 0) return 0; - uint32_t rpm = ((uint32_t)HEPA_TACHOMETER_TIMER_FREQ * 60) \ - / ((uint32_t)tach_period); - return rpm; +bool enable_hepa_fan_tachometer(bool enable) { + /* The update event of the enable/disabled timer is interrupted */ + /* Start/Stop the input capture measurement */ + if (enable) { + __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE); + return HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1) == HAL_OK; + } else { + __HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE); + return HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_1) == HAL_OK; + } } -void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { - if (htim == &htim2) { - uint32_t count = __HAL_TIM_GET_COUNTER((TIM_HandleTypeDef*)htim); - if (captured_val1 == 0) { - val1 = count; - captured_val1 = 1; +uint32_t captured_val = 0; +static hepa_rpm_callback hepa_rpm_cb = NULL; +void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) + { + if (htim->Instance == TIM2) + { + if (captured_val == 0) { + captured_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); } else { - val2 = count; - } - - if (val2 > val1) { - tach_period = val2 - val1; - captured_val1 = 0; + uint32_t new_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); + uint32_t period = new_val > captured_val ? new_val - captured_val : ((0xffffffff - captured_val) + new_val) + 1; + // reset and disable the timer + captured_val = 0; + enable_hepa_fan_tachometer(false); __HAL_TIM_SET_COUNTER(htim, 0); - } else { - tach_period = 0; + if (hepa_rpm_cb != NULL) { + hepa_rpm_cb(round(60 / ((float)period / 1000000))); + } } + } + } - __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); - } -} - -void initialize_tachometer() { +void initialize_tachometer(hepa_rpm_callback rpm_callback) { + hepa_rpm_cb = rpm_callback; tachometer_gpio_init(); TIM2_Tachometer_Init(); } \ No newline at end of file diff --git a/hepa-uv/firmware/main_rev1.cpp b/hepa-uv/firmware/main_rev1.cpp index c99e6153f..4bfed1d3a 100644 --- a/hepa-uv/firmware/main_rev1.cpp +++ b/hepa-uv/firmware/main_rev1.cpp @@ -23,13 +23,14 @@ #include "hepa-uv/core/messages.hpp" #include "hepa-uv/core/tasks.hpp" #include "hepa-uv/firmware/hepa_control_hardware.hpp" +#include "hepa-uv/firmware/hepa_hardware.h" #include "hepa-uv/firmware/led_control_hardware.hpp" #include "hepa-uv/firmware/utility_gpio.h" -#include "hepa-uv/firmware/hepa_hardware.h" -#include "hepa-uv/firmware/uv_hardware.h" #include "hepa-uv/firmware/uv_control_hardware.hpp" +#include "hepa-uv/firmware/uv_hardware.h" #include "i2c/firmware/i2c_comms.hpp" #include "timer_hardware.h" +#include "uv_hardware.h" static auto iWatchdog = iwdg::IndependentWatchDog{}; @@ -130,6 +131,10 @@ static auto gpio_drive_pins = gpio_drive_hardware::GpioDrivePins{ static auto& hepauv_queues = hepauv_tasks::get_main_queues(); +static auto led_hardware = led_control_hardware::LEDControlHardware(); +static auto hepa_hardware = hepa_control_hardware::HepaControlHardware(); +static auto uv_hardware = uv_control_hardware::UVControlHardware(); + extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { switch (GPIO_Pin) { case DOOR_OPEN_MCU_PIN: @@ -150,9 +155,9 @@ extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { } } -static auto led_hardware = led_control_hardware::LEDControlHardware(); -static auto hepa_hardware = hepa_control_hardware::HepaControlHardware(); -static auto uv_hardware = uv_control_hardware::UVControlHardware(); +extern "C" void hepa_fan_rpm_callback(uint16_t rpm) { + hepa_hardware.hepa_fan_rpm_irq(rpm); +} auto main() -> int { HardwareInit(); @@ -160,7 +165,7 @@ auto main() -> int { utility_gpio_init(); initialize_pwm_hardware(); initialize_adc_hardware(); - initialize_tachometer(); + initialize_tachometer(&hepa_fan_rpm_callback); // set push button leds white led_hardware.set_button_led_power(HEPA_BUTTON, 0, 0, 0, 50); led_hardware.set_button_led_power(UV_BUTTON, 0, 0, 0, 50); diff --git a/hepa-uv/firmware/timer_hardware.c b/hepa-uv/firmware/timer_hardware.c index c605684b7..8f4f98aa7 100644 --- a/hepa-uv/firmware/timer_hardware.c +++ b/hepa-uv/firmware/timer_hardware.c @@ -201,10 +201,15 @@ static void MX_TIM_Init(TIM_TypeDef* tim) { htim->Init.CounterMode = TIM_COUNTERMODE_UP; // Set the counter clock frequency to 25kHz for the HEPA fan pwm. - if (tim == TIM3) htim->Init.Prescaler = calc_prescaler(SystemCoreClock, HEPA_TIMER_FREQ); + if (tim == TIM3) { + htim->Init.Prescaler = calc_prescaler(SystemCoreClock, HEPA_TIMER_FREQ);; + htim->Init.Period = PWM_WIDTH - 1; + } // Setting counter clock frequency to 2 kHz for push button LED's - else htim->Init.Prescaler = calc_prescaler(SystemCoreClock, LED_TIMER_FREQ); - htim->Init.Period = PWM_WIDTH - 1; + else { + htim->Init.Prescaler = calc_prescaler(SystemCoreClock, LED_TIMER_FREQ); + htim->Init.Period = PWM_WIDTH - 1; + } htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim->Init.RepetitionCounter = 0; htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; diff --git a/include/can/core/messages.hpp b/include/can/core/messages.hpp index 6d331c947..2a37a0a85 100644 --- a/include/can/core/messages.hpp +++ b/include/can/core/messages.hpp @@ -1699,12 +1699,14 @@ struct GetHepaFanStateResponse uint32_t message_index; uint32_t duty_cycle; uint8_t fan_on; + uint16_t fan_rpm; template auto serialize(Output body, Limit limit) const -> uint8_t { auto iter = bit_utils::int_to_bytes(message_index, body, limit); iter = bit_utils::int_to_bytes(duty_cycle, iter, limit); iter = bit_utils::int_to_bytes(fan_on, iter, limit); + iter = bit_utils::int_to_bytes(fan_rpm, iter, limit); return iter - body; } diff --git a/include/hepa-uv/core/hepa_task.hpp b/include/hepa-uv/core/hepa_task.hpp index 88b11a95f..425eb6f69 100644 --- a/include/hepa-uv/core/hepa_task.hpp +++ b/include/hepa-uv/core/hepa_task.hpp @@ -64,10 +64,12 @@ class HepaMessageHandler { } void visit(const can::messages::GetHepaFanStateRequest &m) { + hepa_fan_rpm = get_hepa_fan_speed(); auto resp = can::messages::GetHepaFanStateResponse{ .message_index = m.message_index, .duty_cycle = hepa_fan_pwm, - .fan_on = hepa_fan_on}; + .fan_on = hepa_fan_on, + .fan_rpm = hepa_fan_rpm}; can_client.send_can_message(can::ids::NodeId::host, resp); } @@ -82,14 +84,32 @@ class HepaMessageHandler { 0}); } else { gpio::reset(drive_pins.hepa_on_off); + hepa_hardware.reset_hepa_fan_rpm(); led_control_client.send_led_control_message( led_control_task_messages::PushButtonLED{HEPA_BUTTON, 0, 0, 0, 50}); } } - uint32_t hepa_fan_pwm = DEFAULT_HEPA_PWM; + uint16_t get_hepa_fan_speed() { + if (!hepa_fan_on) return 0; + hepa_hardware.enable_tachometer(true); + // wait some time to measure rpm + vTaskDelay(pdMS_TO_TICKS(100)); + hepa_hardware.enable_tachometer(false); + // NOTE: The hepa fan only turns on if the duty cycle is at least 10%. + // So read the rpm and if it has not changed, reset the cached rpm + // value. + if (hepa_fan_pwm < 10 && + hepa_fan_rpm == hepa_hardware.get_hepa_fan_rpm()) { + hepa_hardware.reset_hepa_fan_rpm(); + } + return hepa_hardware.get_hepa_fan_rpm(); + } + bool hepa_fan_on = false; + uint32_t hepa_fan_pwm = DEFAULT_HEPA_PWM; + uint16_t hepa_fan_rpm = 0; gpio_drive_hardware::GpioDrivePins &drive_pins; hepa_control_hardware::HepaControlHardware &hepa_hardware; diff --git a/include/hepa-uv/core/interfaces.hpp b/include/hepa-uv/core/interfaces.hpp index 1b1d5aa8e..f4ffa72a7 100644 --- a/include/hepa-uv/core/interfaces.hpp +++ b/include/hepa-uv/core/interfaces.hpp @@ -32,7 +32,10 @@ class HepaControlInterface { virtual ~HepaControlInterface() = default; virtual auto set_hepa_fan_speed(uint32_t duty_cycle) -> void = 0; - virtual auto get_hepa_fan_rpm() -> uint32_t = 0; + virtual auto get_hepa_fan_rpm() -> uint16_t = 0; + virtual auto reset_hepa_fan_rpm() -> void = 0; + virtual auto hepa_fan_rpm_irq(uint16_t rpm) -> void = 0; + virtual auto enable_tachometer(bool enable) -> bool = 0; }; } // namespace hepa_control diff --git a/include/hepa-uv/firmware/hepa_control_hardware.hpp b/include/hepa-uv/firmware/hepa_control_hardware.hpp index 3d3c13873..6495ac505 100644 --- a/include/hepa-uv/firmware/hepa_control_hardware.hpp +++ b/include/hepa-uv/firmware/hepa_control_hardware.hpp @@ -14,7 +14,13 @@ class HepaControlHardware : public hepa_control::HepaControlInterface { ~HepaControlHardware() final = default; void set_hepa_fan_speed(uint32_t duty_cycle) final; - uint32_t get_hepa_fan_rpm() final; + uint16_t get_hepa_fan_rpm() final; + void reset_hepa_fan_rpm() final; + void hepa_fan_rpm_irq(uint16_t rpm) final; + bool enable_tachometer(bool enable) final; + + private: + uint16_t hepa_fan_rpm = 0; }; } // namespace hepa_control_hardware \ No newline at end of file diff --git a/include/hepa-uv/firmware/hepa_hardware.h b/include/hepa-uv/firmware/hepa_hardware.h index 89ed70391..78d11c6b6 100644 --- a/include/hepa-uv/firmware/hepa_hardware.h +++ b/include/hepa-uv/firmware/hepa_hardware.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "hepa-uv/core/constants.h" @@ -8,11 +9,11 @@ extern "C" { #endif // __cplusplus -#define HEPA_TACHOMETER_TIMER_FREQ (20000U) +typedef void (*hepa_rpm_callback)(uint16_t); -void initialize_tachometer(); +void initialize_tachometer(hepa_rpm_callback rpm_callback); +bool enable_hepa_fan_tachometer(bool enable); void set_hepa_fan_pwm(uint32_t duty_cycle); -uint32_t get_hepa_fan_rpm(); #ifdef __cplusplus } // extern "C"