This is a “throw away” .NET nanoFramework application for investigating how Adafruit PMSA003I Inter Integrated Circuit bus(I²C) connectivity works.
My test setup is a simple .NET nanoFramework console application running on an Adafruit FeatherS2- ESP32-S2.
The PMSA0031 application has lots of magic numbers from the PMSA003I Module Datasheet and is just a tool for exploring how the sensor works.
public static void Main()
{
#if SPARKFUN_ESP32_THING_PLUS
Configuration.SetPinFunction(Gpio.IO23, DeviceFunction.I2C1_DATA);
Configuration.SetPinFunction(Gpio.IO22, DeviceFunction.I2C1_CLOCK);
#endif
#if ADAFRUIT_FEATHER_S2
Configuration.SetPinFunction(Gpio.IO08, DeviceFunction.I2C1_DATA);
Configuration.SetPinFunction(Gpio.IO09, DeviceFunction.I2C1_CLOCK);
#endif
Thread.Sleep(1000);
I2cConnectionSettings i2cConnectionSettings = new(1, 0x12, I2cBusSpeed.StandardMode);
using (I2cDevice i2cDevice = I2cDevice.Create(i2cConnectionSettings))
{
{
SpanByte writeBuffer = new byte[1];
SpanByte readBuffer = new byte[1];
writeBuffer[0] = 0x0;
i2cDevice.WriteRead(writeBuffer, readBuffer);
Console.WriteLine($"0x0 {readBuffer[0]:X2}");
}
while (true)
{
SpanByte writeBuffer = new byte[1];
SpanByte readBuffer = new byte[32];
writeBuffer[0] = 0x0;
i2cDevice.WriteRead(writeBuffer, readBuffer);
//Console.WriteLine(System.BitConverter.ToString(readBuffer.ToArray()));
Console.WriteLine($"Length:{ReadInt16BigEndian(readBuffer.Slice(0x2, 2))}");
if ((readBuffer[0] == 0x42) || (readBuffer[1] == 0x4d))
{
Console.WriteLine($"PM 1.0:{ReadInt16BigEndian(readBuffer.Slice(0x4, 2))}, 2.5:{ReadInt16BigEndian(readBuffer.Slice(0x6, 2))}, 10.0:{ReadInt16BigEndian(readBuffer.Slice(0x8, 2))} std");
Console.WriteLine($"PM 1.0:{ReadInt16BigEndian(readBuffer.Slice(0x0A, 2))}, 2.5:{ReadInt16BigEndian(readBuffer.Slice(0x0C, 2))}, 10.0:{ReadInt16BigEndian(readBuffer.Slice(0x0E, 2))} env");
Console.WriteLine($"µg/m3 0.3:{ReadInt16BigEndian(readBuffer.Slice(0x10, 2))}, 0.5:{ReadInt16BigEndian(readBuffer.Slice(0x12, 2))}, 1.0:{ReadInt16BigEndian(readBuffer.Slice(0x14, 2))}, 2.5:{ReadInt16BigEndian(readBuffer.Slice(0x16, 2))}, 5.0:{ReadInt16BigEndian(readBuffer.Slice(0x18, 2))}, 10.0:{ReadInt16BigEndian(readBuffer.Slice(0x1A, 2))}");
// Don't need to display these values everytime
//Console.WriteLine($"Version:{readBuffer[0x1c]}");
//Console.WriteLine($"Error:{readBuffer[0x1d]}");
}
else
{
Console.WriteLine(".");
}
Thread.Sleep(5000);
}
}
}
private static ushort ReadInt16BigEndian(SpanByte source)
{
if (source.Length != 2)
{
throw new ArgumentOutOfRangeException();
}
ushort result = (ushort)(source[0] << 8);
return result |= source[1];
}
The unpacking of the value standard particulate, environmental particulate and particle count values is fairly repetitive, but I will fix it in the next version.
The checksum calculation isn’t great even a simple cyclic redundancy check(CRC) would be an improvement on summing the 28 bytes of the payload.