A compilation of some hardware sensors and their shared programming interfaces.

MAG3110.cpp

Committer:
mgottscho
Date:
2014-03-19
Revision:
1:15396cab58d1
Parent:
0:8d34cc2ff388

File content as of revision 1:15396cab58d1:

/* MAG3110.cpp
 * Tested with mbed board: FRDM-KL46Z
 * Author: Mark Gottscho
 * mgottscho@ucla.edu
 */
 
#include "mbed.h"
#include "I2CSensor.h"
#include "PeriodicSensor.h"
#include "MAG3110.h"

using namespace std;

MAG3110::MAG3110(PinName sda, PinName scl, int i2c_addr) : 
                                    I2CSensor(sda, scl, i2c_addr),
                                    PeriodicSensor(0.05), //default max sampling rate of 20Hz
                                    __x(0),
                                    __y(0),
                                    __z(0),
                                    __active(false),
                                    __adc_rate(adc_smpl_rate_t(0)),
                                    __ratio(oversmpl_ratio_t(0)),
                                    __rate(smpl_rate_t(0))
                                    {
}

MAG3110::~MAG3110() {}

void MAG3110::selfInit() {
    __i2c.frequency(400000);
    setOutputSamplingParameters(HZ80, O16, NULL);
    
    //Enable auto magnetic sensor reset before each sample, as recommended in the datasheet
    uint8_t data = getRegister(CTRL_REG2);
    data |= CTRL_REG2_AUTO_MRST_EN_MASK; //Set the AUTO_MRST_EN bit
    setRegister(CTRL_REG2, data);
}

uint8_t MAG3110::whoAmI() {
    return getRegister(WHO_AM_I);
}
        
uint8_t MAG3110::getDataRegisterStatus() {
    return getRegister(DR_STATUS);      
}

uint8_t MAG3110::getSystemMode() {
    return getRegister(SYSMOD);       
}

bool MAG3110::isActive() {
    return (bool) (getRegister(CTRL_REG1) & 0x01);
}

void MAG3110::setActive(bool activate) {
    uint8_t data;
    data = getRegister(CTRL_REG1);
    if (activate)
        data |= CTRL_REG1_AC_MASK; //Set bit
    else
        data &= ~CTRL_REG1_AC_MASK; //Clear bit
    setRegister(CTRL_REG1, data);
    __active = activate;
}


void MAG3110::getOutputSamplingParameters(smpl_rate_t *rate, oversmpl_ratio_t *ratio, adc_smpl_rate_t *adc_rate) {
    if (rate != NULL)
        *rate = __rate;
    if (ratio != NULL)
        *ratio = __ratio;
    if (ratio != NULL)
        *adc_rate = __adc_rate;
}


