PR

RaspberryPiでMCP23S17を使いこなす方法を徹底解説【SPI通信】

raspberrypi-mcp23s17-spi-eyecatch
プリント基板は個人でも簡単に作れる時代!

 以前からMCP23017(i2c通信)と一緒に購入した、
MCP23S17(SPI通信)を使いこなす方法を徹底解説します。

 今回はコメントで「やってほしい!」という依頼から実現した内容です。具体的には、MCP23S17とRaspberryPiをつなげて、LEDを点灯させます。

 MCP23S17はIOエクスパンダというもので、単純に言うと、このチップに命令を出すと、それぞれの足がHighになったり、Lowになったりします。RaspberryPiに命令を出すと、特定のピンがLowやHighになりますが、その仕組みがこのチップ単体でも実現できます。

 チップ単体でLowやHighにできるなら、RaspbrryPiの制御できるピンが増えたのと同じことになります。ですから、IOエクスパンダ(拡張)というわけです。

 もちろんこのMCP23S17にもピンの数にも限りがあります。A系列に0~7番、
B系列に0~7番搭載されています。つまりMCP23S17を使うことで、自由にLowやHighにできる制御ピンが合計16個増えることになります。

 MCP23S17はSPI通信を使用した制御ですが、I2C通信を使用した兄弟IOエクスパンダーも存在します。それが、MCP23017です。こちらの使い方はすで記事にしていますので、I2C通信を使うMCP23017に興味があるならば、こちらの記事を確認してみてください。

MCP23017をRaspberryPiで使った時の記事
この記事を読むことでわかること

SPI通信を使うIOエクスパンダー(MCP23S17)の使い方が理解できる。

自己紹介

サラリーマンしてます。

主に工場(生産現場)で使用する検査装置のアプリケーション開発してます。

ヒトの作業を自動化して簡略化するアプリケーションを日々開発中。

2022年5月に転職。現役バリバリの技術者です。
現在は超大手企業の新規事業分野で装置の研究・開発をしています。

Youtubeチャンネルにさまざまな動画を上げています

↓↓↓こちらからYoutubeチャンネルにアクセス!! ↓↓↓

注意

本ブログはアフィリエイトを用いた広告を掲載しています。

今回やったことを実行するとこんな感じでLEDが点灯します。

raspberrypi400を使ってMCP23S17(SPI通信の方のIOエキスパンダ)でLED光らせてみた。 #programming #python #raspberrypi
実際にMCP23S17を使って7segの一部を光らせている動画

今回使用した道具たち

今回使用したのは写真のように、主役のMCP23S17と、7セグ、抵抗、RaspberryPi400です。

 まずは今回の主役であるMCP23S17です。ブレッドボードの2.54mmピッチに合ったICとなっていますので、ポン付け可能です。

MCP23S17
今回の主役。MCP23S17

 ブレッドボード上にMCP23S17と7セグLEDを配置した状態です。7セグLEDには、内蔵されているLEDそれぞれ抵抗が必要となるため、少々配線がややこしくなっています。

7segments-mcp23s17
ブレッドボードに載せた7セグLEDと抵抗たち

 そして今回制御に使ったのはRaspberryPi400です。RaspberryPiの中でも少し変わったキーボード一体型のRaspberryPiです。

 RaspberryPi5が出るまでは性能も上位にいましたので、キーボード一体型というだけではなくパワフルなのも使いやすさのポイントでした。

RaspberryPi400あんまり使ってなかったし、VNC接続メインなのでタイピングもあまりしない…

 今回紹介しているのは7セグですが、7セグである必要はありません。
もちろんただのLED1本、抵抗1本でまったく問題ないです。

わたしの場合は、すでにブレッドボードに7セグがくっついていたので、
外すのが面倒だったのでそのままにしました。

そういう意味では、ブレッドボードと
ジャンパーワイヤーも用意しておいてください。

今回使用しているのは、以前シフトレジスタや、MCP23017の時に使用したままの状態だったかな???

とりあえず、アノードコモンのタイプです。
写真の紫の線に+3.3Vを入れた状態で、
各ピンをGNDに落としてあげるとLEDが光るという仕組みですね。

もう少し詳しく解説した記事が以前のものであるので、
気になったら読んでみてください。

これらの部品は基本Amazonや通信販売でも取り扱いされています。
近くに実物を販売している店舗がない場合は、
通販を使うのもオススメです。

↓RaspberryPi400

↓MCP23S17

↓アノードコモンの7セグLED

↓ブレッドボードとか小物類のセット

RaspberryPiとPythonの開発環境について

開発環境はそろえておいたほうがよいので、
今回使用した開発環境についてご紹介しておきます。

  • OSのVer.は11.6
  • pythonのVer.は3.9.2 32-bit
  • このあと紹介するSPI用のライブラリ(spidev)のVer.は3.5
  • エディターはVSCodeを使用

一応執筆時点でほぼほぼ最新にした状態で検証しています。


一部でpython3では実行できないなんて話も出ていましたが、
この状態でできたので、わざわざVer.ダウンはしなくてよさそうです。

