Add preliminary safety ADC which measures the Controller temperature and checks the reference voltage against the STM's internal reference voltage

This commit is contained in:
Mario Hüttel 2020-05-16 21:00:55 +02:00
parent dc8beefb63
commit e97092042b
6 changed files with 290 additions and 6 deletions

View File

@ -46,6 +46,7 @@ CFILES += ui/lcd.c ui/menu.c
CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
CFILES += pid-controller.c oven-driver.c CFILES += pid-controller.c oven-driver.c
CFILES += settings/settings.c settings/settings-sd-card.c CFILES += settings/settings.c settings/settings-sd-card.c
CFILES += safety-adc.c
DEFINES += -DDEBUGBUILD DEFINES += -DDEBUGBUILD

View File

@ -0,0 +1,31 @@
/* 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/>.
*/
#ifndef __SAFETY_ADC_HWCFG_H__
#define __SAFETY_ADC_HWCFG_H__
#include <stm32/stm32f4xx.h>
#define SAFETY_ADC_ADC_PERIPHERAL ADC1
#define SAFETY_ADC_ADC_RCC_MASK RCC_APB2ENR_ADC1EN
#define TEMP_CHANNEL_NUM (16)
#define INT_REF_CHANNEL_NUM (17)
#endif /* __SAFETY_ADC_HWCFG_H__ */

View File

@ -0,0 +1,64 @@
/* 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/>.
*/
#ifndef __SAFETY_ADC_H__
#define __SAFETY_ADC_H__
#include <stdint.h>
#include <stdbool.h>
#define SAFETY_ADC_FRAC_BITS (8)
#define SAFETY_ADC_VREF_VOLT (2.5)
#define SAFETY_ADC_VREF_TOL (0.25)
#define SAFETY_ADC_VREF_INT ()
enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP};
enum safety_adc_check_result {
SAFETY_ADC_CHECK_OK = 0UL,
SAFETY_ADC_CHECK_VREF_LOW = (1U<<0),
SAFETY_ADC_CHECK_VREF_HIGH = (1U<<1),
SAFETY_ADC_CHECK_TEMP_LOW = (1U<<2),
SAFETY_ADC_CHECK_TEMP_HIGH = (1U<<3),
};
void safety_adc_init();
void safety_adc_deinit();
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement);
/**
* @brief Poll ADC result.
* @param results adc results
* @return 1 if measurement successful, 0 if not ready, -1 if ADC aborted or not started
*/
int safety_adc_poll_result(uint16_t *adc_result);
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
float *vref_calculated, float *temp_calculated);
enum safety_adc_check_result handle_safety_adc();
float safety_adc_get_temp();
float safety_adc_get_vref();
#endif /* __SAFETY_ADC_H__ */

View File

