I2C Communication with the particule sensor : SPS30


tags: flipper, I2C

This is an example code of I2C communication between a particulate matter sensor and the flipper board.

The particulate matter sensor is a Sensirion SPS30.

The sensor is wired on I2C1 communication bus so we will use Wire1 instance (if we were using I2C0 it would have been Wire instance, see flipper arduino bus references ). The i2C address of the SPS is 0x69 (see datasheet ).

Following code has been modified and adapted from this source.

1. Arduino code

flipper_sps30.ino
#include "Wire.h"
 
 int Address = 0x69; // device address of SPS30 (fixed).
 
 byte w1, w2,w3;
 byte ND[60];
 long tmp;
 float measure;
 
void setup() {
  //enabling VDD_SW power rail to give 5V source to the dolfin board
 pinMode(SW_VDD_EN, OUTPUT);
 digitalWrite(SW_VDD_EN,HIGH);
 //enabling 5V_sensor power rail to switch on the sensor
 pinMode(EXP_36, OUTPUT);
 digitalWrite(EXP_36,HIGH);
 //enabling 3V3_SW power rail to pull the I2C bus up via the 10K resistors
 pinMode(SW_3V3_EN, OUTPUT);
 digitalWrite(SW_3V3_EN,HIGH);
 //wait for the power sources to be turned on
 delay(1000);
 
  Wire1.begin(); // Initiate the Wire1 instance
  Serial.begin(115200);
  delay(100);
 
}
 
void loop() {
/*
// RESET device
  delay(1000);
  SetPointer(0xD3, 0x04);
  delay(1000);
*/  
 
//Start Measurement
  Wire1.beginTransmission(Address);
  Wire1.write(0x00);
  Wire1.write(0x10);
  Wire1.write(0x03);
  Wire1.write(0x00);
  uint8_t data[2]={0x03, 0x00};
  Wire1.write(CalcCrc(data));
  Wire1.endTransmission();
 
  delay(10000);
/*
//Start Fan Cleaning
  Serial.println("clean");
  Start fan cleaning
  SetPointer(0x56, 0x07);
  delay(12000);
  Serial.println("clean end");
  delay(100);
*/
 while(1){
  Serial.println(" ---------- ");
  //Read data ready flag
  SetPointer(0x02, 0x02);
  Wire1.requestFrom(Address, 3);
  w1=Wire1.read();
  w2=Wire1.read();
  w3=Wire1.read();
 
 
  if (w2==0x01){              //0x01: new measurements ready to read
    SetPointer(0x03,0x00);
    Wire1.requestFrom(Address, 60);
    for(int i=0;i<60;i++) { ND[i]=Wire1.read();                        
//    for(int i=0;i<30;i++) { ND[i]=Wire.read();     //without Wire.h lib modification only first 5 values
    //Serial.print(i);Serial.print(": ");Serial.println(ND[i],HEX);
    }
    // Result: PM1.0/PM2.5/PM4.0,PM10[μg/m³] , PM0.5,PM1.0/PM2.5/PM4.0,PM10 [[#/cm³], Typical Particle Size [μm]
    for(int i=0;i<60;i++) { 
       if ((i+1)%3==0)
       {
         byte datax[2]={ND[i-2], ND[i-1]};
         //Serial.print("crc: ");Serial.print(CalcCrc(datax),HEX);
         //Serial.print("  "); Serial.println(ND[i],HEX);
         if(tmp==0) {
           tmp= ND[i-2]; 
           tmp= (tmp<<8) + ND[i-1]; 
          }
         else{
           tmp= (tmp<<8)+ ND[i-2];
           tmp= (tmp<<8) + ND[i-1];
           //Serial.print(tmp,HEX);Serial.print(" ");
           measure= (*(float*) &tmp);
           Serial.print(measure); Serial.print(" ");
           tmp=0;
         }
 
       }
      }
 
 
  }
  Serial.println("");
 
  delay(2000);
 
 }
 
//  Stop Meaurement
//  SetPointer(0x01, 0x04);
 
}
 
void SetPointer(byte P1, byte P2)
{
  Wire1.beginTransmission(Address);
  Wire1.write(P1);
  Wire1.write(P2);
  Wire1.endTransmission();
  }
 
 
// from datasheet:
byte CalcCrc(byte data[2]) {
  byte crc = 0xFF;
  for(int i = 0; i < 2; i++) {    crc ^= data[i];    for(byte bit = 8; bit > 0; --bit) {
      if(crc & 0x80) {
      crc = (crc << 1) ^ 0x31u;
      } else {
        crc = (crc << 1);
       }
     }
   }
  return crc;
}