foxBMS  1.5.0
The foxBMS Battery Management System API Documentation
bender_ir155_helper.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2023, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file bender_ir155_helper.c
44  * @author foxBMS Team
45  * @date 2021-09-17 (date of creation)
46  * @updated 2023-02-03 (date of last update)
47  * @version v1.5.0
48  * @ingroup DRIVERS
49  * @prefix IR155
50  *
51  * @brief Driver for the insulation monitoring
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "bender_ir155_helper.h"
56 
57 #include "bender_ir155_cfg.h"
58 
59 #include "fram.h"
60 
61 #include <math.h>
62 #include <stdbool.h>
63 #include <stdint.h>
64 
65 /*========== Macros and Definitions =========================================*/
66 /** Maximum measurable resistance according to formula:
67  * ((90 * 1200kOhm) / (dc - 5) ) - 1200kOhm
68  * with dc ]5%,95%[ */
69 #define IR155_MAXIMUM_INSULATION_RESISTANCE_kOhm (106800u)
70 #define IR155_MINIMUM_INSULATION_RESISTANCE_kOhm (0u)
71 
72 /* Normal mode: duty cycle limits */
73 #define IR155_NORMAL_MODE_LOWER_DUTY_CYCLE_LIMIT_perc (4.0f)
74 #define IR155_NORMAL_MODE_UPPER_DUTY_CYCLE_LIMIT_perc (96.0f)
75 
76 /* Speed start mode: duty cycle limits */
77 #define IR155_SPEED_START_ESTIMATION_GOOD_LOWER_DUTY_CYCLE_LIMIT_perc (4.0f)
78 #define IR155_SPEED_START_ESTIMATION_GOOD_UPPER_DUTY_CYCLE_LIMIT_perc (11.0f)
79 
80 #define IR155_SPEED_START_ESTIMATION_BAD_LOWER_DUTY_CYCLE_LIMIT_perc (89.0f)
81 #define IR155_SPEED_START_ESTIMATION_BAD_UPPER_DUTY_CYCLE_LIMIT_perc (96.0f)
82 
83 /* Undervoltage mode: duty cycle limits */
84 #define IR155_UNDERVOLTAGE_MODE_LOWER_DUTY_CYCLE_LIMIT_perc (4.0f)
85 #define IR155_UNDERVOLTAGE_MODE_UPPER_DUTY_CYCLE_LIMIT_perc (96.0f)
86 
87 /* Device error mode: duty cycle limits */
88 #define IR155_DEVICE_ERROR_LOWER_DUTY_CYCLE_LIMIT_perc (46.5f)
89 #define IR155_DEVICE_ERROR_UPPER_DUTY_CYCLE_LIMIT_perc (53.5f)
90 
91 /* Device error mode: duty cycle limits */
92 #define IR155_GROUND_ERROR_LOWER_DUTY_CYCLE_LIMIT_perc (46.5f)
93 #define IR155_GROUND_ERROR_UPPER_DUTY_CYCLE_LIMIT_perc (53.5f)
94 
95 /*========== Static Constant and Variable Definitions =======================*/
96 
97 /*========== Extern Constant and Variable Definitions =======================*/
98 extern IR155_STATE_s ir155_state = {
99  .ir155Initialized = false,
100  .measurement.isMeasurementValid = false,
101  .measurement.isUndervoltageDetected = false,
102  .measurement.measurementState = IR155_UNINITIALIZED,
103  .measurement.measurementMode = IR155_UNKNOWN,
104  .measurement.digitalStatusPin = STD_PIN_LOW,
105  .measurement.resistance_kOhm = 0,
106  .measurement.pwmSignal.dutyCycle_perc = 0.0f,
107  .measurement.pwmSignal.frequency_Hz = 0.0f,
108  .periodTriggerTime_ms = IMD_PERIODIC_CALL_TIME_ms,
109 };
110 
111 /*========== Static Function Prototypes =====================================*/
112 /**
113  * @brief Determines frequency-dependent measurement state.
114  * @details Use of intervals because of measuring and signal inaccuracy. This
115  * interval is configurable via define #IR155_MEASUREMENT_INTERVAL_RANGE_Hz
116  * @param[in] frequency_Hz measured signal frequency in Hz
117  * @return #IR155_MEASUREMENT_MODE_e bender measurement mode
118  */
119 static IR155_MEASUREMENT_MODE_e IR155_GetMeasurementMode(float_t frequency_Hz);
120 
121 /**
122  * @brief Calculate insulation resistance from measured dutycycle.
123  * @details Function check, that passed duty-cycle lies within allowed range.
124  * Otherwise, the calculated resistance will be limited to the next
125  * reasonable value.
126  * @param[in] dutyCycle_perc measured signal duty-cycle in percentage
127  * @return measured insulation resistance in kOhm
128  */
129 static uint32_t IR155_CalculateResistance(float_t dutyCycle_perc);
130 
131 /**
132  * @brief Check if passed duty cycle is within interval limits
133  * @param[in] dutyCycle_perc measured signal duty-cycle in percentage
134  * @param[in] lowerLimit_perc lower interval limit
135  * @param[in] upperLimit_perc upper interval limit
136  * @return measured insulation resistance in kOhm
137  */
138 static bool IR155_IsDutyCycleWithinInterval(float_t dutyCycle_perc, float_t lowerLimit_perc, float_t upperLimit_perc);
139 
140 /*========== Static Function Implementations ================================*/
142  FAS_ASSERT(frequency_Hz >= 0.0f);
144 
145  if ((frequency_Hz >= IR155_NORMAL_CONDITION_LOWER_FREQUENCY_Hz) &&
147  retVal = IR155_NORMAL_MODE;
148  } else if (
149  (frequency_Hz >= IR155_UNDERVOLTAGE_LOWER_FREQUENCY_Hz) &&
150  (frequency_Hz < IR155_UNDERVOLTAGE_UPPER_FREQUENCY_Hz)) {
151  retVal = IR155_UNDERVOLTAGE_MODE; /* should not be detected as default threshold 0V, EOL Bender configurable! */
152  } else if (
153  (frequency_Hz >= IR155_SPEEDSTART_LOWER_FREQUENCY_Hz) && (frequency_Hz < IR155_SPEEDSTART_UPPER_FREQUENCY_Hz)) {
154  retVal = IR155_SPEEDSTART_MODE;
155  } else if (
156  (frequency_Hz >= IR155_IMD_DEVICE_ERROR_LOWER_FREQUENCY_Hz) &&
158  retVal = IR155_IMD_ERROR_MODE;
159  } else if (
160  (frequency_Hz >= IR155_GROUND_ERROR_LOWER_FREQUENCY_Hz) &&
161  (frequency_Hz < IR155_GROUND_ERROR_UPPER_FREQUENCY_Hz)) {
162  retVal = IR155_GROUNDERROR_MODE;
163  } else if (frequency_Hz <= IR155_MINIMUM_FREQUENCY_Hz) {
164  retVal = IR155_SHORT_CLAMP;
165  } else {
166  retVal = IR155_UNDEFINED_FREQUENCY;
167  }
168  return retVal;
169 }
170 
171 static uint32_t IR155_CalculateResistance(float_t dutyCycle_perc) {
172  FAS_ASSERT(dutyCycle_perc <= 100.0f);
173  FAS_ASSERT(dutyCycle_perc > 0.0f);
174 
175  float_t insulationResistance_kOhm = 0.0f;
176  if (dutyCycle_perc <= 5.0f) {
177  insulationResistance_kOhm = (float_t)IR155_MAXIMUM_INSULATION_RESISTANCE_kOhm;
178  } else if (dutyCycle_perc > 95.0f) {
179  insulationResistance_kOhm = (float_t)IR155_MINIMUM_INSULATION_RESISTANCE_kOhm;
180  } else {
181  insulationResistance_kOhm = ((90.0f * 1200.0f) / (dutyCycle_perc - 5.0f)) - 1200.0f;
182  }
183  return (uint32_t)insulationResistance_kOhm;
184 }
185 
186 static bool IR155_IsDutyCycleWithinInterval(float_t dutyCycle_perc, float_t lowerLimit_perc, float_t upperLimit_perc) {
187  bool retval = false;
188  if ((lowerLimit_perc < dutyCycle_perc) && (upperLimit_perc > dutyCycle_perc)) {
189  retval = true;
190  } else {
191  retval = false;
192  }
193  return retval;
194 }
195 
196 /*========== Extern Function Implementations ================================*/
197 
198 void IR155_Initialize(uint8_t triggerTime_ms) {
199  /* Timer peripheral initialization if not already done. */
200  if (false == PWM_IsEcapModuleInitialized()) {
201  PWM_Initialize(); /* TODO: split PWM_Init function in a dedicated function for ecap and etpwm module */
202  }
203 
204  /* Read non-volatile FRAM */
206 
207  /* Check grounderror flag */
209  /* GROUND ERROR occurred before shutting down */
211  } else {
212  /* Normal startup delay -> wait 2.2s until first measurement is trustworthy */
214  }
215 
216  ir155_state.periodTriggerTime_ms = triggerTime_ms;
218 }
219 
220 void IR155_Deinitialize(void) {
221  /* Reset cycle time */
223 
224  /* Reset timer duty cycle struct */
227 
229 
230  /* Set diagnosis message that measurement is not trustworthy */
231  /* TODO: do it really like this? DIAG_Handler(DIAG_CH_ISOMETER_MEAS_INVALID, DIAG_EVENT_NOK, 0); */
232 }
233 
235  /* Initialize struct */
236  IR155_MEASUREMENT_s measurementResult = {
237  .isMeasurementValid = false,
238  .isUndervoltageDetected = true,
239  .pwmSignal.dutyCycle_perc = 0.0f,
240  .pwmSignal.frequency_Hz = 0.0f,
241  .resistance_kOhm = 0u,
242  .digitalStatusPin = STD_PIN_UNDEFINED,
243  .measurementMode = IR155_UNKNOWN,
244  .measurementState = IR155_UNINITIALIZED,
245  };
246 
247  /* read value of Bender IR155 digital status pin (OHKS) */
249 
250  /* get duty-cycle and frequency from PWM input measurement */
251  measurementResult.pwmSignal = PWM_GetPwmData();
252 
253  /* TODO: How-to check valid data? */
254  bool isPwmMeasurementValid = true;
255  if (isPwmMeasurementValid == true) {
256  /* TODO: Throw error? */
257  isPwmMeasurementValid = true;
258  } else {
259  /* Invalid values measurement */
260 
261  /* Invalidate data? */
262  isPwmMeasurementValid = false;
263  }
264 
265  /* Get measurement mode */
266  if (isPwmMeasurementValid == true) {
267  measurementResult.measurementMode = IR155_GetMeasurementMode(measurementResult.pwmSignal.frequency_Hz);
268  } else {
269  measurementResult.measurementMode = IR155_UNKNOWN;
270  /* TODO: Throw what error? */
271  }
272 
273  switch (measurementResult.measurementMode) {
274  case IR155_NORMAL_MODE:
277  measurementResult.pwmSignal.dutyCycle_perc,
280  measurementResult.resistance_kOhm =
282  measurementResult.isMeasurementValid = true;
284  } else {
286  measurementResult.isMeasurementValid = false;
288  }
289  break;
290 
292  measurementResult.isUndervoltageDetected = false;
294  measurementResult.pwmSignal.dutyCycle_perc,
298  measurementResult.isMeasurementValid = true;
299  measurementResult.measurementState = IR155_RESISTANCE_ESTIMATION;
300  } else if (
302  measurementResult.pwmSignal.dutyCycle_perc,
306  measurementResult.isMeasurementValid = true;
307  measurementResult.measurementState = IR155_RESISTANCE_ESTIMATION;
308  } else {
310  measurementResult.isMeasurementValid = false;
312  }
313  break;
314 
316  measurementResult.isUndervoltageDetected = true;
318  measurementResult.pwmSignal.dutyCycle_perc,
321  measurementResult.resistance_kOhm =
323  measurementResult.isMeasurementValid = true;
325  } else {
326  measurementResult.isMeasurementValid = false;
329  }
330  break;
331 
333  measurementResult.isUndervoltageDetected = false;
336  measurementResult.pwmSignal.dutyCycle_perc,
339  /* Error detected and verified with duty cycle */
340  measurementResult.isMeasurementValid = true;
341  measurementResult.measurementState = IR155_IMD_ERROR_MEASUREMENT;
342  } else {
343  /* Error detected but invalid duty cycle */
345  measurementResult.isMeasurementValid = false;
346  }
347  break;
349  measurementResult.isUndervoltageDetected = false;
352  measurementResult.pwmSignal.dutyCycle_perc,
355  /* Error detected and verified with duty cycle */
356  measurementResult.isMeasurementValid = true;
357  measurementResult.measurementState = IR155_GROUND_ERROR_MODE;
358  } else {
359  /* Error detected but invalid duty cycle */
361  measurementResult.isMeasurementValid = false;
362  }
363  break;
364 
365  case IR155_SHORT_CLAMP:
366  measurementResult.isUndervoltageDetected = false;
368  measurementResult.measurementState = IR155_SIGNAL_SHORT;
369  measurementResult.isMeasurementValid = true;
370  break;
371 
372  default:
374  measurementResult.measurementState = IR155_MEASUREMENT_NOT_VALID;
375  measurementResult.isMeasurementValid = false;
376  break;
377  }
378 
379  return measurementResult;
380 }
381 
382 /*========== Externalized Static Function Implementations (Unit Test) =======*/
383 #ifdef UNITY_UNIT_TEST
384 #endif
Headers for the configuration for the insulation monitoring.
#define IR155_SPEEDSTART_LOWER_FREQUENCY_Hz
#define IR155_GROUND_ERROR_UPPER_FREQUENCY_Hz
#define IR155_UNDERVOLTAGE_LOWER_FREQUENCY_Hz
#define IR155_MINIMUM_FREQUENCY_Hz
#define IR155_STARTUP_TIME_ms
#define IR155_SPEEDSTART_UPPER_FREQUENCY_Hz
#define IR155_IMD_DEVICE_ERROR_LOWER_FREQUENCY_Hz
#define IR155_UNDERVOLTAGE_UPPER_FREQUENCY_Hz
#define IR155_IMD_DEVICE_ERROR_UPPER_FREQUENCY_Hz
#define IR155_WAIT_TIME_AFTER_GROUND_ERROR_ms
#define IR155_GROUND_ERROR_LOWER_FREQUENCY_Hz
#define IR155_NORMAL_CONDITION_UPPER_FREQUENCY_Hz
#define IR155_NORMAL_CONDITION_LOWER_FREQUENCY_Hz
#define IR155_DEVICE_ERROR_LOWER_DUTY_CYCLE_LIMIT_perc
static bool IR155_IsDutyCycleWithinInterval(float_t dutyCycle_perc, float_t lowerLimit_perc, float_t upperLimit_perc)
Check if passed duty cycle is within interval limits.
#define IR155_MAXIMUM_INSULATION_RESISTANCE_kOhm
#define IR155_SPEED_START_ESTIMATION_GOOD_UPPER_DUTY_CYCLE_LIMIT_perc
#define IR155_MINIMUM_INSULATION_RESISTANCE_kOhm
#define IR155_GROUND_ERROR_UPPER_DUTY_CYCLE_LIMIT_perc
#define IR155_NORMAL_MODE_LOWER_DUTY_CYCLE_LIMIT_perc
#define IR155_SPEED_START_ESTIMATION_BAD_UPPER_DUTY_CYCLE_LIMIT_perc
#define IR155_UNDERVOLTAGE_MODE_LOWER_DUTY_CYCLE_LIMIT_perc
#define IR155_SPEED_START_ESTIMATION_BAD_LOWER_DUTY_CYCLE_LIMIT_perc
#define IR155_DEVICE_ERROR_UPPER_DUTY_CYCLE_LIMIT_perc
void IR155_Initialize(uint8_t triggerTime_ms)
Software initialization of Timer-module.
void IR155_Deinitialize(void)
Software deinitialization of Timer-module.
static uint32_t IR155_CalculateResistance(float_t dutyCycle_perc)
Calculate insulation resistance from measured dutycycle.
#define IR155_GROUND_ERROR_LOWER_DUTY_CYCLE_LIMIT_perc
IR155_MEASUREMENT_s IR155_GetMeasurementValues(void)
Interface function which delivers the actual signal measurement (duty cyle) and evaluation....
#define IR155_NORMAL_MODE_UPPER_DUTY_CYCLE_LIMIT_perc
IR155_STATE_s ir155_state
#define IR155_UNDERVOLTAGE_MODE_UPPER_DUTY_CYCLE_LIMIT_perc
#define IR155_SPEED_START_ESTIMATION_GOOD_LOWER_DUTY_CYCLE_LIMIT_perc
static IR155_MEASUREMENT_MODE_e IR155_GetMeasurementMode(float_t frequency_Hz)
Determines frequency-dependent measurement state.
Headers for the configuration for the insulation monitoring.
@ IR155_NORMAL_MODE
@ IR155_UNDEFINED_FREQUENCY
@ IR155_SPEEDSTART_MODE
@ IR155_SHORT_CLAMP
@ IR155_IMD_ERROR_MODE
@ IR155_UNKNOWN
@ IR155_UNDERVOLTAGE_MODE
@ IR155_GROUNDERROR_MODE
@ IR155_SIGNAL_SHORT
@ IR155_GROUND_ERROR_MODE_UNKNOWN
@ IR155_UNINITIALIZED
@ IR155_IMD_ERROR_MEASUREMENT_UNKNOWN
@ IR155_UNDERVOLTAGE_MEASUREMENT_UNKNOWN
@ IR155_IMD_ERROR_MEASUREMENT
@ IR155_RESISTANCE_MEASUREMENT
@ IR155_RESISTANCE_ESTIMATION_UNKNOWN
@ IR155_RESISTANCE_ESTIMATION
@ IR155_MEASUREMENT_NOT_VALID
@ IR155_RESISTANCE_MEASUREMENT_UNKNOWN
@ IR155_UNDERVOLTAGE_MEASUREMENT
@ IR155_GROUND_ERROR_MODE
#define IR155_GET_DIGITAL_STATUS_PIN_STATE()
enum IR155_MEASUREMENT_MODE IR155_MEASUREMENT_MODE_e
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:254
FRAM_RETURN_TYPE_e FRAM_ReadData(FRAM_BLOCK_ID_e blockId)
Reads a variable from the FRAM.
Definition: fram.c:211
Header for the driver for the FRAM module.
FRAM_INSULATION_FLAG_s fram_insulationFlags
Definition: fram_cfg.c:79
@ FRAM_BLOCK_ID_INSULATION_FLAG
Definition: fram_cfg.h:111
@ STD_PIN_UNDEFINED
Definition: fstd_types.h:91
@ STD_PIN_LOW
Definition: fstd_types.h:89
#define IMD_PERIODIC_CALL_TIME_ms
Definition: imd.h:68
void PWM_Initialize(void)
Initializes the ETPWM and the ECAP module.
Definition: pwm.c:128
PWM_SIGNAL_s PWM_GetPwmData(void)
Get dutycycle and frequency of input PWM signal.
Definition: pwm.c:205
bool PWM_IsEcapModuleInitialized(void)
Get initialization state of ecap module.
Definition: pwm.c:201
IR155_MEASUREMENT_MODE_e measurementMode
STD_PIN_STATE_e digitalStatusPin
IR155_MEASUREMENT_STATE_e measurementState
uint16_t periodTriggerTime_ms
IR155_MEASUREMENT_s measurement
uint32_t timeUntilValidMeasurement_ms
float_t frequency_Hz
Definition: pwm.h:73
float_t dutyCycle_perc
Definition: pwm.h:72