Problem getting stable data from I2C sensor when receiving by SoftwareSerial

Hello!

I’m trying to obtain pressure samples from a MS5611 altimeter (Drotek 10 DOF), and after some issues with the conversion of RawData I finally got it.

The next step is send this data and some other to another micro (I’m using two ATMEGA328 for this) for later processing, to achieve this I’ve tried using the library SoftEasyTransfer. There seems to be no problem when I use

ET.sendData()

, but the data starts to drift when adding

ET.receiveData()

to my program.

I’m using pins 27 and 28 (SCL and SDA) on one of the ATMEGAs to get info from the sensor, and pins 4 and 5 on both ATMEGAs to communicate between them.

I don’t know why this can be. Maybe they share the same buffer? I’m completely lost.

This is the piece of code for ET.receiveData(), you can find it inside the library SoftEasyTransfer:

boolean SoftEasyTransfer::receiveData(){
  
  //start off by looking for the header bytes. If they were already found in a previous call, skip it.
  if(rx_len == 0){
  //this size check may be redundant due to the size check below, but for now I'll leave it the way it is.
    if(_serial->available() >= 3){
 //this will block until a 0x06 is found or buffer size becomes less then 3.
      while(_serial->read() != 0x06) {
 //This will trash any preamble junk in the serial buffer
 //but we need to make sure there is enough in the buffer to process while we trash the rest
 //if the buffer becomes too empty, we will escape and try again on the next call
 if(_serial->available() < 3)
 return false;
 }
      if (_serial->read() == 0x85){
        rx_len = _serial->read();
 //make sure the binary structs on both Arduinos are the same size.
        if(rx_len != size){
          rx_len = 0;
          return false;
        }
      }
    }
  }
  
  
  
  if(rx_len != 0){
    while(_serial->available() && rx_array_inx <= rx_len){
      rx_buffer[rx_array_inx++] = _serial->read();
    }
    
    if(rx_len == (rx_array_inx-1)){
      //seem to have got whole message
      //last uint8_t is CS
      calc_CS = rx_len;
      for (int i = 0; i<rx_len; i++){
        calc_CS^=rx_buffer[i];
      } 
      
      if(calc_CS == rx_buffer[rx_array_inx-1]){//CS good
        memcpy(address,rx_buffer,size);
 rx_len = 0;
 rx_array_inx = 0;
 return true;
 }
        
  else{
  //failed checksum, need to clear this out anyway
 rx_len = 0;
 rx_array_inx = 0;
 return false;
  } 
 
    }
  }
  
  return false;
}

And this is my program for one of the ATMEGA328, the one I call microB (there are some variables and led functions that I haven’t added for simplifying purposes, I’ve checked they don’t interfere):

/*librerías necesarias para sensor MS561101*/
#include <Wire.h>

/*librerías necesarias para intercomunicación con micro A (SOFTSERIAL)*/
#include <SoftEasyTransfer.h>
#include <SoftwareSerial.h>

SoftwareSerial softSerial(2, 3);

/*variables para calcular press y temp*/
#define ADDRESS 0x77 // 0x76
#define SAMPLENUM 10

uint32_t D1 = 0;
uint32_t D2 = 0;
int64_t dT = 0;
int32_t TEMP = 0;
int64_t OFF = 0;
int64_t SENS = 0;
int32_t P = 0;
uint16_t C[7];

float temperature;
float pressure;

float sampledPress[SAMPLENUM];
unsigned long contadorPress = 0;
int indice = 0;
float pressRef;
int estado = 0; // 0: parado; 2: subiendo; 1: bajando
boolean moveOK = false;
int limite = 3;
int indiceFor = 0;
float cteFiltro1 = 0.85;

/*Softserial !!!*/
SoftEasyTransfer ET;

struct SERIAL_DATA_STRUCTURE
{
 // microB ---->microA
        // there are 7 variables here
 

 //microA---> microB
        //there are 14 variables here
};

//give a name to the group of data
SERIAL_DATA_STRUCTURE soft_serial_data;

void setup()
{
 /** SETUP PARA MS561101 **/
 // Disable internal pullups, 10Kohms are on the breakout
 PORTC |= (1 << 4);
 PORTC |= (1 << 5);

 Wire.begin();
 delay(100);
 initial(ADDRESS);
 
 /** SETUP PARA SOFTSERIAL **/
 softSerial.begin(57600);
 //start the library, pass in the data details and the name of the serial port.
 ET.begin(details(soft_serial_data), &softSerial);
 

 delay(500);
}

void loop()
{
 assignPress();
 
 assignDataToSend();
 ET.sendData();
 
 if(ET.receiveData()){ 
 //assignReceivedData();
 //delay(1000);
 }
 
}