bool MAG3110::setOutputSamplingParameters(smpl_rate_t rate, oversmpl_ratio_t ratio, adc_smpl_rate_t *adc_rate) {
    uint8_t dr;
    uint8_t os;
    adc_smpl_rate_t tmp_adc_rate;
    
    switch (rate) {
        default:
        case HZ80:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ1280;
                    dr = 0;
                    os = 0;
                    break;
                //Other rate-ratio combinations are illegal
                default:
                    return false;
            }
            break;
        
        case HZ40:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ640;
                    dr = 1;
                    os = 0;
                    break;
                case O32:
                    tmp_adc_rate = AHZ1280;
                    dr = 0;
                    os = 1;
                    break;
                //Other rate-ratio combinations are illegal
                default:
                    return false; 
            }  
            break;
        
        case HZ20:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ320;
                    dr = 2;
                    os = 0;
                    break;
                case O32: 
                    tmp_adc_rate = AHZ640;
                    dr = 1;
                    os = 1;
                    break;
                case O64:
                    tmp_adc_rate = AHZ1280;
                    dr = 0;
                    os = 2;
                    break;
                //Other rate-ratio combinations are illegal
                default:
                    return false;
            }
            break;
            
        case HZ10:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ160;
                    dr = 3;
                    os = 0;
                    break;
                case O32:
                    tmp_adc_rate = AHZ320;
                    dr = 2;
                    os = 1;
                    break;
                case O64:
                    tmp_adc_rate = AHZ640;
                    dr = 1;
                    os = 2;
                    break;
                case O128:
                    tmp_adc_rate = AHZ1280;
                    dr = 0;
                    os = 3;
                    break;
                //This should be impossible
                default:
                    return false;     
            }
            break;
        
        case HZ5:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ80;
                    dr = 4;
                    os = 0;
                    break;
                case O32:
                    tmp_adc_rate = AHZ160;
                    dr = 3;
                    os = 1;
                    break;
                case O64:
                    tmp_adc_rate = AHZ320;
                    dr = 2;
                    os = 2;
                    break;
                case O128:
                    tmp_adc_rate = AHZ640;
                    dr = 1;
                    os = 3;
                    break;
                //This should be impossible
                default:
                    return false;  
            }
            break;
            
        case HZ2_5:
            switch (ratio) {
                case O16:
                    tmp_adc_rate = AHZ80;
                    dr = 5;
                    os = 0;
                    break;
                case O32:
                    tmp_adc_rate = AHZ80;
                    dr = 4;
                    os = 1;
                    break;
                case O64:
                    tmp_adc_rate = AHZ160;
                    dr = 3;
                    os = 2;
                    break;
                case O128:
                    tmp_adc_rate = AHZ320;
                    dr = 2;
                    os = 3;
                    break;
                //This should be impossible
                default:
                    return false;
            }
            break;
            
            case HZ1_25:
                switch (ratio) {
                    case O16:
                        tmp_adc_rate = AHZ80;
                        dr = 6;
                        os = 0;
                        break;
                    case O32:
                        tmp_adc_rate = AHZ80;
                        dr = 5;
                        os = 1;
                        break;
                    case O64:
                        tmp_adc_rate = AHZ80;
                        dr = 4;
                        os = 2;
                        break;
                    case O128:
                        tmp_adc_rate = AHZ160;
                        dr = 3;
                        os = 3;
                        break;
                    //This should be impossible
                    default:
                        return false;   
                }
                break;
            
            case HZ0_63:
                switch (ratio) {
                    case O16:
                        tmp_adc_rate = AHZ80;
                        dr = 7;
                        os = 0;
                        break;
                    case O32:
                        tmp_adc_rate = AHZ80;
                        dr = 6;
                        os = 1;
                        break;
                    case O64:
                        tmp_adc_rate = AHZ80;
                        dr = 5;
                        os = 2;
                        break;
                    case O128:
                        tmp_adc_rate = AHZ80;
                        dr = 4;
                        os = 3;
                        break;
                    //This should be impossible
                    default:
                        return false;   
                }
                break;
                
            case HZ0_31:
                switch (ratio) {
                    case O32:
                        tmp_adc_rate = AHZ80;
                        dr = 7;
                        os = 1;
                        break;
                    case O64:
                        tmp_adc_rate = AHZ80;
                        dr = 6;
                        os = 2;
                        break;
                    case O128:
                        tmp_adc_rate = AHZ80;
                        dr = 5;
                        os = 3;
                        break;
                    default:
                        return false;   
                }
                break;
                
            case HZ0_16:
                switch (ratio) {
                    case O64:
                        tmp_adc_rate = AHZ80;
                        dr = 7;
                        os = 2;
                        break;
                    case O128:
                        tmp_adc_rate = AHZ80;
                        dr = 6;
                        os = 3;
                        break;
                    default:
                        return false;   
                }
                break;
                
            case HZ0_08:
                switch (ratio) {
                    case O128:
                        tmp_adc_rate = AHZ80;
                        dr = 7;
                        os = 3;
                        break;
                    default:
                        return false;   
                }
                break;
    }
    
    //Deactivate to update register
    bool wasActive = __active;
    setActive(false);
    
    //Update value for the caller
    if (adc_rate != NULL)
        *adc_rate = tmp_adc_rate;
        
    //Update CTRL_REG1 DR and OS fields
    uint8_t data = getRegister(CTRL_REG1);
    uint8_t dr_os = (dr << 5) | (os << 3); //Set DR in 3 MSB, OS in next 2 bits. 3 LSB are 0
    data = (data & ~(CTRL_REG1_DR_MASK | CTRL_REG1_OS_MASK)) | ((CTRL_REG1_DR_MASK | CTRL_REG1_OS_MASK) & dr_os); //Update 5 MSB
    setRegister(CTRL_REG1, data);
    
    //Update cached values
    __adc_rate = tmp_adc_rate;
    __ratio = ratio;
    __rate = rate;
    
    if (wasActive)
        setActive(true);
    
    return true;
}



int16_t MAG3110::getX(bool sampleNow) {
    __disable_irq();
    if (sampleNow) {
        uint8_t data_msb, data_lsb;
        data_msb = getRegister(OUT_X_MSB);
        data_lsb = getRegister(OUT_X_LSB);
        __x = data_msb << 8;
        __x |= data_lsb;
    }
    
    __dataReady = false;
    __enable_irq();
    
    return __x;
}

int16_t MAG3110::getY(bool sampleNow) {
    __disable_irq();
    if (sampleNow) {
        uint8_t data_msb, data_lsb;
        data_msb = getRegister(OUT_Y_MSB);
        data_lsb = getRegister(OUT_Y_LSB);
        __y = data_msb << 8;
        __y |= data_lsb;
    }
    
    __dataReady = false;
    __enable_irq();
    
    return __y;
}

int16_t MAG3110::getZ(bool sampleNow) {
    __disable_irq();    
    if (sampleNow) {
        uint8_t data_msb, data_lsb;
        data_msb = getRegister(OUT_Z_MSB);
        data_lsb = getRegister(OUT_Z_LSB);
        __z = data_msb << 8;
        __z |= data_lsb;
    }
    
    __dataReady = false;
    __enable_irq();
    
    return __z;
}  

float MAG3110::getFloatX(bool sampleNow) {
    return getX(sampleNow) * DATA_CONVERSION;   
}

float MAG3110::getFloatY(bool sampleNow) {
    return getY(sampleNow) * DATA_CONVERSION;   
}

float MAG3110::getFloatZ(bool sampleNow) {
    return getZ(sampleNow) * DATA_CONVERSION;   
}

int8_t MAG3110::getDieTemp() {
    return (int8_t) getRegister(DIE_TEMP);
}

float MAG3110::getFloatDieTemp() {
    return getDieTemp() * TEMP_DIV;   
}

void MAG3110::__sample_data_ISR() {
    getX(true);
    getY(true);
    getZ(true);
    __dataReady = true;
}