『昼夜逆転』工作室
[トップページへ戻る]

AVR USI-SPI使用例 特にSlave

タイトル画像
2022年12月
ATtinyシリーズのUSI機能を使用してSPIスレーブデバイスを作成しました。 データシートのSPIスレーブ側のサンプルコードがあまり参考にならなかったので、実用レベルを目指して自作しました。

プログラム

ブロック図 回路の様子 回路の様子

SPI(Serial Peripheral Interface)のマスター側はATtiny85、スレーブ側はATtiny44Aで制御しています。 スレーブとなるデバイスは「初めてのVFD点灯制御」のVFDです。
プログラムを実行すると「12,345,678.0-」と「don't,touch.」が交互に表示されます。 1桁表示するのに必要なデータは2byteです。動作としては、マスターから2byte一組でデータを送信し、 スレーブは2byte受信ごとにVFDに1桁表示します。また、スレーブはVFDをダイナミックドライブで制御しています。

マスター

ダウンロード UsiSpiMaster.zip(プロジェクト一式)
開発環境: Windows10, AtmelStudio7

プログラムは基本的にデータシートのサンプルコードと同様です。 そこにスレーブデバイスを選択するためのSS(Slave Select)信号の制御を追加します。 具体的には、適当なI/Oピンを割り当てて任意のタイミングでHi/Loを出力できるようにします。

スレーブ

ダウンロード UsiSpiSlave.zip(プロジェクト一式)
開発環境: Windows10, AtmelStudio7

データシートのサンプルコードは、ポーリング方式でデータ受信完了を検知する動作です。 この方法だとデバイスの独自処理(ここではVFDの表示制御)にかかる時間の分、 マスターは次のデータ送信を待たなくてはならず、高速な通信というSPIのメリットが活かせません。
また、バスに複数のSPIデバイスが接続されていて、マスターはそのうちの一つを選択してデータを送信する、 スレーブは自分が選択されたことを検知してデータを受信する(他のスレーブが選択されたときはバスに流れてくるデータを無視する)、 という使い方を想定したサンプルコードはデータシートにありません。  ※アプリケーションノートにはあったかもしれない。

というわけで、そのような使い方を想定したプログラムを作成しました。 バスに複数のSPIデバイスが接続されている前提で、スレーブは次のように動作します。

データ受信完了の検知とデバイスの独自処理を非同期にすることで、マスターはごく短い待ち時間(スレーブが受信データをバッファに格納するだけの時間)で次々とデータを送信することができます。

USIBRレジスタの罠

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に替えたらあっさり正常値が確認できてげんなり。

データシートのUSIBRの説明

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のデータ送受信が正しく行われているか観察するのにロジックアナライザが役立ちました。 Amazonなど通販サイトで「24MHz 8チャンネル USBロジックアナライザ」と検索して出てくる2,000円程度のものです。 Saleae社製品のパチモノ互換品のようで、ドライバは同じものが使えます。 アプリは「PulseView」がよく知られているようです。
ドライバはこちら→Downloadページ
アプリはこちら→Downloadページ

動作の様子

SPI, I2Cともに通信の様子が分かりやすく表示されます。 今回のSPIデバイスでは、マスターは2byte一組でデータを出力します。 スレーブはデータレジスタ(USIDR)にセットするデータは特にないので、受信したデータがそのまま出力されます。 すると、マスターがDOから1byte目を送信し、続けて2byte目を送信したとき、DIに1byte目の値が戻ってきます。 その様子が波形で分かるのが面白いです。

通信の様子 通信の様子

◆ ◆ ◆

SPIスレーブのサンプルコード、すぐ作れると思いましたが…ひどい罠でした。 それにしてもロジックアナライザは便利です。