Subversion Repositories FlightCtrl

Rev

Blame | Last modification | View Log | RSS feed

/*
MS5611-01BA.cpp - Interfaces a Measurement Specialities MS5611-01BA with Arduino
See http://www.meas-spec.com/downloads/MS5611-01BA01.pdf for the device datasheet

Copyright (C) 2011 Fabio Varesano <fvaresano@yahoo.it>

Development of this code has been supported by the Department of Computer Science,
Universita' degli Studi di Torino, Italy within the Piemonte Project
http://www.piemonte.di.unito.it/


This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/


#include "MS561101BA.h"
#define EXTRA_PRECISION 5 // trick to add more precision to the pressure and temp readings

MS561101BA::MS561101BA() {
  ;
}

void MS561101BA::init(uint8_t address) {  
  _addr =  address;
 
  // disable internal pullups of the ATMEGA which Wire enable by default
  #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
    // deactivate internal pull-ups for twi
    // as per note from atmega8 manual pg167
    cbi(PORTC, 4);
    cbi(PORTC, 5);
  #else
    // deactivate internal pull-ups for twi
    // as per note from atmega128 manual pg204
    cbi(PORTD, 0);
    cbi(PORTD, 1);
  #endif
 
  reset(); // reset the device to populate its internal PROM registers
  delay(1000); // some safety time
  readPROM(); // reads the PROM into object variables for later use
}

float MS561101BA::getPressure(uint8_t OSR) {
  // see datasheet page 7 for formulas
  int64_t dT   = getDeltaTemp(OSR);
  int64_t off  = (((int64_t)_C[1]) << 16) + ((_C[3] * dT) >> 7);
  int64_t sens = (((int64_t)_C[0]) << 15) + ((_C[2] * dT) >> 8);
  return ((((rawPressure(OSR) * sens) >> 21) - off) >> (15-EXTRA_PRECISION)) / ((1<<EXTRA_PRECISION) * 100.0);
}

float MS561101BA::getTemperature(uint8_t OSR) {
  // see datasheet page 7 for formulas
  return ((1<<EXTRA_PRECISION)*2000l + ((getDeltaTemp(OSR) * _C[5]) >> (23-EXTRA_PRECISION))) / ((1<<EXTRA_PRECISION) * 100.0);
}

int64_t MS561101BA::getDeltaTemp(uint8_t OSR) {
  return rawTemperature(OSR) - (((int32_t)_C[4]) << 8);
}

int32_t MS561101BA::rawPressure(uint8_t OSR) {
  return doConversion(MS561101BA_D1 + OSR);
}

int32_t MS561101BA::rawTemperature(uint8_t OSR) {
  return doConversion(MS561101BA_D2 + OSR);
}


unsigned long MS561101BA::doConversion(uint8_t command) {
  unsigned long conversion = 0;
 
  // see page 11 of the datasheet
 
  // initialize pressure conversion
  Wire.beginTransmission(_addr);
  Wire.send(command);
  Wire.endTransmission();
 
  delay(10); // the conversion will take a time <= 9.04 ms to have the output ready
  // TODO: make the delay dependant on the OSR requested in the command
 
  // start read sequence
  Wire.beginTransmission(_addr);
  Wire.send(0);
  Wire.endTransmission();
 
  Wire.beginTransmission(_addr);
  Wire.requestFrom(_addr, (uint8_t) MS561101BA_D1D2_SIZE);
  if(Wire.available()) {
    conversion = Wire.receive() * 65536 + Wire.receive() * 256 + Wire.receive();
  }
  else {
    conversion = -1;
  }
 
  return conversion;
}


/**
 * Reads factory calibration and store it into object variables.
*/

int MS561101BA::readPROM() {
  for (int i=0;i<MS561101BA_PROM_REG_COUNT;i++) {
    Wire.beginTransmission(_addr);
    Wire.send(MS561101BA_PROM_BASE_ADDR + (i * MS561101BA_PROM_REG_SIZE));
    Wire.endTransmission();
   
    Wire.beginTransmission(_addr);
    Wire.requestFrom(_addr, (uint8_t) MS561101BA_PROM_REG_SIZE);
    if(Wire.available()) {
      _C[i] = Wire.receive() << 8 | Wire.receive();
     
      //DEBUG_PRINT(_C[i]);
    }
    else {
      return -1; // error reading the PROM or communicating with the device
    }
  }
  return 0;
}


/**
 * Send a reset command to the device. With the reset command the device
 * populates its internal registers with the values read from the PROM.
*/

void MS561101BA::reset() {
  Wire.beginTransmission(_addr);
  Wire.send(MS561101BA_RESET);
  Wire.endTransmission();
}