/* Reflow Oven Controller * * Copyright (C) 2020 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ #include #include #include #include #include #include #include #include static struct pid_controller IN_SECTION(.ccm.bss) oven_pid; static bool oven_pid_running = false; static bool oven_pid_aborted = false; static uint8_t IN_SECTION(.ccm.bss) oven_driver_power_level = 0U; void oven_driver_init() { rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_PORT_RCC_MASK)); rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK)); OVEN_CONTROLLER_PORT->MODER &= MODER_DELETE(OVEN_CONTROLLER_PIN); OVEN_CONTROLLER_PORT->MODER |= ALTFUNC(OVEN_CONTROLLER_PIN); SETAF(OVEN_CONTROLLER_PORT, OVEN_CONTROLLER_PIN, OVEN_CONTROLLER_PIN_ALTFUNC); OVEN_CONTROLLER_PWM_TIMER->CR2 = 0UL; OVEN_CONTROLLER_PWM_TIMER->CCMR2 = TIM_CCMR2_OC3M; OVEN_CONTROLLER_PWM_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3P; OVEN_CONTROLLER_PWM_TIMER->ARR = 1000U; OVEN_CONTROLLER_PWM_TIMER->PSC = 42000U - 1U; OVEN_CONTROLLER_PWM_TIMER->CR1 = TIM_CR1_CMS | TIM_CR1_CEN; } void oven_driver_set_power(uint8_t power) { if (power > 100U) power = 100U; oven_driver_power_level = power; } void oven_driver_apply_power_level(void) { OVEN_CONTROLLER_PWM_TIMER->CCR3 = oven_driver_power_level * 10; } void oven_driver_disable() { OVEN_CONTROLLER_PWM_TIMER->CR1 = 0UL; OVEN_CONTROLLER_PWM_TIMER->CR2 = 0UL; rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_PORT_RCC_MASK)); rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK)); } void oven_pid_init(struct pid_controller *controller_to_copy) { pid_copy(&oven_pid, controller_to_copy); oven_pid.output_sat_min = 0.0f; oven_pid.output_sat_max = 100.0f; oven_pid_running = true; oven_pid_aborted = false; safety_controller_report_timing(ERR_TIMING_PID); } void oven_pid_handle(float target_temp) { float pid_out; float current_temp; static uint64_t timestamp_last_run; if (oven_pid_running && !oven_pid_aborted) { if (systick_ticks_have_passed(timestamp_last_run, (uint64_t)(oven_pid.sample_period * 1000))) { /* No need to check. Safety controller will monitor this */ (void)adc_pt1000_get_current_resistance(¤t_temp); (void)temp_converter_convert_resistance_to_temp(current_temp, ¤t_temp); pid_out = pid_sample(&oven_pid, target_temp - current_temp); oven_driver_set_power((uint8_t)pid_out); timestamp_last_run = systick_get_global_tick(); safety_controller_report_timing(ERR_TIMING_PID); } } } void oven_pid_stop() { oven_pid_running = false; safety_controller_enable_timing_mon(ERR_TIMING_PID, false); } enum oven_pid_status oven_pid_get_status(void) { enum oven_pid_status ret = OVEN_PID_ABORTED; if (oven_pid_running && !oven_pid_aborted) ret = OVEN_PID_RUNNING; else if (!oven_pid_running && !oven_pid_aborted) ret = OVEN_PID_DEACTIVATED; return ret; }