/* 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 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; }