1 /*!
2 * \file mpl3115.h
3 *
4 * \brief MPL3115 Temperature, pressure and altitude sensor driver implementation
5 *
6 * \copyright Revised BSD License, see section \ref LICENSE.
7 *
8 * \code
9 * ______ _
10 * / _____) _ | |
11 * ( (____ _____ ____ _| |_ _____ ____| |__
12 * \____ \| ___ | (_ _) ___ |/ ___) _ \
13 * _____) ) ____| | | || |_| ____( (___| | | |
14 * (______/|_____)_|_|_| \__)_____)\____)_| |_|
15 * (C)2013-2017 Semtech
16 *
17 * \endcode
18 *
19 * \author Miguel Luis ( Semtech )
20 *
21 * \author Gregory Cristian ( Semtech )
22 */
23 #include <stdbool.h>
24 #include "utilities.h"
25 #include "delay.h"
26 #include "i2c.h"
27 #include "mpl3115.h"
28
29 extern I2c_t I2c;
30
31 /*!
32 * I2C device address
33 */
34 static uint8_t I2cDeviceAddr = 0;
35
36 /*!
37 * Indicates if the MPL3115 is initialized or not
38 */
39 static bool MPL3115Initialized = false;
40
41 /*!
42 * Defines the barometric reading types
43 */
44 typedef enum
45 {
46 PRESSURE,
47 ALTITUDE,
48 }BarometerReadingType_t;
49
50 /*!
51 * \brief Writes a byte at specified address in the device
52 *
53 * \param [IN]: addr
54 * \param [IN]: data
55 *
56 * \retval status [LMN_STATUS_OK, LMN_STATUS_ERROR]
57 */
58 LmnStatus_t MPL3115Write( uint8_t addr, uint8_t data );
59
60 /*!
61 * \brief Writes a buffer at specified address in the device
62 *
63 * \param [IN]: addr
64 * \param [IN]: data
65 * \param [IN]: size
66 *
67 * \retval status [LMN_STATUS_OK, LMN_STATUS_ERROR]
68 */
69 LmnStatus_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
70
71 /*!
72 * \brief Reads a byte at specified address in the device
73 *
74 * \param [IN]: addr
75 * \param [OUT]: data
76 *
77 * \retval status [LMN_STATUS_OK, LMN_STATUS_ERROR]
78 */
79 LmnStatus_t MPL3115Read( uint8_t addr, uint8_t *data );
80
81 /*!
82 * \brief Reads a buffer at specified address in the device
83 *
84 * \param [IN]: addr
85 * \param [OUT]: data
86 * \param [IN]: size
87 *
88 * \retval status [LMN_STATUS_OK, LMN_STATUS_ERROR]
89 */
90 LmnStatus_t MPL3115ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
91
92 /*!
93 * \brief Sets the I2C device slave address
94 *
95 * \param [IN]: addr
96 */
97 void MPL3115SetDeviceAddr( uint8_t addr );
98
99 /*!
100 * \brief Gets the I2C device slave address
101 *
102 * \retval: addr Current device slave address
103 */
104 uint8_t MPL3115GetDeviceAddr( void );
105
106 /*!
107 * \brief Sets the device in barometer Mode
108 */
109 void MPL3115SetModeBarometer( void );
110
111 /*!
112 * \brief Sets the device in altimeter Mode
113 */
114 void MPL3115SetModeAltimeter( void );
115
116 /*!
117 * \brief Sets the device in standby
118 */
119 void MPL3115SetModeStandby( void );
120
121 /*!
122 * \brief Sets the device in active Mode
123 */
124 void MPL3115SetModeActive( void );
125
126 /*!
127 * \brief Toggles the OST bit causing the sensor to immediately take another
128 * reading
129 */
130 void MPL3115ToggleOneShot( void );
131
MPL3115Init(void)132 LmnStatus_t MPL3115Init( void )
133 {
134 uint8_t regVal = 0;
135
136 MPL3115SetDeviceAddr( MPL3115A_I2C_ADDRESS );
137
138 if( MPL3115Initialized == false )
139 {
140 MPL3115Write( CTRL_REG1, RST );
141 DelayMs( 50 );
142 I2cResetBus( &I2c );
143
144 // Check MPL3115 ID
145 MPL3115Read( MPL3115_ID, ®Val );
146 if( regVal != 0xC4 )
147 {
148 return LMN_STATUS_ERROR;
149 }
150
151 MPL3115Write( PT_DATA_CFG_REG, DREM | PDEFE | TDEFE ); // Enable data ready flags for pressure and temperature )
152 MPL3115Write( CTRL_REG1, ALT | OS_32 | SBYB ); // Set sensor to active state with oversampling ratio 128 (512 ms between samples)
153 MPL3115Initialized = true;
154 }
155 return LMN_STATUS_OK;
156 }
157
MPL3115Reset(void)158 LmnStatus_t MPL3115Reset( void )
159 {
160 // Reset all registers to POR values
161 if( MPL3115Write( CTRL_REG1, RST ) == LMN_STATUS_OK )
162 {
163 return LMN_STATUS_OK;
164 }
165 return LMN_STATUS_ERROR;
166 }
167
MPL3115Write(uint8_t addr,uint8_t data)168 LmnStatus_t MPL3115Write( uint8_t addr, uint8_t data )
169 {
170 return MPL3115WriteBuffer( addr, &data, 1 );
171 }
172
MPL3115WriteBuffer(uint8_t addr,uint8_t * data,uint8_t size)173 LmnStatus_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size )
174 {
175 return I2cWriteMemBuffer( &I2c, I2cDeviceAddr << 1, addr, data, size );
176 }
177
MPL3115Read(uint8_t addr,uint8_t * data)178 LmnStatus_t MPL3115Read( uint8_t addr, uint8_t *data )
179 {
180 return MPL3115ReadBuffer( addr, data, 1 );
181 }
182
MPL3115ReadBuffer(uint8_t addr,uint8_t * data,uint8_t size)183 LmnStatus_t MPL3115ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size )
184 {
185 return I2cReadMemBuffer( &I2c, I2cDeviceAddr << 1, addr, data, size );
186 }
187
MPL3115SetDeviceAddr(uint8_t addr)188 void MPL3115SetDeviceAddr( uint8_t addr )
189 {
190 I2cDeviceAddr = addr;
191 }
192
MPL3115GetDeviceAddr(void)193 uint8_t MPL3115GetDeviceAddr( void )
194 {
195 return I2cDeviceAddr;
196 }
197
MPL3115ReadBarometer(BarometerReadingType_t type)198 static float MPL3115ReadBarometer( BarometerReadingType_t type )
199 {
200 uint8_t counter = 0;
201 uint8_t tempBuf[3];
202 uint8_t msb = 0, csb = 0, lsb = 0;
203 uint8_t status = 0;
204
205 if( MPL3115Initialized == false )
206 {
207 return 0;
208 }
209
210 if( type == ALTITUDE )
211 {
212 MPL3115SetModeAltimeter( );
213 }
214 else
215 {
216 MPL3115SetModeBarometer( );
217 }
218
219 MPL3115ToggleOneShot( );
220
221 while( ( status & PDR ) != PDR )
222 {
223 MPL3115Read( STATUS_REG, &status );
224 DelayMs( 10 );
225 counter++;
226
227 if( counter > 20 )
228 {
229 MPL3115Initialized = false;
230 MPL3115Init( );
231 if( type == ALTITUDE )
232 {
233 MPL3115SetModeAltimeter( );
234 }
235 else
236 {
237 MPL3115SetModeBarometer( );
238 }
239 MPL3115ToggleOneShot( );
240 counter = 0;
241
242 while( ( status & PDR ) != PDR )
243 {
244 MPL3115Read( STATUS_REG, &status );
245 DelayMs( 10 );
246 counter++;
247
248 if( counter > 20 )
249 {
250 // Error out after max of 512 ms for a read
251 return 0;
252 }
253 }
254 }
255 }
256
257 MPL3115ReadBuffer( OUT_P_MSB_REG, tempBuf, 3 ); //Read altitude data
258
259 msb = tempBuf[0];
260 csb = tempBuf[1];
261 lsb = tempBuf[2];
262
263 if( type == ALTITUDE )
264 {
265 float altitude = 0;
266 float decimal = ( ( float )( lsb >> 4 ) ) / 16.0;
267 altitude = ( float )( ( int16_t )( ( msb << 8 ) | csb ) ) + decimal;
268 return( altitude );
269 }
270 else
271 {
272 float pressure = ( float )( ( msb << 16 | csb << 8 | lsb ) >> 6 );
273 lsb &= 0x30; // Bits 5/4 represent the fractional component
274 lsb >>= 4; // Get it right aligned
275 float decimal = ( ( float )lsb ) / 4.0;
276 pressure = pressure + decimal;
277 return( pressure );
278 }
279 }
280
MPL3115ReadAltitude(void)281 float MPL3115ReadAltitude( void )
282 {
283 return MPL3115ReadBarometer( ALTITUDE );
284 }
285
MPL3115ReadPressure(void)286 float MPL3115ReadPressure( void )
287 {
288 return MPL3115ReadBarometer( PRESSURE );
289 }
290
MPL3115ReadTemperature(void)291 float MPL3115ReadTemperature( void )
292 {
293 uint8_t counter = 0;
294 uint8_t tempBuf[2];
295 uint8_t msb = 0, lsb = 0;
296 bool negSign = false;
297 uint8_t val = 0;
298 float temperature = 0;
299 uint8_t status = 0;
300
301 if( MPL3115Initialized == false )
302 {
303 return 0;
304 }
305
306 MPL3115ToggleOneShot( );
307
308 while( ( status & TDR ) != TDR )
309 {
310 MPL3115Read( STATUS_REG, &status );
311 DelayMs( 10 );
312 counter++;
313
314 if( counter > 20 )
315 {
316 MPL3115Initialized = false;
317 MPL3115Init( );
318 MPL3115ToggleOneShot( );
319 counter = 0;
320
321 while( ( status & TDR ) != TDR )
322 {
323 MPL3115Read( STATUS_REG, &status );
324 DelayMs( 10 );
325 counter++;
326
327 if( counter > 20 )
328 {
329 // Error out after max of 512 ms for a read
330 return 0;
331 }
332 }
333 }
334 }
335
336 MPL3115ReadBuffer( OUT_T_MSB_REG, tempBuf, 2 );
337
338 msb = tempBuf[0];
339 lsb = tempBuf[1];
340
341 if( msb > 0x7F )
342 {
343 val = ~( ( msb << 8 ) + lsb ) + 1; // 2's complement
344 msb = val >> 8;
345 lsb = val & 0x00F0;
346 negSign = true;
347 }
348
349 if( negSign == true )
350 {
351 temperature = 0 - ( msb + ( float )( ( lsb >> 4 ) / 16.0 ) );
352 }
353 else
354 {
355 temperature = msb + ( float )( ( lsb >> 4 ) / 16.0 );
356 }
357
358 MPL3115ToggleOneShot( );
359
360 return( temperature );
361 }
362
MPL3115ToggleOneShot(void)363 void MPL3115ToggleOneShot( void )
364 {
365 uint8_t ctrlReg = 0;
366
367 MPL3115SetModeStandby( );
368
369 MPL3115Read( CTRL_REG1, &ctrlReg ); // Read current settings
370 ctrlReg &= ~OST; // Clear OST bit
371 MPL3115Write( CTRL_REG1, ctrlReg );
372
373 MPL3115Read( CTRL_REG1, &ctrlReg ); // Read current settings to be safe
374 ctrlReg |= OST; // Set OST bit
375 MPL3115Write( CTRL_REG1, ctrlReg );
376
377 MPL3115SetModeActive( );
378 }
379
MPL3115SetModeBarometer(void)380 void MPL3115SetModeBarometer( void )
381 {
382 uint8_t ctrlReg = 0;
383
384 MPL3115SetModeStandby( );
385
386 MPL3115Read( CTRL_REG1, &ctrlReg ); // Read current settings
387 ctrlReg &= ~ALT; // Set ALT bit to zero
388 MPL3115Write( CTRL_REG1, ctrlReg );
389
390 MPL3115SetModeActive( );
391 }
392
MPL3115SetModeAltimeter(void)393 void MPL3115SetModeAltimeter( void )
394 {
395 uint8_t ctrlReg = 0;
396
397 MPL3115SetModeStandby( );
398
399 MPL3115Read( CTRL_REG1, &ctrlReg ); // Read current settings
400 ctrlReg |= ALT; // Set ALT bit to one
401 MPL3115Write( CTRL_REG1, ctrlReg );
402
403 MPL3115SetModeActive( );
404 }
405
MPL3115SetModeStandby(void)406 void MPL3115SetModeStandby( void )
407 {
408 uint8_t ctrlReg = 0;
409
410 MPL3115Read( CTRL_REG1, &ctrlReg );
411 ctrlReg &= ~SBYB; // Clear SBYB bit for Standby mode
412 MPL3115Write( CTRL_REG1, ctrlReg );
413 }
414
MPL3115SetModeActive(void)415 void MPL3115SetModeActive( void )
416 {
417 uint8_t ctrlReg = 0;
418
419 MPL3115Read( CTRL_REG1, &ctrlReg );
420 ctrlReg |= SBYB; // Set SBYB bit for Active mode
421 MPL3115Write( CTRL_REG1, ctrlReg );
422 }
423