BMS_Set_Error_States.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * BMS_Set_Error_States.c
  3. *
  4. * Created on: Nov 8, 2016
  5. * Author: le8041
  6. */
  7. #include "BMS_Master.h"
  8. /*
  9. * @brief check if Battery is charged or discharged
  10. * return true if discharged false if charged
  11. */
  12. uint32_t BMS_set_Error_check_if_stable_discharge(MASTER_CAN0_STRUCT_t* s) {
  13. // stable when mean value is bigger than -150mA
  14. uint8_t i;
  15. int16_t Current=0;
  16. for(i=0;i<UI_CURRENT_FIFO_SIZE;i++) {
  17. Current=Current + s->UI_Board.IbattFiFo[i] ;
  18. }
  19. Current = (Current*10) /UI_CURRENT_FIFO_SIZE ;
  20. if(Current > -150) {
  21. // stable discharge
  22. return TRUE;
  23. }
  24. //stable discharge
  25. return FALSE;
  26. }
  27. /*
  28. * @brief check if Battery is charged or discharged
  29. * return true if discharged false if charged
  30. */
  31. uint32_t BMS_set_Error_check_if_active_stable_discharge(MASTER_CAN0_STRUCT_t* s) {
  32. // stable when mean value is bigger than -150mA
  33. uint8_t i;
  34. float Current=0;
  35. for(i=0;i<UI_CURRENT_FIFO_SIZE;i++) {
  36. Current=Current + s->UI_Board.IbattFiFo[i] ;
  37. }
  38. Current = (Current*10) /UI_CURRENT_FIFO_SIZE ;
  39. if(Current > 150) {
  40. // stable discharge
  41. return TRUE;
  42. }
  43. //stable discharge
  44. return FALSE;
  45. }
  46. /*
  47. * @brief ceck if battery is charged stable over given amount of samples
  48. */
  49. uint32_t BMS_set_Error_check_if_stable_charge(MASTER_CAN0_STRUCT_t* s) {
  50. // stable when all values of FiFo are greater than -150
  51. uint8_t i;
  52. for(i=0;i<UI_CURRENT_FIFO_SIZE;i++) {
  53. if(s->UI_Board.IbattFiFo[i] *10 > -150) {
  54. // no stable charge
  55. return FALSE;
  56. }
  57. }
  58. //stable charge
  59. return TRUE;
  60. }
  61. /*
  62. * @brief check voltage levels Umin1 Umin2 Umin3 and set Error states accordingly
  63. * return True if everything is of return false if error occured
  64. */
  65. uint32_t BMS_Set_Error_check_Voltage_level_min(MASTER_CAN0_STRUCT_t* s){
  66. uint16_t Umin;
  67. float PvPwrAvailable;
  68. Umin=s->minCellVoltage;
  69. PvPwrAvailable=s->inverter.rxStruct.expectedInputPower;
  70. if(Umin < BMS_SOC_UMIN_3 ) {
  71. // Voltage level below Umin3
  72. // Kill Relays
  73. s->relayState.HS_closed=FALSE;
  74. s->relayState.LS_closed=FALSE;
  75. s->relayState.PRECHARGE_closed=FALSE;
  76. SwitchRelais( LS_RELAIS, 0);
  77. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  78. SwitchRelais( HS_RELAIS, 0);
  79. // set Error state 3 - should be alse set directly after test of Slave Voltage in Salve
  80. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMIN_3,BMS_ERROR_CLASS_3);
  81. return FALSE;
  82. }
  83. else if(Umin < BMS_SOC_UMIN_2 && BMS_set_Error_check_if_stable_discharge(s) && !ErrorStackCheckifUmin2ErrorRecoveryPending(s) ) {
  84. // Voltage level below Umin2 and Battery is discharged
  85. // Kill Relays
  86. SwitchRelais( LS_RELAIS, 0);
  87. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  88. SwitchRelais( HS_RELAIS, 0);
  89. s->relayState.HS_closed=FALSE;
  90. s->relayState.LS_closed=FALSE;
  91. s->relayState.PRECHARGE_closed=FALSE;
  92. // set Error state 2
  93. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMIN_2,BMS_ERROR_CLASS_2);
  94. return FALSE;
  95. }
  96. else if(Umin < BMS_SOC_UMIN_1 && BMS_set_Error_check_if_stable_discharge(s) && !ErrorStackCheckifUmin1ErrorRecoveryPending(s) ) {
  97. // Voltage Level below Umin1 and battery is discharged
  98. // Kill Relays
  99. SwitchRelais( LS_RELAIS, 0);
  100. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  101. SwitchRelais( HS_RELAIS, 0);
  102. s->relayState.HS_closed=FALSE;
  103. s->relayState.LS_closed=FALSE;
  104. s->relayState.PRECHARGE_closed=FALSE;
  105. // set Error state 1
  106. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMIN_1,BMS_ERROR_CLASS_1);
  107. return FALSE;
  108. }
  109. else {
  110. // everything is ok
  111. return TRUE;
  112. }
  113. }
  114. /*
  115. * @brief check max voltage level
  116. */
  117. uint32_t BMS_Set_Error_check_Voltage_level_max(MASTER_CAN0_STRUCT_t* s) {
  118. uint16_t Umax=s->maxCellVoltage;
  119. if(Umax > BMS_SOC_UMAX_3) {
  120. // set Error State 1
  121. // Kill Relays
  122. SwitchRelais( LS_RELAIS, 0);
  123. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  124. SwitchRelais( HS_RELAIS, 0);
  125. s->relayState.HS_closed=FALSE;
  126. s->relayState.LS_closed=FALSE;
  127. s->relayState.PRECHARGE_closed=FALSE;
  128. // set Error state 2
  129. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMAX_3,BMS_ERROR_CLASS_3);
  130. return FALSE;
  131. }
  132. else if(Umax > BMS_SOC_UMAX_2) {
  133. // set Error State 1
  134. // Kill Relays
  135. SwitchRelais( LS_RELAIS, 0);
  136. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  137. SwitchRelais( HS_RELAIS, 0);
  138. s->relayState.HS_closed=FALSE;
  139. s->relayState.LS_closed=FALSE;
  140. s->relayState.PRECHARGE_closed=FALSE;
  141. // set Error state 2
  142. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMAX_2,BMS_ERROR_CLASS_1);
  143. return FALSE;
  144. }
  145. else if(Umax > BMS_SOC_UMAX_1 ) {
  146. // set Error State 0 not implemented yet
  147. // TODO return TRUE; everything is ok
  148. return TRUE;
  149. }
  150. else {
  151. // everything is ok
  152. return TRUE;
  153. }
  154. }
  155. /*
  156. * @brief check if system exceeds maximum System Voltage in case customer plays around with the system
  157. */
  158. uint32_t BMS_Set_Error_check_System_voltage_level_max(MASTER_CAN0_STRUCT_t* s) {
  159. uint32_t Uges=s->systemVoltage;
  160. if(Uges >BMS_ERROR_THRESHOLD_UMAX_SYSTEM) {
  161. // Kill Relays
  162. SwitchRelais( LS_RELAIS, 0);
  163. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  164. SwitchRelais( HS_RELAIS, 0);
  165. s->relayState.HS_closed=FALSE;
  166. s->relayState.LS_closed=FALSE;
  167. s->relayState.PRECHARGE_closed=FALSE;
  168. // set Error state 3
  169. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_UMAX_SYSTEM,BMS_ERROR_CLASS_3);
  170. return FALSE;
  171. }
  172. else {
  173. //everything is ok
  174. return TRUE;
  175. }
  176. }
  177. /*
  178. *@brief do linear interpolation
  179. */
  180. float BMS_Set_Error_linear_interpolate(float x1,float x2,float x,float y1,float y2) {
  181. // solve linear eq y1= m*x1 + b
  182. // y2= m*x2 + b
  183. float m = (y2-y1)/(float)(x2-x1);
  184. float b = y1 - m*(float)(x1);
  185. //
  186. return m*(float)(x) + b;
  187. }
  188. /*
  189. *
  190. */
  191. float BMS_Set_Error_generate_Fcn(float* x_values,float* y_values,uint8_t NrOfPoints, float x) {
  192. uint8_t i;
  193. if(x < x_values[0]) {
  194. // value is to the left of the described area => return left most value
  195. return y_values[0];
  196. }
  197. else if( x> x_values[NrOfPoints -1] ) {
  198. // value is to the right of the described area => return right most value
  199. return y_values[NrOfPoints -1];
  200. }
  201. // find left x_value to x
  202. for(i=0;i< NrOfPoints; i++) {
  203. if(x_values[i] <= x && x_values[i+1] >= x ) {
  204. // x is between x_value[i] and x_value[i+1]
  205. return BMS_Set_Error_linear_interpolate(x_values[i],x_values[i+1],x,y_values[i],y_values[i+1]);
  206. }
  207. }
  208. }
  209. uint32_t BMS_Set_Error_Check_derating(MASTER_CAN0_STRUCT_t* s) {
  210. float Current = (float)(s->UI_Board.Ibatt*10);
  211. float minTemp = (float)s->minCellTemp;
  212. float maxTemp = (float)s->maxCellTemp;
  213. float SoC = s->SoC_estimator.SoC_percentage_smooth_FiFo[5];
  214. float capacity = 26.0 ; // capacity 26.0 Ah
  215. float temp_discharge_x[4]={0,25,40,55};
  216. float temp_discharge_y[4]={0.3,1.1,1.1,0};
  217. float temp_charge_x[5]={-5,0,25,40,50};
  218. float temp_charge_y[5]={0.3,0.6,1.1,1.1,0};
  219. float SoC_charge_x[5]={0,0.8,0.95,0.999,1};
  220. float SoC_charge_y[5]={25,25,2.5,2.5,0};
  221. float SoC_discharge_x[5]={0,0.001,0.05,0.2,1};
  222. float SoC_discharge_y[5]={0,2.5,2.5,25,25};
  223. s->currentLimits.I_max_charge_temp_max = BMS_Set_Error_generate_Fcn(temp_charge_x,temp_charge_y,5,maxTemp)*25*1000;
  224. s->currentLimits.I_max_charge_temp_min = BMS_Set_Error_generate_Fcn(temp_charge_x,temp_charge_y,5,minTemp)*25*1000;
  225. s->currentLimits.I_max_charge_SoC = BMS_Set_Error_generate_Fcn(SoC_charge_x,SoC_charge_y,5,SoC)*1000 *1.1 ;
  226. // at derating use most current SOC
  227. s->currentLimits.I_max_discharge_temp_max = BMS_Set_Error_generate_Fcn(temp_discharge_x,temp_discharge_y,4,maxTemp)*25*1000;
  228. s->currentLimits.I_max_discharge_temp_min = BMS_Set_Error_generate_Fcn(temp_discharge_x,temp_discharge_y,4,minTemp)*25*1000;
  229. s->currentLimits.I_max_discharge_SoC = BMS_Set_Error_generate_Fcn(SoC_discharge_x,SoC_discharge_y,5,s->SoC_estimator.SoC_percentage_smooth)*1000 *1.1 ;
  230. s->currentLimits.I_max_discharge_SoC_test=BMS_Set_Error_generate_Fcn(SoC_discharge_x,SoC_discharge_y,5,s->SoC_estimator.SoC_percentage_smooth)*1000 ;
  231. s->currentLimits.test_SoC = SoC;
  232. s->currentLimits.test_SoC_actual=s->SoC_estimator.SoC_percentage_smooth;
  233. if(Current < -100) {
  234. // Battery is charged
  235. // check temperature derating at tmin
  236. // check if low temperature is violated
  237. if((-1)*Current > s->currentLimits.I_max_charge_temp_min) {
  238. // current to high
  239. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_CHARGE_OP,BMS_ERROR_CLASS_1);
  240. // Kill Relays
  241. SwitchRelais( LS_RELAIS, 0);
  242. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  243. SwitchRelais( HS_RELAIS, 0);
  244. s->relayState.HS_closed=FALSE;
  245. s->relayState.LS_closed=FALSE;
  246. s->relayState.PRECHARGE_closed=FALSE;
  247. return FALSE;
  248. }
  249. // check temperature derating at tmax
  250. // check if low temperature is violated
  251. else if((-1)*Current > s->currentLimits.I_max_charge_temp_max ) {
  252. // current too high
  253. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_CHARGE_OP,BMS_ERROR_CLASS_1);
  254. // Kill Relays
  255. SwitchRelais( LS_RELAIS, 0);
  256. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  257. SwitchRelais( HS_RELAIS, 0);
  258. s->relayState.HS_closed=FALSE;
  259. s->relayState.LS_closed=FALSE;
  260. s->relayState.PRECHARGE_closed=FALSE;
  261. return FALSE;
  262. }
  263. // check SoC derating // normal derating curve + 10%
  264. else if((-1)*Current > s->currentLimits.I_max_charge_SoC) {
  265. // current too high
  266. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_CHARGE_OP,BMS_ERROR_CLASS_1);
  267. // Kill Relays
  268. SwitchRelais( LS_RELAIS, 0);
  269. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  270. SwitchRelais( HS_RELAIS, 0);
  271. s->relayState.HS_closed=FALSE;
  272. s->relayState.LS_closed=FALSE;
  273. s->relayState.PRECHARGE_closed=FALSE;
  274. return FALSE;
  275. }
  276. else {
  277. // derating is ok
  278. return TRUE;
  279. }
  280. }
  281. else if(Current > 100) {
  282. // Battery is discharged
  283. // check temperature derating at tmin
  284. // check if low temperature is violated
  285. if(Current > s->currentLimits.I_max_discharge_temp_min ) {
  286. // current to high
  287. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_DISCHARGE_OP,BMS_ERROR_CLASS_1);
  288. // Kill Relays
  289. SwitchRelais( LS_RELAIS, 0);
  290. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  291. SwitchRelais( HS_RELAIS, 0);
  292. s->relayState.HS_closed=FALSE;
  293. s->relayState.LS_closed=FALSE;
  294. s->relayState.PRECHARGE_closed=FALSE;
  295. return FALSE;
  296. }
  297. // check temperature derating at tmax
  298. // check if low temperature is violated
  299. else if(Current > s->currentLimits.I_max_discharge_temp_max ) {
  300. // current too high
  301. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_DISCHARGE_OP,BMS_ERROR_CLASS_1);
  302. // Kill Relays
  303. SwitchRelais( LS_RELAIS, 0);
  304. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  305. SwitchRelais( HS_RELAIS, 0);
  306. s->relayState.HS_closed=FALSE;
  307. s->relayState.LS_closed=FALSE;
  308. s->relayState.PRECHARGE_closed=FALSE;
  309. return FALSE;
  310. }
  311. // check SoC derating // normal derating curve + 10%
  312. else if(Current > s->currentLimits.I_max_discharge_SoC) {
  313. // current too high
  314. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_I_MAX_DISCHARGE_OP,BMS_ERROR_CLASS_1);
  315. // Kill Relays
  316. SwitchRelais( LS_RELAIS, 0);
  317. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  318. SwitchRelais( HS_RELAIS, 0);
  319. s->relayState.HS_closed=FALSE;
  320. s->relayState.LS_closed=FALSE;
  321. s->relayState.PRECHARGE_closed=FALSE;
  322. return FALSE;
  323. }
  324. else {
  325. // derating is ok
  326. return TRUE;
  327. }
  328. }
  329. else {
  330. // nothing happens
  331. return TRUE;
  332. }
  333. return TRUE;
  334. }
  335. /*
  336. * @brief check if UI has opend relays
  337. */
  338. uint32_t BMS_Set_Error_UI_Relais(MASTER_CAN0_STRUCT_t* s) {
  339. ErrorStackPushUiError(s,BMS_ERROR_STACK_UI_RELAY_OPEN,BMS_ERROR_CLASS_2);
  340. // Kill Relays
  341. SwitchRelais( LS_RELAIS, 0);
  342. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  343. SwitchRelais( HS_RELAIS, 0);
  344. s->relayState.HS_closed=FALSE;
  345. s->relayState.LS_closed=FALSE;
  346. s->relayState.PRECHARGE_closed=FALSE;
  347. return TRUE;
  348. }
  349. uint32_t BMS_Set_Error_CAN1_Timeout(MASTER_CAN0_STRUCT_t* s) {
  350. // CAN 1 Timeout Has occured
  351. ErrorStackPushMasterError(s,BMS_ERROR_STACK_MASTER_EXTERN_CAN_ERROR,BMS_ERROR_CLASS_1);
  352. // Kill Relays
  353. SwitchRelais( LS_RELAIS, 0);
  354. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  355. SwitchRelais( HS_RELAIS, 0);
  356. s->relayState.HS_closed=FALSE;
  357. s->relayState.LS_closed=FALSE;
  358. s->relayState.PRECHARGE_closed=FALSE;
  359. return TRUE;
  360. }
  361. /*
  362. * @brief check if current mesured by UI is consitent wit current measured by Inverter
  363. */
  364. uint32_t BMS_Set_Error_Check_current_consitency(MASTER_CAN0_STRUCT_t* s) {
  365. uint8_t i=0;
  366. float I_av_ui =0 ;
  367. float I_av_inverter =0;
  368. for(i=0; i<UI_CURRENT_FIFO_SIZE;i++) {
  369. I_av_ui = I_av_ui + (float)(s->UI_Board.IbattFiFo[i]);
  370. }
  371. I_av_ui = I_av_ui *10; // convert to mA
  372. I_av_ui = I_av_ui /UI_CURRENT_FIFO_SIZE ; // calc mean
  373. for(i=0;i<UI_CURRENT_FIFO_SIZE;i++ ) {
  374. I_av_inverter = I_av_inverter + s->UI_Board.Ibatt_Inverter_FIFO[i];
  375. }
  376. I_av_inverter = I_av_inverter *1000 /UI_CURRENT_FIFO_SIZE ; // convert to mA and calc mean
  377. // compare
  378. s->UiInverterInconsistency = bms_SoC_get_norm(I_av_inverter) - bms_SoC_get_norm(I_av_ui) ;
  379. if( s->UiInverterInconsistency > BMS_MAX_CURRENT_INCONSITENCY_MA || s->UiInverterInconsistency <( (-1) * BMS_MAX_CURRENT_INCONSITENCY_MA) ) {
  380. // error has occured
  381. ErrorStackPushUiError(s,BMS_ERROR_STACK_UI_CURRENT_INCONSIST,BMS_ERROR_CLASS_1);
  382. // Kill Relays
  383. SwitchRelais( LS_RELAIS, 0);
  384. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  385. SwitchRelais( HS_RELAIS, 0);
  386. s->relayState.HS_closed=FALSE;
  387. s->relayState.LS_closed=FALSE;
  388. s->relayState.PRECHARGE_closed=FALSE;
  389. return TRUE;
  390. }
  391. return TRUE;
  392. }
  393. /*
  394. * @brief check if Voltage measured by UI and by Summation of Slaves are equal
  395. */
  396. uint32_t BMS_Set_Error_Check_voltage_inconsitency(MASTER_CAN0_STRUCT_t* s) {
  397. uint8_t i=0;
  398. uint32_t addedCellVoltage_mean=0;
  399. uint32_t UI_Board_voltage_mean=0;
  400. for(i=0;i<UI_VOLTAGE_FIFO_SIZE;i++) {
  401. addedCellVoltage_mean = addedCellVoltage_mean + s->UI_Board.SystemVoltageFiFo[i];
  402. UI_Board_voltage_mean = UI_Board_voltage_mean + s->UI_Board.UbattFiFo[i];
  403. }
  404. addedCellVoltage_mean = addedCellVoltage_mean /UI_VOLTAGE_FIFO_SIZE ; // voltage in mV
  405. UI_Board_voltage_mean = UI_Board_voltage_mean *100 / UI_VOLTAGE_FIFO_SIZE ;
  406. s->UiSlaveInconsistency = bms_SoC_get_norm((float)addedCellVoltage_mean - (float)UI_Board_voltage_mean) ;
  407. // if voltage error is bigger than threshold and All relais are closed kill relays
  408. if((s->UiSlaveInconsistency > (addedCellVoltage_mean * 0.05) && s->RunMode.onCounter > (UI_VOLTAGE_FIFO_SIZE* CAN0_MAX_NR_OF_SLAVES)) &&
  409. (s->relayState.HS_closed==TRUE && s->relayState.LS_closed==TRUE && s->relayState.PRECHARGE_closed==FALSE && s->UI_Board.Errors.RelayOpen == FALSE) ){
  410. ErrorStackPushUiError(s,BMS_ERROR_STACK_UI_VOLTAGE_INCONSIST,BMS_ERROR_CLASS_1);
  411. // Kill Relays
  412. SwitchRelais( LS_RELAIS, 0);
  413. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  414. SwitchRelais( HS_RELAIS, 0);
  415. s->relayState.HS_closed=FALSE;
  416. s->relayState.LS_closed=FALSE;
  417. s->relayState.PRECHARGE_closed=FALSE;
  418. s->RunMode.onCounter=0;
  419. return TRUE;
  420. }
  421. return TRUE;
  422. }
  423. /*
  424. * @brief check if UI sends error flags
  425. */
  426. uint32_t BMS_set_Error_Check_UI_Flags(MASTER_CAN0_STRUCT_t* s) {
  427. if(s->UI_Board.Errors.OffsetError ==TRUE) {
  428. ErrorStackPushUiError(s,BMS_ERROR_STACK_UI_OFFSET_ERROR,BMS_ERROR_CLASS_2);
  429. // Kill Relays
  430. SwitchRelais( LS_RELAIS, 0);
  431. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  432. SwitchRelais( HS_RELAIS, 0);
  433. s->relayState.HS_closed=FALSE;
  434. s->relayState.LS_closed=FALSE;
  435. s->relayState.PRECHARGE_closed=FALSE;
  436. }
  437. if(s->UI_Board.Errors.SupplyError == TRUE) {
  438. ErrorStackPushUiError(s,BMS_ERROR_STACK_UI_SUPPLY_VOLTAGE,BMS_ERROR_CLASS_2);
  439. // Kill Relays
  440. SwitchRelais( LS_RELAIS, 0);
  441. SwitchRelais( PRE_CHARGE_RELAIS, 0);
  442. SwitchRelais( HS_RELAIS, 0);
  443. s->relayState.HS_closed=FALSE;
  444. s->relayState.LS_closed=FALSE;
  445. s->relayState.PRECHARGE_closed=FALSE;
  446. }
  447. return TRUE;
  448. }