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