Raspberry Pi GPIOを使用したSPI通信(温度センサ)

Raspberry Pi

はじめに

Raspberry PiでSPI(Serial Peripheral Interface)を使用して周辺デバイスと接続する方法について、SPI 対応の温度センサモジュールを例に記載します。SPIは、パラレルに比べて接続端子数が少ないシリアルバスの一種で、I2Cよりも高速なデータ転送を行うことができます。
インストール直後の初期状態ではSPIが無効になっていますので、使用する場合は有効化する必要があります。SPIを有効化する方法には、「raspi-config」コマンドを使用して有効化する方法と「/boot/config.txt」を直接編集して有効化する方法があります。
はじめに、SPIの概要について説明した後、「/boot/config.txt」ファイルを編集し、SPIを有効化します。その後、実際にSPI接続に対応した温度センサモジュールを使用して、動作確認を行います。

環境

  1. ボート
    Raspberry Pi 4 Model B
  2. OS
    Raspberry Pi OS (32-bit) Lite
    Minimal image based on Debian Buster
    Version: August 2020
    Release date: 2020-08-20
    Kernel version: 5.4

SPI について

SPI の概要

SPI (Serial Peripheral Interface)は、マイクロコントローラとその周辺デバイスとの接続に使用されるインターフェイスの一種です。各種センサー、A/Dコンバータ、D/Aコンバータ、SRAMなどとマイクロコントローラを接続するのに幅広く採用されています。
SPIは、同期式/全二重のマスター・スレーブ型のインターフェイスです。マスターまたはスレーブからのデータは、クロックの立ち上がりエッジまたは立ち下がりエッジによって、同期がとられます。また、マスターとスレーブは、同時にデータを送信することも可能です。
SPIには、3線式のものと4線式のもがあります。ここでは、一般的な 4 線式のSPIについて記載します。4線式のSPIデバイスには、次の4つの信号があります。

  • クロック(SPI CLK, SCLK)
  • チップ・セレクト(CS)
  • マスター出力/スレーブ入力(MOSI:Master Output Slave Input)
  • マスター入力/スレーブ出力(MISO:Master Input Slave Output)

2種類のデバイスのうち、クロック信号を生成する方が、マスターと呼ばれます。マスターとスレーブ間で送信されるデータは、マスターによって生成されるクロック信号に同期して転送されます。SPIデバイスは、I2Cインターフェイスよりもはるかに高いクロック周波数に対応していますので、高速なデータ転送を行うことができます。
SPIに対応するデバイスを使用する場合は、データシートを参照しSPIのクロック周波数に関する仕様を確認してください。
SPIでは、1つのマスターに対して、複数のスレーブを接続することができます。マスターとスレーブ間の接続は、標準モードまたはデイジーチェーンモードで接続します。図1に標準モードでのマスターとスレーブ間の接続を示します。

図1:SPI におけるマスターとスレーブの関係

マスターからのCS信号は、スレーブの選択に使用されます。通常、この信号はActive Lowで、SPIバスからスレーブを切り離したいときに、Highにします。複数のスレーブを接続して使用する場合は、マスターから各スレーブに対して、個別にCS信号を送信する必要があります。マスターがCS信号をイネーブルにする(CS信号をLowに引き下げる)と選択されたスレーブに対して、クロックとMOSI/MISO上のデータが有効になります。 複数のCS信号がイネーブルになると、どのスレーブからデータが送信されているか識別できないため、MISO上のデータが壊れてしまいます。
MOSIとMISOは、データを送受信するために使用する信号線です。MOSI(Master Output Slave Input)は、マスターからスレーブに対してデータを送信するために使用されます。MISO(Master Input Slave Output)は、スレーブからマスターに対してデータを送信するために使用されます。

データ転送

SPI による通信を開始するためには、マスターからクロック信号を送信するともに CS 信号をイネーブルにすることより対象のスレーブを選択する必要があります。SPIは全二重インターフェイスのため、マスターとスレーブはそれぞれ MOSIとMISOを使用して、同時にデータを送信することができます。つまり、MOSI/SDOバスに対してシリアルにデータをシフトさせて出力する送信動作とMISO/SDIバスのデータをサンプリングする受信動作を同時に行うことが可能です。シリアル・クロックのエッジによって、データのシフト処理/サンプリング処理の同期がとられます。SPIでは、クロックの立ち上がりエッジと立ち下がりエッジのうち、どちらでデータをシフト/サンプリングするかをユーザーが選択することができます。

SPI モード(クロックの極性と位相)

