I am trying to interface with the Bar30 sensor via the i2c bus on a TX2 loaded with Ubuntu. I tried to make custom C++ code based on the Arduino code linked on the Bar30 product page. When I run the test program that I made, I can read the correct configuration parameters on initialization, but I read in all zeros for the data bytes. The C++ code is very similar to the Arduino code so I am not sure why I could read the initialization values and not the data. Any help is appreciated, thank you. Since I am a new user and cannot upload files, I will include the text below.
testMS5837.h
#ifndef testMS5837_H
#define testMS5837_H
#include "ms5837.h"
#include <stdio.h>
#include <iostream>
//using namespace std;
int initMS5837(MS5837* sensor);
bool getMS5837Values(MS5837* sensor, float& depth, float& temp, float& pressure, int water_type);
#endif</code>
testMS5837.cpp
#include "testMS5837.h"
int initMS5837(MS5837* sensor) {
if (!sensor->init()){
std::cout << "\tSensor could not be initialized\n";
return 1;
}
}
bool getMS5837Values(MS5837* sensor, float& depth, float& temp, float& pressure, int water_type){
// We have to read values from sensor to update depth
if (!sensor->readSens(sensor->OSR_8192)){
std::cout << "\t\tSensor read failed!\n";
return 1;
}
if (water_type == 0) { // freshwater
depth = sensor->depth(); // default is freshwater
} else { //saltwater
sensor->setFluidDensity(sensor->DENSITY_SALTWATER);
depth = sensor->depth(); // No nead to readSens() again
}
temp = sensor->temperature(sensor->UNITS_Farenheit);
pressure = sensor->pressure(sensor->UNITS_atm);
return true;
}
int main() {
MS5837 sensor = MS5837(1,0);
initMS5837(&sensor);
float depth, temp, pressure;
int water_type = 0;
getMS5837Values(&sensor, depth, temp, pressure, water_type);
std::cout << "Depth = " << depth << " m\n";
std::cout << "Temp = " << temp << " F\n";
std::cout << "Pressure = " << pressure << " atm \n";
}
ms5837.h
#ifndef MS5837_TEST_SENSOR_H
#define MS5837_TEST_SENSOR_H
extern "C"{
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include <linux/i2c.h>
}
// Converted from ms5837.py in Blue Robotics MS5837-python github
#include <string>
#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <vector>
#include <math.h>
using namespace std;
class MS5837{
public:
// Registers
__u8 _MS5837_ADDR = 0x76;
__u8 _MS5837_RESET = 0x1E;
__u8 _MS5837_ADC_READ = 0x00;
__u8 _MS5837_PROM_READ = 0xA0;
__u8 _MS5837_CONVERT_D1_8192 = 0x4A;
__u8 _MS5837_CONVERT_D2_8192 = 0x5A;
// Oversampling options
int OSR_8192 = 5;
// kg/m^3 convenience
int DENSITY_FRESHWATER = 997;
int DENSITY_SALTWATER = 1029;
// Conversion factors (from native unit, mbar)
float UNITS_Pa = 100.0f;
float UNITS_mbar = 1.0f;
float UNITS_bar = 0.001f;
float UNITS_atm = 0.000986923f;
float UNITS_Torr = 0.750062f;
float UNITS_psi = 0.014503773773022f;
// Valid units
int UNITS_Centigrade = 1;
int UNITS_Farenheit = 2;
int UNITS_Kelvin = 3;
MS5837() {}
MS5837( int model, int bus);
~MS5837(){}
bool init();
bool readSens(int oversampling=0); // OSR_256
void setFluidDensity(int denisty);
// Pressure in requested units
// mbar * conversion
float pressure(float conversion=1.0); // UNITS_mbar
// Temperature in requested units
// default degrees C
float temperature(float conversion=1); // UNITS_Centigrade
// Depth relative to MSL pressure in given fluid density
float depth();
// Altitude relative to MSL pressure
float altitude();
// Cribbed from datasheet
void _calculate();
// Cribbed from datasheet
uint8_t crc4(uint16_t n_prom[]);
private:
int _file;
float _fluidDensity;
int32_t P;
int32_t TEMP;
uint32_t _D1, _D2;
int _n_rem ;
vector<int> _n_prom;
uint16_t _C[8];
};
#endif
ms5837.cpp
#include "ms5837.h"
extern "C"{
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include <linux/i2c.h>
}
using namespace std;
MS5837::MS5837( int model, int bus){
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", bus);
_file = open(filename, O_RDWR);
if (_file < 0) {
std::cout << "Cannot open device\n";
exit(1);
}
if (ioctl(_file, I2C_SLAVE, _MS5837_ADDR) < 0){
std::cout << "Cannot open device\n";
exit(1);
}
_fluidDensity = DENSITY_FRESHWATER;
}
bool MS5837::init(){
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_RESET);
sleep(0.01); // Wait for reset to complete
// Read calibration values and CRC
for (uint8_t i = 0; i < 7; i++){
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_PROM_READ + 2*i);
__u8 d[2];
__u8 length = 2;
__s32 tmp = i2c_smbus_read_i2c_block_data(_file, _MS5837_PROM_READ + 2*i, length, d);
_C[i] = d[0] << 8 | d[1]; // SMBus is little-endian for word transfers, we need to swap MSB and LSB
std::cout << "Calibration : " << _C[i] << "\n";
}
uint8_t crcRead = _C[0] >> 12;
uint8_t crcCalculated = crc4(_C);
if (crcCalculated != crcRead){
std::cout << "PROM read error, CRC failed!\n";
return false;
}
return true;
}
bool MS5837::readSens(int oversampling){
// Request D1 conversion (temperature)
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_CONVERT_D1_8192);
sleep(0.02); // Max conversion time per datasheet
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_ADC_READ);
_D1 = 0;
__u8 d[3];
__u8 length = 3;
__s32 tmp = i2c_smbus_read_i2c_block_data(_file, _MS5837_ADC_READ, length, d);
_D1 = d[0] << 16 | d[1] << 8 | d[2];
std::cout << "(" << int(d[0]) << ", " << int(d[1]) << ", " << int(d[2]) << ")\n";
std::cout << "D1 = " << _D1 << "\n";
// Request D2 conversion (pressure)
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_CONVERT_D2_8192);
sleep(0.02); // Max conversion time per datasheet
i2c_smbus_write_byte_data(_file, 0x00, _MS5837_ADC_READ);
_D2 = 0;
tmp = i2c_smbus_read_i2c_block_data(_file, _MS5837_ADC_READ, length, d);
_D2 = d[0] << 16 | d[1] << 8 | d[2];
std::cout << "(" << int(d[0]) << ", " << int(d[1]) << ", " << int(d[2]) << ")\n";
std::cout << "D2 = " << _D2 << "\n";
_calculate();
return true;
}
void MS5837::setFluidDensity(int denisty)
{
_fluidDensity = denisty;
}
// Pressure in requested units
// mbar * conversion
float MS5837::pressure(float conversion)
{
return P * conversion / 10.0f;
}
// Temperature in requested units
// default degrees C
float MS5837::temperature(float conversion)
{
float degC = TEMP / 100.0f;
if (conversion == UNITS_Farenheit) return (9.0/5.0)*degC + 32;
else if (conversion == UNITS_Kelvin) return degC + 273;
return degC;
}
// Depth relative to MSL pressure in given fluid density
float MS5837::depth()
{
return (pressure(UNITS_Pa)-101300)/(_fluidDensity*9.80665);
}
// Altitude relative to MSL pressure
float MS5837::altitude()
{
return (1-pow((pressure()/1013.25),.190284))*145366.45*.3048;
}
// Cribbed from datasheet
void MS5837::_calculate()
{
int32_t dT = 0;
int64_t SENS = 0;
int64_t OFF = 0;
int32_t SENSi = 0;
int32_t OFFi = 0;
int32_t Ti = 0;
int64_t OFF2 = 0;
int64_t SENS2 = 0;
dT = _D2-uint32_t(_C[5])*256l;
SENS = int64_t(_C[1])*32768l+(int64_t(_C[3])*dT)/256l;
OFF = int64_t(_C[2])*65536l+(int64_t(_C[4])*dT)/128l;
P = (_D1*SENS/(2097152l)-OFF)/(8192l);
TEMP = 2000l+int64_t(dT)*_C[6]/8388608LL;
if ((TEMP/100) < 20){ // Low temp
Ti = (3*int64_t(dT)*int64_t(dT))/(8589934592LL);
OFFi = (3*(TEMP-2000)*(TEMP-2000))/2;
SENSi = (5*(TEMP-2000)*(TEMP-2000))/8;
if ((TEMP/100) < -15){ // Very low temp
OFFi = OFFi+7*(TEMP+1500l)*(TEMP+1500l);
SENSi = SENSi+4*(TEMP+1500l)*(TEMP+1500l);
}
} else if ((TEMP/100) >= 20){ // High temp
Ti = 2*(dT*dT)/(137438953472LL);
OFFi = (1*(TEMP-2000)*(TEMP-2000))/16;
SENSi = 0;
}
OFF2 = OFF-OFFi;
SENS2 = SENS-SENSi;
TEMP = (TEMP-Ti);
P = (((_D1*SENS2)/2097152l-OFF2)/8192l);
}
// Cribbed from datasheet
uint8_t MS5837::crc4(uint16_t n_prom[]){
uint16_t n_rem = 0;
n_prom[0] = ((n_prom[0]) & 0x0FFF);
n_prom[7] = 0;
for (uint8_t i = 0; i < 16; i++){
if (i%2 == 1)
n_rem ^= (uint16_t)((n_prom[i>>1]) & 0x00FF);
else
n_rem ^= (uint16_t)(n_prom[i>>1] >> 8);
for (uint8_t 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 = ((n_rem >> 12) & 0x000F);
return n_rem ^ 0x00;
}