foxBMS  1.6.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-10-12 (date of last update)
47  * @version v1.6.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 =======================*/
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 duty cycle.
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_SPEED_START_LOWER_FREQUENCY_Hz) &&
154  (frequency_Hz < IR155_SPEED_START_UPPER_FREQUENCY_Hz)) {
155  retVal = IR155_SPEED_START_MODE;
156  } else if (
157  (frequency_Hz >= IR155_IMD_DEVICE_ERROR_LOWER_FREQUENCY_Hz) &&
159  retVal = IR155_IMD_ERROR_MODE;
160  } else if (
161  (frequency_Hz >= IR155_GROUND_ERROR_LOWER_FREQUENCY_Hz) &&
162  (frequency_Hz < IR155_GROUND_ERROR_UPPER_FREQUENCY_Hz)) {
163  retVal = IR155_GROUND_ERROR_MODE;
164  } else if (frequency_Hz <= IR155_MINIMUM_FREQUENCY_Hz) {
165  retVal = IR155_SHORT_CLAMP;
166  } else {
167  retVal = IR155_UNDEFINED_FREQUENCY;
168  }
169  return retVal;
170 }
171 
172 static uint32_t IR155_CalculateResistance(float_t dutyCycle_perc) {
173  FAS_ASSERT(dutyCycle_perc <= 100.0f);
174  FAS_ASSERT(dutyCycle_perc > 0.0f);
175 
176  float_t insulationResistance_kOhm = 0.0f;
177  if (dutyCycle_perc <= 5.0f) {
178  insulationResistance_kOhm = (float_t)IR155_MAXIMUM_INSULATION_RESISTANCE_kOhm;
179  } else if (dutyCycle_perc > 95.0f) {
180  insulationResistance_kOhm = (float_t)IR155_MINIMUM_INSULATION_RESISTANCE_kOhm;
181  } else {
182  insulationResistance_kOhm = ((90.0f * 1200.0f) / (dutyCycle_perc - 5.0f)) - 1200.0f;
183  }
184  return (uint32_t)insulationResistance_kOhm;
185 }
186 
187 static bool IR155_IsDutyCycleWithinInterval(float_t dutyCycle_perc, float_t lowerLimit_perc, float_t upperLimit_perc) {
188  bool retval = false;
189  if ((lowerLimit_perc < dutyCycle_perc) && (upperLimit_perc > dutyCycle_perc)) {
190  retval = true;
191  } else {
192  retval = false;
193  }
194  return retval;
195 }
196 
197 /*========== Extern Function Implementations ================================*/
198 
199 void IR155_Initialize(uint8_t triggerTime_ms) {
200  /* Timer peripheral initialization if not already done. */
201  if (false == PWM_IsEcapModuleInitialized()) {
202  PWM_Initialize(); /* TODO: split PWM_Init function in a dedicated function for ecap and etpwm module */
203  }
204 
205  /* Read non-volatile FRAM */
207 
208  /* Check ground error flag */
210  /* GROUND ERROR occurred before shutting down */
212  } else {
213  /* Normal startup delay -> wait 2.2s until first measurement is trustworthy */
215  }
216 
217  ir155_state.periodTriggerTime_ms = triggerTime_ms;
219 }
220 
221 void IR155_Deinitialize(void) {
222  /* Reset cycle time */
224 
225  /* Reset timer duty cycle struct */
228 
230 
231  /* Set diagnosis message that measurement is not trustworthy */
232  /* TODO: do it really like this? DIAG_Handler(DIAG_CH_ISOMETER_MEAS_INVALID, DIAG_EVENT_NOK, 0); */
233 }
234 
236  /* Initialize struct */
237  IR155_MEASUREMENT_s measurementResult = {
238  .isMeasurementValid = false,
239  .isUndervoltageDetected = true,
240  .pwmSignal.dutyCycle_perc = 0.0f,
241  .pwmSignal.frequency_Hz = 0.0f,
242  .resistance_kOhm = 0u,
243  .digitalStatusPin = STD_PIN_UNDEFINED,
244  .measurementMode = IR155_UNKNOWN,
245  .measurementState = IR155_UNINITIALIZED,
246  };
247 
248  /* read value of Bender IR155 digital status pin (OHKS) */
250 
251  /* get duty-cycle and frequency from PWM input measurement */
252  measurementResult.pwmSignal = PWM_GetPwmData();
253 
254  /* TODO: How-to check valid data? */
255  bool isPwmMeasurementValid = true;
256  if (isPwmMeasurementValid == true) {
257  /* TODO: Throw error? */
258  isPwmMeasurementValid = true;
259  } else {
260  /* Invalid values measurement */
261 
262  /* Invalidate data? */
263  isPwmMeasurementValid = false;
264  }
265 
266  /* Get measurement mode */
267  if (isPwmMeasurementValid == true) {
268  measurementResult.measurementMode = IR155_GetMeasurementMode(measurementResult.pwmSignal.frequency_Hz);
269  } else {
270  measurementResult.measurementMode = IR155_UNKNOWN;
271  /* TODO: Throw what error? */
272  }
273 
274  switch (measurementResult.measurementMode) {
275  case IR155_NORMAL_MODE:
278  measurementResult.pwmSignal.dutyCycle_perc,
281  measurementResult.resistance_kOhm =
283  measurementResult.isMeasurementValid = true;
285  } else {
287  measurementResult.isMeasurementValid = false;
289  }
290  break;
291 
293  measurementResult.isUndervoltageDetected = false;
295  measurementResult.pwmSignal.dutyCycle_perc,
299  measurementResult.isMeasurementValid = true;
300  measurementResult.measurementState = IR155_RESISTANCE_ESTIMATION;
301  } else if (
303  measurementResult.pwmSignal.dutyCycle_perc,
307  measurementResult.isMeasurementValid = true;
308  measurementResult.measurementState = IR155_RESISTANCE_ESTIMATION;
309  } else {
311  measurementResult.isMeasurementValid = false;
313  }
314  break;
315 
317  measurementResult.isUndervoltageDetected = true;
319  measurementResult.pwmSignal.dutyCycle_perc,
322  measurementResult.resistance_kOhm =
324  measurementResult.isMeasurementValid = true;
326  } else {
327  measurementResult.isMeasurementValid = false;
330  }
331  break;
332 
334  measurementResult.isUndervoltageDetected = false;
337  measurementResult.pwmSignal.dutyCycle_perc,
340  /* Error detected and verified with duty cycle */
341  measurementResult.isMeasurementValid = true;
342  measurementResult.measurementState = IR155_IMD_ERROR_MEASUREMENT;
343  } else {
344  /* Error detected but invalid duty cycle */
346  measurementResult.isMeasurementValid = false;
347  }
348  break;
350  measurementResult.isUndervoltageDetected = false;
353  measurementResult.pwmSignal.dutyCycle_perc,
356  /* Error detected and verified with duty cycle */
357  measurementResult.isMeasurementValid = true;
358  measurementResult.measurementState = IR155_GROUND_ERROR_STATE;
359  } else {
360  /* Error detected but invalid duty cycle */
362  measurementResult.isMeasurementValid = false;
363  }
364  break;
365 
366  case IR155_SHORT_CLAMP:
367  measurementResult.isUndervoltageDetected = false;
369  measurementResult.measurementState = IR155_SIGNAL_SHORT;
370  measurementResult.isMeasurementValid = true;
371  break;
372 
373  default:
375  measurementResult.measurementState = IR155_MEASUREMENT_NOT_VALID;
376  measurementResult.isMeasurementValid = false;
377  break;
378  }
379 
380  return measurementResult;
381 }
382 
383 /*========== Externalized Static Function Implementations (Unit Test) =======*/
384 #ifdef UNITY_UNIT_TEST
385 #endif
Headers for the configuration for the insulation monitoring.
#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_SPEED_START_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_SPEED_START_LOWER_FREQUENCY_Hz
#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 duty cycle.
#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_SPEED_START_MODE
@ IR155_SHORT_CLAMP
@ IR155_IMD_ERROR_MODE
@ IR155_UNKNOWN
@ IR155_UNDERVOLTAGE_MODE
@ IR155_GROUND_ERROR_MODE
@ IR155_SIGNAL_SHORT
@ 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_GROUND_ERROR_STATE_UNKNOWN
@ IR155_MEASUREMENT_NOT_VALID
@ IR155_RESISTANCE_MEASUREMENT_UNKNOWN
@ IR155_GROUND_ERROR_STATE
@ IR155_UNDERVOLTAGE_MEASUREMENT
#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:255
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