foxBMS  1.6.0
The foxBMS Battery Management System API Documentation
pex.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 pex.c
44  * @author foxBMS Team
45  * @date 2021-08-02 (date of creation)
46  * @updated 2023-10-12 (date of last update)
47  * @version v1.6.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 #include <stdint.h>
63 
64 /*========== Macros and Definitions =========================================*/
65 /** PEX I2C interface */
66 #define PEX_I2C_INTERFACE (i2cREG1)
67 
68 /** Number of ports per register */
69 #define PEX_NR_OF_PORTS_PER_REGISTER (8u)
70 
71 /** Initial value: all 1 */
72 #define PEX_DEFAULT_VALUE_ALL_1 (0xFFu)
73 /** Initial value: all 0 */
74 #define PEX_DEFAULT_VALUE_ALL_0 (0x0u)
75 
76 /** Address of Input Port 0 register (port 1 is one higher, 0x1u) */
77 #define PEX_INPUT_PORT0_REGISTER_ADDRESS (0x0u)
78 /** Address of Output Port 0 register (port 1 is one higher, 0x3u) */
79 #define PEX_OUTPUT_PORT0_REGISTER_ADDRESS (0x2u)
80 /** Address of Polarity Inversion Port 0 register (port 1 is one higher, 0x5u) */
81 #define PEX_POL_INV_PORT0_REGISTER_ADDRESS (0x4u)
82 /** Address of Configuration Port 0 register (port 1 is one higher, 0x7u) */
83 #define PEX_DIRECTION_PORT0_REGISTER_ADDRESS (0x6u)
84 
85 /** Port expander pin polarity inversion in registers
86  * @{*/
87 #define PEX_PIN_POLARITY_RETAINED (0u)
88 #define PEX_PIN_POLARITY_INVERTED (1u)
89 /**@}*/
90 
91 /** Port expander pin direction configuration in registers
92  * @{*/
93 #define PEX_PIN_DIRECTION_OUTPUT (0u)
94 #define PEX_PIN_DIRECTION_INPUT (1u)
95 /**@}*/
96 
97 /*========== Static Constant and Variable Definitions =======================*/
98 /** I2C write buffer for PEX */
99 #pragma SET_DATA_SECTION(".sharedRAM")
100 static uint8_t pex_i2cDataWrite[3u] = {0};
101 static uint8_t pex_i2cDataRead[2u] = {0};
102 #pragma SET_DATA_SECTION()
103 
104 /**
105  * These variables are used to configure the port expanders (input, output,
106  * configuration) from external modules.
107  * @{
108  */
117 /**@}*/
118 
119 /** These local variables hold the state of the port expanders (input, output,
120  * configuration)
121  * @{
122  */
131 /**@}*/
132 
133 /*========== Extern Constant and Variable Definitions =======================*/
134 
135 /*========== Static Function Prototypes =====================================*/
136 
137 /**
138  * @brief reads input state of port expander pins over I2C.
139  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
140  */
141 static STD_RETURN_TYPE_e PEX_ReadInputs(void);
142 
143 /**
144  * @brief sets output state of port expander pins over I2C.
145  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
146  */
148 
149 /**
150  * @brief sets polarity inversion state of port expander pins over I2C.
151  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
152  */
154 
155 /**
156  * @brief sets direction of port expander pins over I2C.
157  * @return #STD_OK if I2C transmission ok, #STD_NOT_OK otherwise
158  */
160 
161 /**
162  * @brief copies values from the externally available variables to the
163  * local ones.
164  */
165 static void PEX_CopyToLocalVariable(void);
166 
167 /**
168  * @brief copies values from the local variables to the
169  * externally available ones.
170  */
171 static void PEX_GetFromLocalVariable(void);
172 
173 /*========== Static Function Implementations ================================*/
174 
176  STD_RETURN_TYPE_e retVal = STD_OK;
177 
178  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
179  /*
180  * Input Port 0 as address, next read register will be Input Port 1
181  * data sheet: Rev. 9 - 8 November 2017
182  * "After the first byte is read, additional bytes may be read but
183  * the data will now reflect the information in the other register in the pair.
184  * For example, if you read Input port 1, then the next byte read would be Input port 0."
185  */
187  pex_i2cDataRead[0u] = 0u;
188  pex_i2cDataRead[1u] = 0u;
189  STD_RETURN_TYPE_e i2cReadReturn =
191  if (i2cReadReturn == STD_NOT_OK) {
192  retVal = STD_NOT_OK;
193  } else {
196  }
197  }
198  return retVal;
199 }
200 
202  STD_RETURN_TYPE_e retVal = STD_OK;
203  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
204  /**
205  * Outport Port 0 as address, next read register will be Output Port 1
206  * data sheet: Rev. 9 - 8 November 2017
207  * Figure 10: one register pair can be written in one transaction
208  */
213  if (i2cWriteReturn == STD_NOT_OK) {
214  retVal = STD_NOT_OK;
215  }
216  }
217  return retVal;
218 }
219 
221  STD_RETURN_TYPE_e retVal = STD_OK;
222  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
223  /**
224  * Inversion Polarity Port 0 as address, next read register will be Inversion Polarity Port 1
225  * data sheet: Rev. 9 - 8 November 2017
226  * Figure 10: one register pair can be written in one transaction
227  */
232  if (i2cWriteReturn == STD_NOT_OK) {
233  retVal = STD_NOT_OK;
234  }
235  }
236  return retVal;
237 }
238 
240  STD_RETURN_TYPE_e retVal = STD_OK;
241  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
242  /**
243  * Direction Port 0 as address, next read register will be Direction Port 1
244  * data sheet: Rev. 9 - 8 November 2017
245  * Figure 10: one register pair can be written in one transaction
246  */
251  if (i2cWriteReturn == STD_NOT_OK) {
252  retVal = STD_NOT_OK;
253  }
254  }
255  return retVal;
256 }
257 
258 static void PEX_CopyToLocalVariable(void) {
260  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
267  }
269 }
270 
271 static void PEX_GetFromLocalVariable(void) {
273  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
276  }
278 }
279 
280 /*========== Extern Function Implementations ================================*/
281 
282 /**
283  * In the data sheet, pins are grouped in two sets, numbered from 00 to 07 and from 10 to 17.
284  * Each set is handled by a separate register, so pin 00 is numbered 0, pin 01 is numbered 01, ..,
285  * pin 07 is numbered 07. But also pin 10 is numbered 0, pin 11 is numbered 01, .., pin 17 is numbered 07.
286  * Using defines from 0 to 15, it is possible to get with pin number which register has to be addressed:
287  * 0 to 7 means register for 00 to 07, 8 to 15 means register for 10 to 17.
288  * Applying (pin%8) for 8 to 15 gives 0 to 7, so the numbering in register is obtained immediately.
289  */
290 extern void PEX_Initialize(void) {
291  for (uint8_t i = 0u; i < PEX_NR_OF_PORT_EXPANDERS; i++) {
292  /** Default state of output registers data sheet: Rev. 9 - 8 November 2017, Table 7 and 8 */
297  /**
298  * Default state of polarity inversion registers data sheet: Rev. 9 - 8 November 2017, Table 9 and 10
299  */
304  /** Default state of direction registers data sheet: Rev. 9 - 8 November 2017, Table 11 and 12 */
309  }
310 }
311 
312 extern void PEX_Trigger(void) {
314  uint32_t current_time = OS_GetTickCount();
315 
316  STD_RETURN_TYPE_e writeConfigDirectionReturn = PEX_WriteConfigDirection();
317  OS_DelayTaskUntil(&current_time, 2u);
318  STD_RETURN_TYPE_e writeConfigPolarityReturn = PEX_WriteConfigPolarity();
319  OS_DelayTaskUntil(&current_time, 2u);
320  STD_RETURN_TYPE_e readInputsReturn = PEX_ReadInputs();
321  OS_DelayTaskUntil(&current_time, 2u);
322  STD_RETURN_TYPE_e writeOutputsReturn = PEX_WriteOutputs();
323  OS_DelayTaskUntil(&current_time, 2u);
324 
325  /* notify diag if one of these functions failed, but continue normally */
326  if ((writeConfigDirectionReturn == STD_NOT_OK) || (writeConfigPolarityReturn == STD_NOT_OK) ||
327  (readInputsReturn == STD_NOT_OK) || (writeOutputsReturn == STD_NOT_OK)) {
329  } else {
331  }
332 
334 }
335 
336 extern void PEX_SetPin(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 void PEX_ResetPin(uint8_t portExpander, uint8_t pin) {
352  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
353  FAS_ASSERT(pin <= PEX_PIN17);
354 
355  if (pin <= PEX_PIN07) {
357  pex_outputPort0[portExpander] &= ~(PEX_PIN_HIGH << pin);
359  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
361  pex_outputPort1[portExpander] &= ~(PEX_PIN_HIGH << (pin % PEX_NR_OF_PORTS_PER_REGISTER));
363  }
364 }
365 
366 extern uint8_t PEX_GetPin(uint8_t portExpander, uint8_t pin) {
367  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
368  FAS_ASSERT(pin <= PEX_PIN17);
369 
370  uint8_t pinState = UINT8_MAX;
371 
372  if (pin <= PEX_PIN07) {
374  pinState = (pex_inputPort0[portExpander] >> pin) & 0x1u;
376  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
378  pinState = (pex_inputPort1[portExpander] >> (pin % PEX_NR_OF_PORTS_PER_REGISTER)) & 0x1u;
380  }
381 
382  if (pinState == 0u) {
383  pinState = PEX_PIN_LOW;
384  } else if (pinState == 1u) {
385  pinState = PEX_PIN_HIGH;
386  } else {
387  /* invalid pin state */
389  }
390 
391  return pinState;
392 }
393 
394 extern void PEX_SetPinDirectionInput(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_INPUT << pin;
402  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
406  }
407 }
408 
409 extern void PEX_SetPinDirectionOutput(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_configDirectionPort0[portExpander] &= ~(((~PEX_PIN_DIRECTION_OUTPUT) & 0x1u) << pin);
417  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
419  pex_configDirectionPort1[portExpander] &=
420  ~(((~PEX_PIN_DIRECTION_OUTPUT) & 0x1u) << (pin % PEX_NR_OF_PORTS_PER_REGISTER));
422  }
423 }
424 
425 extern void PEX_SetPinPolarityInverted(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_INVERTED << pin;
433  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
437  }
438 }
439 
440 extern void PEX_SetPinPolarityRetained(uint8_t portExpander, uint8_t pin) {
441  FAS_ASSERT(portExpander < PEX_NR_OF_PORT_EXPANDERS);
442  FAS_ASSERT(pin <= PEX_PIN17);
443 
444  if (pin <= PEX_PIN07) {
446  pex_configPolarityPort0[portExpander] &= ~(((~PEX_PIN_POLARITY_RETAINED) & 0x1u) << pin);
448  } else { /* pin is in range PEX_PIN10 to PEX_PIN17 */
450  pex_configPolarityPort1[portExpander] &=
453  }
454 }
455 
456 /*========== Externalized Static Function Implementations (Unit Test) =======*/
457 #ifdef UNITY_UNIT_TEST
458 #endif
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:246
Diagnosis driver header.
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:268
@ DIAG_EVENT_OK
Definition: diag_cfg.h:267
@ DIAG_SYSTEM
Definition: diag_cfg.h:280
@ DIAG_ID_I2C_PEX_ERROR
Definition: diag_cfg.h:255
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:255
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:129
STD_RETURN_TYPE_e
Definition: fstd_types.h:82
@ STD_NOT_OK
Definition: fstd_types.h:84
@ STD_OK
Definition: fstd_types.h:83
STD_RETURN_TYPE_e I2C_WriteReadDma(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytesWrite, uint8_t *writeData, uint32_t nrBytesRead, uint8_t *readData)
reads from an I2C slave, using DMA.
Definition: i2c.c:599
STD_RETURN_TYPE_e I2C_WriteDma(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytes, uint8_t *writeData)
writes to an I2C slave, no register address written first, using DMA.
Definition: i2c.c:510
Header for the driver for the I2C module.
Declaration of the OS wrapper interface.
void OS_DelayTaskUntil(uint32_t *pPreviousWakeTime, uint32_t milliseconds)
Delay a task until a specified time.
Definition: os_freertos.c:162
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:154
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:150
uint32_t OS_GetTickCount(void)
Returns OS based system tick value.
Definition: os_freertos.c:158
static uint8_t pex_configPolarityPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:113
#define PEX_PIN_POLARITY_RETAINED
Definition: pex.c:87
static uint8_t pex_inputPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:124
static STD_RETURN_TYPE_e PEX_WriteConfigPolarity(void)
sets polarity inversion state of port expander pins over I2C.
Definition: pex.c:220
static uint8_t pex_i2cDataWrite[3u]
Definition: pex.c:100
#define PEX_I2C_INTERFACE
Definition: pex.c:66
static uint8_t pex_configDirectionPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:130
#define PEX_PIN_POLARITY_INVERTED
Definition: pex.c:88
static uint8_t pex_inputPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:110
static uint8_t pex_inputPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:109
#define PEX_DIRECTION_PORT0_REGISTER_ADDRESS
Definition: pex.c:83
static void PEX_CopyToLocalVariable(void)
copies values from the externally available variables to the local ones.
Definition: pex.c:258
static STD_RETURN_TYPE_e PEX_WriteConfigDirection(void)
sets direction of port expander pins over I2C.
Definition: pex.c:239
static uint8_t pex_outputPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:112
static void PEX_GetFromLocalVariable(void)
copies values from the local variables to the externally available ones.
Definition: pex.c:271
uint8_t PEX_GetPin(uint8_t portExpander, uint8_t pin)
get pin state of port expander pins.
Definition: pex.c:366
static uint8_t pex_configDirectionPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:115
#define PEX_PIN_DIRECTION_INPUT
Definition: pex.c:94
static uint8_t pex_configPolarityPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:114
#define PEX_PIN_DIRECTION_OUTPUT
Definition: pex.c:93
void PEX_SetPin(uint8_t portExpander, uint8_t pin)
sets pin to high.
Definition: pex.c:336
void PEX_ResetPin(uint8_t portExpander, uint8_t pin)
sets pin to low.
Definition: pex.c:351
#define PEX_DEFAULT_VALUE_ALL_1
Definition: pex.c:72
static uint8_t pex_configDirectionPort1[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:116
void PEX_SetPinPolarityRetained(uint8_t portExpander, uint8_t pin)
sets pin polarity to retained.
Definition: pex.c:440
void PEX_SetPinDirectionOutput(uint8_t portExpander, uint8_t pin)
sets pin to input.
Definition: pex.c:409
#define PEX_POL_INV_PORT0_REGISTER_ADDRESS
Definition: pex.c:81
void PEX_SetPinPolarityInverted(uint8_t portExpander, uint8_t pin)
sets pin polarity to inverted.
Definition: pex.c:425
static STD_RETURN_TYPE_e PEX_WriteOutputs(void)
sets output state of port expander pins over I2C.
Definition: pex.c:201
static uint8_t pex_configPolarityPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:127
#define PEX_NR_OF_PORTS_PER_REGISTER
Definition: pex.c:69
void PEX_Initialize(void)
initialize local variable containing state of port expander.
Definition: pex.c:290
static uint8_t pex_outputPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:126
static uint8_t pex_outputPort0[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:111
static uint8_t pex_outputPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:125
void PEX_SetPinDirectionInput(uint8_t portExpander, uint8_t pin)
sets pin direction to input.
Definition: pex.c:394
#define PEX_OUTPUT_PORT0_REGISTER_ADDRESS
Definition: pex.c:79
#define PEX_INPUT_PORT0_REGISTER_ADDRESS
Definition: pex.c:77
static uint8_t pex_inputPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:123
static uint8_t pex_configDirectionPort0Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:129
static uint8_t pex_i2cDataRead[2u]
Definition: pex.c:101
static uint8_t pex_configPolarityPort1Local[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex.c:128
void PEX_Trigger(void)
implements reading/writing to the port expander registers.
Definition: pex.c:312
#define PEX_DEFAULT_VALUE_ALL_0
Definition: pex.c:74
static STD_RETURN_TYPE_e PEX_ReadInputs(void)
reads input state of port expander pins over I2C.
Definition: pex.c:175
Header for the driver for the NXP PCA9539 port expander module.
#define PEX_PIN_LOW
Definition: pex.h:67
#define PEX_PIN_HIGH
Definition: pex.h:68
const uint8_t pex_addressList[PEX_NR_OF_PORT_EXPANDERS]
Definition: pex_cfg.c:73
#define PEX_NR_OF_PORT_EXPANDERS
Definition: pex_cfg.h:70
#define PEX_PIN17
Definition: pex_cfg.h:97
#define PEX_PIN07
Definition: pex_cfg.h:89