Arduino Interfacing with SMI Pressure Sensor

Hi all!

Currently working on a research project that involves using an SMI SM9333 micro pressure sensor. I am not too high tech when it comes to coding and looked online for some code that would work with this sensor. I found a library originally created by a Github user by the name of jhschwartz but when I use the code on my sensor it pops up with a collect2.exe: error: ld returned 1 exit status exit status 1 Error compiling for board error. Does anyone know why this is? From what I can tell the code is optimized for multiple sensors of the same type but my setup is only using one. Any and all help much appreciated!

// SM9333.cpp
#include "SM9333.h"
#include <Wire.h>
#include <assert.h>
#include <math.h>

SM9333::SM9333() {}

void SM9333::set_multiplex(int multiplex_output) {
    if (multiplex_output < 0x71 || multiplex_output > 0x77)
        assert(false);
    this->multiplex_output = multiplex_output;
    assert(this->isConnected());
}

bool SM9333::isConnected() {
    // do an actual check that the address can be reached??
    return true;
}

double SM9333::readPressure() {
    pressureTemperaturePair pair = readBoth();
    return pair.pressure;
}

double SM9333::readTemperature() {
    pressureTemperaturePair pair = readBoth();
    return pair.temperature;
}

pressureTemperaturePair SM9333::readBoth() {
    // int command[3] = {0x2E, 0x5B, 0xDB};
    // commandSequence seq = {command, 3};
    // writer(seq);
    int* result = doRead(7, true, 0x2E);
    int temp_low_bit = result[0];
    int temp_high_bit = result[1];
    int pres_low_bit = result[2];
    int pres_high_bit = result[3];

    pressureTemperaturePair pair = {
        calculatePressure(pres_low_bit, pres_high_bit),
        calculateTemperature(temp_low_bit, temp_high_bit)
    };

    return pair;
}

double SM9333::calculatePressure(int pressureLowByte, int pressureHighByte) {
    int digital = pressureLowByte | pressureHighByte << 8;
    double p_pc = 100.0/(pow(2,16)-1)*double(digital) + 100.0*pow(2,16)/(2.0*(pow(2,16)-1));
    // the datasheet calculation of p_p appears to be a mistake. -P_MIN instead of +. 
    double p_p = (P_MIN-P_MAX)/80.0 * p_pc - P_MIN - (P_MIN-P_MAX)/8.0;
    return p_p;
}

double SM9333::calculateTemperature(int temperatureLowBit, int temperatureHighBit) {
    int digital = temperatureLowBit | temperatureHighBit << 8;
    double temp = (double(digital) - b0)/b1;
    return temp;
}

void SM9333::writer(commandSequence seq) {
    this->multiplex_switch();
    Wire.beginTransmission(SM9333_UNPROTECTED);
    for (int i = 0; i < seq.length; i++) {
        int val = seq.sequence[i];
        // Wire.write((byte)val);
        Wire.write(val);
    }
    Wire.endTransmission();
}

int* SM9333::doRead(int numBits, bool crcProtected, int location) {
    this->multiplex_switch();
    int crcLoc = crcProtected ? SM9333_CRC_PROTECTED : SM9333_UNPROTECTED;
    int command[3] = {location, 0x5B, 0xDB};
    commandSequence seq = {command, 3};
    writer(seq);
    Wire.requestFrom(crcLoc, numBits);

    // int result[numBits];
    int* result;
    for (int i = 0; i < numBits; i++) {
        *(result+i) = Wire.read();
    }
    return result;
}

void SM9333::multiplex_switch() {
    Wire.beginTransmission(0x70);
    Wire.write(this->multiplex_output);
    Wire.endTransmission();
}

This file is a resource not a program. You much put this file and the .ino and .h file in your project directory.

Compile and run the INO file. Specify only one sensor.

Ok that makes sense. I have now done this and the serial monitor writes only pressure readouts and even when blowing on the sensor there is no change. However I did realize I miss-wired the SCL and SDA wires but even after correction the sensor isn't changing in pressure. It's a differential pressure sensor so it definitely should be able to pick up on me blowing on it? Any ideas are appreciated.

