Arduino UNO R4 WIFI & PMS5003

Hello everyone,

I'm experiencing an issue with the PMS5003 particle sensor when interfacing it with two different Arduino boards: a standard Arduino Uno and an Arduino Uno R4 WiFi. Although the sensor operates as expected on the standard Arduino Uno, I am facing significant challenges on the Arduino Uno R4 WiFi, including frequent checksum failures and occasional invalid header errors.

Problem Description:

Setup: I'm using a PMS5003 sensor to measure air quality, specifically particulate matter concentrations (PM2.5, PM10). The data from the sensor is expected to be in the form of a byte frame that includes a header, data payload, and a checksum.

Standard Arduino Uno: When connected to a standard Arduino Uno, the sensor sends data frames that are consistently recognized and processed correctly. The frames typically begin with a header (0x42, 0x4D), followed by the data representing particulate matter measurements and ending with a checksum. There are no issues with data integrity or checksum errors.

Arduino Uno R4 WiFi: With the Arduino Uno R4 WiFi, the frames are often not recognized correctly. Even when frames are recognized, there are frequent checksum errors. The checksum calculated from the received data often does not match the checksum transmitted by the sensor, leading to data rejection.

Sample Data Frames:

Working (Standard Uno): 0x42, 0x4D, ... (correct data structure) ..., checksum
Not Working (Uno R4 WiFi): Sometimes the frames appear as expected, but the checksums fail. Other times, the header itself is not recognized.
Attempts to Resolve:

I have attempted to ignore the checksum to see if the data itself might still be correct. By doing this, the sensor readings seem plausible, suggesting that only the checksum computation or transmission is flawed.
I've implemented a more robust data reading strategy, ensuring synchronization starts exactly at the header start and confirming that a full frame is available before processing.
Questions for the Forum:

Has anyone experienced similar issues with the PMS5003 on different Arduino models, particularly with the Uno R4 WiFi?
Are there known issues with the UART interface or interrupt handling on the Arduino Uno R4 WiFi that could affect serial data integrity?
Any suggestions on alternate approaches to verify data integrity aside from relying solely on the checksum?
Any insights or suggestions would be greatly appreciated as I continue to troubleshoot this issue.
Thank you!

Welcome to the forum

I assume that you are using pins 0 and 1 of the Uno R4 and the Serial1 interface, or are you ?

Please post your sketch used on the Uno R4

No, I use pins 2 and 3. It works on UNO but does not work on UNO R4 WIFI

#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(2, 3);
 
void setup() {
  // our debugging output
  Serial.begin(115200);
 
  // sensor baud rate is 9600
  pmsSerial.begin(9600);
}
 
struct pms5003data {
  uint16_t framelen;
  uint16_t pm10_standard, pm25_standard, pm100_standard;
  uint16_t pm10_env, pm25_env, pm100_env;
  uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
  uint16_t unused;
  uint16_t checksum;
};
 
struct pms5003data data;
    
void loop() {
  if (readPMSdata(&pmsSerial)) {
    // reading data was successful!
    Serial.println();
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (standard)");
    Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (environmental)");
    Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
    Serial.println("---------------------------------------");
    Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
    Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
    Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
    Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
    Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
    Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
    Serial.println("---------------------------------------");
  }
}
 
boolean readPMSdata(Stream *s) {
  if (! s->available()) {
    return false;
  }
  
  // Read a byte at a time until we get to the special '0x42' start-byte
  if (s->peek() != 0x42) {
    s->read();
    return false;
  }
 
  // Now read all 32 bytes
  if (s->available() < 32) {
    return false;
  }
    
  uint8_t buffer[32];    
  uint16_t sum = 0;
  s->readBytes(buffer, 32);
 
  // get checksum ready
  for (uint8_t i=0; i<30; i++) {
    sum += buffer[i];
  }
 
  /* debugging
  for (uint8_t i=2; i<32; i++) {
    Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
  }
  Serial.println();
  */
  
  // The data comes in endian'd, this solves it so it works on all platforms
  uint16_t buffer_u16[15];
  for (uint8_t i=0; i<15; i++) {
    buffer_u16[i] = buffer[2 + i*2 + 1];
    buffer_u16[i] += (buffer[2 + i*2] << 8);
  }
 
  // put it into a nice struct :)
  memcpy((void *)&data, (void *)buffer_u16, 30);
 
  if (sum != data.checksum) {
    Serial.println("Checksum failure");
    return false;
  }
  // success!
  return true;
}

You don't need to use SoftwareSerial on the R4. It has 2 independent hardware serial interfaces unlike the R3

Connect the sensor to pins 0 and 1 and use Serial1 to communicate with it

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.