目的
FSPライブラリ(sci_spi)のサンプルプログラムを動作させて、RAのSPI通信動作の確認をおこなう。
サンプルプログラムはSEGGERのRTTを使用してプログラムの表示/入出力をおこなっているので、この操作も確認する。
全体フロー
- RA6M4基板 SPI通信I/O 接続
- サンプルプログラム インポート
- コンフィギュレーション/ビルド/プログラム書き込み
- 動作確認
準備
- RA6M4評価基板
- サンプルプログラム 前回(Part.4)と同様にルネサスのサンプルコードを使用。今回は「spi_ek_ra6m4_ep」プロジェクトを使用。 https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra6m4-evaluation-kit-ra6m4-mcu-group#document
- 基板接続用ケーブル 上記のサンプルコードはSPIのマスターとスレーブにチャンネルを分けてループバックを構成しているので
チャンネルで使用しているI/Oポート間を接続することが必要。QIコネクタ(メスーメス)ケーブルを3本用意。
本編
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ポートから給電し、基板を起動。
今回はSEGGERのJ-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を更新する処理となる。
