This is a simple wrapper class for the MPL3115A5 pressure and temperature sensor. It allows either single readings for continuous readings using polling or interrupts. It also contains a wrapper class for mbed-rpc.
Revision 0:b12a7d396be9, committed 2015-03-22
- Comitter:
- rhourahane
- Date:
- Sun Mar 22 20:55:38 2015 +0000
- Commit message:
- Initial revision.
Changed in this revision
diff -r 000000000000 -r b12a7d396be9 RpcMPL3115A2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RpcMPL3115A2.cpp Sun Mar 22 20:55:38 2015 +0000 @@ -0,0 +1,66 @@ +#include "RpcMPL3115A2.h" + +RpcMPL3115A2::RpcMPL3115A2(PinName sda, PinName scl, const char *name) : + RPC(name), + chip(sda, scl) +{ +} + +int RpcMPL3115A2::id(void) { + return chip.getId(); +} + +void RpcMPL3115A2::setMode(int mode) { + chip.setDataMode(static_cast<MPL3115A2::DataMode>(mode)); +} + +int RpcMPL3115A2::getMode(void) { + return chip.getDataMode(); +} + +void RpcMPL3115A2::setOverSampling(int rate) { + chip.setOverSampling(rate); +} + +int RpcMPL3115A2::getOverSampling() { + return chip.getOverSampling(); +} + +void RpcMPL3115A2::read(Arguments *args, Reply *reply) { + float pres; + float temp; + + chip.getReadings(pres, temp); + + reply->putData(pres); + reply->putData(temp); +} + + +const struct rpc_method *RpcMPL3115A2::get_rpc_methods() { + static const rpc_method rpc_methods[] = { + {"id", rpc_method_caller<int, RpcMPL3115A2, &RpcMPL3115A2::id>}, + {"read", rpc_method_caller<RpcMPL3115A2, &RpcMPL3115A2::read> }, + {"writeMode", rpc_method_caller<RpcMPL3115A2, int, &RpcMPL3115A2::setMode> }, + {"readMode", rpc_method_caller<int, RpcMPL3115A2, &RpcMPL3115A2::getMode> }, + {"writeSamples", rpc_method_caller<RpcMPL3115A2, int, &RpcMPL3115A2::setOverSampling> }, + {"readSamples", rpc_method_caller<int, RpcMPL3115A2, &RpcMPL3115A2::getOverSampling> }, + RPC_METHOD_SUPER(RPC) + }; + + return rpc_methods; +} + +const char *RpcMPL3115A2::get_rpc_class_name() { + return get_rpc_class()->name; +} + +struct rpc_class *RpcMPL3115A2::get_rpc_class() { + static const rpc_function funcs[] = { + {"new", rpc_function_caller<const char*, PinName, PinName, const char*, &RPC::construct<RpcMPL3115A2, PinName, PinName, const char*> >}, + RPC_METHOD_END + }; + static rpc_class c = {"MPL3115A2", funcs, NULL}; + + return &c; +}
diff -r 000000000000 -r b12a7d396be9 RpcMPL3115A2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RpcMPL3115A2.h Sun Mar 22 20:55:38 2015 +0000 @@ -0,0 +1,72 @@ +#ifndef PRCMPL3115A2_H +#define RPCMPL3115A2_H + +#include "rpc.h" +#include "mpl3115a2.h" + +/// RPC wrapper class for MPL3115A2 driver class. +/// This class provides a simple single shot interface to the +/// MPL3115A2 allowing the user to get the altimeter/barometric +/// mode and number of samples per reading. +class RpcMPL3115A2 : public mbed::RPC { +public: + /// Create a new instance of the class using the specified pins for the I2C bus. + /// @param sda The pin name for the sda line of the I2C bus. + /// @param scl The pin name for the scl line of the I2C bus. + RpcMPL3115A2(PinName sda, PinName scl, const char *name=NULL); + + /// Read the chip id, this is a fixed value of 0xC4. This method is + /// linked to the RPC method method "id". + /// @returns Chip id. + int id(void); + + /// Set the how the pressure is read. The default is BarometricMode if + /// it is to be change then is must be called before getReadings or activate. + /// This method is linked to to the RPC method "writeMode". + /// @param mode New mode to read pressure in. + void setMode(int mode); + + /// Get the current setting for the pressure reading mode. + /// This method is linked to the RPC method "readMode". + /// @returns Current pressure reading mode. + int getMode(void); + + /// Set the number of samples to be used for each reading. + /// The number must be a power of two between 1 and 128. + /// This method is linked to the RPC method "writeSamples". + /// @param samples Number of samples per reading. + void setOverSampling(int rate); + + /// Get the number of samples to be used for each reading. + /// This method is linked to the RPC method "readSamples". + /// @returns Number of samples per reading. + int getOverSampling(); + + /// Reads both pressure and temperature. Returns pressure + /// in the units set by mode and the temperature in Celsius, + /// the values are separated by a space. + /// This method is linked to the RPC method "read". + void read(Arguments*, Reply*); + + /// Override of RPC method to return array of methods + /// that can be called through RPC. + /// @returns array of method structures terminated by a + /// null structure. + virtual const struct rpc_method *get_rpc_methods(); + + /// Override of RPC method to return the RPC name of the class + /// for this object. + /// @returns RPC name of class for this instance. + virtual const char *get_rpc_class_name(); + + /// Get the predefined RPC class structure for this + /// class. Allows using template to register class + /// this RPC. + /// @returns Point to RPC class information structure. + static struct rpc_class *get_rpc_class(); + +private: + MPL3115A2 chip; +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r b12a7d396be9 mpl3115a2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpl3115a2.cpp Sun Mar 22 20:55:38 2015 +0000 @@ -0,0 +1,318 @@ +#include <mbed.h> +#include "mpl3115a2.h" + +namespace { +const char STATUS = 0x00; +const char OUT_P_MSB = 0x01; +const char OUT_T_MSB = 0x04; +const char WHO_AM_I = 0x0C; +const char SYSMOD = 0x11; +const char PT_DATA_CFG = 0x13; +const char CTRL_REG1 = 0x26; +const char CTRL_REG2 = 0x27; +const char CTRL_REG3 = 0x28; +const char CTRL_REG4 = 0x29; +const char CTRL_REG5 = 0x2A; + +// Values for bits in STATUS +const char STATUS_TDR = 0x02; +const char STATUS_PDR = 0x04; +const char STATUS_TPDR = 0x08; +const char STATUS_DR_MASK = 0x0E; +const char STATUS_TOW = 0x20; +const char STATUS_POW = 0x40; +const char STATUS_TPOW = 0x80; +const char STATUS_OW_MASK = 0xE0; + +// Values for bits in PT_DATA_CFG +const char PT_DATA_CFG_TDEFE = 0x01; +const char PT_DATA_CFG_PDEFE = 0x02; +const char PT_DATA_CFG_DREM = 0x04; + +// Values for bits in CTRL_REG1 +const char CTRL_REG1_SBYB = 0x01; +const char CTRL_REG1_OSB = 0x02; +const char CTRL_REG1_RST = 0x04; +const char CTRL_REG1_OS_MASK = 0x38; +const char CTRL_REG1_RAW = 0x40; +const char CTRL_REG1_ALT = 0x80; + +// Values for bits in CTRL_REG2 +const char CTRL_REG2_ST_MASK = 0x0F; +const char CTRL_REG2_ALARM_SEL = 0x10; +const char CTRL_REG2_LOAD_OUTPUT = 0x20; + +// Values for bits in CTRL_REG4 +const char CTRL_REG4_INT_EN_TCHG = 0x01; +const char CTRL_REG4_INT_EN_PCHG = 0x02; +const char CTRL_REG4_INT_EN_TTH = 0x04; +const char CTRL_REG4_INT_EN_PTH = 0x08; +const char CTRL_REG4_INT_EN_TW = 0x10; +const char CTRL_REG4_INT_EN_PW = 0x20; +const char CTRL_REG4_INT_EN_FIFO = 0x40; +const char CTRL_REG4_INT_EN_DRDY = 0x80; + +// Values for bits in CTRL_REG5 +const char CTRL_REG5_INT_CFG_TCHG = 0x01; +const char CTRL_REG5_INT_CFG_PW = 0x20; +const char CTRL_REG5_INT_CFG_TTH = 0x04; +const char CTRL_REG5_INT_CFG_PTH = 0x08; +const char CTRL_REG5_INT_CFG_TW = 0x10; +const char CTRL_REG5_INT_CFG_PCHG = 0x02; +const char CTRL_REG5_INT_CFG_FIFO = 0x40; +const char CTRL_REG5_INT_CFG_DRDY = 0x80; +}; + +MPL3115A2::MPL3115A2(PinName sda, PinName scl) : + m_i2c(sda, scl), + m_addr(0x60<<1), + m_readMode(Single), + m_dataMode(BarometricMode), + m_overSample(0), + m_samplePeriod(0), + m_dataReadInt(INT2) +{ + // Reset the chip so we know where we are. + char data[2] = { CTRL_REG1, CTRL_REG1_RST}; + writeRegs(data, 2); + wait(0.1); + + // Configure to get data ready events. + data[0] = PT_DATA_CFG; + data[1] = PT_DATA_CFG_TDEFE | PT_DATA_CFG_PDEFE | PT_DATA_CFG_DREM; + writeRegs(data, 2); +} + +void MPL3115A2::setDataMode(DataMode mode) { + m_dataMode = mode; +} + +MPL3115A2::DataMode MPL3115A2::getDataMode(void) { + return m_dataMode; +} + +void MPL3115A2::setReadMode(ReadMode mode) { + m_readMode = mode; +} + +MPL3115A2::ReadMode MPL3115A2::getReadMode(void) { + return m_readMode; +} + +void MPL3115A2::setOverSampling(int samples) { + int pow = 0; + while (((samples % 2) != 1) && (pow < 8)) { + ++pow; + samples = samples >> 1; + } + m_overSample = pow; +} + +int MPL3115A2::getOverSampling(void) { + return 1 << m_overSample; +} + +void MPL3115A2::setSamplingPeriod(int period) { + int pow = 0; + while (((period % 2) != 1) && (pow < 16)) { + ++pow; + period = period >> 1; + } + m_samplePeriod = pow; +} + +int MPL3115A2::getSamplingPeriod(void) { + return 1 << m_samplePeriod; +} + +void MPL3115A2::setDataReadyInt(InterruptPin intPin) { + m_dataReadInt = intPin; +} + +MPL3115A2::InterruptPin MPL3115A2::getDataReadyInt(void) { + return m_dataReadInt; +} + +int MPL3115A2::getId(void) { + char id; + + // Read the WHO_AM_I register to get the value. + readRegs(WHO_AM_I, &id, 1); + return id; +} + +int MPL3115A2::getStatus(void) { + char status; + + readRegs(STATUS, &status, 1); + return status; +} + +bool MPL3115A2::isDataReady(void) { + char status; + + // Read the STATUS register and and in the data ready mask + // to get a boolean. + readRegs(STATUS, &status, 1); + return (status & STATUS_DR_MASK) != 0; +}; + +void MPL3115A2::activate() { + if (m_readMode != Single) { + char reg1 = CTRL_REG1_SBYB; + char reg2 = 0; + char reg4 = 0; + char reg5 = 0; + + // Set the data mode and over sampling correctly + switch (m_dataMode) { + case BarometricMode: + // nothing to set. + break; + + case AltimeterMode: + reg1 |= CTRL_REG1_ALT; + break; + + case RawMode: + reg1 |= CTRL_REG1_RAW; + break; + } + reg1 |= (m_overSample << 3) & CTRL_REG1_OS_MASK; + + // Set the sampling period + reg2 = m_samplePeriod & CTRL_REG2_ST_MASK; + + // If we are using interupts then configure the + // interrupt registers. + if (m_readMode == Interupt) { + reg4 = CTRL_REG4_INT_EN_DRDY; + if (m_dataReadInt == INT1) { + reg5 = CTRL_REG5_INT_CFG_DRDY; + } + } + + char data[6] = { CTRL_REG1, reg1, reg2, 0, reg4, reg5 }; + writeRegs(data, 6); + } +} + +bool MPL3115A2::isActive() { + char status; + + // read the active status from the SYSMOD register + readRegs(SYSMOD, &status, 1); + return status != 0; +} + +void MPL3115A2::standby() { + + // Clear the CTRL_REG1 to put the chip into standby. + char data[2] = { CTRL_REG1, 0 }; + writeRegs(data, 2); +} + + +bool MPL3115A2::getReadings(float &pres, float &temp) { + if (m_dataMode == RawMode) { + // Raw mode not supported. + return false; + } + + // If we're in single read mode then we need to initiate + // a new read cycle. + if (m_readMode == Single) { + // Set the OSB bit to initiate a new reading. + char value = CTRL_REG1_OSB; + + // Add in oversampling + value |= (m_overSample << 3) & CTRL_REG1_OS_MASK; + + // Set the pressure reading mode to altimeter if needed. + if (m_dataMode == AltimeterMode) { + value |= CTRL_REG1_ALT; + } + + // Write the new value to CTRL_REG1 to kick things off. + char data[2] = { CTRL_REG1, value}; + writeRegs(data, 2); + } + + int status = 0; + + // Loop until the data is ready. + while ((status & STATUS_DR_MASK) == 0) { + status = getStatus(); + printf("0x%X-", status); + } + + // Read the pressure and temperature data all at once + // and then convert it into real values. + char data[5]; + readRegs(OUT_P_MSB, &data[0], 5); + if (m_dataMode == AltimeterMode) { + pres = convAltimeter(&data[0]); + } else { + pres = convPressure(&data[0]); + } + temp = convTemperature(&data[3]); + + return true; +} + + +float MPL3115A2::convTemperature(char *data) { + short temp; + float ftemp; + + // Move the signed byte up to the top of the short so + // that it is in the right place and or in the bottom + // 8bits. + temp = (data[0] << 8) | data[1]; + + // shift out the bottom 4 0 bits and convert + // the integer temp into a float value by + // dividing by 16. + ftemp = (temp >> 4) / 16.0f; + return ftemp; +} + +float MPL3115A2::convAltimeter(char *data) { + int altInt; + float altFloat; + + // Put the 3 byte value in the upper 24 bits so the sign + // is correct. + altInt = (data[0] << 24) | (data[1] << 16) | (data[2] << 8); + + // Shift down extending the sign as we go and then + // divide by 16 to get fractions. + altFloat = (altInt >> 12) / 16.0f; + + return altFloat; +} + +float MPL3115A2::convPressure(char *data) { + int presInt; + float fprs; + + // Or in the three bytes containing the 18bit int + // into the top 18bits so the sign bit is correct. + presInt = (data[0] << 24) | (data[1] << 16) | (data[2] << 8); + + // Shift the in into the correct position and then + // divide by 4 to generate the fractional part. + fprs = (presInt >> 12) / 4.0f; + + return fprs; +} + +void MPL3115A2::readRegs(char addr, char *data, int len) { + m_i2c.write(m_addr, &addr, 1, true); + m_i2c.read(m_addr, data, len); +} + +void MPL3115A2::writeRegs(const char *data, int len) { + m_i2c.write(m_addr, data, len); +} +
diff -r 000000000000 -r b12a7d396be9 mpl3115a2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpl3115a2.h Sun Mar 22 20:55:38 2015 +0000 @@ -0,0 +1,150 @@ +#ifndef __MPL3115A2_H__ +#define __MPL3115A2_H__ +#include <mbed.h> + +/// Class to provide simple control of the Freescale MPL311A2 pressure and +/// temperature sensor. The class allows the user to read the pressure as +/// barometric, altimeter or raw and the temperature in Celsius. +/// +/// Reading can be taken either on demand or continuously using either polling +/// or interrupts to wait for the next reading. +/// +/// The correct modes should be get before either calling getReadings for +/// single readings or activate to start continuous readings. +class MPL3115A2 { +public: + /// Enum for how the pressure data is to be read. + enum DataMode { + BarometricMode, ///< Barometric presure in Pascals + AltimeterMode, ///< Altitude in meters + RawMode ///< Raw values from internal DACs + }; + + /// Enum for how consecutive readings are made + enum ReadMode { + Single, ///< Make a single reading when calling getReadings, chip remains in standby the rest of the time + Polling, ///< Make consecutive readings by polling isDataReady, chip is active all the time. + Interupt ///< Make consecutive readings with an interrupt raised when data is ready, chip is active all the time. + }; + + /// Enum to allow specifying which of the chips two interrupt pins to use. + enum InterruptPin { + INT1, ///< Pin called INT1 on chip + INT2 ///< Pin called INT2 on chip + }; + + /// Create a new instance of the class using the specified pins for the I2C bus. + /// Once initialised the chip is in standby mode. + /// @param sda The pin name for the sda line of the I2C bus. + /// @param scl The pin name for the scl line of the I2C bus. + MPL3115A2(PinName sda, PinName scl); + + /// Read the chip id, this is a fixed value of 0xC4. + /// @returns Chip id. + int getId(void); + + /// Set the how the pressure is read. The default is BarometricMode if to + /// be change then is must be called before getReadings or activate. + /// @param mode New mode to read pressure in. + void setDataMode(DataMode mode); + + /// Get the current setting for the pressure reading mode. + /// @returns Current pressure reading mode. + DataMode getDataMode(void); + + /// Set the how get continuous reading. The default is Single if to + /// be change then is must be called before getReadings or activate. + /// @param mode New continuous reading mode. + void setReadMode(ReadMode mode); + + /// Get the current setting for the continuous reading mode. + /// @returns Current continuous reading mode. + ReadMode getReadMode(void); + + /// Set the number of samples to be used for each reading. + /// The number must be a power of two between 1 and 128. + /// @param samples Number of samples per reading. + void setOverSampling(int samples); + + /// Get the number of samples to be used for each reading. + /// @returns Number of samples per reading. + int getOverSampling(void); + + /// Sets the number of seconds between consecutive readings. + /// The number must be a power of two between 1 and 32768. + /// @param period Number of seconds between consecutive readings. + void setSamplingPeriod(int period); + + /// Get the number of seconds between consecutive readings. + /// @returns Seconds between samples. + int getSamplingPeriod(void); + + /// Set which of the chips two interrupt pins should be used to signal + /// that the data is ready. It is up to the user to attach the interrupt + /// handler to the correct MCU pin and then call either getStatus or + /// getReadings within the handler to clear the interrupt. + /// @param intPin Chip interrupt pin to signal data ready interrupts. + void setDataReadyInt(InterruptPin intPin); + + /// Get the configured interrupt pin used to signal that the data + /// is ready. + /// @returns Current data ready interrupt pin. + InterruptPin getDataReadyInt(void); + + /// Read the chips STATUS register. The register contains data ready and + /// overwrite flags. + /// @returns Value of the STATUS register. + int getStatus(void); + + /// Returns true if there is data available to read. + /// @returns True is data is available to read otherwise false. + bool isDataReady(void); + + /// Put the chip into active state to allow taking of consecutive + /// samples. How often the samples are taken depends on the sampling + /// period, the maximum frequency is every one second and the minimum + /// every 9 hours. + void activate(); + + /// Gives the active state of the chip + /// @returns True if the chip is in the active state otherwise false. + bool isActive(); + + /// Puts the chip into the standby state and stops automatic readings. + void standby(); + + /// Wait for and get the next readings for pressure and temperature. + /// If the reading mode is Single then the chip is setup and a wait + /// loop entered until the data is available. + /// If the reading mode is Polling then the wait loop is entered until + /// the next reading is available. + /// If the reading mode is Interrupt then the wait loop will exit imediately + /// as the data is already available. This will clear the interrupt. + /// @param pres Reference to variable to hold the pressure reading in Pascals + /// meters depending on the data mode. + /// @param temp Reference to variable to hold the temperature reading in + /// Celsius. + /// @returns True is the reading was sucessful otherwise false. The reading will + /// be unsuccessful if the data mode is raw. + bool getReadings(float &pres, float &temp); + +private: + float convTemperature(char *data); + float convAltimeter(char *data); + float convPressure(char *data); + + void readRegs(char addr, char *data, int len); + void writeRegs(const char *data, int len); + +private: + I2C m_i2c; + int m_addr; + + ReadMode m_readMode; + DataMode m_dataMode; + int m_overSample; + int m_samplePeriod; + InterruptPin m_dataReadInt; +}; + +#endif \ No newline at end of file