hmx-17の日記

技術ネタとかプライベート

SensirionのSPS30(PM2.5センサ)を触る (3)

I2Cで触ってみます。
Raspberry PiのI2Cバスにまず細工をします。
/boot/config.txtで
dtparam=i2c_arm=on
を有効にしている場合にはコメントアウトして、
dtoverlay=i2c-gpio,bus=1,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=20
をおもむろに差し込みます。
Raspberry Pi の SoC にあるI2C通信機能は、Clock Stretchingに対応していないので
i2c-gpioというモジュールを使ってソフトウエアI2Cデバイスを作成します。

I2CデバイスRaspberry Piの接続については割愛します。
SPS30は5VをVDDとして取りますが、I2Cバスは3.3Vで問題無いので、
レベルシフタなしでOKです。

接続できたら、PiGpioをまず入れます。
$ sudo apt install pigpio

次に.NET 5でConsole Programのプロジェクトを作ります。
NugetでPiGpio.NETをインストールした状態で以下のようなプログラムを書きます。

using Unosquare.PiGpio.NativeMethods;
をusingに入れるのをお忘れ無いように。

static void Main(string args)
{
Setup.GpioCfgSetInternals(ConfigFlags.NoSignalHandler);
Setup.GpioInitialise();
devicePtr = I2c.I2cOpen(1, 0x69);
if (devicePtr.ToUInt64() < 0)
{
throw new Exception("I2C Open Error");
}
I2c.I2cWriteDevice(devicePtr, new byte
{0xD0, 0x02});
var serial = I2c.I2cReadDevice(devicePtr, 12);
Console.WriteLine(BitConverter.ToString(ParseSensrionPacketBytes(serial)));
I2c.I2cClose(devicePtr);
}
public static byte ParseSensrionPacketBytes(byte packet)
{
var data = new List();
if ((packet.Length % 3) != 0) return null;
for (var i = 0; i < packet.Length; i += 3)
{
data.Add(packet[i]);
data.Add(packet[i+1]);
}
return data.ToArray();
}

Setup.GpioCfgSetInternals(ConfigFlags.NoSignalHandler);
Setup.GpioInitialise();

で初期化をします。GpioCfgSetInternalsでセットしなくても良いのですが、
SIGが飛んできてプログラムが終了してしまうことがあるので設定しています。
次にI2c.I2cOpen()でI2Cデバイスを作ります。Raspberry PiSlot 1からで、SPS30は0x69なのでさっくり設定します。
次に 0xD0, 0x02をデバイスに書き込みます。この命令はバージョン情報を教えてくれと言う命令です。
バイスに指示を書き込んだら、データを読み取ります。 0xD0, 0x02 は12バイトを返すので、その通りにします。
SensirionのI2Cデータは [DATA1] [DATA2] [CRC8(DATA1+DATA2)] [DATA3] [DATA4] [CRC8(DATA3+DATA4)]...のように、2バイト+1バイトのチェックサムが延々と続くのでデータ列だけを切り出します。本来であればCRC8を計算して、データが化けてないか検証する必要がありますがここでは割愛しています。
このデータをコンソールに16進数でダンプしています。
最後に I2c.I2cClose()でI2Cデバイスをクローズします。

ということで、I2Cで通信することろまでできました。
次は実データを取得します。