reflow-oven-control-sw/stm-firmware/safety/safety-adc.c

192 lines
5.8 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/rcc-manager.h>
#include <reflow-controller/hw-version-detect.h>
#include <reflow-controller/safety/safety-controller.h>
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
/**
* @brief Safety ADC conversion complete. Set in interrupt.
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_conversion_complete;
/**
* @brief Safety ADC has been started. It will perform all specified conversions and
* set @ref safety_adc_conversion_complete afterwards
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_triggered;
/**
* @brief Safety ADC conversion storage. This is filled by DMA.
* @note Do not move this to CCM RAM as the DMA won't be able to access it.
*/
static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS];
void safety_adc_init(void)
{
enum hw_revision hw_rev;
int i;
hw_rev = get_pcb_hardware_version();
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
if (hw_rev != HW_REV_V1_2) {
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK));
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
}
/* Enable temperature and VREFINT measurement */
ADC->CCR |= ADC_CCR_TSVREFE;
/* Set sample time for channels 16 and 17 and 15 */
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15;
/* Standard sequence. Measure all channels in one sequence */
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20 ;
SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL;
for (i = 0; i < SAFETY_ADC_NUM_OF_CHANNELS; i++) {
switch (i) {
case 0 ... 5:
SAFETY_ADC_ADC_PERIPHERAL->SQR3 |= safety_adc_channels[i] << (i * 5);
break;
case 6 ... 11:
SAFETY_ADC_ADC_PERIPHERAL->SQR2 |= safety_adc_channels[i] << ((i-6) * 5);
break;
case 12 ... 15:
SAFETY_ADC_ADC_PERIPHERAL->SQR1 |= safety_adc_channels[i] << ((i-12) * 5);
break;
}
}
safety_adc_conversion_complete = 0;
safety_adc_triggered = 0;
/* Setup the DMA to move the data */
DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR;
DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions;
DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS;
DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN;
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
/* Enable ADC */
SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
}
void safety_adc_deinit(void)
{
SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
DMA2_Stream4->CR = 0;
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
}
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
{
float converted_val;
enum hw_revision hw_rev;
switch (channel) {
case SAFETY_ADC_MEAS_TEMP:
converted_val = (((float)analog_value / 4096.0f * 2500.0f - SAFETY_ADC_TEMP_NOM_MV) /
SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
break;
case SAFETY_ADC_MEAS_VREF:
converted_val = (SAFETY_ADC_INT_REF_MV * 4096.0f) / (float)analog_value;
break;
case SAFETY_ADC_MEAS_SUPPLY:
hw_rev = get_pcb_hardware_version();
if (hw_rev >= HW_REV_V1_3)
converted_val = ((float)analog_value) / 4096.0f * 2500.0f * 2.0f;
else
converted_val = 3300.0f;
break;
default:
/* Generate NaN value as default return */
converted_val = 0.0f / 0.0f;
break;
}
return converted_val;
}
int safety_adc_poll_result(void)
{
if (safety_adc_triggered)
return 0;
if (safety_adc_conversion_complete)
return 1;
else
return -1;
}
const uint16_t *safety_adc_get_values(void)
{
safety_adc_conversion_complete = 0;
return (const uint16_t *)safety_adc_conversions;
}
void safety_adc_trigger_meas(void)
{
safety_adc_conversion_complete = 0;
SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_ADON;
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
safety_adc_triggered = 1;
}
void DMA2_Stream4_IRQHandler()
{
uint32_t hisr;
hisr = DMA2->HISR & 0x3F;
DMA2->HIFCR = hisr;
if (hisr & DMA_HISR_TCIF4) {
safety_adc_triggered = 0;
safety_adc_conversion_complete = 1;
}
}
/** @} */