RaspberryPiとMCP23S17と7セグLEDを接続する

次に配線ですね。
MCP23S17は先述の通り、SPI通信を使用します。
RaspberryPiのほうもSPI通信のピンを使用しますが、
対応するピンがあらかじめ決まっていますので、間違えないように注意が必要です。

配線はこんな感じです。↓↓↓

raspberryPi-mcp23017
RaspberryPiとMCP23S17を接続した状態。7セグはアノードコモン。

繰り返しになりますが、
LEDは7segのLEDを使用する必要はありません。

砲弾型の普通のLEDを使用したい場合は、
オレンジ線にLEDのアノード(足の長い方)を接続して、
カソードを抵抗のうちどちらかにつなげてあげればいいです。

それから、I2C通信Ver.のMCP23017では重要だったアドレスについてですが、
これは今はあまり気にしなくていいです。
というのも、別記事で解説する予定のためです。
とにかく今回はこちらのように配線してもらえればLEDは光ります。

MCP23S17をRaspberryPiとPythonで制御するには

配線は完了したので、
ここからはRaspberryPiで実際に操作をしていきます。
RaspberryPi側で初期設定が必要ですので、
いったん確認しておきましょう。

RaspberryPiでSPI通信ができるようになっているか確認

RaspberryPiはOSを書き込んだ初期の状態だと、
SPI通信をしてくれない状態です。

ですので、SPI通信ができるように、
設定を変更してあげる必要があります。

具体的にはここを見てあげればいいです。
RaspberryPiの設定のところですね。

Raspberry Pi setting
RaspberryPiの設定画面の出し方。UIがしっかりしているので違和感なく使えますね。

上から3つ目のRaspberry Piの設定をクリックしましょう。
するとこんな画面が出てきますので、インターフェイスのタブを選択します。

Raspberry Pi interface tab
Raspberry Piの設定画面。インターフェイスのタブを選択した状態。

ここで確認するのが、上から3つ目のSPIというところです。
これに濃いグレーの色がついていれば、使えるということになります。

もし、ここに色がついていなければ、
クリックをしてSPIを有効化しましょう。

また、このSPIに限らない話ですが、
ここらへんの設定を変更したら、必ず再起動(reboot)しましょう。

再起動しないと、設定が反映されません。
これ結構重要です。

RaspberryPiでSPIを使うための準備

さて、SPIの機能をONにしたところで、
次にやることは、pythonでSPI通信をするために必要なライブラリの取得です。

ライブラリの取得とは言ってもそんなに大変な作業ではありません。
いわゆるpipです。

ちなみに初期状態でSPIのライブラリはインストールされているとの情報もありますが、
なんどpipをやっても特に問題はありません。

念のため実行しておくことをオススメします。

使用するライブラリの名前は、spidevというものです。
具体的にpipのコマンドを書いておくと、

sudo pip3 install spidev

このようにLXterminal上で打ち込むと、
spidevすなわち、pythonを使ったRaspberryPiのSPI通信用のライブラリがインストールできます。

冒頭でご紹介した開発環境の紹介のところでも書きましたが、
このspidevのVer.は3.5で実行しています。

ご自分のspidevのver.が知りたい方は、
LXterminalで、次のコマンドを打てばVer.の一覧が出てきます。

pip3 list

pythonのコードを書く

さて、ライブラリも準備できたところで、
いよいよコードを書きます。

まずはコードの全体を掲載していきましょう。

import spidev
import time

# 初期設定
spi = spidev.SpiDev()
# ここの引数は、(bus,CE0orCE1)。今回はCE0に配線しているので0。
spi.open(0,0)
spi.mode = 0
# 1MHzで設定。MCP23S17はデータシート上だと10MHzが最高らしい。
spi.max_speed_hz = 1000000

# CHも含めたアドレス関係をまとめた文字列。
Control_Byte = 0x40
# IOの向き(入力or出力)を決めるレジスタのアドレス。
REG_IODIRA = 0x00 
# GPIOAの入出力指令を出すためのレジスタのアドレス。
REG_GPIOA = 0x12 

# 今回はGPA0~A7まで全て出力に指定。出力:0,入力:1
spi.xfer2([Control_Byte,REG_IODIRA,0x00]) 
# whileの無限ループを中断するための退避用の関数。
def destroy():
    print("end")
try:
   # ここから無限ループ
    while True:
       # 0x03つまり、00000011となり、GPIOAの0と1をONする指令。
        spi.xfer2([Control_Byte,REG_GPIOA,0x03]) #ON
        time.sleep(1)
       # 0x00 つまり、すべての出力指示をOFF。
        spi.xfer2([Control_Byte,REG_GPIOA,0x00]) #OFF
        time.sleep(1)
# Ctrl + Cでここに入る。
except KeyboardInterrupt:
        destroy()

こんな感じです。

これでとりあえず動くはずです。
ただ、引っ掛かるポイントはいくつかあると思いますので、詳しく解説していきます。

spi.open(0,0)はこれ意外に設定方法がないか?

こちらは、コード上にコメントを入れていますが、
引数は取り合えず今回紹介した配線通りになっていればそのまま使えます。

