Skip to main content

クイック ノート

ビルド イベント

Raspberry Pi Model 3Bで調査用プログラムの動作確認をしていると、何かの拍子にGPIO17(普通のデジタル信号)が使えなくなり、GPIOの使用状況を調べると、GPIO17のコンシューマがSysfsになっている。なんで勝手に使っているのか?ラズパイの中にゴーストでもいるのか?と思い、更に調べると、原因はVisual Studioで新規作成したプロジェクトの「リモートのビルド後イベント」でした。Raspberry Pi プロジェクト テンプレートからプロジェクトを生成すると、ARMプラット フォームの「リモートのビルド後イベント」に"gpio export 17 out"が登録されるようで...。

ここで、一句、「親切も、余計な時が、あるのです。」

Raspberry Pi Model 4B 5×SPI

ネット上に「RasPi 4BのSPI有効化には縛りがある」との情報があり、今後の開発作業に影響があるかも知れないと思い、Raspberry Pi Model 4BのSPI0とSPI3~6の同時有効化(同時使用)の可不可を確認しました。

確認に使用したRasPiのリビジョンとOSは以下の通りです。

  • Raspberry Pi 4 Model B Rev 1.4
  • Raspberry Pi OS 10 Buster 64BITβ(2021-05-28 16:08に公開された image でインストール)
    この記事を書いている時に気づいたのですが、2021-11-08 07:49公開の新しい image があるようです。

SPI0とSPI3~6を同時有効化(同時使用)する為の設定は、以下の通りです。

/boot/config.txt に以下の設定行を追加

dtoverlay=spi0-2cs,cs1_pin=17
dtoverlay=spi3-2cs
dtoverlay=spi4-2cs
dtoverlay=spi5-2cs
dtoverlay=spi6-2cs

設定後にリブートして、ls /dev/spi* を実行すると、デバイス ファイルが生成されていることを確認できました。

/dev/spidev0.0  /dev/spidev3.0  /dev/spidev4.0  /dev/spidev5.0  /dev/spidev6.0
/dev/spidev0.1  /dev/spidev3.1  /dev/spidev4.1  /dev/spidev5.1  /dev/spidev6.1

念のため、C/C++言語でテスト プログラムを作成して、実際に通信できるかも確認しました。

テスト内容

  • SPI0.0,SPI3.0,SPI4.1,SPI5.0,SPI6.1をオープン
    SPI0.0 : クロック4MHzでICM-20948と接続
    SPI3.0 : クロック4MHzでRaspberry Pi Picoと接続
    SPI4.1 : MOSIとMISOを接続(クロック4MHzで折り返し)
    SPI5.0 : MOSIとMISOを接続(クロック4MHzで折り返し)
    SPI6.1 : MOSIとMISOを接続(クロック4MHzで折り返し)
  • SPI0.0で一連のICM-20948初期化が正常完了することを確認
  • SPI3.0でRaspberry Pi Picoと64バイト長のデータを全二重通信できることを確認
  • SPI4.1で折り返し通信ができることを確認
  • SPI5.0で折り返し通信ができることを確認
  • SPI6.1で折り返し通信ができることを確認

(SPI4,6でCS1を指定しましたが、そもそもCS信号を見ているデバイスが存在しないので、特に意味がある訳ではありません。)

Raspberry Pi Model 4BのSPI0とSPI3~6の同時有効化(同時使用)は、特に縛りなくできるようです。(OSに修正が入ったのかも知れません。)

Raspberry Piのspidevクロック設定

SPI0に ioctl (SPI_IOC_WR_MODE)でクロックの極性と位相を設定する際、戻り値が「正常完了(0)」となっていたので気にしていなかったのですが、ioctl (SPI_IOC_RD_MODE)で設定値を読み取ると実際に設定した値 + 0x04の値が取得されることに気づきました。電源ON直後の状態を読み取ると0x04が取得されます。SPI1の場合は設定した値が取得されます。(モデル:3B、OS:Raspbian 32Bit Release 10)

Raspberry Pi 3/4のSPI1とSPI2は補助的?

SPI0で接続されたICM-20948と通信を行うプログラムを、SPI1接続に変更して実行すると初期化でエラーとなる事例が発生しました。(モデル:3B、OS:Raspbian 32Bit Release 10、SPIのクロックは4MHz)

SPI1接続に変更するために行った対応は以下の通りです。

  • /boot/config.txt に dtoverlay=spi1-3cs を追加後にリブート
  • ls /dev/spi* で /dev/spi1.0~2が表示されることを確認後にシャット ダウン
  • 配線をSPI0からSPI1に変更
    MOSI : 物理ピン38、MISO : 物理ピン35、SCLK : 物理ピン40、CE0 : 物理ピン12
  • プログラムの spidev オープン時のデバイス名指定を "/dev/spidev0.0" を "/dev/spidev1.0" に変更

BROADCOMのARM PerifheralsのドキュメントのSPI1/2とSPI0/3/4/5/6に関する記載が別の章になっていることは認識していたのですが、「想定している使用範囲では同じ」と思い込んでしまったことが原因でした。
具体的には、クロックの極性と位相の設定で、CPHA=1を指定できないことが原因で、結論として SPI_MODE_1と SPI_MODE_3を指定できないと言うことのようです。(既存のプログラムは、SPI_MODE_3 を指定していました。)
In risingとOut risingが位相用の設定レジスタのような気がするのですが・・・?
SPI_MODE_0を指定すると通信できるようになりました。(ビットの状態を取り込むタイミングは同じになるのか・・・)

spidev の spi_ioc_transfer構造体

名称

説明

tx_buf

送信データ格納領域の先頭アドレス.
nullptrを指定した場合、通信相手のデバイスは0が受信データとなる.

rx_buf

受信データ格納領域の先頭アドレス.
nullptrを指定した場合、受信データは読み捨てられる.

len

転送(送受信)サイズ.(単位はバイト)

speed_hz

転送時のSPIクロック周波数.

delay_usecs

最後のビットを送信し終えてからCSを非アクティブ化するまでの時間.
(マイクロ秒単位)

bits_per_word

ワードのビット サイズ.

cs_change

0 : spi_ioc_transferデータのエレメント毎にCSを非アクティブ/アクティブ化しない.
1 : spi_ioc_transferデータのエレメント毎にCSを非アクティブ/アクティブ化する.
(1を指定した場合、転送完了後はアクティブ状態のままになる)

tx_nbits

並列に送信するビット数.
(0 : Single SPI/SPI_TX_DUAL : Dual SPI/SPI_TX_QUAD : Quad SPI)

rx_nbits

並列に受信するビット数.
(0 : Single SPI/SPI_RX_DUAL : Dual SPI/SPI_RX_QUAD : Quad SPI)

word_delay_usecs

ワード間で待機する時間.(マイクロ秒単位)
SPIコントローラがワード間待機をサポートしている場合のみ有効で、サポートしていない場合は無視される.