@ -47,6 +47,7 @@
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <reflow-controller/button.h> #include <reflow-controller/button.h>
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <reflow-controller/safety-adc.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
static void setup_nvic_priorities() static void setup_nvic_priorities()
@ -142,12 +143,10 @@ static bool mount_sd_card_if_avail(bool mounted)
} }
static inline int32_t handle_pid_controller(struct pid_controller *pid, float target_temperature, static inline int32_t handle_pid_controller(struct pid_controller *pid, float target_temperature,
float current_pt1000_resistance) float current_temperature)
{ {
float current_temperature;
int32_t pid_out; int32_t pid_out;
(void)temp_converter_convert_resistance_to_temp(current_pt1000_resistance, (float *)&current_temperature);
pid_out = (int32_t)pid_sample(pid, target_temperature - current_temperature); pid_out = (int32_t)pid_sample(pid, target_temperature - current_temperature);
/* Blink green LED */ /* Blink green LED */
@ -179,6 +178,7 @@ static inline void setup_system()
rotary_encoder_setup(); rotary_encoder_setup();
button_init(); button_init();
lcd_init(); lcd_init();
safety_adc_init();
uart_gpio_config(); uart_gpio_config();
setup_sell_uart(&shell_uart); setup_sell_uart(&shell_uart);
@ -198,6 +198,8 @@ static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
shell_handle_input(shell_handle, uart_input, uart_input_len); shell_handle_input(shell_handle, uart_input, uart_input_len);
} }
int main() int main()
{ {
bool sd_card_mounted = false; bool sd_card_mounted = false;
@ -209,6 +211,8 @@ int main()
uint64_t display_timestamp = 0ULL; uint64_t display_timestamp = 0ULL;
char disp[4][21] = {0}; char disp[4][21] = {0};
enum lcd_fsm_ret lcd_ret = LCD_FSM_NOP; enum lcd_fsm_ret lcd_ret = LCD_FSM_NOP;
int temp_status;
float current_temp;
target_temperature = 25.0f; target_temperature = 25.0f;
@ -228,15 +232,25 @@ int main()
pt1000_value_status = adc_pt1000_get_current_resistance(&pt1000_value); pt1000_value_status = adc_pt1000_get_current_resistance(&pt1000_value);
if (systick_ticks_have_passed(pid_timestamp, 250)) { if (systick_ticks_have_passed(pid_timestamp, 250)) {
(void)handle_safety_adc();
pid_timestamp = systick_get_global_tick(); pid_timestamp = systick_get_global_tick();
temp_status = temp_converter_convert_resistance_to_temp(pt1000_value,
&current_temp);
if (pt1000_value_status >= 0 && pid_controller_active) if (pt1000_value_status >= 0 && pid_controller_active)
pid_controller_output = handle_pid_controller(&pid, target_temperature, pt1000_value); pid_controller_output = handle_pid_controller(&pid, target_temperature, current_temp);
/* Blink red led in case of temp error */ /* Blink red led in case of temp error */
if (pt1000_value_status < 0) if (pt1000_value_status < 0)
led_set(0, !led_get(0)); led_set(0, !led_get(0));
else else
led_set(0, 0); led_set(0, 0);
snprintf(&disp[3][0], 17, "Temp: %s%.1f C", (temp_status == 0 ? "" : temp_status < 0 ? "<" : ">")
, current_temp);
} }
/* Handle error in case PID controller should be active, but temperature measurement failed */ /* Handle error in case PID controller should be active, but temperature measurement failed */

153
stm-firmware/safety-adc.c Normal file
View File

@ -0,0 +1,153 @@
/* 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/safety-adc.h>
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
#include <stm-periph/clock-enable-manager.h>
void safety_adc_init()
{
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
/* Enable temperature and VREFINT measurement */
ADC->CCR |= ADC_CCR_TSVREFE;
/* Set sample time for channels 16 and 17 */
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16;
/* Standard sequence. One measurement */
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = 0UL;
}
void safety_adc_deinit()
{
SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
}
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
float *vref_calculated, float *temp_calculated)
{
enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK;
if (vref_calculated) {
*vref_calculated = (1210.0 * 4095) / (float)vref_result;
}
if (temp_calculated) {
*temp_calculated = (((float)temp_result / 4095.0f * 2500.0f - 760.0f) / 2.5f) + 25.0f;
}
return res;
}
int safety_adc_poll_result(uint16_t *adc_result)
{
int ret = 0;
if (!adc_result)
return -1000;
if (!(SAFETY_ADC_ADC_PERIPHERAL->CR2 & ADC_CR2_ADON)) {
return -1;
}
if (SAFETY_ADC_ADC_PERIPHERAL->SR & ADC_SR_EOC) {
*adc_result = (uint16_t)SAFETY_ADC_ADC_PERIPHERAL->DR;
SAFETY_ADC_ADC_PERIPHERAL->CR2 &= ~ADC_CR2_ADON;
ret = 1;
}
return ret;
}
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement)
{
switch (measurement) {
case SAFETY_ADC_MEAS_TEMP:
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = TEMP_CHANNEL_NUM;
break;
case SAFETY_ADC_MEAS_VREF:
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = INT_REF_CHANNEL_NUM;
break;
default:
return;
}
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_ADON;
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
}
static volatile uint16_t safety_vref_meas_raw;
static volatile bool safety_vref_valid = false;
static volatile uint16_t safety_temp_meas_raw;
static volatile bool safety_temp_valid = false;
static float safety_vref;
static float safety_temp;
enum safety_adc_check_result handle_safety_adc()
{
static enum safety_adc_meas_channel safety_meas_channel = SAFETY_ADC_MEAS_VREF;
uint16_t result;
int poll_status;
poll_status = safety_adc_poll_result(&result);
if (poll_status < 0) {
safety_adc_trigger_meas(safety_meas_channel);
} else if (poll_status > 0) {
switch (safety_meas_channel) {
case SAFETY_ADC_MEAS_TEMP:
safety_temp_meas_raw = result;
safety_temp_valid = true;
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
break;
case SAFETY_ADC_MEAS_VREF:
safety_vref_meas_raw = result;
safety_vref_valid = true;
safety_meas_channel = SAFETY_ADC_MEAS_TEMP;
break;
default:
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
return -2000;
}
}
if (safety_temp_valid && safety_vref_valid) {
return safety_adc_check_results(safety_vref_meas_raw, safety_temp_meas_raw, &safety_vref, &safety_temp);
} else {
return SAFETY_ADC_CHECK_OK;
}
}
float safety_adc_get_temp()
{
return safety_temp;
}
float safety_adc_get_vref()
{
return safety_vref;
}