INO file:

#include "SM9333.h"

SM9333 sensor1;
SM9333 sensor2;
SM9333 sensor3;
SM9333 sensor4;
SM9333 sensor5;

void setup() {
  Serial.begin(9600);

  sensor1.set_multiplex(0x71);
  sensor2.set_multiplex(0x72);
  sensor3.set_multiplex(0x73);
  sensor4.set_multiplex(0x74);
  sensor5.set_multiplex(0x75);

}

void loop() {
  double p1 = sensor1.readPressure();
  double p2 = sensor2.readPressure();
  double p3 = sensor2.readPressure();
  double p4 = sensor2.readPressure();
  double p5 = sensor2.readPressure();

  Serial.println("Sensor 1: " + (String)p1 + " Pa");
  Serial.println("Sensor 2: " + (String)p2 + " Pa");
  Serial.println("Sensor 3: " + (String)p3 + " Pa");
  Serial.println("Sensor 4: " + (String)p4 + " Pa");
  Serial.println("Sensor 5: " + (String)p5 + " Pa");

  Serial.println("------------------------");

  delay(200);

}

(I deleted any and all instances of sensors other than sensor 1)

The code you posted doesn't look that way.

Are you also using the TCA9548A I2C Multiplexer like the original author was? That .set_multiplex() call is talking to it. Maybe you have your 1 sensor wired up directly?

If that is the case, you will have to alter their code to talk to the sensor directly.

Sorry I meant when I uploaded it to my controller. I just posted the original for redundancy. And no I do not have a multiplexer, the circuit is directly connected to the arduino. How would I need to change the code in order to communicate directly with the sensor? Thanks in advance!

The circuit I have wired up below:

Just remove all the calls/references to the multiplexer. It will just use the Wire library directly

The original code shows different addresses for each sensor.

Have you run the I2C scanner to see if the sensor is addressable?

If the I2C scanner works and shows an address listed in the SMI example, run the original code as is but increase the loop delay to something like 2 seconds, i.e. delay(2000)

#include <Wire.h>

void setup() {
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  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();

    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("Unknown 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");

  delay(5000);           // wait 5 seconds for next scan
}



Looking at the library, I noticed a bug in the doRead() function. It was writing to unallocated memory. Forked the code, fixed the bug and removed the multiplex stuff

Ran the code, it says there are no I2C devices connected

Hey thanks so much! I ended up trying the code though and it is still showing no change in the pressure when blowing on the sensor. Could this mean there is a problem with the sensor itself?

So there is a hardware problem. There is no use trying other code if the scanner can't find the device.

Triple check the specification and connections. If you have a voltmeter you should measure the voltage on the SMI board/sensor.

Could the I2C connections be reversed?

Do you have pullup resistors?

Ah ok. So there are a few possibilities I can think of. Maybe I need to apply more solder to the connections to make sure they are properly connected. Maybe from soldering next to the sensor, the high temperatures ended up frying the sensor and making it unable to work. Would a higher capacitance than recommended or higher resistance than recommended stop it from working properly? It requires a 0.1uF capacitor but all I had laying around was a 220uF. I also can't tell the exact resistance needed for the SCL and SDA connection so I am using 2.2k resistors.

Post a photo before reheating the device again.

0.1 vs 220µF WHere is this connected, if it is the power then it will likely not be an issue but the 220 does not perform well at high frequencies so you should still get a 0.1µF.

SCL SDA pullups are usually around 5k. If you don't have a 4.7k or 5k or anywhere close, put two 2.2k's in series to pullup both lines.

Hey thanks for the advice! Sorry about yesterday, ended up having a late night at work. ANYWAYS, went and looked at the connections between the sensor and the board and they seem a little sloppy but they all seem connected. Also the capacitor is the black cylinder in the photo and is directly connected to GND and power supply. As for the resistance I do have a few 5k resistors so i'll switch those out.

pictures of the connections:

(apparently I can only upload 1 pic at a time, the other one looks good)

I would try to clean up those joints. You will need some thin solder and a decent iron. I don't know it I would recommend this when you have nothing disposable to practice on but you might Google "drag solder"