SPI通信
基本操作
SPI(シリアルペリフェラルインタフェース)通信では,マスタデバイスが1つと,1つ以上のスレーブデバイスがある.マイクロコントローラは,マスタデバイスとしてもスレーブデバイスとしても設定できる.
SCK(シリアルクロック)信号はマスタによって生成される.クロック線はSCLK線またはCLK線とも呼ばれる.マスタはMISO(マスタ入力スレーブ出力)線を介してスレーブからデータを受け取る.マスタがデータをスレーブに送信するときはMOSI(マスタ出力スレーブ入力)線を使用する.どの時点においても,マスタと1つのスレーブの間で通信が行われている.マスタはスレーブのSS(スレーブ選択)線をLowにプルすることでスレーブと通信を行う.SSピンはCS(チップ選択)ピンと呼ばれることもある.通信の最後に,マスタはSS線をHighにプルする.
| "SELECT" | スレーブを選択する |
| "DESELECT" | スレーブの選択を解除する |
| "READ" | SPIデバイスから入力チャンネルに読み込む |
| "WRITE" | 出力チャンネルからSPIデバイスに書き込む |
| "data" | data をSPIデバイスに書き込む |
"SELECT"と"DESELECT"はマスタデバイスのみが指定する."READ"は入力チャンネルが,"WRITE"は出力チャンネルが使用し,data は入出力チャンネルのどちらでも使うことができる.
マイクロコントローラが通信する必要のあるSPIデバイスの指定は"SPI"オプションで"SPI"->{name1->{spec11,spec12,…},name2->{spec21,spec22,…},…}として与えられる.SPIデバイスの namei は,以下の値を取ることができる:
名前
|
マイクロコントローラのモード
|
SS接続
|
| "pin" | master | SPIデバイス上のSSへのマイクロコントローラの pin |
| "label" | master | 接続されておらず,"SELECT"と"DESELECT"は使用されていない |
| "Master" | slave | マスタSPIデバイス上の適切なピンへのマイクロコントローラのSSピン |
入力チャンネルでは,サブオプション"Conversion"は,届いたデータをどのように変換して入力に割り当てる必要があるのかを指定する.
出力チャンネルでは,サブオプション"Conversion"は出力をどのように変換して送信する必要があるのかを指定する.
例
この例では,ArduinoをSPIバスを介してデータの送受信を行うマスタモードで使用する.また,スレーブモードのArduinoも使用し,こちらもデータの送受信を行う.つまり,この例ではマスタモードとスレーブモードの両方において,送信と受信の両方を行う.
ポテンショメータとLEDはマスタとスレーブの両方に接続する.マスタはポテンショメータの値をスレーブに送る.スレーブはこの値をもとにLEDの輝度を設定する.マスタはスレーブのポテンショメータの値を受け取り,その値を使ってLEDの輝度を設定する.
Needs["MicrocontrollerKit`"]sys = StateSpaceModel[{{}, {}, {}, {{1, 0}, {0, 1}}}, SamplingPeriod -> 1,
SystemsModelLabels -> {{"Pot.", "SPI"}, {"SPI", "LED"}, {}}]マスタのピン
またはその他のどのピンでも,スレーブを選択するのに使うことができる.その他の接続には変更があってはならない.
SSがLowになったとき,マスタがデータを送ろうとしているのか,データの送信を要求しているのかをスレーブはどのようにして知るのだろうか.これを明確にするために,SSがLowになった後の最初のバイトを使って,マスタがスレーブから読み取ろうとしているのか,スレーブに書き込もうとしているのかを示す.
readFromSlave = "0x01";
writeToSlave = "0x02";ポテンショメータは
から
Vまでの値を示す.これを
から
までの値に変換し,それをSPIバス上で送信する.
obConversion[byte_] := {CDeclare["double", "outValue"], CAssign[byte, COperator[Times, {"outValue", COperator[Divide, {255, 5}]}]]}ToCCodeString[obConversion["byte"]]マイクロコントローラが
から
までの範囲のデータバイトを受け取ったら,それをLEDの輝度として設定する前に
から
までの値に変換する.
ibConversion[byte_] := {CDeclare["uint8_t", CAssign["inValue", byte]], COperator[Times, {5.0, COperator[Divide, {"inValue", 255.0}]}]}ToCCodeString[ibConversion["byte"]]実際には,
の値の範囲から
の範囲に変換し,さらにもとに戻す必要はない.ここでは変換をどのように指定するのかを説明し,必要に応じて使えるようにするために行う.
次に,スレーブがSPIバス上で見る交換シーケンスを指定する.writeToSlave バイトを見たらスレーブは次のバイトを読む必要があり,readFromSlave バイトを見たら,マスタが読めるようにSPIバスにバイトをロードする.
Subscript[exSequence, s] = "Master" -> {{writeToSlave, "READ"}, {readFromSlave, "WRITE"}};マスタはSSピンがマスタのピン
に接続されている1つのスレーブとトークする.読み込む,または書き込むためには,マスタはまずスレーブを選択し,データを読み込むのか書き込むのかを設定し,操作を行い,スレーブの選択を解除する.
Subscript[exSequence, m] = "9" -> {{"SELECT", readFromSlave, "READ", "DESELECT"}, {"SELECT", writeToSlave, "WRITE", "DESELECT"}};これで,スレーブの入出力チャンネルを指定し,コードを埋め込むことができる.
Subscript[ics, s] = {{"A3", "Analog"}, {"11", "SPI", "Conversion" -> ibConversion}};Subscript[ocs, s] = {{"12", "SPI", "Conversion" -> obConversion}, {"3", "PWM"}};MicrocontrollerEmbedCode[sys,
<|"Target" -> "ArduinoUno", "Inputs" -> Subscript[ics, s], "Outputs" -> Subscript[ocs, s]|>, "/dev/cu.usbmodem141201", <|"SPI" -> Subscript[exSequence, s]|>]Subscript[ics, m] = {{"A3", "Analog"}, {"12", "SPI", "SlaveSelect" -> "9", "Conversion" -> ibConversion}};Subscript[ocs, m] = {{"11", "SPI", "SlaveSelect" -> "9", "Conversion" -> obConversion}, {"3", "PWM"}};MicrocontrollerEmbedCode[sys,
<|"Target" -> "ArduinoUno", "Inputs" -> Subscript[ics, m], "Outputs" -> Subscript[ocs, m]|>, "/dev/cu.usbmodem141101", <|"SPI" -> Subscript[exSequence, m]|>]