I'm working with a couple of BME280 sensors using i2c_t3. I'm sampling them using IntervalTimer and putting their values in a RingBuffer (from the ADC library). I'm outputting the available samples in the RingBuffer over serial in the loop.
If I don't do any actual i2c sampling in the sampling function, the serial output is fine. Although I'm sampling from the sensors, I'm only storing/outputting an incremented counter until I can figure out this problem.
I'm using the teensy-LC, and using Wire and Wire1 to access both sensors simultaneously. Is there something about using i2c and interrupts that I should be doing to allow this to work?
Here's the output I usually see over serial, and the problem seems to start to crop up when the string gets longer when the digits get longer with 1000.
Thanks for any insights into what is the issue.
Here's the code. If I comment out the relevant portion for i2c sampling then it works.
Here's the full code
If I don't do any actual i2c sampling in the sampling function, the serial output is fine. Although I'm sampling from the sensors, I'm only storing/outputting an incremented counter until I can figure out this problem.
I'm using the teensy-LC, and using Wire and Wire1 to access both sensors simultaneously. Is there something about using i2c and interrupts that I should be doing to allow this to work?
Here's the output I usually see over serial, and the problem seems to start to crop up when the string gets longer when the digits get longer with 1000.
Thanks for any insights into what is the issue.
Code:
line: 977:982
977,978,979,980,981,
line: 982:987
982,983,984,985,986,
line: 987:992
987,988,989,990,991,
line: 992:997
992,993,994,995,996,
line: 997:1002
997,998,999,1000,1001,
line: 1002:1007
1,0,1004,1005,1006,
line: 1007:1012
1007,536870880,1074163715,536870880,1011,
line: 1012:1017
0,222121527,253,9845,1016,
line: 1017:1022
9845,590,4294967281,536870880,1021,
line: 1022:1027
1000005,8331,1024,1025,1026,
line: 1027:1032
1027,1028,1029,1030,1031,
line: 1032:1037
1032,1033,1034,1035,1036,
Here's the code. If I comment out the relevant portion for i2c sampling then it works.
Code:
rawTemp1 = readBME280TemperatureWire();
rawPress1 = readBME280PressureWire();
rawHumidity1 = readBME280HumidityWire();
rawTemp2 = readBME280TemperatureWire1();
rawPress2 = readBME280PressureWire1();
rawHumidity2 = readBME280HumidityWire1();
Here's the full code
Code:
#include <i2c_t3.h>
#include <RingBuffer.h>
#include <IntervalTimer.h>
// BME280 registers
#define BME280_HUM_LSB 0xFE
#define BME280_HUM_MSB 0xFD
#define BME280_TEMP_XLSB 0xFC
#define BME280_TEMP_LSB 0xFB
#define BME280_TEMP_MSB 0xFA
#define BME280_PRESS_XLSB 0xF9
#define BME280_PRESS_LSB 0xF8
#define BME280_PRESS_MSB 0xF7
#define BME280_CONFIG 0xF5
#define BME280_CTRL_MEAS 0xF4
#define BME280_STATUS 0xF3
#define BME280_CTRL_HUM 0xF2
#define BME280_RESET 0xE0
#define BME280_ID 0xD0 // should be 0x60
#define BME280_CALIB00 0x88
#define BME280_CALIB26 0xE1
// Device address
#define BME280_ADDRESS 0x76 // Address of BME280 pressure/temperature sensor
enum Posr {
P_OSR_00 = 0, // no op
P_OSR_01,
P_OSR_02,
P_OSR_04,
P_OSR_08,
P_OSR_16
};
enum Hosr {
H_OSR_00 = 0, // no op
H_OSR_01,
H_OSR_02,
H_OSR_04,
H_OSR_08,
H_OSR_16
};
enum Tosr {
T_OSR_00 = 0, // no op
T_OSR_01,
T_OSR_02,
T_OSR_04,
T_OSR_08,
T_OSR_16
};
enum IIRFilter {
full = 0, // bandwidth at full sample rate
BW0_223ODR,
BW0_092ODR,
BW0_042ODR,
BW0_021ODR // bandwidth at 0.021 x sample rate
};
enum Mode {
BME280Sleep = 0,
forced,
forced2,
normal
};
enum SBy {
t_00_5ms = 0,
t_62_5ms,
t_125ms,
t_250ms,
t_500ms,
t_1000ms,
t_10ms,
t_20ms,
};
uint32_t rawPress1, rawTemp1; // pressure and temperature raw count output for BME280
uint16_t rawHumidity1;
uint32_t rawPress2, rawTemp2; // pressure and temperature raw count output for BME280
uint16_t rawHumidity2;
// Specify BME280 configuration
uint8_t Posr = P_OSR_16, Hosr = H_OSR_16, Tosr = T_OSR_02, Mode = normal, IIRFilter = BW0_042ODR, SBy = t_62_5ms; // set pressure amd temperature output data rate
// t_fine carries fine temperature as global value for BME280
int32_t t_fine;
// BME280 compensation parameters
uint8_t dig_H1A, dig_H3A, dig_H6A;
uint16_t dig_T1A, dig_P1A, dig_H4A, dig_H5A;
int16_t dig_T2A, dig_T3A, dig_P2A, dig_P3A, dig_P4A, dig_P5A, dig_P6A, dig_P7A, dig_P8A, dig_P9A, dig_H2A;
// BME280 compensation parameters
uint8_t dig_H1B, dig_H3B, dig_H6B;
uint16_t dig_T1B, dig_P1B, dig_H4B, dig_H5B;
int16_t dig_T2B, dig_T3B, dig_P2B, dig_P3B, dig_P4B, dig_P5B, dig_P6B, dig_P7B, dig_P8B, dig_P9B, dig_H2B;
RingBuffer *buffer = new RingBuffer();
int baseSampleRate = 5, nStatus = -1;
IntervalTimer samplingTimer;
volatile uint32_t sampleCount = 0, sampleCountSnapshot = 0, currReadSnapshot = 0, rtCount = 0, currReadCount = 0;
char command = ' ';
void setup() {
Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400);
Wire1.begin(I2C_MASTER, 0x00, I2C_PINS_22_23, I2C_PULLUP_EXT, I2C_RATE_400);
delay(5000);
Serial.begin(38400);
while ((command=waitForCommand()) != 'i') {
Serial.print("command was: ");
Serial.println(command);
}
while ((command=waitForCommand()) != 'r') {
Serial.print("command was: ");
Serial.println(command);
}
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
}
void loop() {
delay(1000);
sampleCountSnapshot = sampleCount;
currReadSnapshot = currReadCount;
Serial.print(currReadSnapshot);
Serial.print(":");
Serial.println(sampleCountSnapshot);
Serial.flush();
for (rtCount=currReadSnapshot;rtCount<sampleCountSnapshot;rtCount++) {
currReadCount = buffer->read();
Serial.print(currReadCount);
Serial.print(",");
}
currReadCount=rtCount;
Serial.flush();
}
char waitForCommand() {
char c = ' ';
Serial.println("i = initialize");
Serial.println("s = status");
Serial.println("r = run");
Serial.println("waiting for command...");
Serial.flush();
while (c == ' ') {
if (Serial.available() > 0) {
c=Serial.read();
switch(c) {
case 'i':
initialize();
nStatus = 0;
break;
case 'r':
startSampling();
nStatus = 1;
break;
//output status, this is not a complete status, only the status at setup(), stub now
case 's':
Serial.print("status");
default:
c=' ';
}
}
delay(500);
}
return c;
}
void startSampling() {
sampleCount=0;
samplingTimer.begin(sample, 1000000/baseSampleRate);
}
void sample() {
//read the sensors
// comment out this section and the serial output doesn't get corrupted
rawTemp1 = readBME280TemperatureWire();
rawPress1 = readBME280PressureWire();
rawHumidity1 = readBME280HumidityWire();
rawTemp2 = readBME280TemperatureWire1();
rawPress2 = readBME280PressureWire1();
rawHumidity2 = readBME280HumidityWire1();
buffer->write(sampleCount);
//count after, so that reading knows that it's available
sampleCount++;
}
void writeByteWire(uint8_t address, uint8_t subAddress, uint8_t data) {
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.write(data); // Put data in Tx buffer
Wire.endTransmission(); // Send the Tx buffer
}
void writeByteWire1(uint8_t address, uint8_t subAddress, uint8_t data) {
Wire1.beginTransmission(address); // Initialize the Tx buffer
Wire1.write(subAddress); // Put slave register address in Tx buffer
Wire1.write(data); // Put data in Tx buffer
Wire1.endTransmission(); // Send the Tx buffer
}
uint8_t readByteWire(uint8_t address, uint8_t subAddress) {
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.requestFrom(address, 1); // Read one byte from slave register address
Wire.requestFrom(address, (size_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
uint8_t readByteWire1(uint8_t address, uint8_t subAddress) {
uint8_t data; // `data` will store the register data
Wire1.beginTransmission(address); // Initialize the Tx buffer
Wire1.write(subAddress); // Put slave register address in Tx buffer
Wire1.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire1.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
// Wire1.requestFrom(address, 1); // Read one byte from slave register address
Wire1.requestFrom(address, (size_t) 1); // Read one byte from slave register address
data = Wire1.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void readBytesWire(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) {
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
// Wire.requestFrom(address, count); // Read bytes from slave register address
Wire.requestFrom(address, (size_t) count); // Read bytes from slave register address
while (Wire.available()) {
dest[i++] = Wire.read(); } // Put read results in the Rx buffer
}
void readBytesWire1(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) {
Wire1.beginTransmission(address); // Initialize the Tx buffer
Wire1.write(subAddress); // Put slave register address in Tx buffer
Wire1.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire1.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
// Wire1.requestFrom(address, count); // Read bytes from slave register address
Wire1.requestFrom(address, (size_t) count); // Read bytes from slave register address
while (Wire1.available()) {
dest[i++] = Wire1.read(); } // Put read results in the Rx buffer
}
uint32_t readBME280TemperatureWire() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire(BME280_ADDRESS, BME280_TEMP_MSB, 3, &rawData[0]);
return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
uint32_t readBME280TemperatureWire1() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire1(BME280_ADDRESS, BME280_TEMP_MSB, 3, &rawData[0]);
return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
uint32_t readBME280PressureWire() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire(BME280_ADDRESS, BME280_PRESS_MSB, 3, &rawData[0]);
return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
uint32_t readBME280PressureWire1() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire1(BME280_ADDRESS, BME280_PRESS_MSB, 3, &rawData[0]);
return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
uint16_t readBME280HumidityWire() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire(BME280_ADDRESS, BME280_HUM_MSB, 2, &rawData[0]);
return (uint16_t) (((uint16_t) rawData[0] << 8 | rawData[1]) );
}
uint16_t readBME280HumidityWire1() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytesWire1(BME280_ADDRESS, BME280_HUM_MSB, 2, &rawData[0]);
return (uint16_t) (((uint16_t) rawData[0] << 8 | rawData[1]) );
}
void BME280InitWire() {
// Configure the BME280
// Set H oversampling rate
writeByteWire(BME280_ADDRESS, BME280_CTRL_HUM, 0x07 & Hosr);
// Set T and P oversampling rates and sensor mode
writeByteWire(BME280_ADDRESS, BME280_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode);
// Set standby time interval in normal mode and bandwidth
writeByteWire(BME280_ADDRESS, BME280_CONFIG, SBy << 5 | IIRFilter << 2);
// Read and store calibration data
uint8_t calib[26];
readBytesWire(BME280_ADDRESS, BME280_CALIB00, 26, &calib[0]);
dig_T1A = (uint16_t)(((uint16_t) calib[1] << 8) | calib[0]);
dig_T2A = ( int16_t)((( int16_t) calib[3] << 8) | calib[2]);
dig_T3A = ( int16_t)((( int16_t) calib[5] << 8) | calib[4]);
dig_P1A = (uint16_t)(((uint16_t) calib[7] << 8) | calib[6]);
dig_P2A = ( int16_t)((( int16_t) calib[9] << 8) | calib[8]);
dig_P3A = ( int16_t)((( int16_t) calib[11] << 8) | calib[10]);
dig_P4A = ( int16_t)((( int16_t) calib[13] << 8) | calib[12]);
dig_P5A = ( int16_t)((( int16_t) calib[15] << 8) | calib[14]);
dig_P6A = ( int16_t)((( int16_t) calib[17] << 8) | calib[16]);
dig_P7A = ( int16_t)((( int16_t) calib[19] << 8) | calib[18]);
dig_P8A = ( int16_t)((( int16_t) calib[21] << 8) | calib[20]);
dig_P9A = ( int16_t)((( int16_t) calib[23] << 8) | calib[22]);
dig_H1A = calib[25];
readBytesWire(BME280_ADDRESS, BME280_CALIB26, 7, &calib[0]);
dig_H2A = ( int16_t)((( int16_t) calib[1] << 8) | calib[0]);
dig_H3A = calib[2];
dig_H4A = ( int16_t)(((( int16_t) calib[3] << 8) | (0x0F & calib[4]) << 4) >> 4);
dig_H5A = ( int16_t)(((( int16_t) calib[5] << 8) | (0xF0 & calib[4]) ) >> 4 );
dig_H6A = calib[6];
}
void BME280InitWire1() {
// Configure the BME280
// Set H oversampling rate
writeByteWire1(BME280_ADDRESS, BME280_CTRL_HUM, 0x07 & Hosr);
// Set T and P oversampling rates and sensor mode
writeByteWire1(BME280_ADDRESS, BME280_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode);
// Set standby time interval in normal mode and bandwidth
writeByteWire1(BME280_ADDRESS, BME280_CONFIG, SBy << 5 | IIRFilter << 2);
// Read and store calibration data
uint8_t calib[26];
readBytesWire1(BME280_ADDRESS, BME280_CALIB00, 26, &calib[0]);
dig_T1B = (uint16_t)(((uint16_t) calib[1] << 8) | calib[0]);
dig_T2B = ( int16_t)((( int16_t) calib[3] << 8) | calib[2]);
dig_T3B = ( int16_t)((( int16_t) calib[5] << 8) | calib[4]);
dig_P1B = (uint16_t)(((uint16_t) calib[7] << 8) | calib[6]);
dig_P2B = ( int16_t)((( int16_t) calib[9] << 8) | calib[8]);
dig_P3B = ( int16_t)((( int16_t) calib[11] << 8) | calib[10]);
dig_P4B = ( int16_t)((( int16_t) calib[13] << 8) | calib[12]);
dig_P5B = ( int16_t)((( int16_t) calib[15] << 8) | calib[14]);
dig_P6B = ( int16_t)((( int16_t) calib[17] << 8) | calib[16]);
dig_P7B = ( int16_t)((( int16_t) calib[19] << 8) | calib[18]);
dig_P8B = ( int16_t)((( int16_t) calib[21] << 8) | calib[20]);
dig_P9B = ( int16_t)((( int16_t) calib[23] << 8) | calib[22]);
dig_H1B = calib[25];
readBytesWire1(BME280_ADDRESS, BME280_CALIB26, 7, &calib[0]);
dig_H2B = ( int16_t)((( int16_t) calib[1] << 8) | calib[0]);
dig_H3B = calib[2];
dig_H4B = ( int16_t)(((( int16_t) calib[3] << 8) | (0x0F & calib[4]) << 4) >> 4);
dig_H5B = ( int16_t)(((( int16_t) calib[5] << 8) | (0xF0 & calib[4]) ) >> 4 );
dig_H6B = calib[6];
}
// simple function to scan for I2C devices on the bus
void i2cScanWire1() {
// scan for i2c devices
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire1.beginTransmission(address);
error = Wire1.endTransmission();
//sensor2Status = error;
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
} else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
// simple function to scan for I2C devices on the bus
void i2cScanWire() {
// scan for i2c devices
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
//sensor1Status=error;
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
} else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else {
Serial.println("done\n");
}
}
void initialize() {
i2cScanWire(); // Wire Check for I2C devices on the I2C bus
i2cScanWire1(); // Wire1
delay(1000);
// Read the WHO_AM_I register of the BME280 this is a good test of communication
byte f = readByteWire(BME280_ADDRESS, BME280_ID); // Read WHO_AM_I register for BME280
Serial.print("BME280 ");
Serial.print("I AM ");
Serial.print(f, HEX);
Serial.print(" I should be ");
Serial.println(0x60, HEX);
Serial.println(" ");
delay(1000);
if(f == 0x60) {
writeByteWire(BME280_ADDRESS, BME280_RESET, 0xB6); // reset BME280 before initilization
delay(100);
BME280InitWire(); // Initialize BME280 altimeter
Serial.println("Calibration coeficients:");
Serial.print("dig_T1A =");
Serial.println(dig_T1A);
Serial.print("dig_T2A =");
Serial.println(dig_T2A);
Serial.print("dig_T3A =");
Serial.println(dig_T3A);
Serial.print("dig_P1A =");
Serial.println(dig_P1A);
Serial.print("dig_P2A =");
Serial.println(dig_P2A);
Serial.print("dig_P3A =");
Serial.println(dig_P3A);
Serial.print("dig_P4A =");
Serial.println(dig_P4A);
Serial.print("dig_P5A =");
Serial.println(dig_P5A);
Serial.print("dig_P6A =");
Serial.println(dig_P6A);
Serial.print("dig_P7A =");
Serial.println(dig_P7A);
Serial.print("dig_P8A =");
Serial.println(dig_P8A);
Serial.print("dig_P9A =");
Serial.println(dig_P9A);
Serial.print("dig_H1A =");
Serial.println(dig_H1A);
Serial.print("dig_H2A =");
Serial.println(dig_H2A);
Serial.print("dig_H3A =");
Serial.println(dig_H3A);
Serial.print("dig_H4A =");
Serial.println(dig_H4A);
Serial.print("dig_H5A =");
Serial.println(dig_H5A);
Serial.print("dig_H6A =");
Serial.println(dig_H6A);
}
else Serial.println(" BME280 not functioning!");
// Read the WHO_AM_I register of the BME280 this is a good test of communication
byte f2 = readByteWire1(BME280_ADDRESS, BME280_ID); // Read WHO_AM_I register for BME280
Serial.print("BME280 ");
Serial.print("I AM ");
Serial.print(f, HEX);
Serial.print(" I should be ");
Serial.println(0x60, HEX);
Serial.println(" ");
delay(1000);
if(f2 == 0x60) {
writeByteWire1(BME280_ADDRESS, BME280_RESET, 0xB6); // reset BME280 before initilization
delay(100);
BME280InitWire1(); // Initialize BME280 altimeter
Serial.println("Calibration coeficients:");
Serial.print("dig_T1B =");
Serial.println(dig_T1B);
Serial.print("dig_T2B =");
Serial.println(dig_T2B);
Serial.print("dig_T3B =");
Serial.println(dig_T3B);
Serial.print("dig_P1B =");
Serial.println(dig_P1B);
Serial.print("dig_P2B =");
Serial.println(dig_P2B);
Serial.print("dig_P3B =");
Serial.println(dig_P3B);
Serial.print("dig_P4B =");
Serial.println(dig_P4B);
Serial.print("dig_P5B =");
Serial.println(dig_P5B);
Serial.print("dig_P6B =");
Serial.println(dig_P6B);
Serial.print("dig_P7B =");
Serial.println(dig_P7B);
Serial.print("dig_P8B =");
Serial.println(dig_P8B);
Serial.print("dig_P9B =");
Serial.println(dig_P9B);
Serial.print("dig_H1B =");
Serial.println(dig_H1B);
Serial.print("dig_H2B =");
Serial.println(dig_H2B);
Serial.print("dig_H3B =");
Serial.println(dig_H3B);
Serial.print("dig_H4B =");
Serial.println(dig_H4B);
Serial.print("dig_H5B =");
Serial.println(dig_H5B);
Serial.print("dig_H6B =");
Serial.println(dig_H6B);
}
}