SPIマスターは、クロックの極性と位相を選択することができます。CPOLビットは、アイドル状態におけるクロック信号の極性を設定するためのものです。アイドル状態とは、送信を開始するためにCS信号がHighからLowに遷移するまでの間と、送信を終了するためにCS信号がLowからHighに遷移するまでの間のことです。CPHAビットは、クロックの位相を選択するためのものです。CPHAビットにより、データのサンプリング/シフトにクロックの立ち上がりエッジと立ち下がりエッジのうち、どちらを使用するかを設定します。マスターでは、スレーブの要件に適合するように、クロックの極性と位相を選択する必要があります。表1 に示すように、CPOLビットとCPHAビットの組み合わせによって、4つの SPIモードが存在することになります。

SPI
モード
CPOLCPHAアイドル状態の
クロックの極性
データのサンプリング/シフト
に使用されるクロックの位相
000Logic Lowデータを立ち上がりエッジでサンプリング、
立ち下がりエッジでシフト
101Logic Lowデータを立ち下がりエッジでサンプリング、
立ち上がりエッジでシフト
211Logic Highデータを立ち下がりエッジでサンプリング、
立ち上がりエッジでシフト
310Logic Highデータを立ち上がりエッジでサンプリング、
立ち下がりエッジシフト
表1:4 つの SPI モード

図2 から図5 に、4つのSPIモードにおけるタイミング図の例を示します。各例において、データの値は MOSIとMISOの部分に示しています。送信の開始と終了は緑色の点線、サンプリング用のエッジは橙色の点線、シフト用のエッジは青色の点線で示しています。

図2:SPI モード 0のタイミング図
図3:SPI モード 1 のタイミング図
図4:SPI モード 2 のタイミング図
図5:SPI モード 3 のタイミング図

図2は、SPI モード0のタイミング図です。このモードでは、クロックの極性を0に設定しているので、アイドル状態におけるクロック信号はLowになります。クロックの位相については、0に設定しているので、データはクロック信号の立ち上がりエッジ(橙色の点線)でサンプリングされ、立ち下がりエッジ(青色の点線)でシフトされます。

図3は、SPIモード1のタイミング図です。このモードでは、クロックの極性を0に設定しているので、アイドル状態におけるクロック信号はLowになります。クロックの位相については、1に設定しているので、データはクロック信号の立ち下がりエッジ(橙色の点線)でサンプリングされ、立ち上がりエッジ(青色の点線)でシフトされます。

図4は、SPIモード2のタイミング図です。このモードでは、クロックの極性を1に設定しているので、アイドル状態におけるクロック信号はHighになります。クロックの位相については、1に設定しているので、データはクロック信号の立ち下がりエッジ(橙色の点線)でサンプリングされ、立ち上がりエッジ(青色の点線)でシフトされます。

図5は、SPIモード3のタイミング図です。このモードでは、クロックの極性を1に設定しているので、アイドル状態におけるクロック信号はHighになります。クロックの位相については、0に設定しているので、データはクロック信号の立ち上がりエッジ(橙色の点線)でサンプリングされ、立ち下がりエッジ(青色の点線)でシフトされます。

Raspberry Pi における SPI の有効化

インストール直後の初期状態では、SPIは無効になっています。SPIを有効化するため、「/boot/config.txt」ファイルを以下のように編集します。
「#dtparam=spi=on」の行のコメントアウトを削除します。

pi@raspberrypi:~ $ sudo vi /boot/config.txt
(略)
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on   <-- コメントアウトを削除する。
(略)
pi@raspberrypi:~ $

「/boot/config.txt」ファイルを編集後、SPI を有効化するため、再起動を行います。

pi@raspberrypi:~ $ sudo reboot

SPI の有効化確認

SPIが有効化されていることを確認します。
以下のコマンドを実行し、「spi_bcm2835」モジュールがロードされていることを確認します。

pi@raspberrypi:~ $ lsmod | grep spi
spidev                 20480  0
spi_bcm2835            24576  0
pi@raspberrypi:~ $

以下のコマンドを実行し、/devディレクトリに SPI0 のデバイスファイル「spidev0.X」が作成されていることを確認します。

pi@raspberrypi:~ $ ls -l /dev | grep spi
crw-rw---- 1 root spi     153,   0 Nov  3 20:17 spidev0.0
crw-rw---- 1 root spi     153,   1 Nov  3 20:17 spidev0.1
pi@raspberrypi:~ $

SPI の動作確認

ここでは、SPI対応のMAX6675を搭載したK型熱電対温度センサモジュールを使用して、SPI接続を行い温度を取得して動作確認を行います。MAX6675は MAXIM integrated 社の販売しているSPI対応のK型熱電対温度センサのコントロール IC です。
動作確認には、Python spidevライブラリを使用してSPI通信を行い、温度センサーモジュールから温度を取得します。Pythonは、Python 3.7.3を使用します。

