172 lines
4.8 KiB
C
172 lines
4.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/>.
|
|
*/
|
|
|
|
|
|
#include <reflow-controller/calibration.h>
|
|
#include <reflow-controller/adc-meas.h>
|
|
#include <stm-periph/uart.h>
|
|
#include <helper-macros/helper-macros.h>
|
|
#include <arm_math.h>
|
|
#include <stdlib.h>
|
|
#include <float.h>
|
|
|
|
void calibration_calculate(float low_measured, float low_setpoint, float high_measured, float high_setpoint,
|
|
float *sens_deviation, float *sens_corrected_offset)
|
|
{
|
|
if (!sens_deviation || !sens_corrected_offset)
|
|
return;
|
|
|
|
float delta_y;
|
|
float delta_x;
|
|
float sens_corr_mult;
|
|
|
|
delta_y = high_measured - low_measured;
|
|
delta_x = high_setpoint - low_setpoint;
|
|
|
|
sens_corr_mult = delta_x / delta_y;
|
|
*sens_deviation = sens_corr_mult - 1.0f;
|
|
|
|
*sens_corrected_offset = low_setpoint - low_measured * sens_corr_mult;
|
|
}
|
|
|
|
|
|
|
|
int calibration_acquire_data(float *mu, float *max_dev, uint32_t count)
|
|
{
|
|
int status;
|
|
float *stream_mem;
|
|
float min_val = FLT_MAX;
|
|
float max_val = -FLT_MAX;
|
|
uint32_t i;
|
|
int ret_val = 0;
|
|
|
|
static volatile int flag = 0;
|
|
|
|
if (!mu || !max_dev || !count)
|
|
return -1000;
|
|
|
|
stream_mem = (float *)calloc(count, sizeof(float));
|
|
if (!stream_mem)
|
|
return -2;
|
|
|
|
status = adc_pt1000_stream_raw_value_to_memory(stream_mem, count, &flag);
|
|
if (status)
|
|
return status;
|
|
|
|
/* Wait for data to be transferred */
|
|
while (flag == 0);
|
|
|
|
if (flag != 1) {
|
|
/* Error */
|
|
ret_val = -1;
|
|
goto ret_free_mem;
|
|
}
|
|
|
|
/* Convert the stream memory to Ohm readings */
|
|
adc_pt1000_convert_raw_value_array_to_resistance(NULL, stream_mem, count);
|
|
|
|
/* Do not compute std-deviation. Too imprecise
|
|
* arm_std_f32(stream_mem, count, sigma);
|
|
*/
|
|
arm_mean_f32(stream_mem, count, mu);
|
|
|
|
/* Find min and max values of array */
|
|
for (i = 0U; i < count; i++) {
|
|
min_val = MIN(min_val, stream_mem[i]);
|
|
max_val = MAX(max_val, stream_mem[i]);
|
|
}
|
|
|
|
/* Compute maximum deviation range */
|
|
*max_dev = max_val - min_val;
|
|
|
|
ret_free_mem:
|
|
free(stream_mem);
|
|
return ret_val;
|
|
}
|
|
|
|
static void wait_for_uart_enter()
|
|
{
|
|
int enter_received = 0;
|
|
const char *recv_data;
|
|
size_t recv_len;
|
|
size_t iter;
|
|
int uart_recv_status;
|
|
|
|
do {
|
|
uart_recv_status = uart_receive_data_with_dma(&recv_data, &recv_len);
|
|
if (uart_recv_status >= 1) {
|
|
for (iter = 0; iter < recv_len; iter++) {
|
|
if (recv_data[iter] == '\n' || recv_data[iter] == '\r')
|
|
enter_received = 1;
|
|
}
|
|
}
|
|
} while (enter_received == 0);
|
|
}
|
|
|
|
int calibration_sequence_shell_cmd(shellmatta_handle_t shell)
|
|
{
|
|
float mu, mu2, dev, dev2;
|
|
float sens_dev, offset;
|
|
|
|
/* Clear errors of PT1000 reading */
|
|
adc_pt1000_clear_error();
|
|
|
|
shellmatta_printf(shell, "Starting calibration: Insert 1000 Ohm calibration resistor and press ENTER\r\n");
|
|
wait_for_uart_enter();
|
|
shellmatta_printf(shell, "Measurement...\r\n");
|
|
|
|
/* Clear errors of PT1000 reading */
|
|
adc_pt1000_clear_error();
|
|
calibration_acquire_data(&mu, &dev, 512UL);
|
|
shellmatta_printf(shell, "R=%.2f, Noise peak-peak: %.2f\r\n", mu, dev);
|
|
if (adc_pt1000_check_error() != ADC_PT1000_NO_ERR) {
|
|
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
|
|
return -1;
|
|
}
|
|
|
|
/* Measure 2nd calibration point */
|
|
shellmatta_printf(shell, "Insert 2000 Ohm calibration resistor and press ENTER\r\n");
|
|
wait_for_uart_enter();
|
|
shellmatta_printf(shell, "Measurement...\r\n");
|
|
|
|
/* Clear errors of PT1000 reading */
|
|
adc_pt1000_clear_error();
|
|
calibration_acquire_data(&mu2, &dev2, 512UL);
|
|
shellmatta_printf(shell, "R=%.2f, Noise peak-peak: %.2f\r\n", mu2, dev2);
|
|
if (adc_pt1000_check_error() != ADC_PT1000_NO_ERR) {
|
|
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
|
|
return -2;
|
|
}
|
|
|
|
/* Check noise values */
|
|
if (dev > CALIBRATION_MAX_PEAK_PEAK_NOISE_OHM || dev2 > CALIBRATION_MAX_PEAK_PEAK_NOISE_OHM) {
|
|
shellmatta_printf(shell, "Calibration failed! Too much noise. Check you're hardware.\r\n");
|
|
return -3;
|
|
}
|
|
|
|
/* Calculate calibration */
|
|
calibration_calculate(mu, 1000.0f, mu2, 2000.0f, &sens_dev, &offset);
|
|
|
|
shellmatta_printf(shell, "Calibration done:\r\n\tSENS_DEVIATION: %.4f\r\n\tOFFSET_CORR: %.2f\r\n", sens_dev, offset);
|
|
adc_pt1000_set_resistance_calibration(offset, sens_dev, true);
|
|
|
|
return 0;
|
|
}
|