/* 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 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 = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result; } if (temp_calculated) { *temp_calculated = (((float)temp_result / 4095.0f * 2500.0f - SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM; } /* TODO: Implement safety ADC checking */ 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 SAFETY_ADC_INTERNAL_ERROR; } } 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; }