2020-04-20 21:16:39 +02:00
|
|
|
/* 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>
|
2020-06-13 23:23:59 +02:00
|
|
|
#include <reflow-controller/systick.h>
|
2020-06-14 19:09:59 +02:00
|
|
|
#include <reflow-controller/adc-meas.h>
|
|
|
|
#include <reflow-controller/temp-converter.h>
|
2020-06-13 23:23:59 +02:00
|
|
|
|
|
|
|
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,
|
2020-06-13 23:23:59 +02:00
|
|
|
.target_temp = 0.0f,
|
|
|
|
.current_temp = 0.0f,
|
|
|
|
.timestamp_last_run = 0ULL
|
|
|
|
};
|
2020-05-05 18:55:55 +02:00
|
|
|
|
|
|
|
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-05 18:55:55 +02:00
|
|
|
|
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;
|
2020-05-05 18:55:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void oven_driver_set_power(uint8_t power)
|
|
|
|
{
|
2020-05-10 23:13:03 +02:00
|
|
|
if (power > 100U)
|
|
|
|
power = 100U;
|
2020-05-05 18:55:55 +02:00
|
|
|
|
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-05-05 18:55:55 +02:00
|
|
|
}
|
2020-06-13 23:23:59 +02:00
|
|
|
|
2020-06-14 23:36:49 +02:00
|
|
|
void oven_pid_ack_errors(void)
|
2020-06-13 23:23:59 +02:00
|
|
|
{
|
2020-06-14 23:36:49 +02:00
|
|
|
oven_pid_current_status.error_set = false;
|
2020-06-14 19:09:59 +02:00
|
|
|
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-13 23:23:59 +02:00
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-06-14 19:09:59 +02:00
|
|
|
void oven_pid_handle(float target_temp)
|
2020-06-13 23:23:59 +02:00
|
|
|
{
|
|
|
|
float pid_out;
|
2020-06-14 19:09:59 +02:00
|
|
|
float current_temp;
|
|
|
|
int resistance_status;
|
|
|
|
enum adc_pt1000_error pt1000_error;
|
2020-06-13 23:23:59 +02:00
|
|
|
|
2020-06-14 23:36:49 +02:00
|
|
|
if (oven_pid_current_status.active && !oven_pid_current_status.error_set) {
|
2020-06-13 23:23:59 +02:00
|
|
|
if (systick_ticks_have_passed(oven_pid_current_status.timestamp_last_run,
|
|
|
|
(uint64_t)(oven_pid.sample_period * 1000))) {
|
2020-06-14 19:09:59 +02:00
|
|
|
|
|
|
|
resistance_status = adc_pt1000_get_current_resistance(¤t_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, ¤t_temp);
|
|
|
|
|
2020-06-13 23:23:59 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-14 19:09:59 +02:00
|
|
|
void oven_pid_report_error(enum oven_pid_error_report report)
|
2020-06-13 23:23:59 +02:00
|
|
|
{
|
2020-06-14 19:09:59 +02:00
|
|
|
struct oven_pid_errors *e = &oven_pid_current_status.error_flags;
|
|
|
|
|
2020-06-13 23:23:59 +02:00
|
|
|
oven_pid_current_status.active = false;
|
2020-06-14 23:36:49 +02:00
|
|
|
oven_pid_current_status.error_set = true;
|
2020-06-14 19:09:59 +02:00
|
|
|
|
|
|
|
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;
|
2020-06-13 23:23:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|