foxBMS-UnitTests  1.0.0
The foxBMS Unit Tests API Documentation
adc.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der
4  * angewandten Forschung e.V. All rights reserved.
5  *
6  * BSD 3-Clause License
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * We kindly request you to use one or more of the following phrases to refer
31  * to foxBMS in your hardware, software, documentation or advertising
32  * materials:
33  *
34  * ″This product uses parts of foxBMS®″
35  *
36  * ″This product includes parts of foxBMS®″
37  *
38  * ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file adc.c
44  * @author foxBMS Team
45  * @date 2019-01-07 (date of creation)
46  * @updated 2021-03-24 (date of last update)
47  * @ingroup DRIVERS
48  * @prefix ADC
49  *
50  * @brief Driver for the ADC module.
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "adc.h"
56 
57 #include "beta.h"
58 #include "database.h"
59 #include "epcos_b57251v5103j060.h"
60 #include "io.h"
61 #include "spi.h"
62 
63 /*========== Macros and Definitions =========================================*/
64 
65 /** scaling factor for the conversion of a measurement value to a temperature */
66 #define ADC_TEMPERATURE_FACTOR (10.0f)
67 
68 /**
69  * Type of temperature sensors
70  */
72  ADC0_TEMPERATURE_SENSOR, /*!< First ADC (ADC0) */
73  ADC1_TEMPERATURE_SENSOR, /*!< Second ADC (ADC1) */
75 
76 /*========== Static Constant and Variable Definitions =======================*/
77 
78 /**
79  * @brief describes the current state of the conversion
80  * @details This variable is used as a state-variable for switching through the
81  * steps of a conversion.
82  */
83 static uint8_t adc_conversionState = ADC_INIT;
84 
85 /** NULL command sent to initialize the ADC */
86 static uint16_t adc_txNull[SINGLE_MESSAGE_LENGTH] = {0x0000u, 0x0000u};
87 
88 /**
89  * Unlock command for the ADC
90  * When ADC is locked, regsiters cannot be written
91  */
92 static uint16_t adc_txUnlockCommand[SINGLE_MESSAGE_LENGTH] = {0x0655u, 0x0000u};
93 
94 /**
95  * Lock command the ADC
96  * When ADC is locked, regsiters cannot be written
97  */
98 static uint16_t adc_txLockCommand[SINGLE_MESSAGE_LENGTH] = {0x0555u, 0x0000u};
99 
100 /** The wake-up command starts the conversions by the ADC */
101 static uint16_t adc_txWakeupCommand[SINGLE_MESSAGE_LENGTH] = {0x0033u, 0x0000u};
102 
103 /** This command is used to read registers */
104 static uint16_t adc_txReadRegisterCommand[SINGLE_MESSAGE_LENGTH] = {0x2F00u, 0x0000u};
105 
106 /** This command is used to write registers */
107 static uint16_t adc_txWriteRegisterCommand[SINGLE_MESSAGE_LENGTH] = {0x4F0Fu, 0x0000u};
108 
109 /**
110  * This is a generic purpose receive buffer.
111  * It is used to read the answer of the ADC to the commands
112  * defined above.
113  */
114 static uint16_t adc_rxReadSingleMessage[SINGLE_MESSAGE_LENGTH] = {0x0000u, 0x0000u};
115 
116 /**
117  * This message is used to read conversion results
118  * It consists of NULL commands. When receiving NULL commands,
119  * the ADC outputs conversion data on the MasterInSlaveOut line.
120  */
121 static uint16_t adc_txConvert[CONVERT_LENGTH] =
122  {0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u};
123 
124 /** This message is used to get the result of conversions */
125 static uint16_t adc_rxConvert[CONVERT_LENGTH] =
126  {0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u};
127 
128 /** Voltages measured by the 4 channels of ADC0 */
129 static float adc_adc0Voltage[4] = {0.0f, 0.0f, 0.0f, 0.0f};
130 /** Voltages measured by the 4 channels of ADC1 */
131 static float adc_adc1Voltage[4] = {0.0f, 0.0f, 0.0f, 0.0f};
132 /** LSB of ADC0, used to convert raw measurement to voltage in V */
133 static float adc_lsb1 = 0.0f;
134 /** LSB of ADC1, used to convert raw measurement to voltage in V */
135 static float adc_lsb2 = 0.0f;
136 
137 /** local copy of the adc temperature table */
139 
140 /*========== Extern Constant and Variable Definitions =======================*/
141 
142 /*========== Static Function Prototypes =====================================*/
143 
144 /** transmission wrapper for the SPI communication to the ADC */
146  uint32 blocksize,
147  uint16 *pTxBuffer,
148  uint16 *pRxBuffer,
149  SPI_INTERFACE_CONFIG_s *pSpiInterface);
150 
151 /**
152  * @brief converts a raw voltage from ADC to a temperature value in Celsius.
153  *
154  * The temperatures are read from NTC elements via voltage dividers.
155  * This function implements the look-up table between voltage and temperature,
156  * taking into account the NTC characteristics and the voltage divider.
157  *
158  * @param v_adc_V voltage read from ADC in V
159  * @param TsensorType sensor type, dependent on ADC used (ADC0 or ADC1)
160  *
161  * @return temperature value in deci &deg;C
162  */
163 static float ADC_ConvertVoltagesToTemperatures(float v_adc_V, ADC_TEMPERATURE_SENSOR_TYPE_e TsensorType);
164 
165 /*========== Static Function Implementations ================================*/
166 
168  uint32 blocksize,
169  uint16 *pTxBuffer,
170  uint16 *pRxBuffer,
171  SPI_INTERFACE_CONFIG_s *pSpiInterface) {
172  FAS_ASSERT(pTxBuffer != NULL_PTR);
173  FAS_ASSERT(pRxBuffer != NULL_PTR);
174  FAS_ASSERT(pSpiInterface != NULL_PTR);
175 
176  return SPI_TransmitReceiveData(pSpiInterface, pTxBuffer, pRxBuffer, blocksize);
177 }
178 
179 static float ADC_ConvertVoltagesToTemperatures(float v_adc_V, ADC_TEMPERATURE_SENSOR_TYPE_e TsensorType) {
180  float temperature_degC = 0.0f;
181  if (TsensorType == ADC0_TEMPERATURE_SENSOR) {
182  temperature_degC = ADC_TEMPERATURE_FACTOR * TS_Epc00GetTemperatureFromLut((uint16_t)(v_adc_V * 1000.0f));
183  } else if (TsensorType == ADC1_TEMPERATURE_SENSOR) {
184  temperature_degC = ADC_TEMPERATURE_FACTOR * BETA_GetTemperatureFromBeta((uint16_t)(v_adc_V * 1000.0f));
185  } else {
186  temperature_degC = ADC_TEMPERATURE_FACTOR * v_adc_V;
187  }
188 
189  return (10.0f * temperature_degC); /* Convert to deci &deg;C */
190 }
191 
192 /*========== Extern Function Implementations ================================*/
193 
194 void ADC_Initialize(void) {
195  /* set reset pin to output */
196  ADC_HET1_GIO->DIR |= (uint32)((uint32)1u << ADC_HET1_RESET_PIN);
197 
198  /* first set reset pin to 0 */
199  IO_PinReset((uint32_t *)&ADC_HET1_GIO->DOUT, ADC_HET1_RESET_PIN);
200  /* wait after pin toggle */
201  for (uint8_t i = 0u; i < 20u; i++) {
202  }
203  /* set reset pin to 1 to go out of reset */
204  IO_PinSet((uint32_t *)&ADC_HET1_GIO->DOUT, ADC_HET1_RESET_PIN);
205 
206  /* LSB computation, datasheet equation 9 page 38 */
207  adc_lsb1 = (2 * ADC_VREF_1 / ADC_GAIN) / (16777216.0f);
208  adc_lsb2 = (2 * ADC_VREF_2 / ADC_GAIN) / (16777216.0f);
209 }
210 
211 void ADC_Control(void) {
212  switch (adc_conversionState) {
213  case ADC_INIT:
214  /* set reset pin to output */
215  ADC_HET1_GIO->DIR |= (uint32)((uint32)1u << ADC_HET1_RESET_PIN);
216  /* first set reset pin to 0 */
217  IO_PinReset((uint32_t *)&ADC_HET1_GIO->DOUT, ADC_HET1_RESET_PIN);
219  break;
220 
221  case ADC_ENDINIT:
222  /* set reset pin to 1 to go out of reset */
223  IO_PinSet((uint32_t *)&ADC_HET1_GIO->DOUT, ADC_HET1_RESET_PIN);
224  /* LSB computation, datasheet equation 9 page 38 */
225  adc_lsb1 = (2 * ADC_VREF_1 / ADC_GAIN) / (16777216.0f);
226  adc_lsb2 = (2 * ADC_VREF_2 / ADC_GAIN) / (16777216.0f);
228  break;
229 
230  /* Start initialization procedure, datasheet figure 106 page 79 */
231  case ADC_READY:
233  /* if device 1 is ready after startup */
234  if (adc_rxReadSingleMessage[0] == 0xFF04u) {
236  /* if device 2 is ready after startup */
237  if (adc_rxReadSingleMessage[0] == 0xFF04u) {
239  }
240  }
241  break;
242 
243  case ADC_UNLOCK:
247  break;
248 
249  case ADC_UNLOCKED:
251  /* if unlock message received by ADC 1*/
252  if (adc_rxReadSingleMessage[0] == 0x0655u) {
254  /* if unlock message received by ADC 2*/
255  if (adc_rxReadSingleMessage[0] == 0x0655u) {
257  }
258  }
259  break;
260 
261  case ADC_WRITE_ADC_ENA:
262  ADC_Transmit(
264  ADC_Transmit(
267  break;
268 
269  case ADC_READ_ADC_ENA:
273  break;
274 
275  case ADC_CHECK_ADC_ENA:
276  /* If register not written successfully, retry */
279  /* if ADC 1 register written successfully */
280  if ((adc_rxReadSingleMessage[0] & 0xFFu) == 0x0Fu) {
282  /* if ADC 1 register written successfully */
283  if ((adc_rxReadSingleMessage[0] & 0xFFu) == 0x0Fu) {
285  }
286  }
287  break;
288 
289  case ADC_WAKEUP:
293  break;
294 
295  case ADC_LOCK:
299  break;
300  /* end initialization procedure, datasheet figure 106 page 79 */
301 
302  /* To read channel data (i.e., measured voltages), send null message */
303  case ADC_CONVERT_1:
304  /* The first 3 voltages are the NTCs located on the master board */
306  for (uint8_t i = 0u; i < ADC_NUMBER_OF_CHANNELS; i++) {
307  /* datasheet SBAS590D -MARCH 2016-REVISED JANUARY 2018 */
308  /* ADC in 32 bit mode (M1 tied to IOVDD via 1kOhm), 24 bits output by ADC, datasheet page 38 */
309  adc_adc0Voltage[i] = (adc_rxConvert[2u + (2u * i)] << 8u) |
310  ((adc_rxConvert[3u + (2u * i)] >> 8u) & 0xFFu);
312  }
315  for (uint8_t i = 0u; i < BS_NR_OF_TEMP_SENSORS_ON_ADC0; i++) {
318  }
320  break;
321 
322  case ADC_CONVERT_2:
323  /* The first 3 voltages are the external NTCs connected to the master board */
325  for (uint8_t i = 0u; i < ADC_NUMBER_OF_CHANNELS; i++) {
326  /* ADC in 32 bit mode (M1 tied to IOVDD via 1kOhm), 24 bits output by ADC, datasheet page 38 */
327  adc_adc1Voltage[i] = (adc_rxConvert[2u + (2u * i)] << 8u) |
328  ((adc_rxConvert[3u + (2u * i)] >> 8u) & 0xFFu);
330  }
333  for (uint8_t i = 0u; i < BS_NR_OF_TEMP_SENSORS_ON_ADC1; i++) {
336  }
338  break;
339 
340  default:
341  /* invalid state */
343  break;
344  }
345 }
346 
347 /*========== Externalized Static Function Implementations (Unit Test) =======*/
DATA_BLOCK_ADC_TEMPERATURE::header
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:148
BS_NR_OF_TEMP_SENSORS_ON_ADC0
#define BS_NR_OF_TEMP_SENSORS_ON_ADC0
Definition: battery_system_cfg.h:161
adc_lsb2
static float adc_lsb2
Definition: adc.c:135
ADC0_TEMPERATURE_SENSOR
@ ADC0_TEMPERATURE_SENSOR
Definition: adc.c:72
TS_Epc00GetTemperatureFromLut
int16_t TS_Epc00GetTemperatureFromLut(uint16_t adcVoltage_mV)
returns temperature based on measured ADC voltage
Definition: epcos_b57251v5103j060.c:145
spi_adc0Interface
SPI_INTERFACE_CONFIG_s spi_adc0Interface
Definition: spi_cfg.c:190
ADC_Control
void ADC_Control(void)
determines which ADC is measured and stores result in database.
Definition: adc.c:211
DATA_BLOCK_ADC_TEMPERATURE::temperatureAdc0_ddegC
int16_t temperatureAdc0_ddegC[BS_NR_OF_TEMP_SENSORS_ON_ADC0]
Definition: database_cfg.h:149
STD_RETURN_TYPE_e
enum STD_RETURN_TYPE STD_RETURN_TYPE_e
ADC_HET1_GIO
#define ADC_HET1_GIO
Definition: adc.h:68
spi.h
Headers for the driver for the SPI module.
adc_txWakeupCommand
static uint16_t adc_txWakeupCommand[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:101
ADC_Transmit
static STD_RETURN_TYPE_e ADC_Transmit(uint32 blocksize, uint16 *pTxBuffer, uint16 *pRxBuffer, SPI_INTERFACE_CONFIG_s *pSpiInterface)
Definition: adc.c:167
DATA_BLOCK_ADC_TEMPERATURE
Definition: database_cfg.h:144
DATA_WRITE_DATA
#define DATA_WRITE_DATA(...)
Definition: database.h:82
epcos_b57251v5103j060.h
Resistive divider used for measuring temperature.
ADC_CONVERT_1
@ ADC_CONVERT_1
Definition: adc.h:103
adc.h
Headers for the driver for the ADC module.
ADC_ConvertVoltagesToTemperatures
static float ADC_ConvertVoltagesToTemperatures(float v_adc_V, ADC_TEMPERATURE_SENSOR_TYPE_e TsensorType)
converts a raw voltage from ADC to a temperature value in Celsius.
Definition: adc.c:179
adc_txUnlockCommand
static uint16_t adc_txUnlockCommand[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:92
adc_conversionState
static uint8_t adc_conversionState
describes the current state of the conversion
Definition: adc.c:83
adc_txWriteRegisterCommand
static uint16_t adc_txWriteRegisterCommand[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:107
ADC_WRITE_ADC_ENA
@ ADC_WRITE_ADC_ENA
Definition: adc.h:98
ADC_VREF_2
#define ADC_VREF_2
Definition: adc.h:75
ADC_ENDINIT
@ ADC_ENDINIT
Definition: adc.h:94
ADC_INIT
@ ADC_INIT
Definition: adc.h:93
ADC_VREF_1
#define ADC_VREF_1
Definition: adc.h:73
ADC_TEMPERATURE_SENSOR_TYPE
ADC_TEMPERATURE_SENSOR_TYPE
Definition: adc.c:71
ADC_WAKEUP
@ ADC_WAKEUP
Definition: adc.h:101
FAS_ASSERT
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:233
ADC_UNLOCK
@ ADC_UNLOCK
Definition: adc.h:96
adc_txLockCommand
static uint16_t adc_txLockCommand[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:98
SPI_TransmitReceiveData
STD_RETURN_TYPE_e SPI_TransmitReceiveData(SPI_INTERFACE_CONFIG_s *pSpiInterface, uint16 *pTxBuff, uint16 *pRxBuff, uint32 frameLength)
Transmits and receives data on SPI without DMA.
Definition: spi.c:138
ADC_Initialize
void ADC_Initialize(void)
initializes the ADC devices. It is called during startup.
Definition: adc.c:194
adc_rxReadSingleMessage
static uint16_t adc_rxReadSingleMessage[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:114
DATA_BLOCK_ID_ADC_TEMPERATURE
@ DATA_BLOCK_ID_ADC_TEMPERATURE
Definition: database_cfg.h:101
SPI_INTERFACE_CONFIG
Definition: spi_cfg.h:107
ADC_CONVERT_2
@ ADC_CONVERT_2
Definition: adc.h:104
adc_rxConvert
static uint16_t adc_rxConvert[CONVERT_LENGTH]
Definition: adc.c:125
spi_adc1Interface
SPI_INTERFACE_CONFIG_s spi_adc1Interface
Definition: spi_cfg.c:199
ADC_NUMBER_OF_CHANNELS
#define ADC_NUMBER_OF_CHANNELS
Definition: adc.h:87
ADC_LOCK
@ ADC_LOCK
Definition: adc.h:102
adc_txNull
static uint16_t adc_txNull[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:86
IO_PinReset
void IO_PinReset(uint32_t *pRegisterAddress, uint32_t pin)
Set pin by writing in pin output register.
Definition: io.c:79
DATA_READ_DATA
#define DATA_READ_DATA(...)
Definition: database.h:72
adc_lsb1
static float adc_lsb1
Definition: adc.c:133
database.h
Database module header.
NULL_PTR
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:66
ADC_READY
@ ADC_READY
Definition: adc.h:95
io.h
Header for the driver for the IO module.
adc_txReadRegisterCommand
static uint16_t adc_txReadRegisterCommand[SINGLE_MESSAGE_LENGTH]
Definition: adc.c:104
BS_NR_OF_TEMP_SENSORS_ON_ADC1
#define BS_NR_OF_TEMP_SENSORS_ON_ADC1
Definition: battery_system_cfg.h:163
ADC_READ_ADC_ENA
@ ADC_READ_ADC_ENA
Definition: adc.h:99
ADC1_TEMPERATURE_SENSOR
@ ADC1_TEMPERATURE_SENSOR
Definition: adc.c:73
ADC_TEMPERATURE_FACTOR
#define ADC_TEMPERATURE_FACTOR
Definition: adc.c:66
ADC_CHECK_ADC_ENA
@ ADC_CHECK_ADC_ENA
Definition: adc.h:100
adc_txConvert
static uint16_t adc_txConvert[CONVERT_LENGTH]
Definition: adc.c:121
adc_adc1Voltage
static float adc_adc1Voltage[4]
Definition: adc.c:131
DATA_BLOCK_ADC_TEMPERATURE::temperatureAdc1_ddegC
int16_t temperatureAdc1_ddegC[BS_NR_OF_TEMP_SENSORS_ON_ADC1]
Definition: database_cfg.h:150
ADC_TEMPERATURE_SENSOR_TYPE_e
enum ADC_TEMPERATURE_SENSOR_TYPE ADC_TEMPERATURE_SENSOR_TYPE_e
CONVERT_LENGTH
#define CONVERT_LENGTH
Definition: adc.h:85
IO_PinSet
void IO_PinSet(uint32_t *pRegisterAddress, uint32_t pin)
Set pin by writing in pin output register.
Definition: io.c:72
FAS_TRAP
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:108
ADC_UNLOCKED
@ ADC_UNLOCKED
Definition: adc.h:97
SINGLE_MESSAGE_LENGTH
#define SINGLE_MESSAGE_LENGTH
Definition: adc.h:83
ADC_GAIN
#define ADC_GAIN
Definition: adc.h:77
BETA_GetTemperatureFromBeta
int16_t BETA_GetTemperatureFromBeta(uint16_t adcVoltage_mV)
returns temperature based on measured ADC voltage
Definition: beta.c:95
adc_tableTemperature
static DATA_BLOCK_ADC_TEMPERATURE_s adc_tableTemperature
Definition: adc.c:138
ADC_HET1_RESET_PIN
#define ADC_HET1_RESET_PIN
Definition: adc.h:70
adc_adc0Voltage
static float adc_adc0Voltage[4]
Definition: adc.c:129
beta.h
Resistive divider used for measuring temperature.
DATA_BLOCKHEADER::uniqueId
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:109