part.6 SPI通信

目的

FSPライブラリ(sci_spi)のサンプルプログラムを動作させて、RAのSPI通信動作の確認をおこなう。
サンプルプログラムはSEGGERのRTTを使用してプログラムの表示/入出力をおこなっているので、この操作も確認する。

全体フロー

  • RA6M4基板 SPI通信I/O 接続
  • サンプルプログラム インポート
  • コンフィギュレーション/ビルド/プログラム書き込み
  • 動作確認

準備

本編

SPI通信は基板内でMPUと接続するデバイス(FPGAやADC, DACなど)と通信するための標準的な方法であり
UART通信と同様 非常に使用頻度が高い。
なので、RAでのSPI通信の使いやすさをサンプルプログラムで検証することにした。

SPI通信I/O 接続

サンプルプログラム「spi_ek_ra6m4_ep」内のreadmeファイルを読むと、サンプルプログラムを動かすには以下のピン配列の接続が
必要との記載があった。
プログラムはSPIマスタとスレーブをチャンネルごとに分けてループバックさせているのでこのような配線になっている。
これらのI/O間をQIコネクタのケーブルでショートする。

Pin Connection for EK-RA6M4
MISO ----> P202 - P410
MOSI ----> P203 - P411
RSPCK ----> P204 - P412


EK-RA6M4評価基板の各I/Oの位置は以下の通り。同色で指定したジャンパポストにQIコネクタケーブルを接続する。



サンプルプログラム インポート

続いて、サンプルプログラム内の「 spi_ek_ra6m4_ep」
e2studioから「ファイル」→「インポート」→「既存プロジェクトをワークスペースへ」を選んでインポート
ここは他のPartで方法を紹介しており、特に操作の変更点はないので詳細は割愛。

コンフィギュレーション / ビルド / プログラム書き込み

プロジェクトのインポートが終わったら、コンフィギュレーションファイル(configuration.xml)を開いて、「Generate Project Content」を実行。
モジュール構成は、SPIマスタ(g_spi_master)とSPIスレーブ(g_spi_slave)がそれぞれチャンネル0, チャンネル1で宣言されている。

テストプログラムを動かすのにモジュールのプロパティは特に変更する必要はないが、
SPI通信仕様に基づく基本的なオプションがいくつか用意されていて、今後必要に応じてここを変更すれば期待の動作にすることは
容易であることが確認できた。



合わせてpin Configurationも確認。

SPIマスタ(SPI0)のMISOA/MISIA/RSPCKA信号がP202/P203/P204,
SPIスレーブ(SPI1)のMISOB/MISIB/RSPCKB信号がP410/P411/P412にアサインされているのがわかる。 



後はプロジェクトエクスプローラから本プロジェクトを右クリックしてメニューから「プロジェクトのビルド」を選択。
正常終了すればDebug下に「spi_ek_ra6m4_ep.hex」が生成されるので、前回と同様JFlashLiteから評価基板にhexファイルを書き込む。

動作確認

評価基板のDEBUG1のUSBポートから給電し、基板を起動。

今回はSEGGERJ-Link RTT Viewerから入出力操作をおこなうことになっているので、SEGGERのフォルダから同プログラムを起動。

プログラムが起動したら、下記のウィンドウが開くので設定をおこなう。
Connection to JLinkは「USB」、Specify Target Deviceは「R7FA6M4AF」を選択。
後重要なのはRTT Control Blockを「Address」にして、RTT Control blockのアドレスを入力する欄に「0x2000026c」を入力する点。

これは先にビルドしたコードの中にSEGGER_RTT/SEGGER_RTT.cがあり、このオブジェクトが配置されているアドレスを指定するよう。
これはビルドした後に生成される「spi_ek_ra6m4_ep.map」ファイルを見ると確認できる。


プロジェクトから「spi_ek_ra6m4_ep.map」ファイルをみると、確かに0x2000026c番地にSEGGER_RTT.oのオブジェクトが
配置されているがわかる。



後はプログラムの動作確認のみ。

ちなみにテストプログラムはRTTから入力した文字列の末尾はLF or CRの1バイトであることを前提としていたため
入出力を正しく行うにはRTT Viewerのメニューより、デフォルトから以下の設定変更が必要となる。
Input/Sending… Send/on Enter」
「Input/End of Line/(Unix)LF」

RTT ViewerのAll Terminalのウィンドウにプログラムのメッセージと入力用のプロンプトが表示されるので、メニューから「1」を選んで適当に
Hello World!」と入力してみると、正常終了であることが確認できた。
テストプログラムは、SPIマスタからスレーブに入力の文字列を転送し、その後スレーブからマスターに受信した文字が転送、送信データと
受信データが一致していれば正常であることをメッセージに表示する仕組みになっている。 

メニューの「2」はSPI通信で使用するAPIが異なるがこちらも特に問題はなく正常終了。
ひとまずテストプログラムによる簡単なSPI通信動作確認は完了。


このテストプログラムではSPIマスタ/スレーブの1:1通信であり、スレーブセレクト信号を使用していない例になっている。
一つのマスターから複数のデバイスを通信する1:Nの場合はセレクト信号を使用する必要があるので、
このあたりの設定もRA評価基板で難なくできるのかを検証するのが今後の課題となる。

コード解析

SPI通信を実行するためのAPIをテストプログラムより確認。
主要な関数は

FSP関数:

 R_SPI_Open() : SPIモジュールの初期化
 R_SPI_Read() : 指定のSPIモジュールのデータリード
 R_SPI_Write() : 指定のSPIモジュールのデータライト
コールバック関数:
 spi_master_callback():
SPIマスターモジュール用 (チャンネル0)
 spi_slave_callback(): SPIスレーブモジュール (チャンネル1)

となる。

spi_ep.cの関数:spi_init()内でFSP関数:R_SPI_Open()によるマスターとスレーブモジュールの初期化が実行される。

関数:spi_write_and_read()内にてFSP関数:R_SPI_Read()R_SPI_Write()が呼び出される。
134行ではスレーブモジュールに対してデータリード, 146行はマスターモジュールに対してライトが実行されているが
コールバック関数での割り込み処理を使った非同期処理であるため、関数実行後はノンブロックで速やかに155行以降にステップする。

155から178行はコールバック関数:spi_master_callback(), spi_slave_callback()で変数g_master_event_flag, g_slave_event_flagが
転送 or 送信完了状態に更新されるまで待ちとなる。
while文での待ちが完了したときには、R_SPI_Read()にはR_SPI_Write()で指定した送信バッファ:g_master_tx_buffと同じデータがSPI通信により受信バッファ: g_slave_rx_buffに転送が完了したことになる。
ちなみにR_SPI_Read()とR_SPI_Write()の3カラム目に設定してあるnum_bytesは「バイト数」ではなく、122-130行の処理で
SPI通信での転送幅 32ビット✕「長さ」に変換されているので注意。



SPIマスターからスレーブへの転送が完了したら、今度はスレーブからマスターに対して先ほど受信したデータ列を転送する処理になる。
処理の流れは前述を同じで、コールバック関数で転送、送信完了待ちをおこなう。



ステータスが更新され待ち状態が解除されたら最後に
238行でマスターがスレーブから受信したデータ列: g_mastere_rx_buffと元データ: g_master_tx_buffのコンペアマッチをおこない、
SPI通信の一連の処理が完了する。



最後に割り込み処理を確認して終了とする。

SPIモジュールの割り込み関数: spi_master_callback()spi_slave_callback()内の処理は
各々のイベントフラグ: g_master_event_flag, g_slave_event_flagを更新する処理となる。