こんにちは。
現在自作のボードにてRX651を使用してSPI通信(ジャイロセンサ)を行っているものです。
スマートコンフィグレータのAPIを使用して、ジャイロセンサと通信を行っているのですが、正しくスレーブからの値を受信できずに困っています。
詳細を下記にまとめます。お心当たりがある方がおられましたら、本件についてご教授頂けないでしょうか。
↓現在のスマコンのRSPI設定内容
現在の問題として、マイコンからスレーブ(ジャイロ)へ読み出しアドレス(1byte)を送信後、受信のためもう1byte送信するのですが、バス上では正しくジャイロからの返答がある事をロジックアナライザで確認済みなのですが、スマコンのAPI関数から、ユーザー関数へは何も値が格納されない状況です。
↓SPIバス上のデータ(スレーブ側の返答は成功)
↓ただし、スマコンAPIからの返答はゼロ
↓その際のAPIコール内容
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
次に関数の内容を変更し、100msごとに送信内容を2種類に切り替えて送信を行ってみたところ、なぜか状況は変わって、前回送信(受信)した内容がAPIから出てくるおかしな状況が起こりました。
RSPIの送受信は非同期APIです。関数を実行後、割り込みハンドラ(設定のコールバック関数)で通信完了を確認する作りにする必要があります。
RSPI1_busy = 1; // global variable
R_Config_RSPI1_Send_Receive()
while (RSPI1_busy) { // do nothing }
printf....
(void)g_rspi0_tx_buf;
(void)g_rspi0_rx_buf;
r_Config_RSPI1_callback_receiveend(void) { // 生成コードのコメントに挟まれたエリアに追記してくださいね。
extern volatile int RSPI1_busy;
RSPI1_busy = 0;
}
こんな感じです。あと通信バッファを自動変数にしておくと送受信APIを呼び終わったあと勝手に解放されたりする場合があるので(void)とか使って参照エリアをコンパイラに明示するかstatic指定してやることをお勧めします。
YAMAMOTOさんいつもアドバイスを頂きありがとうございます。早い段階でコメント頂けて助かります。
そういう事だったんですね。関数が終了したからと言って、ユーザー変数へ受信値が格納されているわけではなく、ユーザー側は受信完了割り込みを確認したのちに、読み出さないといけない。と理解しました。認識あっていますか??それを監視しているのが、記載頂いた while (RSPI1_busy) { // do nothing }の部分かと思います。
だから、前回の値が(まだ受信完了割り込みが発生していないタイミングで読むと)出て来たんですね。
そういうことです。割り込みハンドラ経由が面倒ならたとえば、受信が完了できるくらいの時間とりあえずで強制的に待ちをさせてやるのでも値の確認ができます。なおシリアルデバイスの送受信は全て非同期です。ArduinoなんかでもSerialは受信数を確認してから動作しますよね?I2CとSPIが同期で作ってあるので、ここでもそうだろうって気になるのかもですが。組み込みなんでRTSOでも導入していなければ自力で他の処理にCPUを明け渡すようにプログラムを書くのがいいのですが。
全て完璧に理解しました。ご回答ありがとうございます。
完全に関数終了後に値が入っているものとばかり…笑
これで作業が進みそうです。仕事が終わったら試して見ようと思います。
生成コードへの追記は、開発者が追加していい場所がコメントで区切られています。そのコメントは消さずに追記してましょう。コード生成が再度実行されたときに追記分が自動的にマージされます。
なのですが、どうもその受信割り込みの関数は実行されていないようです… GPIOに接続されているLEDの点灯トグルで確認してみました。
ちょっと時間が取れず参考資料などが用意出来ず申し訳無いです。
何か割り込ませるための設定などあったりしますか??
スマコンの方の設定では受信割り込みにチェックが入っているのですが…
_Createはmain関数開始前で実行されますが、_Startが実行されないと送受信APIを実行しても動きません。_Startで割込有効化しています。この辺は分かりにくいんですよね。生成コードの中を見るとイメージがつくと思います。
こちらの件ですが、年末年始に時間が取れたため、教えていただいた内容で進めてみました。結果として、無事にr_Config_RSPI1_callback_receiveend(void) { 内にオリジナルフラグを用意して、受信完了フラグ待ち処理を入れたところ、無事に値を読み取ることができました。ありがとうございます。本件はオシロやらロジックアナライザやらを引っ張り出したりなど大掛かりなことになりましたが、無事に取得できてよかったです。笑
無事にできてよかったですね。スマートコンフォギュレータのシリアル系は大体同じ考え方です。注意点として、通信異常検出のあるものとタイムアウトの概念があるものです。I2Cならタイムアウト処理を入れておかないと、通信が止まったままになります(EEPROMなら書き込みでブロック書き込み完了待ち時間の処理なども元々必要ですしね)。UARTならフレーミングエラーなどの受信エラーで受信バッファを無視するなどの対策が必要になる場合があるので、それは該当する割り込みハンドラから処理を呼び出せるようにする必要が出ます。UARTの場合、受信前に受信数を指定するAPIなので私はバッファ操作している部分に直接、自作の受信FIFOで処理させるようにしています。そういった自作コードを無理やり突っ込むためのコメント行も用意されています。
/* Start user code */
hoge();
/* End user code */
このコメントで囲んだコードはコード生成を再実行しても残ります。あと、SPI通信マスタの場合RSPIよりSCIの3線式SPIの方が扱いやすい場合があるのでそれも気に留めておくといいかと思います。RSPIと3線式SCIのピンは被っている場合があるので回路設計後でもRSPIから変更なら多分、対応可能です。