もし、複数のMCP23S17を使用したい。
もしくは、他のSPI通信を使用する機器を増設したい。

そんなときは、
その機器をRaspberryPi上のCE1のピンにCSピンをつなげてあげればいいです。
その後、spi.open(0,1)とすれば接続できます。

ここは理論ではそうなるはずなのですが、
実際に試してみないと納得できないですよね。
そのうちMCP23S17を2つにして接続してみる予定です。

spi.modeは0でいいのか?

spiモードは、0~4ありますが、
一般的なSPI通信のモジュールは0で動くようになっているようです。

もちろんデータシートを確認したうえで決定してくださいね。
ここら辺の決め方は、詳しく解説している記事がありましたので
ご紹介しておきます。

SPIモードについて詳しく解説している記事

Control_Byteはなぜ0x40なの?

ここは少し説明が長くなりますが、
ちゃんと説明します。

以前のi2c版のIOエキスパンダーMCP23017の時は、A0~A2をGNDにつなげるか、
Vddにつなげるかでアドレスが変わる。とお話しました。

具体的には、A0~A2をGNDにつなげると、アドレスが、
0b010 0000で0x20になる。

A0~A2をVddにつなげるとbitが立って、
0b010 0111で0x27でアドレスをずらすことで最大8本つなげられる。

という論理でした。

では今回3本ともGNDに入れているから、0x20じゃないの?
と思いましたか?鋭いですね。

実は私も勘違いしていました。ですから、最初は0x20として「あれ、光らない…」
なんてやってました。

ここで重要になるのが、アドレスを決めた後のビットです。
データシートで確認しましょう。

MCP23S17のデータシートより。

こちらを見てもらうとわかる通り、R/Wのビットが最後に入ります。

つまり、0x20の最後に0or1が入ります。
今回はwriteしたいので、0が入ります。

というわけで、0b0010 0000となるわけです。
同様に、A0~A2をVddに入れると、0b0100 1110で、4Eになります。

なので、今回0x40を最初のコマンドとしているというわけです。

REG_〇〇はどこで決めているの?

REGは、レジスタの略です。
レジスタとは、簡単に言うと、あらかじめ決まっている機能の番地のようなものです。

この番地を指定して、その機能に合った信号を送ると思い通りに設定できますよ。
ということです。

これは、i2c通信Ver.のMCP23017でも解説しています。
今回のMCP23S17も確認してもらえればほぼ一緒であることがわかってもらえると思います。

どこで決めているかという疑問の答えは、
ズバリ…データシートですね。

データシートに詳しく記載がありますので、
データシートを参考にしてみてください。
きっと、0x00がIOの向き、0x12が入出力指令であるとわかってもらえるはずです。

spi.xfer2()は何をしているの?

spi.xfer2()←こちらは、実際にMCP23S17にコマンドを送っています。

引数()のなかに必要なコマンドを入れて実行します。
引数は必ず配列[]で渡します。
今回のMCP23S17の場合は、(アドレス+W/R+レジスタアドレス+コマンド)
という引数になっています。

これはMCP23S17のデータシート通りに送る場合の決まったフォーマットになります。
つなげて送る場合、引数の中でカンマ(,)を入れることで続けてコマンドが送られます。

具体的に1つ目のGPIOの向きを設定するところを例にして解説しましょう。

spi.xfer2([Control_Byte,REG_IODIRA,0x00]) 

さて、Control_Byteは、先ほど解説した通り、0x40です。


次に、REG_IODIRAは0x00です。
こちらはデータシートでレジスタのアドレスを確認すればOKのはずです。

最後に0x00は、GPIOAの0~7のピンをすべて出力(:0)に設定しています。

わかってしまえばそんなに難しくないですよね??
やりたいことがあれば少し変えるだけでいけそうです。

例えば、Aだけでなく、Bも使いたい…となれば、
IODIRBのアドレスをデータシートで確認すればいいですし、
GPIOAの0番だけ入力にしたいのであれば、
3つ目の0x00を0b00000001 = 0x01とすればOK。

ここからは、次回につながるMCP23017と異なるところ…

さて、ここまでで動作確認ができましたかね。
じつは、重要なことを説明せずにここまで来ました…
いちおうこれで目的の動きはできるはずですが、
もし2個目、3個目とMCP23S17を追加しようとすると必ずぶつかる壁があります。

それがCH設定です。

A0~A2までGNDに落としていますが、
じつは、このA0~A2、Vddに入れても動作するんです!
CHが0x20じゃなくなるじゃないか!でも動作するんですね。
試していただければすぐにわかります。

さてなんででしょうか?
このおはなしを次回の記事にする予定です。

今回のまとめ

今回はSPI通信を使用するIOエキスパンダ
MCP23S17をRaspberryPi400で制御してみました。

まともにSPI通信をしたことが無かったので、
今回の内容でだいぶ勉強になりました。

MSP23S17に限る話ではありませんが、
データシートの確認が重要であることを再確認しました。

ぜひこの記事を読んでSPI通信にチャレンジしてみてくださいね!

コメント

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