#include "stm32l1xx_hal.h" #include "app/thermo/NTCtsensor.h" #include "core/csect.h" #include "core/config.h" #include "core/config_pins.h" #include "drivers/adc/adc.h" #include "app/nfm/nfm_base.h" #include "math.h" // THERMO_SENSOR_KEEP_INITIALIZED // Do not turn off (=1) the sensor periferal driver btw measures #define NTC_THERMO_SENSOR_KEEP_INITIALIZED 1 // THERMO_SENSOR_AVG_WINDOW // Digital exp-filter window size #define NTC_THERMO_SENSOR_AVG_WINDOW 8 // THERMO_SENSOR_INTERVAL // Temperature measuring interval, ms #define NTC_DETECTION_HIGH_LEVEL 3970 // (3.2v) Value that indicates existance of sensor on line #define NTC_DETECTION_LOW_LEVEL 15 // (0.012v) Value that indicates existance of sensor on line #define NTC_THERMO_SENSOR_INTERVAL CONFIG_NTC_TSENSOR_INTERVAL #define NTC_LOW_RESISTANCE 1e3 #define NTC_HIGH_RESISTANCE 35e4 #define NTC_DEFAULT_TEMP_COEFF 3988 static tNTCSensorTemp vNtcThermoSensor_AVGTemp = THERMO_SENSOR_INVALID_TEMP_VALUE; static size_t vNtcThermoSensor_AVGPoints = 0; static uint32_t vNtcThermoSensor_LastTick = 0; static uint32_t vNtcThermoSensor_Interval = NTC_THERMO_SENSOR_INTERVAL; static bool vNtcThermoSensor_bInitialized = false; static bool NtcThermoSensor_Init(); static void NtcThermoSensor_UpdateAVGTemp( tNTCSensorTemp new_value ) ; static void NtcThermoSensor_ResetAvgTemp(); static bool NtcThermoSensor_Serve(); static bool NtcThermoSensor_GetReady(); static tNTCSensorTemp NtcThermoSensor_GetAvgTemp(); static void NtcThermoSensor_SetInterval(size_t ms); static bool NtcThermoSensor_GetAdcValue( tNTCSensorTemp * temp ); static void NtcUpdateCurrentTempCoeff(uint16_t temp_coeff); const sNtcThermoSensorHandle_t NtcThermoSensor = { .Init = NtcThermoSensor_Init, .GetReady = NtcThermoSensor_GetReady, .ResetTempAVG = NtcThermoSensor_ResetAvgTemp, .ServeSensor = NtcThermoSensor_Serve, .GetTempAVG = NtcThermoSensor_GetAvgTemp, .SetSensorInterval = NtcThermoSensor_SetInterval, .UpdateCurrentTempCoeff = NtcUpdateCurrentTempCoeff }; static uint16_t B_coeff = 0; static bool NtcThermoSensor_Init() { GPIO_InitTypeDef GPIO_NTC = {0}; GPIO_NTC.Pin = CONFIG_PIN__NTC_TSENS_PWR; GPIO_NTC.Mode = GPIO_MODE_ANALOG; GPIO_NTC.Pull = GPIO_NOPULL; HAL_GPIO_Init(CONFIG_PORT__NTC_TSENS_PWR, &GPIO_NTC); if(!NFMClass->methods.tempCoefficient.getTempCoeff(&B_coeff)) { B_coeff = NTC_DEFAULT_TEMP_COEFF; } return true; } static bool NtcThermoSensor_GetReady() { bool bReady = false; __DI__ bReady = ( vNtcThermoSensor_AVGPoints > 0 ) && ( vNtcThermoSensor_AVGTemp != THERMO_SENSOR_INVALID_TEMP_VALUE ); __EI__ return bReady; } static void NtcThermoSensor_SetInterval(uint32_t ms) { __DI__ vNtcThermoSensor_Interval = ms; __EI__ } static void NtcThermoSensor_ResetAvgTemp() { DI(); vNtcThermoSensor_AVGTemp = THERMO_SENSOR_INVALID_TEMP_VALUE; vNtcThermoSensor_AVGPoints = 0; EI(); } static tNTCSensorTemp NtcThermoSensor_GetAvgTemp() { tNTCSensorTemp value; __DI__ value = vNtcThermoSensor_AVGTemp; __EI__ return value; } static int NtcThermoSensor_GetTempFromVoltage( tADCValue_t * adc_code ) { uint16_t voltage = *adc_code * 3300 / 4095; float T1 = 298; double R1 = 10e3; double R2 = R1 * voltage / (3300 - voltage); // Resistance of NTC if(R2 <= NTC_LOW_RESISTANCE) R2 = NTC_LOW_RESISTANCE; if(R2 >= NTC_HIGH_RESISTANCE) R2 = NTC_HIGH_RESISTANCE; float b_value = ((log(R1)) - (log(R2))) / B_coeff; float temperature = (1 / ( (1 / T1) - b_value)) - 273; return (int)(temperature * 100); // in °C } static bool NtcThermoSensor_GetAdcValue( tNTCSensorTemp * temp ) { tADCValue_t value; if(ADC1Handle.Start(CONFIG_ADC_CHANNEL_NTC_TSENS)) { if(ADC1Handle.Measure(100, &value)) { if(value <= NTC_DETECTION_HIGH_LEVEL && value >= NTC_DETECTION_LOW_LEVEL) { *temp = NtcThermoSensor_GetTempFromVoltage(&value); //Debug return true; } } } return false; } static void NtcUpdateCurrentTempCoeff(uint16_t temp_coeff) { B_coeff = temp_coeff; } static bool NtcThermoSensor_Serve() { bool bServe = false; __DI__ bServe = (HAL_GetTick() - vNtcThermoSensor_LastTick > vNtcThermoSensor_Interval); __EI__ if( bServe ) { if( !vNtcThermoSensor_bInitialized ) { vNtcThermoSensor_bInitialized = NtcThermoSensor_Init(); } if( vNtcThermoSensor_bInitialized ) { tNTCSensorTemp temp_value; if( NtcThermoSensor_GetAdcValue( &temp_value ) ) { NtcThermoSensor_UpdateAVGTemp( temp_value ); } else { NtcThermoSensor_ResetAvgTemp(); } } __DI__ vNtcThermoSensor_LastTick = HAL_GetTick(); __EI__ } return bServe; } // ThermoSensor_UpdateAVGTemp // Performs averaging with exponential digital filter static void NtcThermoSensor_UpdateAVGTemp( tNTCSensorTemp new_value ) { DI(); if( (THERMO_SENSOR_INVALID_TEMP_VALUE) == vNtcThermoSensor_AVGTemp ) { vNtcThermoSensor_AVGTemp = new_value; vNtcThermoSensor_AVGPoints = 1; } else { vNtcThermoSensor_AVGTemp = ( new_value + (tNTCSensorTemp)( vNtcThermoSensor_AVGTemp * vNtcThermoSensor_AVGPoints ) ) / (tNTCSensorTemp)( vNtcThermoSensor_AVGPoints + 1 ); if( vNtcThermoSensor_AVGPoints < (NTC_THERMO_SENSOR_AVG_WINDOW) ) vNtcThermoSensor_AVGPoints++; // Now @tmp is 16-bit value: [BBBBBBBBBB000000] // So, lets perform averaging: // n * AVG[i-1] + tmp // AVG[i] = ------------------- // n+1 // where // @AVG[i-1] is averaged temperature before operation, // @AVG[i] is averaged temperature after operation, // @n is the filter window size (=24), // @tmp is momentary measured temperature, [BBBBBBBBBB000000]. // // So after averaging, bits 5..0 will be filled up. // Since the sensor has a 0.25*C accuracy, the @tmp should be divided // by 4 to get the value in degrees. But after averaging the whole accuracy // is changed due to the bits 5..0 are filled up. So, we need to divide // the value not 4, but 256 times to get value in degrees: // /4 - sensor accuracy // /64 - averaging accuracy (6 bits, 2^6=64) // So, 4*64 = /256 of degree. } EI(); }