reflow-oven-control-sw/stm-firmware/include/reflow-controller/adc-meas.h

200 lines
6.1 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.
*
* GDSII-Converter 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/>.
*/
/**
* @file adc-meas.h
*/
#ifndef __ADCMEAS_H__
#define __ADCMEAS_H__
#include <stdbool.h>
#include <stdint.h>
#include <stm32/stm32f4xx.h>
/*If this is changed, change DMA code to fit the channel assignment! */
#define ADC_PT1000_PERIPH ADC3
#define ADC_PT1000_DMA2_STREAM0_CHANNEL 2
/**
* @brief Moving average filter coefficient for PT1000 measurement
*/
#define ADC_PT1000_FILTER_WEIGHT 0.01f
/**
* @brief Moving average filter weight used for fast regaulation. This is used when the measured resistance
* is more than @ref ADC_PT1000_FILTER_UNSTABLE_DIFF Ohms away from the current averaged value.
*/
#define ADC_PT1000_FILTER_WEIGHT_FAST 0.05
/**
* @brief Difference in Ohm between filter input and output that determines if the filter is stable or unstable.
*/
#define ADC_PT1000_FILTER_UNSTABLE_DIFF 20
/**
* @brief Sample count, the moving average filter has to be within @ref ADC_PT1000_FILTER_UNSTABLE_DIFF for the filter
* to be considered stable
*/
#define ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT 200
/**
* @brief ADC channel number of PT1000 sensor input
*/
#define ADC_PT1000_CHANNEL 2U
/**
* @brief GPIO Port the ADC converter for the PT1000 measurement is connected to
*/
#define ADC_PT1000_PORT GPIOA
/**
* @brief The clock enable mask of the RCC register for ADC_PT1000_PORT
*/
#define ADC_PT1000_PORT_RCC_MASK RCC_AHB1ENR_GPIOAEN
/**
* @brief The GPIO pin number the PT1000 analog voltage is connected to
*/
#define ADC_PT1000_PIN 2U
/**
* @brief The delay value programmed into the sample timer
*/
#define ADC_PT1000_SAMPLE_CNT_DELAY 1000U
/**
* @brief The amount of samples to take to prefilter the analog signal
*/
#define ADC_PT1000_DMA_AVG_SAMPLES 6U
/**
* @brief Lower value for valid input range for PT1000 measurement
*
* If the input of the PT1000 sensor is below this value, an error is thrown. This is used to disable the temperature control loop
*/
#define ADC_PT1000_LOWER_WATCHDOG 200U
/**
* @brief Upper value for valid input range for PT1000 measurement
*
* If the input of the PT1000 sensor is above this value, an error is thrown. This is used to disable the temperature control loop
*/
#define ADC_PT1000_UPPER_WATCHDOG 4000U
/**
* @brief Number of ADC samples the value has to be outside the Watchdog limit (@ref ADC_PT1000_UPPER_WATCHDOG and @ref ADC_PT1000_LOWER_WATCHDOG)
* in order to produce a watchdog error
*/
#define ADC_PT1000_WATCHDOG_SAMPLE_COUNT 25U
/**
* @brief Conversion macro: ADC value to resistance
*/
#define ADC_TO_RES(adc) ((float)(adc) / 4096.0f * 2500.0f)
#define RES_TO_ADC(res) ((float)(res) / 2500.0f * 4096.0f)
/**
* @brief This function sets up the ADC measurement fo the external PT1000 temperature sensor
*
* Used peripherals:
* - Timer 2 for sampling control
* - ADC1
*
* The filter weight \f$\alpha\f$ is configured for @ref ADC_PT1000_FILTER_WEIGHT
*
*/
void adc_pt1000_setup_meas(void);
/**
* @brief Set moving average filter parameters
*
* The sampled resistance value is filtered with an exponential average filter
* specified by following difference equation:
*
* \f$ y[n] = (1-\alpha)y[n-1] + \alpha x[n] \f$
*
* @param alpha
*/
void adc_pt1000_set_moving_average_filter_param(float alpha);
/**
* @brief Set the calibration data for the PT1000 measurement
*
* The resulting resistance reading is
* \f$R_{corrected} = (1 + \sigma) R_{raw} + O\f$
*
* @param offset Offset \f$O\f$
* @param sensitivity_deviation Sensitivity Deviation \f$\sigma\f$ after offset correction
* @param active Calibration is active
*/
void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_deviation, bool active);
/**
* @brief Get the state and values of the resistance calibration
* @param offset Offset
* @param sensitivity_deviation Sensitivity deviation
* @param active Active state of the correction
*/
void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_deviation, bool *active);
/**
* @brief Get the current resistance value
*
* If the resistance calibration is enabled, this function applies the calculations of the raw resistance reading and
* returns the corrected value.
*
* If an ADC error is set, the status is negative. The status is 2 during the first measurements with a given filter setting. Technically, the resistance value is
* correct but the filter is not stable yet.
*
* @param[out] resistance Resistance output in Ohms
* @return Status
*/
int adc_pt1000_get_current_resistance(float *resistance);
/**
* @brief Stream the raw ADC data to an array in memory.
* @param adc_array Array to stream data to
* @param length Amount of data points to be measured
* @param flag_to_set This flag is set to 1 once the data has been measured and is transferred. A negative value indicates an error
* @return 0 if measurement could be started
*/
int adc_pt1000_stream_raw_value_to_memory(volatile float *adc_array, uint32_t length, volatile int *flag_to_set);
/**
* @brief Convert an array of raw adc values to resistance values
*
* In case \p resistance_dest is NULL, the conversion is done inplace in the
* \p raw_source array.
*
* @param resistance_dest Destination. Maybe NULL.
* @param raw_source Source array
* @param count Number of values to convert
*/
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, float *raw_source, uint32_t count);
/**
* @brief Disable the PT1000 measurement
*/
void adc_pt1000_disable(void);
#endif // __ADCMEAS_H__