Skip to content

Commit

Permalink
refactor hepa rpm feature so we use irq callback to update the rpm value
Browse files Browse the repository at this point in the history
get_hepa_fan_speed is now defined in the hepa_tast, it enables the tachometer, waits 100ms, and returns the calculated rpm to the caller
set rpm value to uint16_t instead if uint32_t since the expected values are < 0xffff
  • Loading branch information
vegano1 committed Mar 31, 2024
1 parent 57484d2 commit 7d19abb
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 61 deletions.
12 changes: 9 additions & 3 deletions hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
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; }
90 changes: 48 additions & 42 deletions hepa-uv/firmware/hepa_hardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
#include "hepa-uv/firmware/utility_gpio.h"
#include "common/firmware/errors.h"
#include "timer_hardware.h"
#include <math.h>

#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) {
Expand All @@ -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) !=
Expand All @@ -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);
}

Expand All @@ -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();
}
17 changes: 11 additions & 6 deletions hepa-uv/firmware/main_rev1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{};

Expand Down Expand Up @@ -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:
Expand All @@ -150,17 +155,17 @@ 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();
RCC_Peripheral_Clock_Select();
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);
Expand Down
11 changes: 8 additions & 3 deletions hepa-uv/firmware/timer_hardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions include/can/core/messages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1699,12 +1699,14 @@ struct GetHepaFanStateResponse
uint32_t message_index;
uint32_t duty_cycle;
uint8_t fan_on;
uint16_t fan_rpm;

template <bit_utils::ByteIterator Output, typename Limit>
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;
}

Expand Down
24 changes: 22 additions & 2 deletions include/hepa-uv/core/hepa_task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion include/hepa-uv/core/interfaces.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 7 additions & 1 deletion include/hepa-uv/firmware/hepa_control_hardware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 4 additions & 3 deletions include/hepa-uv/firmware/hepa_hardware.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

#include "hepa-uv/core/constants.h"

#ifdef __cplusplus
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"
Expand Down

0 comments on commit 7d19abb

Please sign in to comment.