/** FUNCIONES PARA MS561101 **/
//filtramos el valor obtenido de presión y lo metemos a un registro FIFO
void assignPress()
{
 pressure = pressure*cteFiltro1 + getPress()*(1-cteFiltro1);
 indice = contadorPress%SAMPLENUM;
 sampledPress[indice] = pressure;
 contadorPress++;
}

//cálculos necesarios para obtener una muestra de presión en mbar
float getPress()
{
 D1 = getVal(ADDRESS, 0x48); // Pressure raw
 D2 = getVal(ADDRESS, 0x58);// Temperature raw
 
 dT   = D2 - ((uint64_t)C[5] << 8);
 OFF  = ((int64_t)C[2] << 16) + ((dT * C[4]) >> 7);
 SENS = ((int32_t)C[1] << 15) + ((dT * C[3]) >> 8);

 TEMP = (int64_t)dT * (int64_t)C[6] / 8388608 + 2000;

 if(TEMP < 2000) // if temperature lower than 20 Celsius
 {
 int32_t T1    = 0;
 int64_t OFF1  = 0;
 int64_t SENS1 = 0;

 T1    = pow(dT, 2) / 2147483648;
 OFF1  = 5 * pow((TEMP - 2000), 2) / 2;
 SENS1 = 5 * pow((TEMP - 2000), 2) / 4;
 
 if(TEMP < -1500) // if temperature lower than -15 Celsius
 {
 OFF1  = OFF1 + 7 * pow((TEMP + 1500), 2);
 SENS1 = SENS1 + 11 * pow((TEMP + 1500), 2) / 2;
 }
 
 TEMP -= T1;
 OFF -= OFF1;
 SENS -= SENS1;
 }

 temperature = (float)TEMP / 100;
 
 P  = ((int64_t)D1 * SENS / 2097152 - OFF) / 32768;

 pressure = (float)P / 100;
 
 return pressure;
}

//obtener valores de la prom del IMU
long getVal(int address, byte code)
{
 unsigned long ret = 0;
 Wire.beginTransmission(address);
 Wire.write(code);
 Wire.endTransmission();
 delay(10);
 // start read sequence
 Wire.beginTransmission(address);
 Wire.write((byte) 0x00);
 Wire.endTransmission();
 Wire.beginTransmission(address);
 Wire.requestFrom(address, (int)3);
 if (Wire.available() >= 3)
 {
 ret = Wire.read() * (unsigned long)65536 + Wire.read() * (unsigned long)256 + Wire.read();
 }
 else {
 ret = -1;
 }
 Wire.endTransmission();
 return ret;
}

//cálculo de coeficientes necesarios para las posteriores fórmulas matemáticas mediante las que se consigue muestrear la presión ambiental
void initial(uint8_t address)
{
 Wire.beginTransmission(address);
 Wire.write(0x1E); // reset
 Wire.endTransmission();
 delay(10);

 for (int i=0; i<6  ; i++) {

 Wire.beginTransmission(address);
 Wire.write(0xA2 + (i * 2));
 Wire.endTransmission();

 Wire.beginTransmission(address);
 Wire.requestFrom(address, (uint8_t) 6);
 delay(1);
 if(Wire.available())
 {
 C[i+1] = Wire.read() << 8 | Wire.read();
 }
 else {
 //Serial.println("Error reading PROM 1"); // error reading the PROM or communicating with the device
 }
 }
}

As you can see I haven’t added the functions assignReceivedData() and assignDataToSend(), but this is because I’m actually not using them until I solve the press data problem.

Without adding this:

if(ET.receiveData()){ 
 //assignReceivedData();
 //delay(1000);
 }

to the above program I get very stable samples of press, but if I add those lines, the samples go fast down occasionally and then returns to the stable value which I can’t stand.

Could anyone, please, suggest me a solution?

I've tried decreasing soft_serial variables from 21 to 5 but it keeps on happening the same...

I'd suggest you stop using a library that's giving you so much grief. Why don't you just use the hardware serial to get the atmegas to talk to each other? At least then, if you have problems, you'll likely find someone that can help.

I doubt many are going to be prepared to download a library to start debugging it.

KenF:
I'd suggest you stop using a library that's giving you so much grief. Why don't you just use the hardware serial to get the atmegas to talk to each other? At least then, if you have problems, you'll likely find someone that can help.

I doubt many are going to be prepared to download a library to start debugging it.

I'll try it. I started using that library cause it's very fast for transmitting, if I'm not wrong it transmit in binary and maybe I won't be able to achieve that. But I'll try it anyway. Thank's a lot for your suggestion, I'll keep the thread updated with any news.

Kind regards.

You realise that you can use a baud rate of 1,000,000 between arduinos. (yes 1 Million) That's fairly fast.