Files
LFP_48V_mBMS_FW/APP_R3221/App/Source/temp.c

689 lines
18 KiB
C

/**
******************************************************************************
* @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.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include <includes.h>
#include <stdlib.h>
#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******/