Super Sylphide 進捗状況(14) -- McBSP(SPI)におけるCPU割込とEDMAの協調

製作中のオートパイロットシステムsuper Sylphideですが、DSP上で動作するプログラムのブラッシュアップを進めています。その中でDSPにかかるCPU割り込みが予想外に多く、処理負荷を上げていることがプロファイラによって判明しました。これは以前の記事『DSP/BIOSを利用した割込みMcBSP(SPI Slave)』にもあるとおり、SPIモードで利用しているMcBSPにおいて、4bytesつまり32bits受信するたびにCPUに割込みをかけて受信後の処理をしていたためです。そこで今回はCPU割り込み+CPUに負荷をかけることなくメモリの転送が行えるEnhanced DMA(EDMA)を協調させることによってCPU負荷軽減を目指してみました。

ここで、なぜEDMA単体ではなくCPU割込みと協調なのか、と疑問を持たれる方がいらっしゃるかもしれません。SPIやI2CといったCPUから見れば非常に低速なペリフェラルに対して適用されるDMAは、複数バイトをブロック処理するために使われることが多く、電源ONから電源OFFまでDMAは起動しっぱなし、CPU本体はDMAの起動、停止をいちいち行わない、というのが普通であると思います。特にターゲットとしているDSPのTMS320C6713に搭載されたEDMAは単体でピンポンバッファ(ダブルバッファといったほうが一般的でしょうか)を構成できるので、CPUがEDMAの起動、停止を動作中に変更する必要は全くありません。

ところが残念ながら以前の記事でも書いたとおり、McBSPをSPI互換モード(クロックストップモード)で動作させると、ハードウェアでは複数バイトで意味を構成するフレーム転送がサポートされません。そこでフレームの頭だしをソフトウェアで行うために、CPU割込みが必要となってきます。CPU割込みによって頭だしが行えたらCPU割込みを停止、EDMAを起動して1フレーム分溜まるまでEDMAを動作、EDMAによる1フレーム受信完了後、EDMA終了割込みによってCPU割込みを復活という動作によって解決を図りました。図で示すと、以下のような動作になっています。

McBSP_EDMA_cooperative.png

このアイデアを実装すると公開中のソースコードのようになりました。この記事を書いている時点でのCVSの管理番号はmain.cpp.1.34です。
ひとつ注意書きをしておきますと、EDMAとCPU割込みを同時に行うサンプルコードが探した限りでは見つかりませんでした。そのためコードの大部分は試行錯誤によって書かれており、動作が怪しいところが依然としてあります。
怪しい部分は、CPUが高負荷になった時点でMcBSP受信イベントがEDMAに伝わらずにEDMA割込み完了がおこらず、またEDMA動作時にはCPU割込みを無効にしているため、デットロック状態が発生していることです。しかもそのような状態に陥った際は、McBSPの受信レジスタ(DRR)に対してCPUから直接アクセスをすることによって、デットロック状態が解消(McBSPの受信イベントがEDMAに伝わるようになる)されるようなので、コードにはそのような対処法を追加してあります。おそらくEDMA、キャッシュ、McBSPあたりが臭いとにらんでいますが、現在解決には至っていません。この問題についてご存知の方がいらしたら情報を待っております。

最後に、このコードを書くにあたって2点ほど苦労しました。参考になる方がいらっしゃるかもしれませんので記録をつけておこうと思います。

一つはEDMA先がL2キャッシュが効いているCS0上のSDRAMであるため、EDMAを起動する以前にCACHE_wbInvL2()やCACHE_wbL2()によってキャッシュの掃除をしておく必要がありました。これを忘れると、SDRAMに受信内容が書き込まれていなかったり、送信内容が古いままになってしまいます。

もう一つはEDMAとMcBSPの初期化手順です。spra488『TMS320C6000 McBSP Initialization』に厳密な規定があり、これを守らないとEDMAがうまくかかりません。ここには先述のより一般的な使用方法であるEDMAが電源ONからOFFまで起動しっぱなし、というサンプルコードがあり、今回のコーディングはこのサンプルコードをもとに行いました。

※その後、I/O拡張基板の設計をしました。
※※随分と時間がかかりましたが、通信の問題が解消しました。

December 04, 2007 11:00 fenrir が投稿 : 固定リンク | | このエントリーを含むはてなブックマーク

コメント

いったん頭だしができた後も継続的にCPU割り込みを使う理由が分かりません。4バイト固定ならDMAで4バイトずつ転送すればいいと思うのですが。
エラー状態から復帰することを前提にしているのでしょうか。

Posted by: 酔漢 : December 8, 2007 08:47 AM

>酔漢さん
コメントどうもです。理由は現在、強い理由と弱い理由の2つがあります。
強い理由としては、DSP側がスレーブになるプロトコルで通信しており、マスターである外部のマイコンの指令によって送受信を切り替えている(=全二重ではなく半二重通信)ため、マスターからフレーム先頭を受信後、即座にDSPから送信しなければならない事態があるためです。
弱い理由としては、1フレームを可変長にしようかと考えていたためです。現在ヘッダ(SPIのハードウェア的処理単位4byteのうち先頭1byte)を除いた1フレームは32byte固定(つまり実質1フレームはceil(32/3)*4=44byte)としたため、仮に強い理由で示した送受信の切り替えがなく受信のみでしたら、一度フレーム先頭を検出すれば、ご指摘のとおりDMAで可能です。しかし可変長となるとDMAの転送数をどこかしらで再設定する必要があり、それで割込みと併用して解決する方法を検討していました。
勿論割込みをなくした方がスマートであると思いますので、これらの2つの理由を解消できる方法を検討してみたいと思います。

Posted by: fenrir : December 8, 2007 11:40 PM

コメントする