reflow-oven-control-sw/stm-firmware/oven-driver.c

164 lines
5.2 KiB
C
Raw Normal View History

/* Reflow Oven Controller
*
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/oven-driver.h>
2020-05-10 23:13:03 +02:00
#include <reflow-controller/periph-config/oven-driver-hwcfg.h>
#include <stm-periph/clock-enable-manager.h>
#include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h>
#include <reflow-controller/temp-converter.h>
static struct pid_controller oven_pid;
static struct oven_pid_status oven_pid_current_status = {
.active = false,
2020-06-14 23:36:49 +02:00
.error_set = false,
.target_temp = 0.0f,
.current_temp = 0.0f,
.timestamp_last_run = 0ULL
};
void oven_driver_init()
{
2020-05-10 23:13:03 +02:00
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));
2020-05-10 23:13:03 +02:00
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)
{
2020-05-10 23:13:03 +02:00
if (power > 100U)
power = 100U;
2020-05-10 23:13:03 +02:00
OVEN_CONTROLLER_PWM_TIMER->CCR3 = power * 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));
}
2020-06-14 23:36:49 +02:00
void oven_pid_ack_errors(void)
{
2020-06-14 23:36:49 +02:00
oven_pid_current_status.error_set = false;
oven_pid_current_status.error_flags.vref_tol = false;
oven_pid_current_status.error_flags.pt1000_other = false;
oven_pid_current_status.error_flags.generic_error = false;
oven_pid_current_status.error_flags.pt1000_adc_off = false;
oven_pid_current_status.error_flags.controller_overtemp = false;
oven_pid_current_status.error_flags.pt1000_adc_watchdog = false;
}
2020-06-14 23:36:49 +02:00
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_current_status.timestamp_last_run = 0ULL;
oven_pid_current_status.active = true;
oven_pid_ack_errors();
}
void oven_pid_handle(float target_temp)
{
float pid_out;
float current_temp;
int resistance_status;
enum adc_pt1000_error pt1000_error;
2020-06-14 23:36:49 +02:00
if (oven_pid_current_status.active && !oven_pid_current_status.error_set) {
if (systick_ticks_have_passed(oven_pid_current_status.timestamp_last_run,
(uint64_t)(oven_pid.sample_period * 1000))) {
resistance_status = adc_pt1000_get_current_resistance(&current_temp);
if (resistance_status < 0) {
oven_driver_set_power(0);
pt1000_error = adc_pt1000_check_error();
if (pt1000_error & ADC_PT1000_WATCHDOG_ERROR)
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_WATCHDOG);
if (pt1000_error & ADC_PT1000_INACTIVE)
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_OFF);
if (pt1000_error & ADC_PT1000_OVERFLOW)
oven_pid_report_error(OVEN_PID_ERR_PT1000_OTHER);
return;
}
(void)temp_converter_convert_resistance_to_temp(current_temp, &current_temp);
pid_out = pid_sample(&oven_pid, target_temp - current_temp);
oven_driver_set_power((uint8_t)pid_out);
oven_pid_current_status.timestamp_last_run = systick_get_global_tick();
oven_pid_current_status.target_temp = target_temp;
oven_pid_current_status.current_temp = current_temp;
}
}
}
void oven_pid_report_error(enum oven_pid_error_report report)
{
struct oven_pid_errors *e = &oven_pid_current_status.error_flags;
oven_pid_current_status.active = false;
2020-06-14 23:36:49 +02:00
oven_pid_current_status.error_set = true;
if (report == 0) {
e->generic_error = true;
}
if (report & OVEN_PID_ERR_OVERTEMP)
e->controller_overtemp = true;
if (report & OVEN_PID_ERR_VREF_TOL)
e->controller_overtemp = true;
if (report & OVEN_PID_ERR_PT1000_OTHER)
e->pt1000_other = true;
if (report & OVEN_PID_ERR_PT1000_ADC_OFF)
e->pt1000_adc_off = true;
if (report & OVEN_PID_ERR_PT1000_ADC_WATCHDOG)
e->pt1000_adc_watchdog = true;
}
const struct oven_pid_status *oven_pid_get_status()
{
return &oven_pid_current_status;
}
void oven_pid_stop()
{
oven_pid_current_status.active = false;
oven_pid_current_status.target_temp = 0.0f;
oven_pid_current_status.current_temp = 0.0f;
}