foxBMS - Unit Tests  1.4.0
The foxBMS Unit Tests API Documentation
pex.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2022, 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 pex.c
44  * @author foxBMS Team
45  * @date 2021-08-02 (date of creation)
46  * @updated 2022-07-28 (date of last update)
47  * @version v1.4.0
48  * @ingroup DRIVERS
49  * @prefix PEX
50  *
51  * @brief Driver for the NXP PCA9539 port expander module
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "pex.h"
57 
58 #include "diag.h"
59 #include "i2c.h"
60 #include "os.h"
61 
62 /*========== Macros and Definitions =========================================*/
63 /** Number of ports per register */
64 #define PEX_NR_OF_PORTS_PER_REGISTER (8u)
65 
66 /** Initial value: all 1 */
67 #define PEX_DEFAULT_VALUE_ALL_1 (0xFFu)
68 /** Initial value: all 0 */
69 #define PEX_DEFAULT_VALUE_ALL_0 (0x0u)
70 
71 /** Address of Input Port 0 register (port 1 is one higher, 0x1u) */
72 #define PEX_INPUT_PORT0_REGISTER_ADDRESS (0x0u)
73 /** Address of Output Port 0 register (port 1 is one higher, 0x3u) */
74 #define PEX_OUTPUT_PORT0_REGISTER_ADDRESS (0x2u)
75 /** Address of Polarity Inversion Port 0 register (port 1 is one higher, 0x5u) */
76 #define PEX_POL_INV_PORT0_REGISTER_ADDRESS (0x4u)
77 /** Address of Configuration Port 0 register (port 1 is one higher, 0x7u) */
78 #define PEX_DIRECTION_PORT0_REGISTER_ADDRESS (0x6u)
79 
80 /** Port expander pin polarity inversion in registers
81  * @{*/
82 #define PEX_PIN_POLARITY_RETAINED (0u)
83 #define PEX_PIN_POLARITY_INVERTED (1u)
84 /**@}*/
85 
86 /** Port expander pin direction configuration in registers
87  * @{*/
88 #define PEX_PIN_DIRECTION_OUTPUT (0u)
89 #define PEX_PIN_DIRECTION_INPUT (1u)
90 /**@}*/
91 
92 /*========== Static Constant and Variable Definitions =======================*/
93 /** I2C write buffer for PEX */
94 static uint8_t pex_i2cDataWrite[2u] = {0};
95 
96 /**
97  * These variables are used to configure the port expanders (input, output,
98  * configuration) from external modules.
99  * @{
100  */
109 /**@}*/
110 
111 /** These local variables hold the state of the port expanders (input, output,
112  * configuration)
113  * @{
114  */
123 /**@}*/
124 
125 /*========== Extern Constant and Variable Definitions =======================*/
126 
127 /*========== Static Function Prototypes =====================================*/
128 
129 /**
130  * @brief reads input state of port expander pins over I2C.
131  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
132  */
133 static STD_RETURN_TYPE_e PEX_ReadInputs(void);
134 
135 /**
136  * @brief sets output state of port expander pins over I2C.
137  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
138  */
140 
141 /**
142  * @brief sets polarity inversion state of port expander pins over I2C.
143  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
144  */
146 
147 /**
148  * @brief sets direction of port expander pins over I2C.
149  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
150  */
152 
153 /**
154  * @brief copies values from the externally available variables to the
155  * local ones.
156  */
157 static void PEX_CopyToLocalVariable(void);
158 
159 /**
160  * @brief copies values from the local variables to the
161  * externally available ones.
162  */
163 static void PEX_GetFromLocalVariable(void);
164 
165 /*========== Static Function Implementations ================================*/
166 
168  STD_RETURN_TYPE_e retVal = STD_OK;
169 
170  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
171  /*
172  * Input Port 0 as address, next read register will be Input Port 1
173  * data sheet: Rev. 9 - 8 November 2017
174  * "After the first byte is read, additional bytes may be read but
175  * the data will now reflect the information in the other register in the pair.
176  * For example, if you read Input port 1, then the next byte read would be Input port 0."
177  */
178  uint8_t pex_i2cDataRead[2u] = {0u, 0u};
179  STD_RETURN_TYPE_e i2cReadReturn =
181  if (i2cReadReturn == STD_NOT_OK) {
182  retVal = STD_NOT_OK;
183  } else {
184  pex_inputPort0Local[i] = pex_i2cDataRead[0u];
185  pex_inputPort1Local[i] = pex_i2cDataRead[1u];
186  }
187  }
188  return retVal;
189 }
190 
192  STD_RETURN_TYPE_e retVal = STD_OK;
193  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
194  /**
195  * Outport Port 0 as address, next read register will be Output Port 1
196  * data sheet: Rev. 9 - 8 November 2017
197  * Figure 10: one register pair can be written in one transaction
198  */
201  STD_RETURN_TYPE_e i2cWriteReturn =
203  if (i2cWriteReturn == STD_NOT_OK) {
204  retVal = STD_NOT_OK;
205  }
206  }
207  return retVal;
208 }
209 
211  STD_RETURN_TYPE_e retVal = STD_OK;
212  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
213  /**
214  * Inversion Polarity Port 0 as address, next read register will be Inversion Polarity Port 1
215  * data sheet: Rev. 9 - 8 November 2017
216  * Figure 10: one register pair can be written in one transaction
217  */
220  STD_RETURN_TYPE_e i2cWriteReturn =
222  if (i2cWriteReturn == STD_NOT_OK) {
223  retVal = STD_NOT_OK;
224  }
225  }
226  return retVal;
227 }
228 
230  STD_RETURN_TYPE_e retVal = STD_OK;
231  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
232  /**
233  * Direction Port 0 as address, next read register will be Direction Port 1
234  * data sheet: Rev. 9 - 8 November 2017
235  * Figure 10: one register pair can be written in one transaction
236  */
239  STD_RETURN_TYPE_e i2cWriteReturn =
241  if (i2cWriteReturn == STD_NOT_OK) {
242  retVal = STD_NOT_OK;
243  }
244  }
245  return retVal;
246 }
247 
248 static void PEX_CopyToLocalVariable(void) {
250  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
257  }
259 }
260 
261 static void PEX_GetFromLocalVariable(void) {
263  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
266  }
268 }
269 
270 /*========== Extern Function Implementations ================================*/
271 
272 /**
273  * In the data sheet, pins are grouped in two sets, numbered from 00 to 07 and from 10 to 17.
274  * Each set is handled by a separate register, so pin 00 is numbered 0, pin 01 is numbered 01, ..,
275  * pin 07 is numbered 07. But also pin 10 is numbered 0, pin 11 is numbered 01, .., pin 17 is numbered 07.
276  * Using defines from 0 to 15, it is possible to get with pin number which register has to be addressed:
277  * 0 to 7 means register for 00 to 07, 8 to 15 means register for 10 to 17.
278  * Applying (pin%8) for 8 to 15 gives 0 to 7, so the numbering in register is obtained immediately.
279  */
280 extern void PEX_Initialize(void) {
281  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
282  /** Default state of output registers data sheet: Rev. 9 - 8 November 2017, Table 7 and 8 */
287  /**
288  * Default state of polarity inversion registers data sheet: Rev. 9 - 8 November 2017, Table 9 and 10
289  */
294  /** Default state of direction registers data sheet: Rev. 9 - 8 November 2017, Table 11 and 12 */
299  }
300 }
301 
302 extern void PEX_Trigger(void) {
304 
305  STD_RETURN_TYPE_e writeConfigDirectionReturn = PEX_WriteConfigDirection();
306  STD_RETURN_TYPE_e writeConfigPolarityReturn = PEX_WriteConfigPolarity();
307  STD_RETURN_TYPE_e readInputsReturn = PEX_ReadInputs();
308  STD_RETURN_TYPE_e writeOutputsReturn = PEX_WriteOutputs();
309 
310  /* notify diag if one of these functions failed, but continue normally */
311  if ((writeConfigDirectionReturn == STD_NOT_OK) || (writeConfigPolarityReturn == STD_NOT_OK) ||
312  (readInputsReturn == STD_NOT_OK) || (writeOutputsReturn == STD_NOT_OK)) {
314  } else {
316  }
317 
319 }
320 
321 extern void PEX_SetPin(uint8_t portExpander, uint8_t pin) {
322  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
323  FAS_ASSERT(pin <= PEX_PIN17);
324 
325  if (pin <= PEX_PIN07) {
327  pex_outputPort0[portExpander] |= PEX_PIN_HIGH << pin;
329  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
331  pex_outputPort1[portExpander] |= PEX_PIN_HIGH << (pin % PEX_NR_OF_PORTS_PER_REGISTER);
333  }
334 }
335 
336 extern void PEX_ResetPin(uint8_t portExpander, uint8_t pin) {
337  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
338  FAS_ASSERT(pin <= PEX_PIN17);
339 
340  if (pin <= PEX_PIN07) {
342  pex_outputPort0[portExpander] &= ~(PEX_PIN_HIGH << pin);
344  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
346  pex_outputPort1[portExpander] &= ~(PEX_PIN_HIGH << (pin % PEX_NR_OF_PORTS_PER_REGISTER));
348  }
349 }
350 
351 extern uint8_t PEX_GetPin(uint8_t portExpander, uint8_t pin) {
352  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
353  FAS_ASSERT(pin <= PEX_PIN17);
354 
355  uint8_t pinState = UINT8_MAX;
356 
357  if (pin <= PEX_PIN07) {
359  pinState = (pex_inputPort0[portExpander] >> pin) & 0x1u;
361  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
363  pinState = (pex_inputPort1[portExpander] >> (pin % PEX_NR_OF_PORTS_PER_REGISTER)) & 0x1u;
365  }
366 
367  if (pinState == 0u) {
368  pinState = PEX_PIN_LOW;
369  } else if (pinState == 1u) {
370  pinState = PEX_PIN_HIGH;
371  } else {
372  /* invalid pin state */
374  }
375 
376  return pinState;
377 }
378 
379 extern void PEX_SetPinDirectionInput(uint8_t portExpander, uint8_t pin) {
380  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
381  FAS_ASSERT(pin <= PEX_PIN17);
382 
383  if (pin <= PEX_PIN07) {
385  pex_configDirectionPort0[portExpander] |= PEX_PIN_DIRECTION_INPUT << pin;
387  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
391  }
392 }
393 
394 extern void PEX_SetPinDirectionOutput(uint8_t portExpander, uint8_t pin) {
395  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
396  FAS_ASSERT(pin <= PEX_PIN17);
397 
398  if (pin <= PEX_PIN07) {
400  pex_configDirectionPort0[portExpander] &= ~(((~PEX_PIN_DIRECTION_OUTPUT) & 0x1u) << pin);
402  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
404  pex_configDirectionPort1[portExpander] &=
405  ~(((~PEX_PIN_DIRECTION_OUTPUT) & 0x1u) << (pin % PEX_NR_OF_PORTS_PER_REGISTER));
407  }
408 }
409 
410 extern void PEX_SetPinPolarityInverted(uint8_t portExpander, uint8_t pin) {
411  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
412  FAS_ASSERT(pin <= PEX_PIN17);
413 
414  if (pin <= PEX_PIN07) {
416  pex_configPolarityPort0[portExpander] |= PEX_PIN_POLARITY_INVERTED << pin;
418  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
422  }
423 }
424 
425 extern void PEX_SetPinPolarityRetained(uint8_t portExpander, uint8_t pin) {
426  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
427  FAS_ASSERT(pin <= PEX_PIN17);
428 
429  if (pin <= PEX_PIN07) {
431  pex_configPolarityPort0[portExpander] &= ~(((~PEX_PIN_POLARITY_RETAINED) & 0x1u) << pin);
433  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
435  pex_configPolarityPort1[portExpander] &=
438  }
439 }
440 
441 /*========== Getter for static Variables (Unit Test) ========================*/
442 #ifdef UNITY_UNIT_TEST
443 
444 #endif
445 
446 /*========== Externalized Static Function Implementations (Unit Test) =======*/
DIAG_RETURNTYPE_e DIAG_Handler(DIAG_ID_e diagId, DIAG_EVENT_e event, DIAG_IMPACT_LEVEL_e impact, uint32_t data)
DIAG_Handler provides generic error handling, based on diagnosis group.
Definition: diag.c:231
Diagnosis driver header.
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:239
@ DIAG_EVENT_OK
Definition: diag_cfg.h:238
@ DIAG_SYSTEM
Definition: diag_cfg.h:251
@ DIAG_ID_I2C_PEX_ERROR
Definition: diag_cfg.h:231
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:248
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:126
STD_RETURN_TYPE_e
Definition: fstd_types.h:81
@ STD_NOT_OK
Definition: fstd_types.h:83
@ STD_OK
Definition: fstd_types.h:82
STD_RETURN_TYPE_e I2C_Write(uint32_t slaveAddress, uint8_t writeAddress, uint32_t nrBytes, uint8_t *writeData)
writes to an I2C slave, blocking.
Definition: i2c.c:257
STD_RETURN_TYPE_e I2C_Read(uint32_t slaveAddress, uint8_t readAddress, uint32_t nrBytes, uint8_t *readData)
reads from an I2C slave, blocking.
Definition: i2c.c:79
Header for the driver for the I2C module.
Declaration of the OS wrapper interface.
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:135
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:131
static uint8_t pex_configPolarityPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:105
#define PEX_PIN_POLARITY_RETAINED
Definition: pex.c:82
static uint8_t pex_i2cDataWrite[2u]
Definition: pex.c:94
static uint8_t pex_inputPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:116
static STD_RETURN_TYPE_e PEX_WriteConfigPolarity(void)
sets polarity inversion state of port expander pins over I2C.
Definition: pex.c:210
static uint8_t pex_configDirectionPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:122
#define PEX_PIN_POLARITY_INVERTED
Definition: pex.c:83
static uint8_t pex_inputPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:102
static uint8_t pex_inputPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:101
#define PEX_DIRECTION_PORT0_REGISTER_ADDRESS
Definition: pex.c:78
static void PEX_CopyToLocalVariable(void)
copies values from the externally available variables to the local ones.
Definition: pex.c:248
static STD_RETURN_TYPE_e PEX_WriteConfigDirection(void)
sets direction of port expander pins over I2C.
Definition: pex.c:229
static uint8_t pex_outputPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:104
static void PEX_GetFromLocalVariable(void)
copies values from the local variables to the externally available ones.
Definition: pex.c:261
uint8_t PEX_GetPin(uint8_t portExpander, uint8_t pin)
get pin state of port expander pins.
Definition: pex.c:351
static uint8_t pex_configDirectionPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:107
#define PEX_PIN_DIRECTION_INPUT
Definition: pex.c:89
static uint8_t pex_configPolarityPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:106
#define PEX_PIN_DIRECTION_OUTPUT
Definition: pex.c:88
void PEX_SetPin(uint8_t portExpander, uint8_t pin)
sets pin to high.
Definition: pex.c:321
void PEX_ResetPin(uint8_t portExpander, uint8_t pin)
sets pin to low.
Definition: pex.c:336
#define PEX_DEFAULT_VALUE_ALL_1
Definition: pex.c:67
static uint8_t pex_configDirectionPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:108
void PEX_SetPinPolarityRetained(uint8_t portExpander, uint8_t pin)
sets pin polarity to retained.
Definition: pex.c:425
void PEX_SetPinDirectionOutput(uint8_t portExpander, uint8_t pin)
sets pin to input.
Definition: pex.c:394
#define PEX_POL_INV_PORT0_REGISTER_ADDRESS
Definition: pex.c:76
void PEX_SetPinPolarityInverted(uint8_t portExpander, uint8_t pin)
sets pin polarity to inverted.
Definition: pex.c:410
static STD_RETURN_TYPE_e PEX_WriteOutputs(void)
sets output state of port expander pins over I2C.
Definition: pex.c:191
static uint8_t pex_configPolarityPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:119
#define PEX_NR_OF_PORTS_PER_REGISTER
Definition: pex.c:64
void PEX_Initialize(void)
initialize local variable containing state of port expander.
Definition: pex.c:280
static uint8_t pex_outputPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:118
static uint8_t pex_outputPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:103
static uint8_t pex_outputPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:117
void PEX_SetPinDirectionInput(uint8_t portExpander, uint8_t pin)
sets pin direction to input.
Definition: pex.c:379
#define PEX_OUTPUT_PORT0_REGISTER_ADDRESS
Definition: pex.c:74
#define PEX_INPUT_PORT0_REGISTER_ADDRESS
Definition: pex.c:72
static uint8_t pex_inputPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:115
static uint8_t pex_configDirectionPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:121
static uint8_t pex_configPolarityPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:120
void PEX_Trigger(void)
implements reading/writing to the port expander registers.
Definition: pex.c:302
#define PEX_DEFAULT_VALUE_ALL_0
Definition: pex.c:69
static STD_RETURN_TYPE_e PEX_ReadInputs(void)
reads input state of port expander pins over I2C.
Definition: pex.c:167
Header for the driver for the NXP PCA9539 port expander module.
#define PEX_PIN_LOW
Definition: pex.h:65
#define PEX_PIN_HIGH
Definition: pex.h:66
const uint8_t pex_addressList[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex_cfg.c:71
#define PEX_NR_OF_PORT_EXPANDERS
Definition: pex_cfg.h:69
#define PEX_PIN17
Definition: pex_cfg.h:96
#define PEX_PIN07
Definition: pex_cfg.h:88