View File

@ -35,6 +35,7 @@
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <reflow-controller/stack-check.h> #include <reflow-controller/stack-check.h>
#include <reflow-controller/rotary-encoder.h> #include <reflow-controller/rotary-encoder.h>
#include <reflow-controller/safety-adc.h>
#ifndef GIT_VER #ifndef GIT_VER
#define GIT_VER "VERSION NOT SET" #define GIT_VER "VERSION NOT SET"
@ -342,6 +343,18 @@ static shellmatta_retCode_t shell_cmd_cat(const shellmatta_handle_t handle, cons
return SHELLMATTA_OK; return SHELLMATTA_OK;
} }
static shellmatta_retCode_t shell_cmd_safety_adc(const shellmatta_handle_t handle, const char *arguments,
uint32_t length)
{
(void)length;
(void)arguments;
shellmatta_printf(handle, "VREF:\t%8.2f\tmV\r\n", safety_adc_get_vref());
shellmatta_printf(handle, "TEMP:\t%8.2f\tdeg. Celsius\r\n", safety_adc_get_temp());
return SHELLMATTA_OK;
}
//typedef struct shellmatta_cmd //typedef struct shellmatta_cmd
//{ //{
// char *cmd; /**< command name */ // char *cmd; /**< command name */
@ -352,7 +365,7 @@ static shellmatta_retCode_t shell_cmd_cat(const shellmatta_handle_t handle, cons
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */ // struct shellmatta_cmd *next; /**< pointer to next command or NULL */
//} shellmatta_cmd_t; //} shellmatta_cmd_t;
static shellmatta_cmd_t cmd[13] = { static shellmatta_cmd_t cmd[14] = {
{ {
.cmd = "version", .cmd = "version",
.cmdAlias = "ver", .cmdAlias = "ver",
@ -455,8 +468,16 @@ static shellmatta_cmd_t cmd[13] = {
.helpText = "Print file contents", .helpText = "Print file contents",
.usageText = "cat <path>", .usageText = "cat <path>",
.cmdFct = shell_cmd_cat, .cmdFct = shell_cmd_cat,
.next = &cmd[13],
},
{
.cmd = "safety-adc",
.cmdAlias = NULL,
.helpText = "",
.usageText = "",
.cmdFct = shell_cmd_safety_adc,
.next = NULL, .next = NULL,
} },
}; };