libpropeller
Making PropellerGCC Easier
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
ms5611.h
Go to the documentation of this file.
1 #ifndef LIBPROPELLER_MS5611_H_
2 #define LIBPROPELLER_MS5611_H_
3 
4 #include <propeller.h>
5 #include "libpropeller/i2c/i2c.h"
6 
7 #ifdef UNIT_TEST
8 #undef UNIT_TEST
9 #define UNIT_TEST_
10 #endif
12 #ifdef UNIT_TEST_
13 #define UNIT_TEST
14 #endif
15 
23 class MS5611 {
24 public:
25 
28  enum AddressLSB {
30  };
31 
35  MS5611(){
36  bus_ = NULL;
37  status_ = false;
38  }
39 
51  bool Init(I2C * newbus, const AddressLSB address = LSB_0) {
52 
53  SetAddress(address);
54 
55  bus_ = newbus;
56 
57  GetStatus();
58  if (status_ == false) {
59  return false;
60  }
61 
62  static const char kPROMRead [] = {
63  0b10100000, // 16 bit reserved for manufacturer
64  0b10100010, // C1
65  0b10100100, // C2
66  0b10100110, // C3
67  0b10101000, // C4
68  0b10101010, // C5
69  0b10101100, // C6
70  0b10101110 // CRC
71  };
72 
73 
74  D1_ = 0; // Pressure
75  D2_ = 0; // Temperature
76 
77  //Read PROM here
78  int C[6];
79  for (int i = 0; i < 6; i++) {
80  char data[2];
81  bus_->Put(device_address, kPROMRead[i + 1]);
82  bus_->Get(device_address, data, 2);
83  C[i] = data[0] << 8 | data[1];
84 
85  }
86  SetC(C[0], C[1], C[2], C[3], C[4], C[5]);
87 
88  convertingTemperature_ = true;
89  bus_->Put(device_address, kConvertD2OSR4096);
90 
91  newData_ = false;
92 
93  timer.Start();
94 
95  return status_;
96  }
97 
112  bool Touch(void) {
113  if (timer.GetElapsed() < 9) {
114  return false;
115  }
116 
117  //Read ADC on MS5611, and get whatever it was converting.
118  char data[3];
119 
120  bus_->Put(device_address, kADCRead);
121 
122  bus_->Get(device_address, data, 3);
123  int reading = ExpandReading(data);
124  newData_ = true;
125 
126  timer.Start();
127 
128 
129  if (convertingTemperature_) {
130  D2_ = reading;
131  //Set ADC to convert pressure
132  bus_->Put(device_address, kConvertD1OSR4096);
133 
134  convertingTemperature_ = false;
135  return false;
136  } else {
137  D1_ = reading;
138  //Set ADC to convert temperature
139  bus_->Put(device_address, kConvertD2OSR4096);
140 
141  convertingTemperature_ = true;
142  return true;
143  }
144  }
145 
161  void Get(int & tPressure, int & tTemperature,
162  const bool calibrationCalculation = true) {
163 
164  if (calibrationCalculation == true) {
165  if (newData_) {
166  Calculate();
167  }
168  tPressure = pressure_;
169  tTemperature = temperature_;
170  newData_ = false;
171  } else {
172  tPressure = D1_;
173  tTemperature = D2_;
174  }
175  }
176 
180  bool GetStatus(void) {
181  if (bus_ == NULL) {
182  status_ = false;
183  } else {
184  status_ = bus_->Ping(device_address);
185  }
186  return status_;
187  }
188 
194  bool Reset(void) {
195  return bus_->Put(device_address, kReset);
196  }
197 private:
198 
208  void SetC(const int newC1, const int newC2, const int newC3,
209  const int newC4, const int newC5, const int newC6) {
210  C1_ = ((int64_t) newC1) << 15;
211  C2_ = ((int64_t) newC2) << 16;
212  C3_ = (int64_t) newC3;
213  C4_ = (int64_t) newC4;
214 
215  C5_ = newC5 << 8;
216  C6_ = newC6;
217  }
218 
228  void GetC(int & oldC1, int & oldC2, int & oldC3,
229  int & oldC4, int & oldC5, int & oldC6) {
230  oldC1 = (int) (C1_ >> 15);
231  oldC2 = (int) (C2_ >> 16);
232  oldC3 = (int) C3_;
233  oldC4 = (int) C4_;
234  oldC5 = C5_ >> 8;
235  oldC6 = C6_;
236  }
237 
243  void TEST_SetD(const int newD1, const int newD2) {
244  D1_ = newD1;
245  D2_ = newD2;
246  newData_ = true;
247  }
248 
249  void Calculate(void) {
250  //These equations are straight from the MS5611 datasheet.
251  int dT = D2_ - C5_;
252  temperature_ = 2000 + ((dT * C6_) >> 23);
253 
254  int64_t T2 = 0;
255  int64_t OFF2 = 0;
256  int64_t SENS2 = 0;
257 
258  if (temperature_ < 2000) {
259 
260  int64_t dT64 = dT;
261 
262  T2 = (dT64 * dT64) >> 31;
263  OFF2 = (5 * (temperature_ - 2000) * (temperature_ - 2000)) >> 1;
264  SENS2 = OFF2 >> 1;
265 
266  if (temperature_ < -1500) { //Very low temperature
267  OFF2 = OFF2 + (7 * (temperature_ + 1500) * (temperature_ + 1500));
268  SENS2 = SENS2 + ((11 * (temperature_ + 1500) * (temperature_ + 1500)) >> 1);
269  }
270  }
271 
272 
273  int64_t OFF = C2_ + ((C4_ * dT) >> 7);
274  int64_t SENS = C1_ + ((C3_ * dT) >> 8);
275 
276  temperature_ = temperature_ - T2;
277  OFF = OFF - OFF2;
278  SENS = SENS - SENS2;
279 
280  pressure_ = (int) ((((((int64_t) D1_) * SENS) >> 21) - OFF) >> 15);
281  }
282 
283  int ExpandReading(const char data[]) const {
284  //MS5611 returns a 24 bit unsigned number.
285  return data[0] << 16 | data[1] << 8 | data[2];
286  }
287 
288  I2C * bus_;
289  Stopwatch timer;
290 
291  // These variables are straight from the MS5611 datasheet.
292  int64_t C1_, C2_, C3_, C4_;
293  int C5_, C6_;
294 
295  int D1_, D2_;
296  int temperature_, pressure_;
297 
298  bool newData_;
299  bool convertingTemperature_;
300  bool status_;
301 
302  //unsigned int conversionValidCNT_;
303 
304 
305  const static char kConvertD1OSR4096 = 0x48; //D1 is the pressure value
306  const static char kConvertD2OSR4096 = 0x58; //D2 is the temperature value
307  const static char kADCRead = 0x00;
308  const static char kReset = 0b00011110;
309 
310  unsigned char device_address;
311 
312  void SetAddress(const AddressLSB address) {
313  if (address == LSB_0) {
314  device_address = 0b11101100;
315  } else if (address == LSB_1) {
316  device_address = 0b11101110;
317  }
318  }
319 
320 
321 public:
322  friend class UnityTests;
323 
324 };
325 
326 #endif // LIBPROPELLER_MS5611_H_