.NET nanoFramework Seeedstudio HM3301 Basic connectivity

This is a “throw away” .NET nanoFramework application for investigating how Seeedstudio Grove HM3301 Inter Integrated Circuit bus(I²C) connectivity works.

Seeedstudio Grove HM3301 Sensor

My test setup is a simple .NET nanoFramework console application running on an STM32F7691 Discovery board.

Seeedstudio Grove HM3301 + STM32F769 Discovery test rig

The HM3301I2C application has lots of magic numbers from the HM3301 datasheet and is just a tool for exploring how the sensor works.

public static void Main()
{
    I2cConnectionSettings i2cConnectionSettings = new(1, 0x40);

    // i2cDevice.Dispose
    I2cDevice i2cDevice = I2cDevice.Create(i2cConnectionSettings);

    while (true)
    {
        byte[] writeBuffer = new byte[1];
        byte[] readBuffer = new byte[29];

        writeBuffer[0] = 0x88;

        i2cDevice.WriteRead(writeBuffer, readBuffer);

        //i2cDevice.WriteByte(0x88);
        //i2cDevice.Read(readBuffer);

        ushort standardParticulatePm1 = (ushort)(readBuffer[4] << 8);
        standardParticulatePm1 |= readBuffer[5];

        ushort standardParticulatePm25 = (ushort)(readBuffer[6] << 8);
        standardParticulatePm25 |= readBuffer[7];

        ushort standardParticulatePm10 = (ushort)(readBuffer[8] << 8);
                standardParticulatePm10 |= readBuffer[9];

        Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Standard particulate    PM 1.0: {standardParticulatePm1}  PM 2.5: {standardParticulatePm25}  PM 10.0: {standardParticulatePm10} ug/m3");

        ushort atmosphericPm1 = (ushort)(readBuffer[10] << 8);
        atmosphericPm1 |= readBuffer[11];

        ushort atmosphericPm25 = (ushort)(readBuffer[12] << 8);
        atmosphericPm25 |= readBuffer[13];

        ushort atmosphericPm10 = (ushort)(readBuffer[14] << 8);
        atmosphericPm10 |= readBuffer[15];

        Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Atmospheric particulate PM 1.0: {atmosphericPm1:3}  PM 2.5: {atmosphericPm25}  PM 10.0: {atmosphericPm10} ug/m3");


        ushort particulateCountPm03 = (ushort)(readBuffer[16] << 8);
        particulateCountPm03 |= readBuffer[17];

        ushort particulateCountPm05 = (ushort)(readBuffer[18] << 8);
        particulateCountPm05 |= readBuffer[19];

        ushort particulateCountPm1 = (ushort)(readBuffer[20] << 8);
        particulateCountPm1 |= readBuffer[21];

        Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Particulate count       PM 0.3: {particulateCountPm03:3}  PM 0.5: {particulateCountPm05}  PM 1.0: {particulateCountPm1} ug/m3");


        ushort particleCountPm25 = (ushort)(readBuffer[22] << 8);
        particleCountPm25 |= readBuffer[23];

        ushort particleCountPm5 = (ushort)(readBuffer[24] << 8);
        particleCountPm5 |= readBuffer[25];

        ushort particleCountPm10 = (ushort)(readBuffer[26] << 8);
        particleCountPm10 |= readBuffer[27];

        Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Particle count/0.1L     PM 2.5: {particleCountPm25}  PM 5.0: {particleCountPm5}  PM 10.0: {particleCountPm10} particles/0.1L");


        byte checksum = 0;
        for (int i = 0; i < readBuffer.Length - 1; i++)
        {
            checksum += readBuffer[i];
        }
        Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Checksum payload:{readBuffer[28]} calculated:{checksum}");
        Console.WriteLine("");

        Thread.Sleep(5000);
    }
}

The unpacking of the value standard particulate, particulate count and particle count values is fairly repetitive, but I will fix it in the next version.

Visual Studio 2022 Debug output

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.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.