Initial revision for MS5611_01BA03 variometer, spi interface.

MS5611_01BA03.cpp

Committer:
eseerge
Date:
2013-01-03
Revision:
0:4343d7e75385

File content as of revision 0:4343d7e75385:

/**
 * @author Sergii Doroshenko
 *
 * @section LICENSE
 *
 * Copyright (c) 2010 ARM Limited
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * MS5611_01BA03 Barometric Pressure Sensor, Variometer.
 *
 * Datasheet:
 *
 * http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
 */
 
#include "MS5611_01BA03.h"

extern Serial pc;

uint8_t MS5611_01BA03::baro_read_reg(char reg)
{
    uint8_t byte;
   
    ENABLE_BARO;
    spi_.write(reg);
    byte = spi_.write(0x00);
    DISABLE_BARO;

    return byte;
}

void MS5611_01BA03::baro_write_reg(uint8_t reg, uint8_t val)
{
    ENABLE_BARO;
    spi_.write(reg);
    spi_.write(val);
    DISABLE_BARO;
}

void MS5611_01BA03::ms5611_01ba_reset() {
    ENABLE_BARO;
    spi_.write(MS561101BA_RESET);
    wait(0.03);
    DISABLE_BARO;
}

static bool ms5611_01ba_crc(uint16_t* n_prom) {
    uint8_t cnt;                            // simple counter  
    uint16_t n_rem;                         // crc reminder 
    uint8_t crc_read;                       // original value of the crc 
    uint8_t  n_bit; 

    n_rem = 0x00; 
    crc_read = n_prom[7] & 0xF;             //save read CRC 
    n_prom[7]=(0xFFF0 & (n_prom[7]));       //CRC byte is replaced by 0 - 0xFF00 // but 4 bit CRC!!!!!!
    for (cnt = 0; cnt < 16; cnt++) {        // operation is performed on bytes 
        // choose LSB or MSB 
        if (cnt % 2 == 1) 
            n_rem ^= (uint16_t)((n_prom[cnt>>1]) & 0x00FF); 
        else 
            n_rem ^= (uint16_t) (n_prom[cnt>>1]>>8); 
            
        for (n_bit = 8; n_bit > 0; n_bit--) { 
            if (n_rem & (0x8000)) { 
                n_rem = (n_rem << 1) ^ 0x3000; 
            } 
            else { 
                n_rem = (n_rem << 1); 
            } 
        } 
    } 

    n_rem = (0x000F & (n_rem >> 12));   // final 4-bit reminder is CRC code 
    n_prom[7] = crc_read;               // restore the crc_read to its original place 

    return (crc_read == (n_rem ^ 0x00)) ;
}

static bool ms5611_01ba_crc2(uint16_t prom[]) {
    int32_t i, j;
    uint32_t res = 0;
    uint8_t crc = prom[7] & 0xF;
    prom[7] &= 0xFFF0;

    for (i = 0; i < 16; i++) {
        if (i & 1) 
            res ^= ((prom[i>>1]) & 0x00FF);
        else 
            res ^= (prom[i>>1]>>8);

        for (j = 8; j > 0; j--) {
            if (res & 0x8000) res ^= 0x1800;
            res <<= 1;
        }
    }
    prom[7] |= crc;

    return (crc == ((res >> 12) & 0xF)); 
}

void MS5611_01BA03::ms5611_01ba_readCalibration() {
    union { uint16_t val; uint8_t raw[2]; } data;
    uint8_t i;

    //read first prom settings
    for(i=0;i<8;i++) {
        ENABLE_BARO;
        spi_.write(0xA0+2*i);
        data.raw[1] = spi_.write(0x0);  // read a 16 bit register
        data.raw[0] = spi_.write(0x0);
        ms5611_01ba_ctx.c[i] = data.val;
        DISABLE_BARO;
        wait(0.01);
    }
}

bool MS5611_01BA03::init() {
    ms5611_01ba_reset();
    ms5611_01ba_readCalibration();
    wait(0.5);
    return true; //ms5611_01ba_crc(ms5611_01ba_ctx.c); 
}
 
// read uncompensated temperature value: send command first
void MS5611_01BA03::ms5611_01ba_UT_Start() {
    ENABLE_BARO;
    spi_.write(MS561101BA_TEMPERATURE + OSR);
    DISABLE_BARO;
} 

