SPI(Serial Peripheral Interface)のマスター側はATtiny85、スレーブ側はATtiny44Aで制御しています。
スレーブとなるデバイスは「初めてのVFD点灯制御」のVFDです。
プログラムを実行すると「12,345,678.0-」と「don't,touch.」が交互に表示されます。
1桁表示するのに必要なデータは2byteです。動作としては、マスターから2byte一組でデータを送信し、
スレーブは2byte受信ごとにVFDに1桁表示します。また、スレーブはVFDをダイナミックドライブで制御しています。
プログラムは基本的にデータシートのサンプルコードと同様です。 そこにスレーブデバイスを選択するためのSS(Slave Select)信号の制御を追加します。 具体的には、適当なI/Oピンを割り当てて任意のタイミングでHi/Loを出力できるようにします。
データシートのサンプルコードは、ポーリング方式でデータ受信完了を検知する動作です。
この方法だとデバイスの独自処理(ここではVFDの表示制御)にかかる時間の分、
マスターは次のデータ送信を待たなくてはならず、高速な通信というSPIのメリットが活かせません。
また、バスに複数のSPIデバイスが接続されていて、マスターはそのうちの一つを選択してデータを送信する、
スレーブは自分が選択されたことを検知してデータを受信する(他のスレーブが選択されたときはバスに流れてくるデータを無視する)、
という使い方を想定したサンプルコードはデータシートにありません。
※アプリケーションノートにはあったかもしれない。
というわけで、そのような使い方を想定したプログラムを作成しました。 バスに複数のSPIデバイスが接続されている前提で、スレーブは次のように動作します。
ATtinyシリーズのUSI機能を利用したSPIのスレーブにおいて、USIDRレジスタのバッファであるUSIBRレジスタは正しく機能しません。
詳細はこちら→
USIBR loses the MSB of the received byte in ATtiny45/85 of AVR family
実験中の現象としては、スレーブのデータ受信完了時にUSIDRは正しい値(マスターが送信した値)となっていますが、
そのコピーであるはずのUSIBRの値はUSIDRの値を左に1bitシフトしたようなものでした。
なお、マスター側ではUSIBRの値はUSIDRの値と一致しています。
※何度プログラムを見直してもスレーブ側で正しい値が得られず何日も悩み、ふとUSIBRをUSIDRに替えたらあっさり正常値が確認できてげんなり。
ATtiny44AもATtiny85もデータシートのUSIBRの説明は同じです。
USIDRよりもUSIBRを使う方がメリットがあるようなので積極的に使ったのですが、まさかエラッタだったとは。
ATtiny24A/44A/84A - Microchip Technology (PDF)
14.5.4 USIBR - USI Buffer Register
Instead of reading data from the USI Data Register the USI Buffer Register can be used.
This makes controlling the USI less time critical and gives the CPU more time to handle other program tasks.
USI flags as set similarly as when reading the USIDR register.
The content of the USI Data Register is loaded to the USI Buffer Register when the transfer has been completed.
[Google翻訳]
USI データ レジスタからデータを読み取る代わりに、USI バッファ レジスタを使用できます。
これにより、USI の制御が時間的に重要ではなくなり、CPU が他のプログラム タスクを処理するための時間が増えます。
USIDR レジスタを読み取る場合と同様に、USI フラグが設定されます。
転送が完了すると、USI データ レジスタの内容が USI バッファ レジスタにロードされます。
SPI, I2Cともに通信の様子が分かりやすく表示されます。 今回のSPIデバイスでは、マスターは2byte一組でデータを出力します。 スレーブはデータレジスタ(USIDR)にセットするデータは特にないので、受信したデータがそのまま出力されます。 すると、マスターがDOから1byte目を送信し、続けて2byte目を送信したとき、DIに1byte目の値が戻ってきます。 その様子が波形で分かるのが面白いです。
SPIスレーブのサンプルコード、すぐ作れると思いましたが…ひどい罠でした。 それにしてもロジックアナライザは便利です。