Mario Hüttel
67a32cdc20
* Add watchdog code * Add file structure for safety controller * Lay groundstones to move all error flags to the safety controller * Improve doxygen
196 lines
4.9 KiB
C
196 lines
4.9 KiB
C
/* 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/>.
|
|
*/
|
|
|
|
/**
|
|
* @addtogroup safety-adc
|
|
* @{
|
|
*/
|
|
|
|
#include <reflow-controller/safety/safety-adc.h>
|
|
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
|
|
#include <helper-macros/helper-macros.h>
|
|
#include <stm-periph/clock-enable-manager.h>
|
|
|
|
enum safety_adc_check_result global_safety_adc_status;
|
|
|
|
enum safety_adc_check_result safety_adc_get_errors()
|
|
{
|
|
return global_safety_adc_status;
|
|
}
|
|
|
|
void safety_adc_clear_errors(void)
|
|
{
|
|
global_safety_adc_status = SAFETY_ADC_CHECK_OK;
|
|
}
|
|
|
|
void safety_adc_init()
|
|
{
|
|
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
|
|
|
|
safety_adc_clear_errors();
|
|
|
|
/* 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;
|
|
float vref;
|
|
float temp;
|
|
|
|
|
|
vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result;
|
|
if (vref_calculated) {
|
|
*vref_calculated = vref;
|
|
}
|
|
|
|
temp = (((float)temp_result / 4095.0f * 2500.0f -
|
|
SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
|
|
if (temp_calculated) {
|
|
*temp_calculated = temp;
|
|
}
|
|
|
|
if (ABS(vref - SAFETY_ADC_VREF_MVOLT) > SAFETY_ADC_VREF_TOL_MVOLT) {
|
|
if (vref > SAFETY_ADC_VREF_MVOLT)
|
|
res |= SAFETY_ADC_CHECK_VREF_HIGH;
|
|
else
|
|
res |= SAFETY_ADC_CHECK_VREF_LOW;
|
|
}
|
|
|
|
if (temp < SAFETY_ADC_TEMP_LOW_LIM)
|
|
res |= SAFETY_ADC_CHECK_TEMP_LOW;
|
|
else if (temp < SAFETY_ADC_CHECK_TEMP_HIGH)
|
|
res |= SAFETY_ADC_CHECK_TEMP_HIGH;
|
|
|
|
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 uint16_t safety_vref_meas_raw;
|
|
static bool safety_vref_valid = false;
|
|
static uint16_t safety_temp_meas_raw;
|
|
static 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;
|
|
enum safety_adc_check_result check_result;
|
|
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 SAFETY_ADC_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if (safety_temp_valid && safety_vref_valid) {
|
|
check_result = safety_adc_check_results(safety_vref_meas_raw, safety_temp_meas_raw, &safety_vref, &safety_temp);
|
|
global_safety_adc_status |= check_result;
|
|
} else {
|
|
check_result = SAFETY_ADC_CHECK_OK;
|
|
}
|
|
|
|
return check_result;
|
|
}
|
|
|
|
float safety_adc_get_temp()
|
|
{
|
|
return safety_temp;
|
|
}
|
|
|
|
float safety_adc_get_vref()
|
|
{
|
|
return safety_vref;
|
|
}
|
|
|
|
/** @} */
|