🐥

ラズパイPicoでSPI通信した覚え書き(Arduino)

2023/11/04に公開

Raspberry Pi Pico で LPS25HB を Arduino 言語で SPI 通信してみた

Raspberry Pi Pico を AruduinoIDE を使って動かして遊んでいます。その際、SPI 通信をしようとしてちょっと躓いたので覚え書きとしてこの記事を残しておこうと思います。
今回は秋月電子で購入した LPS25HB を使った気圧センサモジュールと SPI 通信をして気圧と気温を取得しました。

ボードマネージャーは earlephilhower 氏の RP2040 ボードを使用しています。

#include <SPI.h> // SPIライブラリをインクルードする

// SPI通信用のピン設定
const int MISO_PIN = 0;
const int CS_PIN = 1;
const int SCK_PIN = 2;
const int MOSI_PIN = 3;

// SPI転送モード
SPISettings spisettings(1000000, MSBFIRST, SPI_MODE3); // SPI通信の設定を作成する

// テスト用レジスタの結果
bool WHO_AM_I = false;

/// @brief SPIの初期設定
void setupSpi(){
  // SPI0チャンネルならSPI, SPI1チャンネルならSPI1を使う
  SPI.setRX(MISO_PIN);
  SPI.setTX(MOSI_PIN);
  SPI.setSCK(SCK_PIN);
  SPI.begin(); // SPIを開始する
}

/// @brief SPI通信の準備
/// @param csPin Chip Selectピン
void beginSpi(int csPin){
    SPI.beginTransaction(spisettings);
    digitalWrite(csPin, LOW);// CSピンをLOWにする
}

/// @brief SPI通信の終了
/// @param csPin Chip Selectピン
void endSpi(int csPin){
    digitalWrite(CS_PIN, HIGH);// CSピンをHIGHにする
    SPI.endTransaction();
}

/// @brief LPS25HBの初期設定
void setupLPS25HB(){
  // テスト用レジスタの読み込み
  while (!WHO_AM_I) {
    beginSpi(CS_PIN);

    // who_am_iのレジスタアドレス(0x0f)に移動する
    SPI.transfer(0x0F | 0x80);
    // 1byteのデータを取得する
    uint8_t test = SPI.transfer(0x00);

    endSpi(CS_PIN);

    if(0xBD != test){
      Serial.println("レジスタの値が正常に取得できません。");
      WHO_AM_I = false;
      delay(1000);
    }else{
      Serial.println("レジスタの値を正常に取得。");
      WHO_AM_I = true;
    }
  }

  // クロック位相(CPOL) = 1 クロック極性(CPHA) = 1
  // CTRL_REG1(制御レジスタ1)
  beginSpi(CS_PIN);

  // CTRL_REG1のアドレス
  SPI.transfer(0x20);
  // パワーダウンをオフにしてセンサー周期を1Hzにする
  //   パワーダウン制御 : 1->Active mode
  //   出力データレート : 0,0,1->1Hz(1秒1回)
  SPI.transfer(0x90); // 2進 10010000

  endSpi(CS_PIN);
}

void setup() {
  Serial.begin(9600);

  // SPIの初期化
  setupSpi();

  // CSピンを出力に設定する
  pinMode(CS_PIN, OUTPUT);
  // 初期値はLOWに設定
  digitalWrite(CS_PIN,HIGH);

  delay(3000);

  // センサー(LSP25HB)の初期設定
  setupLPS25HB();
}

void loop() {
  // テストに成功しない場合は終了
  if(!WHO_AM_I) {
    Serial.println("接続テスト失敗");
    delay(1000);
    return;
  }

  int i; uint8_t RegTbl[5];

  // 5byteのデータを取得する
  for (int i = 0; i < 5; i++) {
    beginSpi(CS_PIN);

      SPI.transfer(0x80 | (0x28 + i));
      RegTbl[i] = SPI.transfer(0x00);

    endSpi(CS_PIN);
  }

  // --- [気圧] ---
  // 読み取った「3byte」を24bitに変換する
  uint16_t lo = RegTbl[1] << 8 | RegTbl[0];
  uint32_t hi = RegTbl[2] << 16; // 16bitの左シフト

  // ※Arduino UNOは16bitを超えるシフトはできないので、乗算で対処。
  // uint32_t hi = RegTbl[2] * 65536; // 16bitの左シフト

  double P = (hi +  lo) / 4096.0;

  Serial.print("気圧:");
  Serial.print(P);
  Serial.print("hPa(mbar)");

  // --- [温度] ---
  // 温度は符号ありのデータ型でOK
  int temperature = (RegTbl[4] << 8 |  RegTbl[3]);
  if(temperature & 0x8000) {         // 符号判定
    // 負数に変換するために65536を引く
    temperature = temperature - 0xFFFF;
  }
  double T = 42.5 + (temperature / 480.0);
  Serial.print(" 温度:");
  Serial.print(T);
  Serial.println("℃");

  delay(3000);
}

ラズパイ Pico は SPI のチャンネルが 2 つあって、使用するチャンネルによって SPI と SPI1 で使い分けないといけないのが注意点です。そして、使用するピンを setRX とか setTX で指定してあげるのがポイントでした。

以上、誰かの参考になれば幸いです。

Discussion