// read uncompensated pressure value: send command first
void MS5611_01BA03::ms5611_01ba_UP_Start() {
    ENABLE_BARO;
    spi_.write(MS561101BA_PRESSURE + OSR);
    DISABLE_BARO;
}

// read uncompensated pressure value: read result bytes
void MS5611_01BA03::ms5611_01ba_UP_Read() {
    ENABLE_BARO;
    spi_.write(0x0);
    ms5611_01ba_ctx.up.raw[2] = spi_.write(0x0);
    ms5611_01ba_ctx.up.raw[1] = spi_.write(0x0);
    ms5611_01ba_ctx.up.raw[0] = spi_.write(0x0);
    DISABLE_BARO;
}

// read uncompensated temperature value: read result bytes
void MS5611_01BA03::ms5611_01ba_UT_Read() {
    ENABLE_BARO;
    spi_.write(0x0);
    ms5611_01ba_ctx.ut.raw[2] = spi_.write(0x0);
    ms5611_01ba_ctx.ut.raw[1] = spi_.write(0x0);
    ms5611_01ba_ctx.ut.raw[0] = spi_.write(0x0);
    DISABLE_BARO;
}

void MS5611_01BA03::ms5611_01ba_Calculate() {
    int32_t temperature, off2 = 0, sens2 = 0, delt;

    int32_t dT   = ms5611_01ba_ctx.ut.val - ((uint32_t)ms5611_01ba_ctx.c[5] << 8);
    int64_t off  = ((uint32_t)ms5611_01ba_ctx.c[2] << 16) + (((int64_t)dT * ms5611_01ba_ctx.c[4]) >> 7);
    int64_t sens = ((uint32_t)ms5611_01ba_ctx.c[1] << 15) + (((int64_t)dT * ms5611_01ba_ctx.c[3]) >> 8);
    temperature  = 2000 + (((int64_t)dT * ms5611_01ba_ctx.c[6]) >> 23);

    if (temperature < 2000) { // temperature lower than 20st.C 
        delt = temperature - 2000;
        delt  = delt * delt;
        off2  = (5 * delt) >> 1; 
        sens2 = (5 * delt) >> 2; 
        if (temperature < -1500) { // temperature lower than -15st.C
            delt = temperature + 1500;
            delt = delt * delt;
            off2 += 7 * delt; 
            sens2 += (11 * delt) >> 1; 
        }
    } 
    off  -= off2; 
    sens -= sens2;
    pressure = (( (ms5611_01ba_ctx.up.val * sens ) >> 21) - off) >> 15;
}

MS5611_01BA03::MS5611_01BA03(PinName mosi, PinName miso, PinName sclk, PinName cs): spi_(mosi, miso, sclk) { 

    cs_ = new DigitalOut(cs);

    spi_.format(8,3);
    spi_.frequency(1000000); // default 1000000
    
    timer.start();
    
    altitude = 0;
}

MS5611_01BA03::~MS5611_01BA03() {
    timer.stop();
    delete(cs_);
    cs_ = NULL;
}

void MS5611_01BA03::ms5611_01ba_Update() {
    if (timer.read_us() < ms5611_01ba_ctx.deadline) return; 
    ms5611_01ba_ctx.deadline = timer.read_us();
    switch (ms5611_01ba_ctx.state) {
        case 0: 
            ms5611_01ba_UT_Start(); 
            ms5611_01ba_ctx.state++; 
            ms5611_01ba_ctx.deadline += 10000; //according to the specs, the pause should be at least 8.22ms
            break;
        case 1: 
            ms5611_01ba_UT_Read(); 
            ms5611_01ba_ctx.state++;
            break;
        case 2: 
            ms5611_01ba_UP_Start(); 
            ms5611_01ba_ctx.state++; 
            ms5611_01ba_ctx.deadline += 10000; //according to the specs, the pause should be at least 8.22ms
            break;
        case 3: 
            ms5611_01ba_UP_Read();
            ms5611_01ba_Calculate();
            altitude = (1.0f - pow((float)pressure/101325.0f, 0.190295f)) * 4433000.0f; //centimeter
     
            ms5611_01ba_ctx.state = 0; 
            ms5611_01ba_ctx.deadline += 4000;
        break;
    } 
}

int32_t MS5611_01BA03::getPressure() {
    return pressure;
}

int32_t MS5611_01BA03::getAltitude() {
    ms5611_01ba_Update();
    return altitude;
}