BMS_CAN0_Tools.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. ///##############################################################################
  2. //
  3. // FILE: BMS_CAN0_Tools.c
  4. //
  5. // TITLE: CAN 0
  6. // CAN_Tx_Balance
  7. // check_and_save_Voltage
  8. // check_and_save_Status
  9. // check_and_save_UI
  10. // check_and_save_Temperature
  11. // check_Voltage_Border
  12. // check_Status_Border
  13. // check_UI_Border
  14. // check_Temperature_Border
  15. // Sum_Cell_Voltage
  16. // Test_MAX_LOAD_CELL_VOLTAGE
  17. // Search_MIN_CELL_VOLTAGE
  18. // Test_Slave_Presents
  19. //
  20. //
  21. //##############################################################################
  22. //
  23. //==============================================================================
  24. // Change History:
  25. //==============================================================================
  26. // Datum: | Name | Version:| Change / Cause: | No
  27. //------------------------------------------------------------------------------
  28. // | | | | 002
  29. //------------------------------------------------------------------------------
  30. // | | | | 001
  31. //------------------------------------------------------------------------------
  32. // 20.04.12 | TM | 1.0 | New Build | 000
  33. //==============================================================================
  34. //==============================================================================
  35. // Comment Change / Cause:
  36. //==============================================================================
  37. // Change: 003 // 003
  38. //----------------------
  39. //
  40. //
  41. //==============================================================================
  42. // Change: 002 // 002
  43. //----------------------
  44. //
  45. //
  46. //==============================================================================
  47. // Change: 001 // 001
  48. //----------------------
  49. //
  50. //
  51. //==============================================================================
  52. #include "BMS_Master.h"
  53. // ***** Functions for startup *********************************************
  54. uint16_t CAN_Tx_MasterX_BMS(MASTER_CAN0_STRUCT_t* s, uint8_t SlaveNummer, uint8_t MasterAlive, uint8_t SetMode, uint32_t Balancer )
  55. {
  56. uint8_t Data[MAX_SLAVES];
  57. uint16_t ReturnResult = CAN_OK;
  58. Balancer++;
  59. Data[0] = SetMode + (MasterAlive<<5);
  60. Data[1] = 0;
  61. Data[2] = 0;
  62. Data[3] = 0;
  63. Data[4] = 0;
  64. Data[5] = 0;
  65. Data[6] = 0;
  66. Data[7] = 0;
  67. ReturnResult = CAN_Write(s->Slave[SlaveNummer].TxMailbox_ptr , &Data[0] );
  68. return ReturnResult;
  69. }
  70. // ***** CAN_Tx_System300 ********************************************************
  71. uint16_t CAN_Tx_System300( uint16_t IDSEARCH )
  72. {
  73. uint8_t cIDSEARCH[8] = {'I','D','S','E','A','R','C','H'};
  74. uint8_t cSERNRPRG[8] = {'S','E','R','N','R','P','R','G'};
  75. uint16_t ReturnResult = CAN_OK;
  76. if(IDSEARCH)
  77. ReturnResult = CAN_Write( &CAN_TxMB_System300, &(cIDSEARCH[0]) );
  78. else
  79. ReturnResult = CAN_Write( &CAN_TxMB_System300, &cSERNRPRG[0] );
  80. return ReturnResult;
  81. }
  82. // ***** Functions for normal operation ************************************
  83. uint16_t CAN_Rx_readout_Mailbox(CAN_MAILBOX *p_MBox,uint8_t *eight_byte_field) {
  84. if( CAN_Read(p_MBox, eight_byte_field) != CAN_ERROR ) {
  85. return 1;
  86. }
  87. else {
  88. return 0;
  89. }
  90. }
  91. // ***** CAN_Tx_MasterXA ********************************************************
  92. uint16_t CAN_Tx_MasterXA()
  93. {
  94. uint8_t Data[8] = {0,0,0,0,0,0,0,0};
  95. uint16_t ReturnResult = CAN_OK;
  96. ReturnResult = CAN_Write( &CAN_TxMB_Master0A, &Data[0] );
  97. return ReturnResult;
  98. }
  99. //uint16_t CAN0_tx_send_request_telegram(uint8_t slaveNr) {
  100. // MASTER_X_BMS_TELEGRAM* tel_ptr=&TelegramTxContainer[slaveNr];
  101. // CAN_MAILBOX* mailbox_ptr=MB_Container[slaveNr];
  102. //
  103. // CAN_Write(mailbox_ptr,&(tel_ptr->Byte[0]));
  104. // tel_ptr->Values.MasterAlive++;
  105. //}
  106. uint16_t CAN0_tx_send_request_telegram(BMS_CAN0_SLAVE_t* Slave,uint8_t MasterAlive) {
  107. // create Slave Tx Telegram
  108. Slave->TxTelegram_ptr->Values.BalancingCell0_7=Slave->Balance_Cell_0_7;
  109. Slave->TxTelegram_ptr->Values.BalancingCell8_15=Slave->Balance_Cell_8_15;
  110. Slave->TxTelegram_ptr->Values.BalancingCell16_23=Slave->Balance_Cell_16_23;
  111. Slave->TxTelegram_ptr->Values.MasterAlive= MasterAlive;
  112. Slave->TxTelegram_ptr->Values.SetMode=Slave->Set_Mode;
  113. //
  114. CAN_Write(Slave->TxMailbox_ptr,&(Slave->TxTelegram_ptr->Byte[0]));
  115. }
  116. uint16_t CAN0_is_state_active(uint8_t* activeSlaves,uint8_t nrOfActiveSlaves,uint8_t nrOfCurrentSlave) {
  117. uint8_t i;
  118. for(i=0;i<nrOfActiveSlaves;i++) {
  119. if(activeSlaves[i] == nrOfCurrentSlave) {
  120. return TRUE;
  121. }
  122. }
  123. return FALSE;
  124. }
  125. // ***** CAN_Tx_Balance ********************************************************
  126. uint16_t CAN_Tx_Balance( uint16_t i)
  127. {
  128. uint32_t Buffer;
  129. uint8_t Data[MAX_SLAVES];
  130. uint16_t ReturnResult = CAN_OK;
  131. Buffer = gBSD.Balancer.Balancing_OnOff_Flags[i];
  132. Data[0] = (uint8_t)(Buffer & 0xFF); //Balancing 0-7
  133. Buffer >>= 8;
  134. Data[1] = (uint8_t)(Buffer & 0xFF); //Balancing 8-15
  135. Buffer >>= 8;
  136. Data[2] = (uint8_t)(Buffer & 0xFF); //Balancing 16-20
  137. Data[3] = gBSD.Balancer.FanCtrl.R[i]; //Luefter
  138. Data[4] = gBSD.Balancer.Relais_OnOff[i]; //Relais
  139. //ReturnResult = CAN_Write( &CAN_TxMB_BalancingCtrl_100+i, &Data[0] ); Turned off
  140. return ReturnResult;
  141. }
  142. // ***** check_and_save_Voltage ************************************************
  143. void check_and_save_Voltage( CAN_MAILBOX *p_MBox, uint16_t SlaveNr, uint16_t SlaveOffset )
  144. {
  145. uint8_t Data[8]; // Receive Dummy
  146. uint16_t i; // RowCounter
  147. uint16_t j; // CellOffset
  148. if( CAN_Read(p_MBox, &Data[0] ) != CAN_ERROR )
  149. {
  150. i = gBSD.w_Voltage; // RowCounter
  151. j = MAX_SLAVE_CELLS * SlaveNr + SlaveOffset * 4; // CellOffset
  152. gBSE.CountVoltage |= ( 1 << ( 6 * SlaveNr + SlaveOffset ) ); // MSG No Bit
  153. gBSD.CellVoltage[i][j] = (uint16_t)((Data[0]<<8) + Data[1]);
  154. gBSE.ErrorCell[j] = check_Voltage_Border( i, j ); j++;
  155. gBSD.CellVoltage[i][j] = (uint16_t)((Data[2]<<8) + Data[3]);
  156. gBSE.ErrorCell[j] = check_Voltage_Border( i, j ); j++;
  157. gBSD.CellVoltage[i][j] = (uint16_t)((Data[4]<<8) + Data[5]);
  158. gBSE.ErrorCell[j] = check_Voltage_Border( i, j ); j++;
  159. gBSD.CellVoltage[i][j] = (uint16_t)((Data[6]<<8) + Data[7]);
  160. gBSE.ErrorCell[j] = check_Voltage_Border( i, j );
  161. if( gBSE.CountVoltage >= MAX_COUNT_MSG_VOLTAGE ) // All Voltage MSG of all Slaves complete
  162. {
  163. gBSE.CountVoltage = 0; // restart Voltage MSG Scan
  164. gBSD.r_Voltage = i; // W will be new R
  165. i++; // fetch next row
  166. if( i >= MAX_COUNT_VOLTAGE ) // check Overrun write Index
  167. i = 0;
  168. gBSD.w_Voltage = i; // new W
  169. }
  170. }
  171. }
  172. // ***** check_and_save_Status *************************************************
  173. void check_and_save_Status( CAN_MAILBOX *p_MBox, uint16_t SlaveNr )
  174. {
  175. uint8_t Data[8];
  176. uint16_t i; // RowCounter
  177. uint16_t j; // CellOffset
  178. if( CAN_Read( p_MBox, &Data[0] ) != CAN_ERROR )
  179. {
  180. i = gBSD.w_Status; // RowCounter
  181. j = SlaveNr; // CellOffset
  182. gBSE.CountStatus |= ( 1 << SlaveNr ); // MSG No Bit
  183. gBSD.Slave_Status[i][j].StatusFlags.R = (uint16_t)((Data[0]<<8) + Data[1]);
  184. gBSD.Slave_Status[i][j].LTC_PEC_FailCount = Data[2];
  185. gBSD.Slave_Status[i][j].HeatSink_Temp = (int8_t)Data[3];
  186. gBSD.Slave_Status[i][j].SelfTest_Flags.R = (uint16_t)((Data[4]<<8) + Data[5]);
  187. gBSE.ErrorSlave[j] = check_Status_Border( i, j );
  188. if( gBSE.CountStatus >= MAX_COUNT_MSG_STATUS ) // All Status MSG of all Slaves complete
  189. {
  190. gBSE.CountStatus = 0; // restart Status MSG Scan
  191. gBSD.r_Status = i; // W will be new R
  192. i++; // fetch next row
  193. if( i >= MAX_COUNT_STATUS ) // check Overrun write Index
  194. i = 0;
  195. gBSD.w_Status = i; // new W
  196. }
  197. }
  198. }
  199. // ***** check_and_save_UI *****************************************************
  200. void check_and_save_UI( CAN_MAILBOX *p_MBox )
  201. {
  202. static uint8_t Data[8]; // Receive Dummy
  203. uint8_t CS; // Checksum
  204. uint16_t i; // RowCounter
  205. if( CAN_Read( p_MBox, Data ) != CAN_ERROR )
  206. {
  207. i = gBSD.w_UI; // RowCounter
  208. gBSD.BlockVoltage[i] = (uint16_t)((Data[0]<<8) + Data[1]);
  209. gBSD.BlockCurrent[i] = ( int16_t)((Data[2]<<8) + Data[3]);;
  210. gBSD.BlockCounter[i] = Data[6];
  211. CS = Data[0] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[6] ^ 0x00;
  212. gBSE.ErrorBMS = 0;
  213. if( Data[7] != CS )
  214. gBSE.ErrorBMS |= ERROR_UI_PEC_NOK;
  215. //!! gBSE.ErrorBMS |= check_UI_Border( i );
  216. if( !gBSE.ErrorBMS )
  217. {
  218. gBSD.BlockCurrentSum -= gBSD.BlockCurrent[i]; // Integral of Current
  219. Data[0] = (uint8_t)((gBSD.BlockCurrentSum & 0xFF000000)>> 24);
  220. Data[1] = (uint8_t)((gBSD.BlockCurrentSum & 0x00FF0000)>> 16);
  221. Data[2] = (uint8_t)((gBSD.BlockCurrentSum & 0x0000FF00)>> 8);
  222. Data[3] = (uint8_t) (gBSD.BlockCurrentSum & 0x000000FF);
  223. Fram_S.Flags.B.JobFinished = 0;
  224. FRAM_trigger_write(0, &Data[0], 4);
  225. }
  226. gBSD.r_UI = i; // W will be new R
  227. i++; // fetch next row
  228. if( i == MAX_COUNT_UI ) // check Overrun write Index
  229. i = 0;
  230. gBSD.w_UI = i; // new W
  231. }
  232. }
  233. // ***** check_and_save_Temperature ********************************************
  234. void check_and_save_Temperature( CAN_MAILBOX *p_MBox, uint16_t SlaveNr, uint16_t SlaveOffset)
  235. {
  236. uint8_t Data[8]; // Receive Dummy
  237. uint16_t i; // RowCounter
  238. uint16_t j; // CellOffset
  239. if( CAN_Read(p_MBox, Data ) != CAN_ERROR )
  240. {
  241. i = gBSD.w_Temperature; // RowCounter
  242. j = MAX_SLAVE_CELLS * SlaveNr + SlaveOffset * 8; // CellOffset
  243. gBSE.CountTemperature |= ( 1 << ( 3 * SlaveNr + SlaveOffset ) ); // MSG No Bit
  244. gBSD.CellTemperature[i][j] = (int8_t) Data[0];
  245. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  246. gBSD.CellTemperature[i][j] = (int8_t) Data[1];
  247. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  248. gBSD.CellTemperature[i][j] = (int8_t) Data[2];
  249. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  250. gBSD.CellTemperature[i][j] = (int8_t) Data[3];
  251. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  252. gBSD.CellTemperature[i][j] = (int8_t) Data[4];
  253. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  254. gBSD.CellTemperature[i][j] = (int8_t) Data[5];
  255. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  256. gBSD.CellTemperature[i][j] = (int8_t) Data[6];
  257. gBSE.ErrorCell[j] = check_Temperature_Border( i, j ); j++;
  258. gBSD.CellTemperature[i][j] = (int8_t) Data[7];
  259. gBSE.ErrorCell[j] = check_Temperature_Border( i, j );
  260. if( gBSE.CountTemperature >= MAX_COUNT_MSG_TEMPERATURE ) // All Temperature MSG of all Slaves complete
  261. {
  262. gBSE.CountTemperature = 0; // restart Temperature MSG Scan
  263. gBSD.r_Temperature = i; // W will be new R
  264. i++; // fetch next row
  265. if( i == MAX_COUNT_TEMPERATURE ) // check Overrun write Index
  266. i = 0;
  267. gBSD.w_Temperature = i; // new W
  268. }
  269. }
  270. }
  271. // ***** check_Voltage_Border **************************************************
  272. int16_t check_Voltage_Border( uint16_t Row, uint16_t Index )
  273. {
  274. int16_t ReturnResult = CAN_OK;
  275. uint16_t i;
  276. uint32_t Average = 0;
  277. if(gCANErrorInsert == 1) //!! 1.5-3
  278. gBSD.CellVoltage[Row][Index] = MIN_CELL_VOLTAGE_TEST;
  279. if(gCANErrorInsert == 2) //!! 1.5-3
  280. gBSD.CellVoltage[Row][Index] = MAX_CELL_VOLTAGE_TEST;
  281. if( gBSD.CellVoltage[Row][Index] < PRE_CELL_LOW_VOLTAGE )
  282. {
  283. ReturnResult += ERROR_PRE_CELL_LOW_VOLTAGE;
  284. gErrorEvent |= EEV__DEGRADATION;
  285. }
  286. if( gBSD.CellVoltage[Row][Index] > MAX_CELL_VOLTAGE )
  287. {
  288. ReturnResult += ERROR_MAX_CELL_VOLTAGE;
  289. gErrorEvent |= EEV__SHUT_DOWN_CHARGE;
  290. }
  291. if( gBSD.CellVoltage[Row][Index] < MIN_CELL_VOLTAGE )
  292. {
  293. ReturnResult += ERROR_MIN_CELL_VOLTAGE;
  294. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  295. }
  296. if( Row >= MAX_AVE) // after 4 Rows start delta check
  297. {
  298. for(i=0; i<MAX_AVE; i++)
  299. Average += gBSD.CellVoltage[Row-i-1][Index]; // add 4 Rows together
  300. Average = Average >> MAX_AVE_SHIFT; // Average of 4 Rows
  301. if(gCANErrorInsert == 3) //!! 1.5-3
  302. gBSD.CellVoltage[Row][Index] = DELTA_CELL_VOLTAGE_TEST;
  303. if(gBSD.CellVoltage[Row][Index] < ( Average - DELTA_CELL_VOLTAGE ))
  304. {
  305. ReturnResult += ERROR_DELTA_CELL_VOLTAGE;
  306. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  307. }
  308. else
  309. if( gBSD.CellVoltage[Row][Index] > ( Average + DELTA_CELL_VOLTAGE ) )
  310. {
  311. ReturnResult += ERROR_DELTA_CELL_VOLTAGE;
  312. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  313. }
  314. }
  315. return ReturnResult;
  316. }
  317. // ***** check_Status_Border ***************************************************
  318. int16_t check_Status_Border( uint16_t Row, uint16_t Index )
  319. {
  320. int16_t ReturnResult = CAN_OK;
  321. if(gCANErrorInsert == 7) //!! 1.5-3
  322. gBSD.Slave_Status[Row][Index].HeatSink_Temp = MAX_HEATSINK_TEMPERATURE_TEST;
  323. if( gBSD.Slave_Status[Row][Index].HeatSink_Temp > MAX_HEATSINK_TEMPERATURE )
  324. {
  325. ReturnResult += ERROR_MAX_HEATSINK_TEMPERATURE;
  326. gErrorEvent |= EEV__SHUT_DOWN_CHARGE;
  327. }
  328. if( gBSD.Slave_Status[Row][Index].StatusFlags.R & 0x7C00 ) // CAN Rx/Tx Overrun/Warning/Passiv
  329. {
  330. ReturnResult += ERROR_SLAVE_CAN;
  331. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  332. }
  333. if( gBSD.Slave_Status[Row][Index].StatusFlags.R & 0x0003 ) // LTC1/2 Temperature < -40°C
  334. {
  335. ReturnResult += ERROR_MIN_LTC_TEMP;
  336. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  337. }
  338. if( gBSD.Slave_Status[Row][Index].StatusFlags.R & 0x003C ) // LTC1/2 Temperature > +80°C / THSD
  339. {
  340. ReturnResult += ERROR_MAX_LTC_TEMP;
  341. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  342. }
  343. if( gBSD.Slave_Status[Row][Index].StatusFlags.R & 0x00C0 ) // LTC TimeOut / PEC_NOK
  344. {
  345. ReturnResult += ERROR_SLAVE_PEC;
  346. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  347. }
  348. if( gBSD.Slave_Status[Row][Index].SelfTest_Flags.R ) // Any SelfTest Error Flag
  349. {
  350. ReturnResult += ERROR_SLAVE_SELFTEST;
  351. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  352. }
  353. return ReturnResult;
  354. }
  355. // ***** check_UI_Border *******************************************************
  356. int16_t check_UI_Border( uint16_t Row )
  357. {
  358. uint16_t Vbat = 0;
  359. int16_t ReturnResult = CAN_OK;
  360. if(Global_1msCounter > (DELAY_START+DELAY_START) )
  361. Vbat = Sum_Cell_Voltage( Row );
  362. else
  363. Vbat = 4250;
  364. if(gCANErrorInsert == 8) //!! 1.5-3
  365. Vbat = MIN_UI_VOLTAGE_TEST;
  366. if(gCANErrorInsert == 9) //!! 1.5-3
  367. Vbat = MAX_UI_VOLTAGE_TEST;
  368. if( Vbat < MIN_UI_VOLTAGE )
  369. {
  370. ReturnResult += ERROR_MIN_UI_VOLTAGE;
  371. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  372. }
  373. else
  374. if( Vbat > MAX_UI_VOLTAGE )
  375. {
  376. ReturnResult += ERROR_MAX_UI_VOLTAGE;
  377. gErrorEvent |= EEV__SHUT_DOWN_CHARGE;
  378. }
  379. if( gBSD.BlockCurrent[Row] < MIN_UI_LOAD_CURRENT )
  380. {
  381. ReturnResult += ERROR_MIN_UI_CURRENT; // Load => +
  382. gErrorEvent |= EEV__SHUT_DOWN_CHARGE;
  383. }
  384. else
  385. if( gBSD.BlockCurrent[Row] > MAX_UI_DRIVE_CURRENT )
  386. {
  387. ReturnResult += ERROR_MAX_UI_CURRENT; // Drive => -
  388. gErrorEvent |= EEV__DEGRADATION;
  389. }
  390. if( Row )
  391. if( gBSD.BlockCounter[Row] )
  392. if( gBSD.BlockCounter[Row] != (gBSD.BlockCounter[Row-1] + 1) )
  393. {
  394. ReturnResult += ERROR_UI_PEC_NOK;
  395. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  396. }
  397. return ReturnResult;
  398. }
  399. // ***** check_Temperature_Border **********************************************
  400. int16_t check_Temperature_Border( uint16_t Row, uint16_t Index )
  401. {
  402. int16_t ReturnResult = CAN_OK;
  403. if(gCANErrorInsert == 4) //!! 1.5-3
  404. gBSD.CellTemperature[Row][Index] = MAX_CELL_TEMPERATURE_TEST;
  405. if(gCANErrorInsert == 5) //!! 1.5-3
  406. gBSD.CellTemperature[Row][Index] = MIN_CELL_TEMPERATURE_TEST;
  407. if( gBSD.CellTemperature[Row][Index] < MIN_CELL_TEMPERATURE )
  408. {
  409. ReturnResult += ERROR_MIN_CELL_TEMPERATURE;
  410. gErrorEvent |= EEV__SHUT_DOWN_CHARGE;
  411. }
  412. if( gBSD.CellTemperature[Row][Index] > PRE_CELL_OVERHEAT )
  413. {
  414. ReturnResult += ERROR_PRE_CELL_OVERHEAT;
  415. gErrorEvent |= EEV__DEGRADATION;
  416. }
  417. if( gBSD.CellTemperature[Row][Index] > MAX_CELL_TEMPERATURE )
  418. {
  419. ReturnResult += ERROR_MAX_CELL_TEMPERATURE;
  420. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  421. }
  422. if( Row ) // at last 2 Temperatures to compare
  423. {
  424. if(gCANErrorInsert == 6) //!! 1.5-3
  425. gBSD.CellTemperature[Row][Index-1] += DELTA_CELL_TEMPERATURE_TEST;
  426. if(gBSD.CellTemperature[Row][Index] < ( gBSD.CellTemperature[Row-1][Index] - DELTA_CELL_TEMPERATURE ))
  427. {
  428. ReturnResult += ERROR_DELTA_CELL_TEMPERATURE;
  429. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  430. }
  431. else
  432. if( gBSD.CellTemperature[Row][Index] > ( gBSD.CellTemperature[Row-1][Index] + DELTA_CELL_TEMPERATURE ) )
  433. {
  434. ReturnResult += ERROR_DELTA_CELL_TEMPERATURE;
  435. gErrorEvent |= EEV__SHUT_DOWN_EMERGENCY;
  436. }
  437. }
  438. return ReturnResult;
  439. }
  440. // ***** Sum_Cell_Voltage ******************************************************
  441. uint16_t Sum_Cell_Voltage( uint16_t Row )
  442. {
  443. uint32_t ReturnResult = 0;
  444. uint16_t i;
  445. for( i=0; i<MAX_CELLS; i++)
  446. ReturnResult += (uint32_t)gBSD.CellVoltage[Row][i];
  447. ReturnResult /= 100;
  448. return (uint16_t)ReturnResult;
  449. }
  450. // ***** Test_MAX_LOAD_CELL_VOLTAGE ********************************************
  451. uint16_t Test_MAX_LOAD_CELL_VOLTAGE( uint16_t Row )
  452. {
  453. uint16_t ReturnResult = CAN_OK;
  454. uint16_t i;
  455. for( i=0; i<MAX_CELLS; i++)
  456. {
  457. if( gBSD.CellVoltage[Row][i] > MAX_LOAD_CELL_VOLTAGE )
  458. {
  459. ReturnResult = ERROR_MAX_LOAD_CELL_VOLTAGE; // one Error is enough
  460. break;
  461. }
  462. }
  463. return ReturnResult;
  464. }
  465. // ***** Search_MIN_CELL_VOLTAGE ********************************************
  466. uint16_t Search_MIN_CELL_VOLTAGE( uint16_t Row )
  467. {
  468. uint16_t ReturnResult = MAX_CELL_VOLTAGE;
  469. uint16_t i;
  470. for( i=0; i<MAX_CELLS; i++)
  471. if( gBSD.CellVoltage[Row][i] < ReturnResult )
  472. ReturnResult = gBSD.CellVoltage[Row][i];
  473. return ReturnResult;
  474. }
  475. // ***** End BMS_CAN0_Tools.c **************************************************