File dps310.h¶
Go to the documentation of this file
Source Code¶
#pragma once
#ifndef DSY_DPS310_H
#define DSY_DPS310_H
#define DPS310_I2CADDR_DEFAULT (0x77)
#define DPS310_PRSB2 0x00
#define DPS310_TMPB2 0x03
#define DPS310_PRSCFG 0x06
#define DPS310_TMPCFG 0x07
#define DPS310_MEASCFG 0x08
#define DPS310_CFGREG 0x09
#define DPS310_RESET 0x0C
#define DPS310_PRODREVID 0x0D
#define DPS310_TMPCOEFSRCE 0x28
namespace daisy
{
class Dps310I2CTransport
{
public:
Dps310I2CTransport() {}
~Dps310I2CTransport() {}
struct Config
{
I2CHandle::Config::Peripheral periph;
I2CHandle::Config::Speed speed;
Pin scl;
Pin sda;
uint8_t address;
Config()
{
address = DPS310_I2CADDR_DEFAULT;
periph = I2CHandle::Config::Peripheral::I2C_1;
speed = I2CHandle::Config::Speed::I2C_400KHZ;
scl = Pin(PORTB, 8);
sda = Pin(PORTB, 9);
}
};
inline void Init(Config config)
{
config_ = config;
I2CHandle::Config i2c_config;
i2c_config.mode = I2CHandle::Config::Mode::I2C_MASTER;
i2c_config.periph = config.periph;
i2c_config.speed = config.speed;
i2c_config.pin_config.scl = config.scl;
i2c_config.pin_config.sda = config.sda;
i2c_.Init(i2c_config);
}
void Write(uint8_t *data, uint16_t size)
{
error_ |= I2CHandle::Result::OK
!= i2c_.TransmitBlocking(config_.address, data, size, 10);
}
void Read(uint8_t *data, uint16_t size)
{
error_ |= I2CHandle::Result::OK
!= i2c_.ReceiveBlocking(config_.address, data, size, 10);
}
void Write8(uint8_t reg, uint8_t value)
{
uint8_t buffer[2];
buffer[0] = reg;
buffer[1] = value;
Write(buffer, 2);
}
void ReadReg(uint8_t reg, uint8_t *buff, uint8_t size)
{
Write(®, 1);
Read(buff, size);
}
uint8_t Read8(uint8_t reg)
{
uint8_t buffer;
ReadReg(reg, &buffer, 1);
return buffer;
}
uint16_t Read16(uint8_t reg)
{
uint8_t buffer[2];
ReadReg(reg, buffer, 2);
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
}
uint32_t Read24(uint8_t reg)
{
uint8_t buffer[3];
ReadReg(reg, buffer, 3);
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8
| uint32_t(buffer[2]);
}
bool GetError()
{
bool tmp = error_;
error_ = false;
return tmp;
}
private:
I2CHandle i2c_;
Config config_;
// true if error has occured since last check
bool error_;
};
class Dps310SpiTransport
{
public:
Dps310SpiTransport() {}
~Dps310SpiTransport() {}
struct Config
{
SpiHandle::Config::Peripheral periph;
Pin sclk;
Pin miso;
Pin mosi;
Pin nss;
Config()
{
periph = SpiHandle::Config::Peripheral::SPI_1;
sclk = Pin(PORTG, 11);
miso = Pin(PORTB, 4);
mosi = Pin(PORTB, 5);
nss = Pin(PORTG, 10);
}
};
inline void Init(Config config)
{
SpiHandle::Config spi_conf;
spi_conf.mode = SpiHandle::Config::Mode::MASTER;
spi_conf.direction = SpiHandle::Config::Direction::TWO_LINES;
spi_conf.clock_polarity = SpiHandle::Config::ClockPolarity::LOW;
spi_conf.clock_phase = SpiHandle::Config::ClockPhase::ONE_EDGE;
spi_conf.baud_prescaler = SpiHandle::Config::BaudPrescaler::PS_2;
spi_conf.nss = SpiHandle::Config::NSS::SOFT;
spi_conf.periph = config.periph;
spi_conf.pin_config.sclk = config.sclk;
spi_conf.pin_config.miso = config.miso;
spi_conf.pin_config.mosi = config.mosi;
spi_conf.pin_config.nss = config.nss;
spi_.Init(spi_conf);
}
void Write(uint8_t *data, uint16_t size)
{
error_ |= SpiHandle::Result::OK != spi_.BlockingTransmit(data, size);
}
void Read(uint8_t *data, uint16_t size)
{
error_ |= SpiHandle::Result::OK != spi_.BlockingReceive(data, size, 10);
}
void Write8(uint8_t reg, uint8_t value)
{
uint8_t buffer[2];
buffer[0] = reg & ~0x80;
buffer[1] = value;
Write(buffer, 2);
}
void ReadReg(uint8_t reg, uint8_t *buff, uint8_t size)
{
reg = uint8_t(reg | 0x80);
Write(®, 1);
Read(buff, size);
}
uint8_t Read8(uint8_t reg)
{
uint8_t buffer;
ReadReg(reg, &buffer, 1);
return buffer;
}
uint16_t Read16(uint8_t reg)
{
uint8_t buffer[2];
ReadReg(reg, buffer, 2);
return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]);
}
uint32_t Read24(uint8_t reg)
{
uint8_t buffer[3];
ReadReg(reg, buffer, 3);
return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8
| uint32_t(buffer[2]);
}
bool GetError()
{
bool tmp = error_;
error_ = false;
return tmp;
}
private:
SpiHandle spi_;
bool error_;
};
template <typename Transport>
class Dps310
{
public:
Dps310() {}
~Dps310() {}
int32_t oversample_scalefactor[8]
= {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960};
enum dps310_rate_t
{
DPS310_1HZ,
DPS310_2HZ,
DPS310_4HZ,
DPS310_8HZ,
DPS310_16HZ,
DPS310_32HZ,
DPS310_64HZ,
DPS310_128HZ,
};
enum dps310_oversample_t
{
DPS310_1SAMPLE,
DPS310_2SAMPLES,
DPS310_4SAMPLES,
DPS310_8SAMPLES,
DPS310_16SAMPLES,
DPS310_32SAMPLES,
DPS310_64SAMPLES,
DPS310_128SAMPLES,
};
enum dps310_mode_t
{
DPS310_IDLE = 0b000,
DPS310_ONE_PRESSURE = 0b001,
DPS310_ONE_TEMPERATURE = 0b010,
DPS310_CONT_PRESSURE = 0b101,
DPS310_CONT_TEMP = 0b110,
DPS310_CONT_PRESTEMP = 0b111,
};
struct Config
{
typename Transport::Config transport_config;
Config() {}
};
enum Result
{
OK = 0,
ERR
};
Result Init(Config config)
{
config_ = config;
transport_.Init(config_.transport_config);
// make sure we're talking to the right chip
if(Read8(DPS310_PRODREVID) != 0x10)
{
// No DPS310 detected ... return false
return ERR;
}
reset();
_readCalibration();
// default to high precision
configurePressure(DPS310_64HZ, DPS310_64SAMPLES);
configureTemperature(DPS310_64HZ, DPS310_64SAMPLES);
// continuous
setMode(DPS310_CONT_PRESTEMP);
// wait until we have at least one good measurement
while(!temperatureAvailable() || !pressureAvailable())
{
System::Delay(10);
}
return GetTransportError();
}
void reset(void)
{
Write8(DPS310_RESET, 0x89);
// Wait for a bit till its out of hardware reset
System::Delay(10);
while(!ReadBits(DPS310_MEASCFG, 1, 6))
{
System::Delay(1);
}
}
static int32_t twosComplement(int32_t val, uint8_t bits)
{
if(val & ((uint32_t)1 << (bits - 1)))
{
val -= (uint32_t)1 << bits;
}
return val;
}
void _readCalibration(void)
{
// Wait till we're ready to read calibration
while(!ReadBits(DPS310_MEASCFG, 1, 7))
{
System::Delay(1);
}
uint8_t coeffs[18];
for(uint8_t addr = 0; addr < 18; addr++)
{
coeffs[addr] = Read8(0x10 + addr);
}
_c0 = ((uint16_t)coeffs[0] << 4) | (((uint16_t)coeffs[1] >> 4) & 0x0F);
_c0 = twosComplement(_c0, 12);
_c1 = twosComplement((((uint16_t)coeffs[1] & 0x0F) << 8) | coeffs[2],
12);
_c00 = ((uint32_t)coeffs[3] << 12) | ((uint32_t)coeffs[4] << 4)
| (((uint32_t)coeffs[5] >> 4) & 0x0F);
_c00 = twosComplement(_c00, 20);
_c10 = (((uint32_t)coeffs[5] & 0x0F) << 16) | ((uint32_t)coeffs[6] << 8)
| (uint32_t)coeffs[7];
_c10 = twosComplement(_c10, 20);
_c01 = twosComplement(((uint16_t)coeffs[8] << 8) | (uint16_t)coeffs[9],
16);
_c11 = twosComplement(
((uint16_t)coeffs[10] << 8) | (uint16_t)coeffs[11], 16);
_c20 = twosComplement(
((uint16_t)coeffs[12] << 8) | (uint16_t)coeffs[13], 16);
_c21 = twosComplement(
((uint16_t)coeffs[14] << 8) | (uint16_t)coeffs[15], 16);
_c30 = twosComplement(
((uint16_t)coeffs[16] << 8) | (uint16_t)coeffs[17], 16);
}
bool temperatureAvailable(void) { return ReadBits(DPS310_MEASCFG, 1, 5); }
bool pressureAvailable(void) { return ReadBits(DPS310_MEASCFG, 1, 4); }
float GetAltitude(float seaLevelhPa)
{
float altitude;
Process();
altitude = 44330 * (1.0 - pow((_pressure / 100) / seaLevelhPa, 0.1903));
return altitude;
}
void setMode(dps310_mode_t mode) { WriteBits(DPS310_MEASCFG, mode, 3, 0); }
void configurePressure(dps310_rate_t rate, dps310_oversample_t os)
{
WriteBits(DPS310_PRSCFG, rate, 3, 4);
WriteBits(DPS310_PRSCFG, os, 4, 0);
if(os > DPS310_8SAMPLES)
{
WriteBits(DPS310_CFGREG, 1, 1, 2);
}
else
{
WriteBits(DPS310_CFGREG, 0, 1, 2);
}
pressure_scale = oversample_scalefactor[os];
}
void configureTemperature(dps310_rate_t rate, dps310_oversample_t os)
{
WriteBits(DPS310_TMPCFG, rate, 3, 4);
WriteBits(DPS310_TMPCFG, os, 4, 0);
temp_scale = oversample_scalefactor[os];
// Set shift bit if necessary
if(os > DPS310_8SAMPLES)
{
WriteBits(DPS310_CFGREG, 1, 1, 3);
}
else
{
WriteBits(DPS310_CFGREG, 0, 1, 3);
}
// Find out what our calibration source is
uint8_t read = ReadBits(DPS310_TMPCOEFSRCE, 1, 7);
WriteBits(DPS310_TMPCFG, read, 1, 7);
}
void Process(void)
{
raw_temperature = twosComplement(Read24(DPS310_TMPB2), 24);
raw_pressure = twosComplement(Read24(DPS310_PRSB2), 24);
_scaled_rawtemp = (float)raw_temperature / temp_scale;
_temperature = _scaled_rawtemp * _c1 + _c0 / 2.0;
_pressure = (float)raw_pressure / pressure_scale;
_pressure
= (int32_t)_c00
+ _pressure
* ((int32_t)_c10
+ _pressure
* ((int32_t)_c20 + _pressure * (int32_t)_c30))
+ _scaled_rawtemp
* ((int32_t)_c01
+ _pressure
* ((int32_t)_c11 + _pressure * (int32_t)_c21));
}
float GetTemperature() { return _temperature; }
float GetPressure() { return _pressure / 100; }
void Write8(uint8_t reg, uint8_t value)
{
return transport_.Write8(reg, value);
}
void ReadReg(uint8_t reg, uint8_t *buff, uint8_t size)
{
return transport_.ReadReg(reg, buff, size);
}
uint8_t Read8(uint8_t reg) { return transport_.Read8(reg); }
uint16_t Read16(uint8_t reg) { return transport_.Read16(reg); }
uint32_t Read24(uint8_t reg) { return transport_.Read24(reg); }
uint16_t Read16_LE(uint8_t reg)
{
uint16_t temp = Read16(reg);
return (temp >> 8) | (temp << 8);
}
int16_t ReadS16(uint8_t reg) { return (int16_t)Read16(reg); }
int16_t ReadS16_LE(uint8_t reg) { return (int16_t)Read16_LE(reg); }
uint8_t ReadBits(uint8_t reg, uint8_t bits, uint8_t shift)
{
uint8_t val = Read8(reg);
val >>= shift;
return val & ((1 << (bits)) - 1);
}
void WriteBits(uint8_t reg, uint8_t data, uint8_t bits, uint8_t shift)
{
uint8_t val = Read8(reg);
// mask off the data before writing
uint8_t mask = (1 << (bits)) - 1;
data &= mask;
mask <<= shift;
val &= ~mask; // remove the current data at that spot
val |= data << shift; // and add in the new data
Write8(reg, val);
}
Result GetTransportError() { return transport_.GetError() ? ERR : OK; }
private:
Config config_;
Transport transport_;
int16_t _c0, _c1, _c01, _c11, _c20, _c21, _c30;
int32_t _c00, _c10;
int32_t raw_pressure, raw_temperature;
float _temperature, _scaled_rawtemp, _pressure;
int32_t temp_scale, pressure_scale;
};
using Dps310I2C = Dps310<Dps310I2CTransport>;
using Dps310Spi = Dps310<Dps310SpiTransport>;
} // namespace daisy
#endif