Skip to content

Commit

Permalink
feat(hepa-uv): Add the ability to set the duty cycle for the HEPA fan. (
Browse files Browse the repository at this point in the history
  • Loading branch information
vegano1 authored Jan 25, 2024
1 parent 083a816 commit acede48
Show file tree
Hide file tree
Showing 19 changed files with 460 additions and 294 deletions.
6 changes: 4 additions & 2 deletions hepa-uv/core/tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "common/core/freertos_timer.hpp"
#include "hepa-uv/core/can_task.hpp"
#include "hepa-uv/firmware/gpio_drive_hardware.hpp"
#include "hepa-uv/firmware/hepa_control_hardware.hpp"
#include "hepa-uv/firmware/utility_gpio.h"

#pragma GCC diagnostic push
Expand All @@ -29,13 +30,14 @@ static auto led_control_task_builder =
void hepauv_tasks::start_tasks(
can::bus::CanBus& can_bus,
gpio_drive_hardware::GpioDrivePins& gpio_drive_pins,
hepa_control_hardware::HepaControlHardware& hepa_hardware,
led_control_hardware::LEDControlHardware& led_hardware) {
auto& can_writer = can_task::start_writer(can_bus);
can_task::start_reader(can_bus);

// TODO: including led_hardware for testing, this should be a AssesorClient
auto& hepa_task =
hepa_task_builder.start(5, "hepa_fan", gpio_drive_pins, queues);
auto& hepa_task = hepa_task_builder.start(5, "hepa_fan", gpio_drive_pins,
hepa_hardware, queues);
auto& uv_task =
uv_task_builder.start(5, "uv_ballast", gpio_drive_pins, queues);
auto& led_control_task =
Expand Down
3 changes: 3 additions & 0 deletions hepa-uv/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(REVISIONS hepa-rev1)
set(HEPA_UV_FW_LINTABLE_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/freertos_idle_timer_task.cpp
${CMAKE_CURRENT_SOURCE_DIR}/led_control_task/led_control_hardware.cpp
${CMAKE_CURRENT_SOURCE_DIR}/hepa_control_task/hepa_control_hardware.cpp
${COMMON_EXECUTABLE_DIR}/system/iwdg.cpp
${CAN_FW_DIR}/hal_can_bus.cpp
${CAN_FW_DIR}/utils.c
Expand All @@ -24,6 +25,8 @@ set(HEPAUV_FW_NON_LINTABLE_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/stm32g4xx_it.c
${CMAKE_CURRENT_SOURCE_DIR}/clocking.c
${CMAKE_CURRENT_SOURCE_DIR}/utility_gpio.c
${CMAKE_CURRENT_SOURCE_DIR}/timer_hardware.c
${CMAKE_CURRENT_SOURCE_DIR}/hepa_hardware.c
${CMAKE_CURRENT_SOURCE_DIR}/led_hardware.c
${CMAKE_CURRENT_SOURCE_DIR}/can.c
${CMAKE_CURRENT_SOURCE_DIR}/i2c_setup.c
Expand Down
9 changes: 9 additions & 0 deletions hepa-uv/firmware/hepa_control_task/hepa_control_hardware.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "hepa-uv/firmware/hepa_control_hardware.hpp"

#include "hepa-uv/firmware/hepa_hardware.h"

using namespace hepa_control_hardware;

void HepaControlHardware::set_hepa_fan_speed(uint32_t duty_cycle) {
set_hepa_fan_pwm(duty_cycle);
}
13 changes: 13 additions & 0 deletions hepa-uv/firmware/hepa_hardware.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "hepa-uv/firmware/hepa_hardware.h"
#include "timer_hardware.h"

static uint32_t clamp(uint32_t val, uint32_t min, uint32_t max) {
if (val < min) return min;
if (val > max) return max;
return val;
}

void set_hepa_fan_pwm(uint32_t duty_cycle) {
// calculate the pulse width from the duty cycle
htim3.Instance->CCR1 = clamp(duty_cycle, 0, 100) * htim3.Init.Period / 100;
}
5 changes: 0 additions & 5 deletions hepa-uv/firmware/led_control_task/led_control_hardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@

using namespace led_control_hardware;

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
auto LEDControlHardware::initialize() -> void {
button_led_hw_initialize_leds();
}

void LEDControlHardware::set_button_led_power(uint8_t button, uint32_t r,
uint32_t g, uint32_t b,
uint32_t w) {
Expand Down
251 changes: 1 addition & 250 deletions hepa-uv/firmware/led_hardware.c
Original file line number Diff line number Diff line change
@@ -1,234 +1,8 @@
#include "hepa-uv/firmware/led_hardware.h"
#include "hepa-uv/firmware/utility_gpio.h"
#include "common/firmware/errors.h"

#include "platform_specific_hal_conf.h"
#include "system_stm32g4xx.h"

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim8;
TIM_HandleTypeDef htim16;
TIM_HandleTypeDef htim20;

TIM_OC_InitTypeDef htim1_sConfigOC = {0};
TIM_OC_InitTypeDef htim8_sConfigOC = {0};
TIM_OC_InitTypeDef htim16_sConfigOC = {0};
TIM_OC_InitTypeDef htim20_sConfigOC = {0};


uint32_t round_closest(uint32_t dividend, uint32_t divisor) {
return (dividend + (divisor / 2)) / divisor;
}

uint32_t calc_prescaler(uint32_t timer_clk_freq, uint32_t counter_clk_freq) {
return timer_clk_freq >= counter_clk_freq
? round_closest(timer_clk_freq, counter_clk_freq) - 1U
: 0U;
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_pwm) {
if(htim_pwm->Instance == TIM1) {
__HAL_RCC_TIM1_CLK_ENABLE();
} else if(htim_pwm->Instance == TIM8) {
__HAL_RCC_TIM8_CLK_ENABLE();
} else if(htim_pwm->Instance == TIM16) {
__HAL_RCC_TIM16_CLK_ENABLE();
} else if(htim_pwm->Instance == TIM20) {
__HAL_RCC_TIM20_CLK_ENABLE();
}
}

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (htim->Instance == TIM1) {
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM1 GPIO Configuration
PA9 ------> TIM1_CH2
PA10 ------> TIM1_CH3
*/
GPIO_InitStruct.Pin = HEPA_R_CTRL_PIN | HEPA_W_CTRL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
HAL_GPIO_Init(HEPA_R_CTRL_PORT, &GPIO_InitStruct);

// PC5 ------> TIM1_CH4N
GPIO_InitStruct.Pin = UV_B_CTRL_PIN;
HAL_GPIO_Init(UV_B_CTRL_PORT, &GPIO_InitStruct);
} else if (htim->Instance == TIM8) {
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM8 GPIO Configuration
PB0 ------> TIM8_CH2N
PB1 ------> TIM8_CH3N
*/
GPIO_InitStruct.Pin = UV_G_CTRL_PIN | UV_R_CTRL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_TIM8;
HAL_GPIO_Init(UV_G_CTRL_PORT, &GPIO_InitStruct);

/*
PC6 ------> TIM8_CH1
*/
GPIO_InitStruct.Pin = HEPA_G_CTRL_PIN;
HAL_GPIO_Init(HEPA_G_CTRL_PORT, &GPIO_InitStruct);
} else if (htim->Instance == TIM16) {
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM16 GPIO Configuration
PB4 ------> TIM16_CH1
*/
GPIO_InitStruct.Pin = HEPA_B_CTRL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM16;
HAL_GPIO_Init(HEPA_B_CTRL_PORT, &GPIO_InitStruct);
} else if (htim->Instance == TIM20) {
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM20 GPIO Configuration
PB2 ------> TIM20_CH1
*/
GPIO_InitStruct.Pin = UV_W_CTRL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM20;
HAL_GPIO_Init(UV_W_CTRL_PORT, &GPIO_InitStruct);
}
}

/**
* @brief TIM Initialization Function for the LED timers.
* @param tim Pointer to the timer we are configuring
* @retval None
*/
static void MX_TIM_Init(TIM_TypeDef* tim) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

TIM_HandleTypeDef* htim;
TIM_OC_InitTypeDef* htim_sConfigOC;
unsigned int channels[3];
int channels_size = 0;
if (tim == TIM1){
htim = &htim1;
htim_sConfigOC = &htim1_sConfigOC;
/* Channels
HEPA_R_CTRL -> ch2
HEPA_W_CTRL -> ch3
UV_B_CTRL -> ch4
*/
channels_size = 3;
channels[0] = TIM_CHANNEL_2;
channels[1] = TIM_CHANNEL_3;
channels[2] = TIM_CHANNEL_4;
} else if (tim == TIM8) {
htim = &htim8;
htim_sConfigOC = &htim8_sConfigOC;
/* Channels
HEPA_G_CTRL -> ch1
UV_G_CTRL -> ch2
UV_R_CTRL -> ch3
*/
channels_size = 3;
channels[0] = TIM_CHANNEL_1;
channels[1] = TIM_CHANNEL_2;
channels[2] = TIM_CHANNEL_3;
} else if (tim == TIM16) {
htim = &htim16;
htim_sConfigOC = &htim16_sConfigOC;
/* Channels
HEPA_B_CTRL -> ch1
*/
channels_size = 1;
channels[0] = TIM_CHANNEL_1;
} else if (tim == TIM20) {
htim = &htim20;
htim_sConfigOC = &htim20_sConfigOC;
/* Channels
UV_W_CTRL -> ch1
*/
channels_size = 1;
channels[0] = TIM_CHANNEL_1;
} else {
Error_Handler();
return;
}

htim->State = HAL_TIM_STATE_RESET;
htim->Instance = tim;
/*
* Setting counter clock frequency to 2 kHz
*/
htim->Init.Prescaler =
calc_prescaler(SystemCoreClock, LED_TIMER_FREQ);
htim->Init.CounterMode = TIM_COUNTERMODE_UP;
htim->Init.Period = LED_PWM_WIDTH - 1;
htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim->Init.RepetitionCounter = 0;
htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(htim) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(htim, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_PWM_Init(htim) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(htim, &sMasterConfig) !=
HAL_OK) {
Error_Handler();
}
htim_sConfigOC->OCMode = TIM_OCMODE_PWM1;
/* Set duty cycle at 0% */
htim_sConfigOC->Pulse = 0;
htim_sConfigOC->OCPolarity = TIM_OCPOLARITY_HIGH;
htim_sConfigOC->OCNPolarity = TIM_OCNPOLARITY_HIGH;
htim_sConfigOC->OCFastMode = TIM_OCFAST_DISABLE;
htim_sConfigOC->OCIdleState = TIM_OCIDLESTATE_RESET;
htim_sConfigOC->OCNIdleState = TIM_OCNIDLESTATE_RESET;

// Enable the corresponding channels for this timer
for (int i = 0; i < channels_size; i++) {
if (HAL_TIM_PWM_ConfigChannel(htim, htim_sConfigOC, channels[i]) !=
HAL_OK) {
Error_Handler();
}
}

sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
sBreakDeadTimeConfig.Break2Filter = 0;
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(htim, &sBreakDeadTimeConfig) !=
HAL_OK) {
Error_Handler();
}
HAL_TIM_MspPostInit(htim);
}
#include "timer_hardware.h"

void button_led_hw_update_pwm(uint32_t duty_cycle, LED_TYPE led, PUSH_BUTTON_TYPE button) {

// TODO: fix this
if (button == HEPA_BUTTON) {
switch(led) {
case RED_LED:
Expand Down Expand Up @@ -272,26 +46,3 @@ void set_button_led_pwm(PUSH_BUTTON_TYPE button, uint32_t red, uint32_t green, u
button_led_hw_update_pwm(blue, BLUE_LED, button);
button_led_hw_update_pwm(white, WHITE_LED, button);
}

void button_led_hw_initialize_leds() {
// Initialize the timers and channels
MX_TIM_Init(TIM1);
MX_TIM_Init(TIM8);
MX_TIM_Init(TIM16);
MX_TIM_Init(TIM20);

// Set the the button LEDS to idle (white)
set_button_led_pwm(HEPA_BUTTON, 0, 0, 0, 50);
set_button_led_pwm(UV_BUTTON, 0, 0, 0, 50);

// Activate the channels
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim20, TIM_CHANNEL_1);
// Activate the complementary output
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_4);
HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3);
}
12 changes: 9 additions & 3 deletions hepa-uv/firmware/main_rev1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
#include "common/firmware/utility_gpio.h"
#include "hepa-uv/core/messages.hpp"
#include "hepa-uv/core/tasks.hpp"
#include "hepa-uv/firmware/hepa_control_hardware.hpp"
#include "hepa-uv/firmware/led_control_hardware.hpp"
#include "hepa-uv/firmware/led_hardware.h"
#include "hepa-uv/firmware/utility_gpio.h"
#include "timer_hardware.h"

static auto iWatchdog = iwdg::IndependentWatchDog{};

Expand Down Expand Up @@ -118,18 +119,23 @@ 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();

auto main() -> int {
HardwareInit();
RCC_Peripheral_Clock_Select();
utility_gpio_init();
button_led_hw_initialize_leds();
initialize_pwm_hardware();
// 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);

app_update_clear_flags();

canbus.start(can_bit_timings);

hepauv_tasks::start_tasks(canbus, gpio_drive_pins, led_hardware);
hepauv_tasks::start_tasks(canbus, gpio_drive_pins, hepa_hardware,
led_hardware);

iWatchdog.start(6);

Expand Down
Loading

0 comments on commit acede48

Please sign in to comment.