図6:SPI 対応 K 型熱電対温度センサモジュールキット
図7:SPI 対応 K 型熱電対温度センサモジュール

温度センサーモジュールとの接続

以下のとおり、GPIOを使用してRaspberry PiとMAX6675温度センサーモジュールを接続します。

Raspberry Pi
ヘッダーピン
温度センサー
モジュール
21番ピン:GPIO 9 (MISO)SO ピン
23番ピン:GPIO 11 (SCLK)SCK ピン
24番ピン:GPIO 8 (CE0) ピンCS ピン
17番ピン:3V3 power ピンVCC ピン
25番ピン:Ground ピンGND ピン
表2:Raspberry Pi と温度センサモジュールとの接続
図8:温度センサモジュールとの接続

参考までにRaspberry Pi 4 Model B の GPIOピン配置を記載します。

図9:GPIO ピン配置

参考URL:GPIO ピン配置

動作確認環境の準備

Python(Python 3.7.3)の spidevライブラリを使用して、温度計測を行う動作環境の準備を行います。

Python pip パッケージのインストール

Python spidevライブラリをインストールするため、pip(Python パッケージ管理ツール)をインストールします。以下のコマンドを実行し、pipパッケージをインストールします。

pi@raspberrypi:~ $ sudo apt-get install python3.7-dev
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo apt-get install python3-pip
pi@raspberrypi:~ $

以下のコマンドを実行し、インストールされたpipバージョンを確認します。

pi@raspberrypi:~ $ pip3 --version
pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7)
pi@raspberrypi:~ $

Python spidev ライブラリのインストール

pipをインストールした後、以下のコマンドを実行し、pipを使用してPython spidevライブラリをインストールします。

pi@raspberrypi:~ $ sudo pip3 install spidev
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting spidev
  Downloading https://www.piwheels.org/simple/spidev/spidev-3.5-cp37-cp37m-linux_armv7l.whl (40kB)
    100% |????????????????????????????????| 40kB 143kB/s
Installing collected packages: spidev
Successfully installed spidev-3.5
pi@raspberrypi:~ $

MAX6675を使用した温度計測モジュールについて

MAX6675は、冷接点補償を実行しK型熱電対からの信号をデジタル化するICです。データは12ビットの分解能(分解能:0.25°C)で、SPIで接続します。SPIは、読み取り専用形式の 3 線(CS、SCK、SO)を使用して、データを読み取ります。
データは、16ビット(D15 ~ D0)で構成されていて、読み出しに16クロックサイクルが必要です。
読み出しは、クロックの立ち下がりエッジで行います。
最初のD15は、ダミーの符号ビットで常にゼロです。
D14からD3ビットの12ビットに、MSBからLSBの順序で計測された温度データがセットされます。
D2ビットは、通常、Lowで熱電対入力がオープン(接続されていない状態)になっている時に1:Highにセットされます。
D1ビットは、MAX6675のデバイスIDを提供するために0:Lowで、D0ビットは3ステートになっています。
このため、D14からD3ビットの12ビットを使用して計測温度を取得します。図7にSOの出力について記載します。

図7:SOの出力

動作確認

Python spidevライブラリが利用できるようになれば、動作確認環境の準備は完了です。
以下の温度取得テストプログラムを作成し動作確認を行いました。

温度取得テストプログラム「measure_temp.py」

import spidev
import time
import datetime

dummyData = [0x00,0x00]

spi = spidev.SpiDev()
spi.open(0, 0)          # bus 0,cs 0

# Settings
spi.max_speed_hz = 1000000      # 1MHz
spi.mode = 3                    # SPI mode : 3

while 1:
        dt_now = datetime.datetime.now()
        readByteArray = spi.xfer2(dummyData)
        temperatureData = ((readByteArray[0] & 0b01111111) << 5) | ((readByteArray[1] & 0b11111000) >> 3)
        temperature = temperatureData * 0.25
        print(dt_now.strftime('%Y/%m/%d %H:%M:%S') + ',' + str(temperature))
        time.sleep(0.5)

spi.close

温度取得テストプログラムを実行し温度計測を開始します。
以下のように、正常にSPI通信で温度センサモジュールから1秒間隔で温度を取得できました。

pi@raspberrypi:~ $ python measure_temp.py
2020/10/30 06:44:34,Temperature: 22.75
2020/10/30 06:44:35,Temperature: 22.25
2020/10/30 06:44:36,Temperature: 22.75
2020/10/30 06:44:37,Temperature: 22.75
2020/10/30 06:44:38,Temperature: 22.5
(略)
pi@raspberrypi:~ $

以上です。

タイトルとURLをコピーしました