1 /*
2 * Copyright (c) 2023 Wuerth Elektronik eiSos GmbH & Co. KG
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Driver file for the WSEN-PDUS-25131308XXX01 sensor.
10 */
11
12 #include "WSEN_PDUS_25131308XXX01_hal.h"
13
14 #include <stdio.h>
15
16 #include <weplatform.h>
17
18 #define PDUS_BASE (uint64_t)2513130800000LL
19
20 /**
21 * @brief Default sensor interface configuration.
22 */
23 static WE_sensorInterface_t pdusDefaultSensorInterface = {
24 .sensorType = WE_PDUS,
25 .interfaceType = WE_i2c,
26 .options = {.i2c = {.address = PDUS_ADDRESS_I2C, .burstMode = 0, .protocol = WE_i2cProtocol_Raw, .useRegAddrMsbForMultiBytesRead = 0, .reserved = 0},
27 .spi = {.chipSelectPort = 0, .chipSelectPin = 0, .burstMode = 0, .reserved = 0},
28 .readTimeout = 1000,
29 .writeTimeout = 1000},
30 .handle = 0};
31
32 /**
33 * @brief Read data from sensor.
34 *
35 * Note that this sensor doesn't have any registers to request - it
36 * will simply send up to 4 bytes of data in response to any read
37 * request.
38 *
39 * @param[in] sensorInterface Pointer to sensor interface
40 * @param[in] numBytesToRead Number of bytes to be read
41 * @param[out] data Target buffer
42 * @return Error Code
43 */
PDUS_ReadReg(WE_sensorInterface_t * sensorInterface,uint16_t numBytesToRead,uint8_t * data)44 static inline int8_t PDUS_ReadReg(WE_sensorInterface_t* sensorInterface,
45 uint16_t numBytesToRead,
46 uint8_t *data)
47 {
48 /*
49 * Caution: This sensor uses 5V Vcc and logic levels.
50 * Level conversion to 3.3V is required to talk with a STM32 or any
51 * other 3.3V MCU.
52 * This sensor only supports I2C read operation and returns either
53 * 2 or 4 bytes when the sensor address is written to the I2C bus.
54 * Sending a register address is not required.
55 * The first 2 bytes returned are the raw pressure value and the next 2
56 * bytes are the raw temperature values.
57 *
58 * See chapter "reading digital output data" of the PDUS user manual for
59 * the protocol.
60 *
61 * 1st I2C master sends sensor's I2C address (PDUS_ADDRESS_I2C) with read
62 * bit set and waits for ACK by sensor.
63 * 2nd I2C master read either 2 or 4 bytes back from the sensor; the slave
64 * (sensor) will send up to 4 bytes.
65 * Master has to ACK each byte and provide clock.
66 */
67
68 return WE_ReadReg(sensorInterface, 0, numBytesToRead, data);
69 }
70
71 /**
72 * @brief Returns the default sensor interface configuration.
73 * @param[out] sensorInterface Sensor interface configuration (output parameter)
74 * @return Error code
75 */
PDUS_getDefaultInterface(WE_sensorInterface_t * sensorInterface)76 int8_t PDUS_getDefaultInterface(WE_sensorInterface_t* sensorInterface)
77 {
78 *sensorInterface = pdusDefaultSensorInterface;
79 return WE_SUCCESS;
80 }
81
82 /**
83 * @brief Read the raw pressure
84 * @param[in] sensorInterface Pointer to sensor interface
85 * @param[out] data Pointer to raw pressure value (unconverted), 15 bits
86 * @retval Error code
87 */
PDUS_getRawPressure(WE_sensorInterface_t * sensorInterface,uint16_t * pressure)88 int8_t PDUS_getRawPressure(WE_sensorInterface_t* sensorInterface, uint16_t *pressure)
89 {
90 uint8_t tmp[2] = {0};
91
92 if (WE_FAIL == PDUS_ReadReg(sensorInterface, 2, tmp))
93 {
94 return WE_FAIL;
95 }
96
97 *pressure = (uint16_t) ((tmp[0] & 0x7F) << 8);
98 *pressure |= (uint16_t) tmp[1];
99
100 return WE_SUCCESS;
101 }
102
103 /**
104 * @brief Read the raw pressure and temperature values
105 * @param[in] sensorInterface Pointer to sensor interface
106 * @param[out] pressure Pointer to raw pressure value (unconverted), 15 bits
107 * @param[out] temperature Pointer to raw temperature value (unconverted), 15 bits
108 * @retval Error code
109 */
PDUS_getRawPressureAndTemperature(WE_sensorInterface_t * sensorInterface,uint16_t * pressure,uint16_t * temperature)110 int8_t PDUS_getRawPressureAndTemperature(WE_sensorInterface_t* sensorInterface, uint16_t *pressure, uint16_t *temperature)
111 {
112 uint8_t tmp[4] = {0};
113
114 if (WE_FAIL == PDUS_ReadReg(sensorInterface, 4, tmp))
115 {
116 return WE_FAIL;
117 }
118
119 *pressure = (uint16_t) ((tmp[0] & 0x7F) << 8);
120 *pressure |= (uint16_t) tmp[1];
121
122 *temperature = (uint16_t) ((tmp[2] & 0x7F) << 8);
123 *temperature |= (uint16_t) tmp[3];
124
125 return WE_SUCCESS;
126 }
127
128 #ifdef WE_USE_FLOAT
129
130 /**
131 * @brief Read the pressure and temperature values
132 * @param[in] sensorInterface Pointer to sensor interface
133 * @param[in] type PDUS sensor type (i.e. pressure measurement range) for internal conversion of pressure, please refer to Article number mapping table
134 * @param[out] presskPa Pointer to pressure value
135 * @retval Error code
136 */
PDUS_getPressure_float(WE_sensorInterface_t * sensorInterface,PDUS_SensorType_t type,float * presskPa)137 int8_t PDUS_getPressure_float(WE_sensorInterface_t* sensorInterface, PDUS_SensorType_t type, float *presskPa)
138 {
139 uint16_t rawPres = 0;
140
141 if (WE_FAIL == PDUS_getRawPressure(sensorInterface, &rawPres))
142 {
143 return WE_FAIL;
144 }
145
146 if (rawPres < P_MIN_VAL_PDUS)
147 {
148 rawPres = P_MIN_VAL_PDUS;
149 }
150
151 /* Perform conversion (depending on sensor sub-type) */
152 return PDUS_convertPressureToFloat(type, rawPres, presskPa);
153 }
154
155 /**
156 * @brief Read the pressure and temperature values
157 * @param[in] sensorInterface Pointer to sensor interface
158 * @param[in] type PDUS sensor type (i.e. pressure measurement range) for internal conversion of pressure
159 * @param[out] presskPa Pointer to pressure value
160 * @param[out] tempDegC Pointer to temperature value
161 * @retval Error code
162 */
PDUS_getPressureAndTemperature_float(WE_sensorInterface_t * sensorInterface,PDUS_SensorType_t type,float * presskPa,float * tempDegC)163 int8_t PDUS_getPressureAndTemperature_float(WE_sensorInterface_t* sensorInterface, PDUS_SensorType_t type, float *presskPa, float *tempDegC)
164 {
165 uint16_t rawPres = 0;
166 uint16_t rawTemp = 0;
167
168 if (WE_FAIL == PDUS_getRawPressureAndTemperature(sensorInterface, &rawPres, &rawTemp))
169 {
170 return WE_FAIL;
171 }
172
173 /* Apply temperature offset to raw temperature and convert to °C */
174 *tempDegC = (((float) (rawTemp - T_MIN_VAL_PDUS) * 4.272f) / 1000);
175
176 /* Perform conversion regarding sensor sub-type */
177 return PDUS_convertPressureToFloat(type, rawPres, presskPa);
178 }
179
180 /**
181 * @brief Converts a raw pressure value to kPa, depending on the PDUS sensor type.
182 * @param[in] type PDUS sensor type (i.e. pressure measurement range)
183 * @param[in] rawPressure Raw pressure value as returned by the sensor
184 * @param[out] presskPa Pointer to pressure value
185 * @retval Error code
186 */
PDUS_convertPressureToFloat(PDUS_SensorType_t type,uint16_t rawPressure,float * presskPa)187 int8_t PDUS_convertPressureToFloat(PDUS_SensorType_t type, uint16_t rawPressure, float *presskPa)
188 {
189 float temp = (float) (rawPressure - P_MIN_VAL_PDUS);
190 switch (type)
191 {
192 case PDUS_pdus0:
193 *presskPa = ((temp * 7.63f) / 1000000) - 0.1f;
194 break;
195
196 case PDUS_pdus1:
197 *presskPa = ((temp * 7.63f) / 100000) - 1.0f;
198 break;
199
200 case PDUS_pdus2:
201 *presskPa = ((temp * 7.63f) / 10000) - 10.0f;
202 break;
203
204 case PDUS_pdus3:
205 *presskPa = ((temp * 3.815f) / 1000);
206 break;
207
208 case PDUS_pdus4:
209 *presskPa = ((temp * 4.196f) / 100) - 100.0f;
210 break;
211
212 case PDUS_pdus5:
213 *presskPa = ((temp * 5.722f) / 100);
214 break;
215
216 default:
217 return WE_FAIL;
218 }
219 return WE_SUCCESS;
220 }
221
222 #endif /* WE_USE_FLOAT */
223
224
225