/** ****************************************************************************** * @file temp.h * @author AMG Energy Solution Team * @version V1.0.0 * @date 07-Feb-2022 * @brief This file provides all the headers of temperature functions. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *

© COPYRIGHT 2022 AMG

****************************************************************************** */ /** @addtogroup mBMS2 * @{ */ /* Includes ------------------------------------------------------------------*/ #include #include #include "temp.h" #include "adc.h" #include "asutil.h" #include "device_param.h" #include "delay.h" #include "afe_comm.h" /* Private typedef -----------------------------------------------------------*/ typedef struct { int16_t Value; int16_t AdValue; // PARAMETER Information int16_t HighParam; // Temperature parameter referenced only in AD[4](Unify-Temp) int16_t HighCParam; int16_t LowParam; int16_t LowCParam; int16_t FailParam; int16_t FailCParam; uint8_t Enabled; // Enabled/Disabled uint8_t Failed; // Fail/Noraml uint8_t State; // Normal, High(Wet), Low, NotUsed (0/1/2/3) uint8_t Changed; // notchanged, NormToHigh, HighToNorm, NormToLow, LowToNorm, NotUsed->Used, Used->NotUsed, Normal->Failed, Failed->Normal } TAnalogrec, *PAnalogrec; typedef struct { int16_t cpu_temp; int16_t ext1_temp; int16_t ext2_temp; uint16_t vref; uint16_t vbat; uint16_t reserved; } TBmsStatus, *PBmsStatus; /* Private define ------------------------------------------------------------*/ #define TEMP_TASK_TIME 5 // 5ms TASK #define TEMP_CH_MAX 8 #define T1_TEMP_ID 5 // ADC1 CH5 #define T2_TEMP_ID 4 // ADC1 CH4 #define T3_TEMP_ID 3 // ADC1 CH3 #define T4_TEMP_ID 2 // ADC1 CH2 #define T5_TEMP_ID 1 // ADC1 CH1 #define T6_TEMP_ID 0 // ADC1 CH0 #define EXT1_TEMP_ID 6 // ADC1 CH7 #define EXT2_TEMP_ID 7 // ADC1 CH6 #define TEMP_BUF_MAX 50 // Temperature alarm flag define #define cFahr 0x00 #define cCent 0x01 #define cHighOccur 0x01 // Normal -> High(Wet) #define cLowOccur 0x02 // Normal -> Low #define cNotUsed 0x03 // Disabled #define cNotChanged 0x00 // No change #define cNormToHigh 0x11 // Normal -> High(Wet) #define cHighToNorm 0x12 // High(Wet) -> Normal #define cNormToLow 0x13 // Normal -> Low #define cLowToNorm 0x14 // Low -> Normal #define cNotToUsed 0x15 // NotUsed->Used #define cUsedToNot 0x16 // Used->NotUsed #define cFailToNorm 0x17 // Fail->Normal #define cNormToFail 0x18 // Normal->Fail #define cNormalOpen 0 #define cNormalClose 1 #define cNORMAL 0 #define cINITVALUE 0xff #define cOCCUR 1 #define cUNKNOWN 2 #define cDISABLE 3 #define cCANCEL 0 /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ // CPU Status TBmsStatus BmsStatus, disBmsStatus; // ADC Buffer uint16_t AdData[TEMP_CH_MAX][TEMP_BUF_MAX]; uint16_t AdCh = 0; // Temperature Buffer TAnalogrec TD[TEMP_CH_MAX]; TAnalogrec DisTD[TEMP_CH_MAX]; uint8_t TempUnit, BakTempUnit; void InitAD(uint8_t ch); void ADC_Data_Process(void); int16_t GetTemperature(uint8_t ch); /* ********************************************************************************************************* * App_TaskAdc Init * * Description : ADC TASK INIT * ********************************************************************************************************* */ void AdcInit(void) { // ADC initialization // ADC Clock frequency: 115.200 kHz // ADC Voltage Reference: Vref Pin // ADC High Speed Mode: On memset(AdData, 0x00, sizeof(AdData)); memset(TD , 0x00, sizeof(TAnalogrec) * TEMP_CH_MAX); TempUnit = cCent; for (int i = 0; i < TEMP_CH_MAX; i++) InitAD(i); Load_Param(); } /* ********************************************************************************************************* * App_TaskAdc * * Description : ADC TASK * ********************************************************************************************************* */ void AppTaskTempAdc(void) { AdcInit(); ADC_StartConvert(M4_ADC1); for (;;) { if (GetAdcIrgFlag(0) == true) { ADC_Data_Process(); DmaReloadConfig(0); // PORT_SetBits(PortE, Pin00); ADC_StartConvert(M4_ADC1); ADC_Process(); } delay_os_ms(TEMP_TASK_TIME); } } /* ********************************************************************************************************* * Function for App_TaskAdc * * Description : ADC TASK * ********************************************************************************************************* */ void InitAD(uint8_t ch) { for (int i = 0; i < 10; i++) { TD[ch].Value = GetTemperature(ch); } TD[ch].Enabled = true; TD[ch].Failed = false; TD[ch].State = cNORMAL; TD[ch].Changed = cNotChanged; } void ADC_Data_Process(void) { uint32_t sum; for (int i = 0; i < TEMP_CH_MAX; i++) { sum = AvgAdc1DmaValue(i); AdData[i][AdCh] = (uint16_t)((sum * ADC_VBASE) / 0xFFF); } AdCh++; AdCh %= TEMP_BUF_MAX; } int16_t CalcTemperatureNTC__(uint16_t volt, uint16_t beta) { int Rnom = 10000; double Koffset = 273.16; double Tnom = 25 + Koffset; int R1 = 10 * 1000; double Vref = 5.0; // V = RL / (R1 + RL + R2) * Vref --> (V * R1) + (V * RL) + (V * R2) = (Vref * RL) --> (Vref * RL) - (V * RL) = (V * R1) + (V * R2) --> (Vref - V) * RL = (R1 + R2) * V --> RL = ((R1 + R2) * V) / (Vref - V) // V = RL / (R1 + RL) * Vref --> (R1 + RL) * V = (RL * Vref) --> (R1 * V) + (RL * V) = (RL * Vref) --> (R1 * V) = (RL * Vref) - (RL * V) --> (R1 * V) = RL * (Vref - V) --> (R1 * V) / (Vref - V) = RL double V = (double)volt / 1000; double RL = (R1 * V) / (Vref - V); double T = (beta * Tnom / (Tnom * log(RL / Rnom) + beta)) - Koffset; // # Calculate corresponding temperature (above shortened) return (int16_t)(T * 10); } int16_t CalcTemperatureNTC(uint16_t volt, uint16_t beta) { // double beta1 = 3380; // double beta2 = 3950; double Rnom = 10000; double Koffset = 273.16; double Tnom = 25 + Koffset; double R1 = 1.47 * 1000; double R2 = 1.82 * 1000; double Vref = 3.3; // R2 = V * R1 / (Vref - V) # Calculate resistance value of NTC // V = R1 / (R1 + R2) * Vref --> V * R1 + V * R2 = Vref * R1 --> V * R2 = (Vref * R1) - (V * R1) --> R2 = (Vref * R1) / V - R1 // V = R2 / (R1 + R2) * Vref --> (V * R1) + (V * R2) = (Vref * R2) --> (Vref * R2) - (V * R2) = (V * R1) --> R2 = (V * R1)/(Vref - V) * NTC Bottom side // V = R2 / (R1 + RL + R2) * Vref --> V * (R1 + RL + R2) = Vref * R2 --> V * RL = Vref * R2 - (R1 + R2) * V --> RL = (Vref * R2)/V - (R1 + R2) // V = R2 / (R1 + RL + R2) * Vref --> V * (R1 + RL + R2) = Vref * R2 --> V * RL = (Vref * R2) - (V * (R1 + R2)) = RL ((Vref * R2) - (V * (R1 + R2))) / V double V = (double)volt / 1000; double RL = (Vref * R2) / V - (R1 + R2); double T = (beta * Tnom / (Tnom * log(RL / Rnom) + beta)) - Koffset; // # Calculate corresponding temperature (above shortened) return (int16_t)(T * 10); } int16_t CalcTemperatureST32(uint16_t volt) { int16_t cvolt; double imsi; double xx[6]; double flt; cvolt = volt; imsi = (double)cvolt / 1000; // printf("imsi = %6.3f\r\n", imsi); xx[5] = imsi * imsi * imsi * imsi * imsi; xx[4] = imsi * imsi * imsi * imsi; xx[3] = imsi * imsi * imsi; xx[2] = imsi * imsi; xx[1] = imsi; flt = (135.6 * xx[5]) - (578.9 * xx[4]) + (960.5 * xx[3]) - (761.3 * xx[2]) + (354.7 * xx[1]) - 46.39; return(int16_t)(flt * 10); } //int16_t CalcTemperature_LNSK16F103FP(uint16_t volt) //{ // int16_t cvolt; // double imsi; // double xx[6]; // double flt; // cvolt = volt; // imsi = (double)cvolt / 1000; // xx[5] = imsi * imsi * imsi * imsi * imsi; // xx[4] = imsi * imsi * imsi * imsi; // xx[3] = imsi * imsi * imsi; // xx[2] = imsi * imsi; // xx[1] = imsi; // //// y = 100.1x5 - 433.27x4 + 739.18x3 - 610.14x2 + 310.21x - 42.256 // flt = (100.1 * xx[5]) // - (433.27 * xx[4]) // + (739.18 * xx[3]) // - (610.14 * xx[2]) // + (310.21 * xx[1]) // - 42.256; // return(int16_t)(flt * 10); //} int16_t GetTemperature(uint8_t ch) { int32_t tsum = 0; switch (ch) { case EXT1_TEMP_ID : case EXT2_TEMP_ID : for (int i = 0; i < TEMP_BUF_MAX; i++) { tsum += AdData[ch][i]; } tsum /= TEMP_BUF_MAX; tsum = CalcTemperatureNTC(tsum, 3435); break; default: for (int i = 0; i < TEMP_BUF_MAX; i++) { tsum += AdData[ch][i]; } tsum /= TEMP_BUF_MAX; tsum = CalcTemperatureST32(tsum); // tsum = CalcTemperatureNTC(tsum, 3950); break; } return (int16_t)tsum; } void ADC_Param_Load(void) { for (int i = 0; i < TEMP_CH_MAX; i++) { switch (i) { case EXT1_TEMP_ID : case EXT2_TEMP_ID : TD[i].HighParam = 1200; TD[i].HighCParam = 1100; TD[i].LowParam = -400; TD[i].LowCParam = -350; TD[i].FailParam = -450; TD[i].FailCParam = -420; break; default: TD[i].HighParam = device_param.safety.temperature.OT_Chg_Warning; TD[i].HighCParam = device_param.safety.temperature.OT_Chg_Recovery; TD[i].LowParam = device_param.safety.temperature.LT_Chg_Warning; TD[i].LowCParam = device_param.safety.temperature.LT_Chg_Recovery; TD[i].FailParam = device_param.safety.temperature.Open_Thermistor; TD[i].FailCParam = device_param.safety.temperature.Recovery_Thermistor; break; } } } uint8_t Check_Analog(uint8_t ch) { int16_t aValue, ret, aHighOccur, aHighCancel, aLowOccur, aLowCancel; if (ch >= TEMP_CH_MAX) return 0; aValue = TD[ch].Value; aHighOccur = TD[ch].HighParam; aHighCancel = TD[ch].HighCParam; aLowOccur = TD[ch].LowParam; aLowCancel = TD[ch].LowCParam; ret = cNotChanged; // Nothing switch(TD[ch].State) { case cHighOccur: // Past: High(Wet) if (aValue < aHighCancel) ret = cHighToNorm; // HIGH CANCEL break; case cLowOccur: // Past: Low if (aValue > aLowCancel) ret = cLowToNorm; // LOW CANCEL break; default: if (aValue >= aHighOccur) ret = cHighOccur; // HIGH OCCUR else if (aValue <= aLowOccur) ret = cLowOccur; // LOW OCCUR break; } return(ret); } void Analog_Process(uint8_t ch) // Read temperature/humidity and evaluate alarms { TD[ch].Value = GetTemperature(ch); if(TD[ch].Enabled == true) { // Check sensor fail on low temperature range if (TD[ch].Failed != true) { if ((TD[ch].Value < TD[ch].FailParam) || (TD[ch].Value > 1250)) { TD[ch].State = cNORMAL; TD[ch].Changed = cNormToFail; TD[ch].Failed = true; } } else { if ((TD[ch].Value > TD[ch].FailCParam) && (TD[ch].Value < 1200)) { TD[ch].State = cNORMAL; TD[ch].Changed = cFailToNorm; TD[ch].Failed = false; } } // Check temperature alarm if (TD[ch].Failed == false) { switch (Check_Analog(ch)) { case cHighOccur: // HIGH OCCUR TD[ch].State = cHighOccur; TD[ch].Changed = cNormToHigh; break; case cHighToNorm: // HIGH CANCEL TD[ch].State = cNORMAL; TD[ch].Changed = cHighToNorm; break; case cLowOccur: // LOW OCCUR TD[ch].State = cLowOccur; TD[ch].Changed = cNormToLow; break; case cLowToNorm: // LOW CANCEL TD[ch].State = cNORMAL; TD[ch].Changed = cLowToNorm; break; } } } else { TD[ch].State = cNotUsed; } } uint16_t ADState(uint8_t ch) { uint16_t ret = AD_DISABLE; if (TD[ch].Enabled == true) { if (TD[ch].Failed == true) { ret = AD_FAIL; } else { switch (TD[ch].State) { case cHighOccur: ret = AD_HIGH; break; case cLowOccur : ret = AD_LOW; break; case cNORMAL : ret = AD_NORMAL; break; default : ret = AD_NORMAL; break; } } } return ret; } int16_t TEMP_GRADE_CONVERTOR(int16_t aTempValue, uint8_t aGrade) { int16_t Tf, Tc; if (aGrade == 'F') { Tc = aTempValue; Tf = (18 * Tc)/10 + 320; // Celsius to Fahrenheit return(Tf); } else { Tf = aTempValue; Tc = (Tf - 320)/18; return(Tc); } /* // Celsius to Fahrenheit: Tf = 9/5 * Tc + 32 // Fahrenheit to Celsius: Tc = (Tf - 32) * 5/9 */ } int16_t ADValue(uint8_t ch) { int16_t result = 0; if (ch < TEMP_CH_MAX) { if (TempUnit == cCent) result = TD[ch].Value; else result = TEMP_GRADE_CONVERTOR(TD[ch].Value,'F'); } return result; } float ADValueF(uint8_t ch) { float result = 0.0; if (ch < TEMP_CH_MAX) { result = (float)TD[ch].Value / 10; } return result; } void TEMPERATURE_Process(uint8_t ch) { uint8_t aAlarm; aAlarm = TD[ch].State; switch (TD[ch].Changed) { case cHighToNorm : aAlarm = cNORMAL; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,35); break; case cLowToNorm : aAlarm = cNORMAL; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,35); break; case cNormToHigh : aAlarm = cHighOccur; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,36); break; case cNormToLow : aAlarm = cLowOccur; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,37); break; case cNormToFail : aAlarm = cNORMAL; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,38); break; case cFailToNorm : aAlarm = cNORMAL; // ADD_RUN_HISTORY(true,osENVIR,Temp1,(char *)Temp2,mg1,35); break; } if (TD[ch].Enabled != true) aAlarm = cNORMAL; TD[ch].State = aAlarm; } void Analog_Event_Process(uint8_t ch) { if (ch < TEMP_CH_MAX) { TEMPERATURE_Process(ch); } } void CalcAvgTemperature(void) { uint32_t sum; TMinMax min, max; sum = 0; max.value = 0; max.num = 0; min.value = 0; min.num = 0; int j = 0; for (int i = 0; i < (TEMP_CH_MAX - 2); i++) { if (TD[i].Failed == false) { if (j == 0) { max.value = ADValue(i); max.num = i; min.value = ADValue(i); min.num = i; } if (max.value < ADValue(i)) { max.value = ADValue(i); max.num = i; } if (min.value > ADValue(i)) { min.value = ADValue(i); min.num = i; } sum += ADValue(i); j++; } } if (j == 0) device_value.Temp.avg.avg = 0; else device_value.Temp.avg.avg = sum / j; device_value.Temp.avg.Max.value = max.value; device_value.Temp.avg.Max.num = max.num; device_value.Temp.avg.Min.value = min.value; device_value.Temp.avg.Min.num = min.value; device_value.Temp.avg.diff = max.value - min.value; } void ADC_Get_Process(uint8_t ch) { TD[ch].Changed = cNotChanged; // Initialize Changed_Member Analog_Process(ch); Analog_Event_Process(ch); } void ADC_Process(void) { for (int i = 0; i < TEMP_CH_MAX; i++) { ADC_Get_Process(i); } for (int i = 0; i < TEMP_CH_MAX; i++) { switch (i) { case T1_TEMP_ID: case T2_TEMP_ID: case T3_TEMP_ID: case T4_TEMP_ID: case T5_TEMP_ID: case T6_TEMP_ID: device_value.Temp.temperature[i] = ADValue(i); break; case EXT1_TEMP_ID: BmsStatus.ext1_temp = ADValue(i); break; case EXT2_TEMP_ID: BmsStatus.ext2_temp = ADValue(i); break; } } CalcAvgTemperature(); } int16_t GetBmsTemp(int ch) { int16_t result = -800; switch (ch) { case 0: result = BmsStatus.cpu_temp; break; case 1: result = BmsStatus.ext1_temp; break; case 2: result = BmsStatus.ext2_temp; break; } return result; } uint8_t IsTempSensorFailed(void) { for (int i = 0; i < TEMP_CH_MAX; i++) { if (TD[i].Enabled && TD[i].Failed) { return true; } } return false; } #ifdef CONSOLE_DEBUG void ODisplayAdcStatus(uint8_t p) { uint16_t i, x, y; float aParam; uint8_t aRedFont; static int tcount = 0; // TEMP DISPLAY if (p || (tcount == 0)) { tcount = 10; for (i = 0; i < (TEMP_CH_MAX); i++) { if (p || (memcmp(&TD[i], &DisTD[i], sizeof(TAnalogrec)) != 0)) { x = 27 + ((i / 2)* 10); y = 18 + ((i % 2)* 2); if ((TD[i].Enabled == true) & ((TD[i].State != cNORMAL) | (TD[i].Failed == true))) aRedFont = DISPLAY_RED; else aRedFont = DISPLAY_GREEN; if (TD[i].Failed == true) { aParam = (float)ADValue(i) / 10; FloatColorOutIntXY(aRedFont, x, y, aParam, 5, 1); if (p || (TD[i].Failed != DisTD[i].Failed)) ColorOutXY(aRedFont, x + 1, y + 1, (uint8_t *)"FAIL"); } else { aParam = (float)ADValue(i) / 10; FloatColorOutIntXY(aRedFont, x, y, aParam, 5, 1); if (p || (TD[i].State != DisTD[i].State)||(TD[i].Failed != DisTD[i].Failed)) { switch (TD[i].State) { case cHighOccur: ColorOutXY(aRedFont, x + 1, y + 1, (uint8_t *)"HIGH"); break; case cLowOccur: ColorOutXY(aRedFont, x + 1, y + 1, (uint8_t *)"LOW "); break; case cNORMAL : ColorOutXY(aRedFont, x + 1, y + 1, (uint8_t *)"NORM"); break; default : ColorOutXY(aRedFont, x + 1, y + 1, (uint8_t *)"????"); break; } } } memcpy(&DisTD[i], &TD[i], sizeof(TAnalogrec)); } } } tcount--; } void PrintTempAdData(uint8_t ch) { for (int i = 0; i < TEMP_BUF_MAX; i++) { printf("(%3d), %04X\r\n", i, AdData[ch][i]); delay_os_ms(1); } } #endif // #ifdef CONSOLE_DEBUG /*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/