ESP32を用いたMAX3010xセンサーのI2C通信初期化

ESP32におけるMAX3010xパルスオキシメーターセンサーのI2C初期化

MAX3010xは、心拍数と血中酸素飽和度(SpO2)の測定に広く使用される統合型パルスオキシメーターおよび心拍数モニターセンサーです。このセンサーはI2Cインターフェースを介してマイクロコントローラーと通信します。本稿では、ESP32開発ボード上でArduino環境とSparkFun MAX3010xセンサーライブラリを使用して、MAX3010xセンサーのI2C通信を初期化する方法について詳しく解説します。

ライブラリの組み込みとセンサーオブジェクトの生成

MAX3010xセンサーを使用するには、関連するライブラリをプロジェクトに含める必要があります。Arduino IDEのライブラリマネージャーから「SparkFun MAX3010x Sensor Library」を検索してインストールできます。

以下のヘッダーファイルをコードにインクルードし、センサーを制御するためのオブジェクトを生成します。

#include <Wire.h>       // I2C通信用ライブラリ
#include "MAX30105.h"   // SparkFun MAX3010xセンサーライブラリ

// MAX3010xセンサーオブジェクトの生成
// ライブラリはMAX30105としていますが、MAX30102も同様に扱えます。
MAX30105 pulseOximeterSensor;

Wire.hはArduinoのI2C(Two-Wire Interface)通信機能を提供します。MAX30105.hはセンサーの具体的な機能にアクセスするためのAPIを含んでいます。

I2C通信の初期設定

センサーとの通信を開始する前に、I2Cバスを適切に初期化する必要があります。SparkFunライブラリのbegin()メソッドがこの処理を担当します。

if (!pulseOximeterSensor.begin(Wire, I2C_SPEED_STANDARD)) {
    Serial.println("MAX3010xセンサーの検出に失敗しました。配線と電源を確認してください。");
    while (1); // センサーが検出されるまで無限ループ
}
Serial.println("MAX3010xセンサーの初期化が完了しました。");

begin()メソッドの詳細

begin()メソッドは、I2C通信の設定を行います。そのプロトタイプは以下の通りです。

boolean begin(TwoWire &i2cPort = Wire, uint32_t i2cSpeed = I2C_SPEED_STANDARD, uint8_t i2cAddress = MAX30105_ADDRESS);

このメソッドは、以下の3つのオプションパラメータを受け取ります。

  • i2cPort: 使用するTwoWire(I2C)ポートへの参照です。通常はデフォルトのWireを使用します。ESP32などのボードで複数のI2Cバスがある場合は、Wire1などを指定することも可能です。
  • i2cSpeed: I2C通信速度を設定します。デフォルトはI2C_SPEED_STANDARD (100kHz) です。
    • I2C_SPEED_STANDARD: 100 kHz
    • I2C_SPEED_FAST: 400 kHz
    一般的に、MAX30102モジュール(特に小型で素子と回路が同一面に配置されているもの)は、指で触れた際にI2C信号線が人体に接触しやすく、ノイズの影響を受けやすい傾向があります。このため、より安定した通信のためには、デフォルトのI2C_SPEED_STANDARD (100kHz) の使用を推奨します。
  • i2cAddress: MAX3010xセンサーのI2Cアドレスです。デフォルトは0x57です。通常は変更する必要はありません。

上記のコード例では、明示的にWireI2C_SPEED_STANDARDを指定しています。これは、2番目の引数である通信速度を設定するために、最初の引数も渡す必要があるためです。もし低速(100kHz)で通信したいだけであれば、begin()メソッドに引数を渡さないことで、デフォルト設定が適用されます。

begin()メソッドの内部処理

