You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
14 KiB
546 lines
14 KiB
/**
|
|
* TODO file description
|
|
*/
|
|
|
|
#include "main.h"
|
|
#include <string.h>
|
|
#include "app_temp.h"
|
|
#include "snprintf.h"
|
|
#include "app_safety.h"
|
|
#include "eeprom_emul_types.h"
|
|
#include "eeprom_emul.h"
|
|
#include "ee_addresses.h"
|
|
#include "transmute.h"
|
|
|
|
/* DMA dest */
|
|
static volatile uint16_t adc_values[4];
|
|
|
|
const float V_REFINT = 1.23f;
|
|
|
|
#define AVERAGEBUF_DEPTH 4
|
|
#define OVENTEMP_HISTORY_DEPTH 4
|
|
|
|
static struct App {
|
|
float oven_temp;
|
|
float oven_temp_raw;
|
|
float soc_temp;
|
|
|
|
float cal_a;
|
|
float cal_b;
|
|
float reference_resistor;
|
|
float lead_resistance;
|
|
|
|
// original values are copied here during calibration, so they can be reverted
|
|
float saved_cal_a;
|
|
float saved_cal_b;
|
|
float saved_lead_resistance;
|
|
float saved_reference_resistor;
|
|
|
|
float oventemp_history[OVENTEMP_HISTORY_DEPTH]; // raw temp
|
|
uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4];
|
|
uint8_t averagebuf_ptr;
|
|
uint8_t oventemp_history_ptr;
|
|
} s_analog = {
|
|
.reference_resistor = 1000.0f,
|
|
.lead_resistance = 0.0f,
|
|
// Ax + B = y ... X = raw sample (ratio 0-1 of 3.3), Y = corrected sample
|
|
.cal_a = 1.0f, // safe default calibration constants
|
|
.cal_b = 0.0f,
|
|
};
|
|
|
|
#define TSENSE_LOOKUP_LEN 101
|
|
#define TSENSE_T_STEP 5.0f
|
|
#define TSENSE_T_MIN 0.0f
|
|
#define TSENSE_T_MAX 500.0f
|
|
|
|
#if 0 // Ratios
|
|
static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
|
|
0.0909090909090909f,
|
|
0.0925200328471449f,
|
|
0.0941228958173389f,
|
|
0.0957178169362106f,
|
|
0.0973046872002769f,
|
|
0.0988837241910161f,
|
|
0.100454819038946f,
|
|
0.102018187184848f,
|
|
0.103573800259031f,
|
|
0.105121710606384f,
|
|
0.106661970090864f,
|
|
0.108194709632656f,
|
|
0.109719820815089f,
|
|
0.111237512887056f,
|
|
0.112747677594865f,
|
|
0.114250522193605f,
|
|
0.115746016789507f,
|
|
0.117234210034522f,
|
|
0.118715150141415f,
|
|
0.120188962295434f,
|
|
0.121655538774297f,
|
|
0.123115081061434f,
|
|
0.124567481621389f,
|
|
0.126012940077612f,
|
|
0.127451425220842f,
|
|
0.128882982328346f,
|
|
0.13030765627567f,
|
|
0.131725566931108f,
|
|
0.133136607355006f,
|
|
0.134540971782401f,
|
|
0.135938553479917f,
|
|
0.137329544944786f,
|
|
0.138713913835562f,
|
|
0.140091702340679f,
|
|
0.141462952280536f,
|
|
0.142827778585901f,
|
|
0.144186075171443f,
|
|
0.145538029496198f,
|
|
0.146883535696824f,
|
|
0.148222779606307f,
|
|
0.149555727912261f,
|
|
0.150882419971517f,
|
|
0.152202894803216f,
|
|
0.153517262745702f,
|
|
0.154825418625535f,
|
|
0.156127543558165f,
|
|
0.157423532604634f,
|
|
0.158713565356767f,
|
|
0.159997607673187f,
|
|
0.161275696311014f,
|
|
0.162547867717066f,
|
|
0.163814227951767f,
|
|
0.165074672799026f,
|
|
0.166329377427284f,
|
|
0.167578237864685f,
|
|
0.168821427850084f,
|
|
0.170058912538152f,
|
|
0.171290726295724f,
|
|
0.172516903204089f,
|
|
0.17373754533289f,
|
|
0.174952549458501f,
|
|
0.176162085166716f,
|
|
0.177366049485545f,
|
|
0.178564610657697f,
|
|
0.179757733244091f,
|
|
0.180945449410727f,
|
|
0.182127791060477f,
|
|
0.183304856534839f,
|
|
0.184476543628915f,
|
|
0.185643016681207f,
|
|
0.186804173743842f,
|
|
0.18796017789194f,
|
|
0.18911099318983f,
|
|
0.190256649774341f,
|
|
0.191397177539504f,
|
|
0.192532671339319f,
|
|
0.193663030006298f,
|
|
0.194788412940845f,
|
|
0.195908719236171f,
|
|
0.197024107102852f,
|
|
0.198134540194308f,
|
|
0.19924004677399f,
|
|
0.200340654881021f,
|
|
0.201436456102762f,
|
|
0.202527350321362f,
|
|
0.203613492284647f,
|
|
0.204694782137667f,
|
|
0.205771373506423f,
|
|
0.206843229708988f,
|
|
0.20791037727704f,
|
|
0.208972842534733f,
|
|
0.210030714005839f,
|
|
0.211083892628833f,
|
|
0.212132528763072f,
|
|
0.213176523610881f,
|
|
0.214216026472748f,
|
|
0.215251000398025f,
|
|
0.216281470315524f,
|
|
0.21730746096184f,
|
|
0.218329057984116f,
|
|
0.219346163379138f,
|
|
};
|
|
#else
|
|
static const float PT100_LOOKUP[TSENSE_LOOKUP_LEN] = {
|
|
100.f, // 0 C
|
|
101.9527f,
|
|
103.9025f,
|
|
105.8495f,
|
|
107.7935f,
|
|
109.7347f,
|
|
111.6729f,
|
|
113.6083f,
|
|
115.5408f,
|
|
117.4704f,
|
|
119.3971f,
|
|
121.321f,
|
|
123.2419f,
|
|
125.16f,
|
|
127.0751f,
|
|
128.9874f,
|
|
130.8968f,
|
|
132.8033f,
|
|
134.7069f,
|
|
136.6077f,
|
|
138.5055f,
|
|
140.4005f,
|
|
142.2925f,
|
|
144.1817f,
|
|
146.068f,
|
|
147.9514f,
|
|
149.8319f,
|
|
151.7096f,
|
|
153.5843f,
|
|
155.4562f,
|
|
157.3251f,
|
|
159.1912f,
|
|
161.0544f,
|
|
162.9147f,
|
|
164.7721f,
|
|
166.6267f,
|
|
168.4783f,
|
|
170.3271f,
|
|
172.1729f,
|
|
174.0159f,
|
|
175.856f,
|
|
177.6932f,
|
|
179.5275f,
|
|
181.359f,
|
|
183.1875f,
|
|
185.0132f,
|
|
186.8359f,
|
|
188.6558f,
|
|
190.4728f,
|
|
192.2869f,
|
|
194.0981f,
|
|
195.9065f,
|
|
197.7119f,
|
|
199.5145f,
|
|
201.3141f,
|
|
203.1109f,
|
|
204.9048f,
|
|
206.6958f,
|
|
208.4839f,
|
|
210.2692f,
|
|
212.0515f,
|
|
213.831f,
|
|
215.6075f,
|
|
217.3812f,
|
|
219.152f,
|
|
220.9199f,
|
|
222.6849f,
|
|
224.4471f,
|
|
226.2063f,
|
|
227.9627f,
|
|
229.7161f,
|
|
231.4667f,
|
|
233.2144f,
|
|
234.9592f,
|
|
236.7011f,
|
|
238.4402f,
|
|
240.1763f,
|
|
241.9096f,
|
|
243.6399f,
|
|
245.3674f,
|
|
247.092f,
|
|
248.8137f,
|
|
250.5325f,
|
|
252.2485f,
|
|
253.9615f,
|
|
255.6717f,
|
|
257.3789f,
|
|
259.0833f,
|
|
260.7848f,
|
|
262.4834f,
|
|
264.1791f,
|
|
265.872f,
|
|
267.5619f,
|
|
269.249f,
|
|
270.9331f,
|
|
272.6144f,
|
|
274.2928f,
|
|
275.9683f,
|
|
277.6409f,
|
|
279.3107f,
|
|
280.9775f, // 500 C
|
|
};
|
|
#endif
|
|
|
|
void app_temp_get_calib(float *a, float *b, float *l, float *r) {
|
|
*a = s_analog.cal_a;
|
|
*b = s_analog.cal_b;
|
|
*l = s_analog.lead_resistance;
|
|
*r = s_analog.reference_resistor;
|
|
}
|
|
|
|
/// if the calibration constants are zero, reset to defaults
|
|
static void correct_invalid_calib() {
|
|
if (s_analog.cal_a == 0.0f) { // || s_analog.cal_b == 0.0f
|
|
PRINTF("ADC invalid calib, reset\r\n");
|
|
s_analog.cal_a = 1.0f;
|
|
}
|
|
if (s_analog.reference_resistor == 0.0f) {
|
|
s_analog.reference_resistor = 1000.0f;
|
|
}
|
|
// 0 lead_r is a lie, but ok
|
|
// if (s_analog.lead_resistance == 0.0f) {
|
|
// s_analog.lead_resistance = 0.0f;
|
|
// }
|
|
}
|
|
|
|
/// Set and persist calibration constants
|
|
void app_temp_set_calib_persistent(float a, float b) {
|
|
s_analog.cal_a = a;
|
|
s_analog.cal_b = b;
|
|
correct_invalid_calib();
|
|
|
|
EE_Status st = EE_WriteVariable32bits(EE_ADDR_CAL_A, ((x32_t) { .f = a }).u);
|
|
if (st == EE_CLEANUP_REQUIRED) {
|
|
EE_CleanUp();
|
|
} else if (st != EE_OK) {
|
|
PRINTF("EE write err %d!\r\n", st);
|
|
}
|
|
st = EE_WriteVariable32bits(EE_ADDR_CAL_B, ((x32_t) { .f = b }).u);
|
|
if (st == EE_CLEANUP_REQUIRED) {
|
|
EE_CleanUp();
|
|
} else if (st != EE_OK) {
|
|
PRINTF("EE write err %d!\r\n", st);
|
|
}
|
|
}
|
|
|
|
void app_temp_set_calib_persistent_r(float lead, float reference) {
|
|
s_analog.lead_resistance = lead;
|
|
s_analog.reference_resistor = reference;
|
|
correct_invalid_calib();
|
|
|
|
EE_Status st = EE_WriteVariable32bits(EE_ADDR_LEAD_R, ((x32_t) { .f = lead }).u);
|
|
if (st == EE_CLEANUP_REQUIRED) {
|
|
EE_CleanUp();
|
|
} else if (st != EE_OK) {
|
|
PRINTF("EE write err %d!\r\n", st);
|
|
}
|
|
st = EE_WriteVariable32bits(EE_ADDR_REF_R, ((x32_t) { .f = reference }).u);
|
|
if (st == EE_CLEANUP_REQUIRED) {
|
|
EE_CleanUp();
|
|
} else if (st != EE_OK) {
|
|
PRINTF("EE write err %d!\r\n", st);
|
|
}
|
|
}
|
|
|
|
void app_temp_backup_calib() {
|
|
s_analog.saved_cal_a = s_analog.cal_a;
|
|
s_analog.saved_cal_b = s_analog.cal_b;
|
|
s_analog.saved_lead_resistance = s_analog.lead_resistance;
|
|
s_analog.saved_reference_resistor = s_analog.reference_resistor;
|
|
}
|
|
|
|
void app_temp_set_calib_temporary(float a, float b) {
|
|
s_analog.cal_a = a;
|
|
s_analog.cal_b = b;
|
|
}
|
|
|
|
void app_temp_set_calib_temporary_r(float l, float r) {
|
|
s_analog.lead_resistance = l;
|
|
s_analog.reference_resistor = r;
|
|
}
|
|
|
|
void app_temp_restore_calib() {
|
|
s_analog.cal_a = s_analog.saved_cal_a;
|
|
s_analog.cal_b = s_analog.saved_cal_b;
|
|
s_analog.lead_resistance = s_analog.saved_lead_resistance;
|
|
s_analog.reference_resistor = s_analog.saved_reference_resistor;
|
|
}
|
|
|
|
void app_analog_init()
|
|
{
|
|
// read calibration constants
|
|
uint32_t c = 0;
|
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_CAL_A, &c)) {
|
|
s_analog.cal_a = ((x32_t) { .u = c }).f;
|
|
PRINTF("ADC calib a read from EE: %f\r\n", s_analog.cal_a);
|
|
}
|
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_CAL_B, &c)) {
|
|
s_analog.cal_b = ((x32_t) { .u = c }).f;
|
|
PRINTF("ADC calib b read from EE: %f\r\n", s_analog.cal_b);
|
|
}
|
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_LEAD_R, &c)) {
|
|
s_analog.lead_resistance = ((x32_t) { .u = c }).f;
|
|
PRINTF("ADC calib R_LEAD read from EE: %f\r\n", s_analog.lead_resistance);
|
|
}
|
|
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_REF_R, &c)) {
|
|
s_analog.reference_resistor = ((x32_t) { .u = c }).f;
|
|
PRINTF("ADC calib R_REF read from EE: %f\r\n", s_analog.reference_resistor);
|
|
}
|
|
|
|
correct_invalid_calib();
|
|
|
|
LL_ADC_Enable(ADC_TEMP);
|
|
|
|
LL_ADC_StartCalibration(ADC_TEMP);
|
|
while (LL_ADC_IsCalibrationOnGoing(ADC_TEMP)) {}
|
|
|
|
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
|
|
LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA),
|
|
(uint32_t) (void *) adc_values,
|
|
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
|
|
|
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 4);
|
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
|
|
|
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
|
|
|
|
LL_ADC_REG_StartConversionExtTrig(ADC_TEMP, LL_ADC_REG_TRIG_EXT_RISING);
|
|
// LL_ADC_REG_StartConversionSWStart(ADC_TEMP);
|
|
|
|
// this timer runs with 1 kHz clock
|
|
LL_TIM_SetTriggerOutput(TIM1, LL_TIM_TRGO_CC1IF);
|
|
LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1);
|
|
LL_TIM_EnableAllOutputs(TIM1); // TIM1 needs outputs specially enabled - it's "advanced timer"
|
|
LL_TIM_EnableCounter(TIM1);
|
|
}
|
|
|
|
float val_to_c(float x)
|
|
{
|
|
// val is the ratio
|
|
|
|
float pt100r = (x * s_analog.lead_resistance + x * s_analog.reference_resistor - s_analog.lead_resistance) / (1 - x);
|
|
|
|
// TODO use binary search.. lol
|
|
for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) {
|
|
float cur = PT100_LOOKUP[i];
|
|
if (cur >= pt100r) {
|
|
float prev = PT100_LOOKUP[i - 1];
|
|
|
|
float ratio = (pt100r - prev) / (cur - prev);
|
|
return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP;
|
|
}
|
|
}
|
|
return TSENSE_T_MAX;
|
|
}
|
|
|
|
float c_to_val(float cf)
|
|
{
|
|
int lower = (int) (cf / TSENSE_T_STEP);
|
|
|
|
if (lower < 0) {
|
|
lower = 0;
|
|
}
|
|
if (lower >= TSENSE_LOOKUP_LEN - 1) {
|
|
lower = TSENSE_LOOKUP_LEN - 2;
|
|
}
|
|
int upper = lower + 1;
|
|
|
|
float ratio = (cf - ((float)lower * TSENSE_T_STEP)) / 5.0f;
|
|
return PT100_LOOKUP[lower] + (PT100_LOOKUP[upper] - PT100_LOOKUP[lower]) * ratio;
|
|
}
|
|
|
|
void app_temp_sample()
|
|
{
|
|
uint32_t sums[4] = {};
|
|
int count = 0;
|
|
for (int i = 0; i < AVERAGEBUF_DEPTH * 4; i += 4) {
|
|
if (s_analog.adc_averagebuf[i + 3] != 0) {
|
|
sums[0] += s_analog.adc_averagebuf[i];
|
|
sums[1] += s_analog.adc_averagebuf[i + 1];
|
|
sums[2] += s_analog.adc_averagebuf[i + 2];
|
|
sums[3] += s_analog.adc_averagebuf[i + 3];
|
|
count++;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
return;
|
|
}
|
|
|
|
float adc_averages[4];
|
|
|
|
adc_averages[0] = (float) sums[0] / count;
|
|
adc_averages[1] = (float) sums[1] / count;
|
|
adc_averages[2] = (float) sums[2] / count;
|
|
adc_averages[3] = (float) sums[3] / count;
|
|
|
|
// PRINTF("%f\t%f\t%f\t%f\r\n",
|
|
// adc_averages[0],
|
|
// adc_averages[1],
|
|
// adc_averages[2],
|
|
// adc_averages[3]
|
|
// );
|
|
|
|
/* r_pt100, r_ref, internal_temp, v_ref_int */
|
|
float refint = adc_averages[3];
|
|
float scale = V_REFINT / refint;
|
|
|
|
const float avg_slope = 4.3f * scale;
|
|
const float v25 = 1.43f;
|
|
const float v_tsen = adc_averages[2] * scale;
|
|
|
|
s_analog.soc_temp = (v25 - v_tsen) / avg_slope + 25.f;
|
|
//s_analog.v_sensor = adc_averages[0] * scale; // good for debug/tuning
|
|
|
|
|
|
// using a voltage divider, so assuming the reference resistor is measured well,
|
|
// we can just use the ratio and the exact voltage value is not important.
|
|
|
|
float oventemp_sample = adc_averages[0] / adc_averages[1];
|
|
|
|
s_analog.oventemp_history[s_analog.oventemp_history_ptr] = oventemp_sample;
|
|
s_analog.oventemp_history_ptr = (s_analog.oventemp_history_ptr + 1) % OVENTEMP_HISTORY_DEPTH;
|
|
|
|
float sum = 0;
|
|
int depth = 0;
|
|
for (int i = 0; i < OVENTEMP_HISTORY_DEPTH; i++) {
|
|
if (s_analog.oventemp_history[i] > 0.0f) {
|
|
sum += s_analog.oventemp_history[i];
|
|
depth++;
|
|
}
|
|
}
|
|
if (depth > 0) {
|
|
sum /= depth;
|
|
}
|
|
|
|
float y = s_analog.cal_a * sum + s_analog.cal_b;
|
|
|
|
//float y = sum;
|
|
float actual_temp = val_to_c(y);
|
|
PRINTF("T Raw[%f] * A[%f] + B[%f]-> %f, temp %f°C\r\n", sum, s_analog.cal_a, s_analog.cal_b, y, actual_temp);
|
|
|
|
s_analog.oven_temp = actual_temp;
|
|
s_analog.oven_temp_raw = sum;
|
|
|
|
app_safety_pass_temp_calculation();
|
|
|
|
if (s_analog.oven_temp_raw >= 0.05 && s_analog.oven_temp_raw <= 0.22) {
|
|
app_safety_pass_temp_normal();
|
|
}
|
|
|
|
if (s_analog.soc_temp >= 2.0 && s_analog.soc_temp <= 90.0) {
|
|
app_safety_pass_soc_temp_ok();
|
|
} else {
|
|
PRINTF("SOC OVERHEAT!! %f\r\n", s_analog.soc_temp);
|
|
}
|
|
}
|
|
|
|
float app_temp_read_oven()
|
|
{
|
|
return s_analog.oven_temp;
|
|
}
|
|
|
|
float app_temp_read_oven_raw()
|
|
{
|
|
return s_analog.oven_temp_raw;
|
|
}
|
|
|
|
float app_temp_read_soc()
|
|
{
|
|
return s_analog.soc_temp;
|
|
}
|
|
|
|
void app_temp_adc_eos()
|
|
{
|
|
app_safety_pass_adc_sampling();
|
|
|
|
// notify
|
|
memcpy((void *) &s_analog.adc_averagebuf[s_analog.averagebuf_ptr * 4], (const void *) adc_values, 4 * sizeof(uint16_t));
|
|
s_analog.averagebuf_ptr = (s_analog.averagebuf_ptr + 1) % AVERAGEBUF_DEPTH;
|
|
}
|
|
|
|
void app_temp_show_buf()
|
|
{
|
|
PRINTF("%d,%d,%d,%d\r\n", adc_values[0], adc_values[1], adc_values[2], adc_values[3]);
|
|
}
|
|
|