SPI Problem Arduino Mega with pressure sensor MS5803-05BA

Hello,

I need your help for a project.

I have actually 2 parallel sensors of the type: MS5803-05BA, which supports I2C and SPI connection. One sensor is on I2C bus and one sensor is on SPI. They are both sending to my Arduino Mega. The I2C works perfect with short cables.

Here the datasheet of the sensor:

For some informations who wants to do the same with I2C. Here you can find a good code. (You can find the other MS580X typs there too). For the communication between the sensor and the Arduino Mega you need an logic converter like this txs0108e, which can be bought with a break out board (you need pull up resistors on the sensor side!):

But to my problem: I have an sensor distance for about 3-5 meters and the I2C connections doesnt work. Yes I can try to fix the pullup resistors but it doesnt worked for me (I have tried some different lower resistors between 3-10kOhm). Therefore I want to switch to the SPI bus.

I have edit the code from GitHub - millerlp/MS5803_05: Arduino library for the MS5803_05BA pressure sensor from Measurement Specialties. Communicates via I2C., GitHub - vic320/Arduino-MS5803-14BA: An Arduino library for the MS5803-14BA pressure/temperature sensor. Works with SPI and i2C. and Teensy: SPI and Pressure Sensor - Arduino Stack Exchange.

The File is added. (You have to put the .h and .cpp files in the folder of the arduino code (.spi).

I have problems with the code from the SPI (ccp and header). There is no right communication. I have checked my cables twice. I couldnt find a problem and the connection with the txs0108e works for parallel I2C sensor. Both sensors are working on I2C.

Here is the main code for SPI and I2C parallel:

/_____ I N C L U D E S
#include <stdio.h>
#include <math.h>
#include <SPI.h>
#include <Wire.h>
#include "MS5803_05.h"
#include "MS5803_05_SPI.h"


const int miso_port = 50; //SDI
const int mosi_port = 51; //SDO
const int sck_port = 52;  //SLCK
const int slaveSelectPin = 53; // CSB

MS_5803 sensor = MS_5803(512);
MS_5803_SPI sensor_spi = MS_5803_SPI(4096, slaveSelectPin);


void setup()
{
  pinMode(miso_port, INPUT);
  pinMode(mosi_port, OUTPUT);
  pinMode(slaveSelectPin, OUTPUT);
  pinMode(sck_port, OUTPUT);  

  Serial.begin(9600);
  //SPI BUS
  if (sensor_spi.initializeMS_5803_SPI()) {
    Serial.println( "MS5803 SPI CRC check OK." );
  }
  else {
    Serial.println( "MS5803 SPI CRC check FAILED!" );
  }  

  //I2C BUS
  delay(1000);
  if (sensor.initializeMS_5803()) {
    Serial.println( "MS5803 I2C CRC check OK." );
  }
  else {
    Serial.println( "MS5803 I2C CRC check FAILED!" );
  }  

}

void loop()
{
  Serial.println("SPI Sensor first pressure [mbar], than temperature[°C]:");
  sensor_spi.readSensor();

  // Show pressure
  Serial.print("Pressure = ");
  Serial.print(sensor_spi.pressure());
  Serial.println(" mbar");

  // Show temperature
  Serial.print("Temperature = ");
  Serial.print(sensor_spi.temperature());
  Serial.println("C");

  ////********************************************************
  Serial.println("");

  Serial.println("I2C Sensor first pressure [mbar], than temperature[°C]:");
  sensor.readSensor();
  // Show pressure
  Serial.print("Pressure = ");
  Serial.print(sensor.pressure());
  Serial.println(" mbar");

  // Show temperature
  Serial.print("Temperature = ");
  Serial.print(sensor.temperature());
  Serial.println("C");

  delay(2000);
}

The first connection with SPI is here:

#include "MS5803_05_SPI.h"
#include <SPI.h>

#define CMD_RESET 0x1E // ADC reset command
#define CMD_ADC_READ 0x00 // ADC read command
#define CMD_ADC_CONV 0x40 // ADC conversion command
#define CMD_ADC_D1 0x00 // ADC D1 conversion
#define CMD_ADC_D2 0x10 // ADC D2 conversion
#define CMD_ADC_256 0x00 // ADC resolution=256
#define CMD_ADC_512 0x02 // ADC resolution=512
#define CMD_ADC_1024 0x04 // ADC resolution=1024
#define CMD_ADC_2048 0x06 // ADC resolution=2048
#define CMD_ADC_4096 0x08 // ADC resolution=4096
#define CMD_PROM_RD 0xA0 // Prom read command

#define spi_write SPI_MODE3
#define spi_write2 SPI_MODE1

// Create array to hold the 8 sensor calibration coefficients
static unsigned int      sensorCoeffs[8]; // unsigned 16-bit integer (0-65535)
// D1 and D2 need to be unsigned 32-bit integers (long 0-4294967295)
static uint32_t     D1 = 0;    // Store uncompensated pressure value
static uint32_t     D2 = 0;    // Store uncompensated temperature value
// These three variables are used for the conversion steps
// They should be signed 32-bit integer initially 
// i.e. signed long from -2147483648 to 2147483647
static int32_t dT = 0;
static int32_t TEMP = 0;
// These values need to be signed 64 bit integers 
// (long long = int64_t)
static int64_t Offset = 0;
static int64_t Sensitivity  = 0;
static int64_t T2 = 0;
static int64_t OFF2 = 0;
static int64_t Sens2 = 0;

// Some constants used in calculations below
const uint64_t POW_2_33 = 8589934592ULL; // 2^33 = 8589934592
SPISettings settings_write(500000, MSBFIRST, spi_write);
SPISettings settings_write2(500000, MSBFIRST, spi_write2);

//-------------------------------------------------
// Constructor
MS_5803_SPI::MS_5803_SPI( uint16_t Resolution, uint16_t cs) {
 // The argument is the oversampling resolution, which may have values
 // of 256, 512, 1024, 2048, or 4096.
 _Resolution = Resolution;
  //Chip Select
  _cs=cs;
}

boolean MS_5803_SPI::initializeMS_5803_SPI(boolean Verbose) {
      digitalWrite( _cs, HIGH );
      SPI.begin();
      // Reset the sensor during startup
      resetSensor(); 
      
      if (Verbose) 
      {
       // Display the oversampling resolution or an error message
       if (_Resolution == 256 | _Resolution == 512 | _Resolution == 1024 | _Resolution == 2048 | _Resolution == 4096){
           Serial.print("Oversampling setting: ");
           Serial.println(_Resolution);     
       } else {
   Serial.println("*******************************************");
   Serial.println("Error: specify a valid oversampling value");
   Serial.println("Choices are 256, 512, 1024, 2048, or 4096");
   Serial.println("*******************************************");
       }
  
      }  
     
      // Read sensor coefficients
      for (int i = 0; i < 8; i++ )
      {
        SPI.beginTransaction(settings_write2);
        digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low          
        unsigned int ret;
        unsigned int rC = 0;         
        SPI.transfer(CMD_PROM_RD + i * 2); // send PROM READ command
        /*
        ret = SPI.transfer(0x00); // send 0 to read the MSB
        rC = 256 * ret;
        ret = SPI.transfer(0x00); // send 0 to read the LSB
        rC = rC + ret;    
        */
        // send a value of 0 to read the first byte returned:
        rC = SPI.transfer( 0x00 );
        rC = rC << 8;
        rC |= SPI.transfer( 0x00 ); // and the second byte        
       sensorCoeffs[i] = (rC);
      
        digitalWrite( _cs, HIGH );
        delay(3); 
    }
    //SPI.endTransaction(); // interrupt can now be accepted
    // The last 4 bits of the 7th coefficient form a CRC error checking code.
    unsigned char p_crc = sensorCoeffs[7];
    // Use a function to calculate the CRC value
    unsigned char n_crc = MS_5803_CRC(sensorCoeffs); 
    
    if (Verbose) {
      for (int i = 0; i < 8; i++ )
      {
        // Print out coefficients 
        Serial.print("C");
        Serial.print(i);
        Serial.print(" = ");
        Serial.println(sensorCoeffs[i]);
        delay(10);
      }      
   Serial.print("p_crc: ");
   Serial.println(p_crc);
   Serial.print("n_crc: ");
   Serial.println(n_crc);
    }
    // If the CRC value doesn't match the sensor's CRC value, then the 
    // connection can't be trusted. Check your wiring. 
    if (p_crc != n_crc) {
        return false;
    }
    // Otherwise, return true when everything checks out OK. 
    return true;
}
// Sends a power on reset command to the sensor.
void MS_5803_SPI::resetSensor() {
  SPI.beginTransaction(settings_write);
  digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low to start the command
  SPI.transfer(CMD_RESET); // send reset sequence
  delay(3); // wait for the reset sequence timing delay(3)
  digitalWrite(_cs, HIGH); //csb_hi(); // pull CSB high to finish the command
  SPI.endTransaction(); // interrupt can now be accepted
}


I have problems to read the calibration values of the sensors. What is wrong with my code and the SPI connection? Is the SPI.setDataMode wrong or other options for the connection? The sensor works for I2C.

ms5803_i2c_spi.zip (13.8 KB)

Yes I can try to fix the pullup resistors but it doesnt worked for me

No, you cannot. The only way to make it work on longer wires is to dramatically lower the clock frequency. At 5 meter I would try a frequency of 1kHz.

But to my problem: I have an sensor distance for about 3-5 meters and the I2C connections doesnt work.

Move the Arduino directly to the sensor. If you need the information at a distance of 3-5 meters, use a second board and transfer it by WiFi, Ethernet, Bluetooth or RS485 (there are other options but these are the more common ones).

Therefore I want to switch to the SPI bus.

Wrong decision. SPI doesn't allow for longer wires.

I have problems with the code from the SPI (ccp and header). There is no right communication. I have checked my cables twice. I couldnt find a problem and the connection with the txs0108e works for parallel I2C sensor. Both sensors are working on I2C.

SDI on the sensor connects to MOSI (not MISO) and SDO connects to MISO (not MOSI). The way you wired it, it cannot work. You don't need the pull-ups if you use the TXS0108E, it contains pull-ups on both sides (see the functional block diagram on page 18 of the datasheet).

The solution was: https://www.hackster.io/tarantula3/tca9548a-i2c-multiplexer-module-with-arduino-and-nodemcu-3d3313. The sensors influenced each other and the multiplexer tc9548 solved the problem. I took the i2c connection and now it works. If you have a long distance to the sensor this should help: SparkFun Differential I2C Breakout - PCA9615 (Qwiic) (https://www.sparkfun.com/products/14589). But for my 3m it was not necessary.

Thanks for your support.

Yes maybe thats why SDI didnt work i didnt try it (wrong connection MISO / MOSI).But i am not sure about the SPI Mode to send and receive (in the Header file). You need to try it if you have the same problems. I will redraw the schematic for someone with the same problems. The pullups are needed like in the datasheet of the sensor. The arduino has internal pullups. They are correct on the schematic.