begin()メソッドの内部では、以下のような処理が行われます。

  1. 指定されたI2Cポートの参照を内部変数に格納します。
  2. _i2cPort->begin();を呼び出し、I2Cバスを初期化します。
  3. _i2cPort->setClock(i2cSpeed);を呼び出し、I2C通信速度を設定します。
  4. センサーのI2Cアドレスを内部変数に設定します。
  5. readPartID()メソッドを呼び出し、センサーの部品IDを読み取って、期待されるIDと一致するかを確認します。これにより、センサーが正しく接続され、通信可能であるかを検証します。
  6. readRevisionID()メソッドを呼び出し、センサーのリビジョンIDを読み取ります。

部品IDが期待値(MAX_30105_EXPECTEDPARTID = 0x15)と異なる場合、begin()メソッドはfalseを返し、センサーが見つからないことを示します。

I2Cレジスタの読み書き操作

ライブラリのbegin()メソッドやその他のセンサー設定関数は、内部的にI2Cを介したレジスタの読み書き操作を行っています。ここでは、基本的な8ビットレジスタの読み書きについて解説します。

8ビットレジスタの読み取り (readRegister8相当)

MAX3010xセンサーから1バイトのデータを読み取る関数は、以下のようなI2Cシーケンスで実装されます。

  1. I2C通信を開始し、センサーのアドレス(書き込みモード)を送信します。
  2. 読み取りたいレジスタのアドレスを送信します。
  3. リピートスタート条件を送信し、再度センサーのアドレス(読み取りモード)を送信します。
  4. センサーから1バイトのデータを受信します。
  5. NACK(非確認応答)を送信し、通信を終了します。
uint8_t readI2CRegister(TwoWire* i2cPort, uint8_t deviceAddress, uint8_t registerAddress) {
    // 1. 読み取りたいレジスタアドレスを送信
    i2cPort->beginTransmission(deviceAddress);
    i2cPort->write(registerAddress);
    i2cPort->endTransmission(false); // STOP条件なしで終了(リピートスタートのため)

    // 2. センサーから1バイトのデータを要求
    i2cPort->requestFrom(deviceAddress, (uint8_t)1);

    // 3. データが利用可能であれば読み取る
    if (i2cPort->available()) {
        return i2cPort->read();
    }
    return 0; // 読み取り失敗またはデータなし
}

endTransmission(false)は、I2Cバスを解放せずにリピートスタート条件を生成するために使用されます。もしセンサーがノイズの影響などで正しく応答しない場合、requestFromがデータを受信できず、available()falseを返すか、read()が意図しない値を返す可能性があります。特に0が返された場合、それが実際にレジスタの値なのか、通信失敗によるものなのか判別が難しい場合があります。

endTransmission()の戻り値は、通信の状態を示します。主なステータスコードは以下の通りです。

ステータスコード 意味
0 送信成功
1 データ量が送信バッファの容量を超過
2 アドレス送信時にNACKを受信
3 データ送信時にNACKを受信
4 その他のエラー

8ビットレジスタへの書き込み (writeRegister8相当)

MAX3010xセンサーのレジスタに1バイトのデータを書き込む関数は、以下のようなI2Cシーケンスで実装されます。

  1. I2C通信を開始し、センサーのアドレス(書き込みモード)を送信します。
  2. 書き込みたいレジスタのアドレスを送信します。
  3. 書き込みたいデータを送信します。
  4. STOP条件を送信し、通信を終了します。
void writeI2CRegister(TwoWire* i2cPort, uint8_t deviceAddress, uint8_t registerAddress, uint8_t dataValue) {
    i2cPort->beginTransmission(deviceAddress); // センサーアドレスで通信開始
    i2cPort->write(registerAddress);         // 書き込み対象レジスタアドレスを送信
    i2cPort->write(dataValue);               // 書き込むデータを送信
    i2cPort->endTransmission(true);          // STOP条件を送信して通信終了
}

endTransmission(true)は、データの送信後にSTOP条件を生成し、I2C通信を終了させます。引数を省略した場合もデフォルトでtrueが指定されます。

タグ: ESP32 MAX3010x I2C Arduino EmbeddedSystems

8月8日 14:57 投稿