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, &regVal );
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