/** * TODO file description */ #include "main.h" #include #include #include #include #include "app_temp.h" #include "adc.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 16 #define OVENTEMP_HISTORY_DEPTH 20 static struct App { float oven_temp; float oven_temp_raw; float soc_temp; float cal_a; float cal_b; 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 = { // 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 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, }; /// 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; s_analog.cal_b = 0.0f; } } /// Set and persist calibration constants void app_temp_set_calib(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_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); } 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 val) { // TODO use binary search.. lol for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) { float cur = TSENSE_LOOKUP[i]; if (cur >= val) { float prev = TSENSE_LOOKUP[i - 1]; float ratio = (val - 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 TSENSE_LOOKUP[lower] + (TSENSE_LOOKUP[upper] - TSENSE_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 actual_temp = val_to_c(y); PRINTF("Compensated x %f -> y %f, temp %f C\r\n", sum, 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 <= 80.0) { app_safety_pass_soc_temp_ok(); } } 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]); }