2019年3月22日金曜日

【ARM】【Cortex-M0+】【SAMD21】DMA転送の罠

【DMA転送の罠】

ソフトバンクが買収したARM社のマイコンをこれから積極的に活用しようとして色々勉強してるんだけど、ARMコアのDMA転送のしくみは罠すぎるというか改善余地ありに思えるw


DMA転送を語る前にまずCPUの仕組みを理解するにはOSを設計できるレベルの知識が必要で、特にスケジューリング周りは外せない。

FreeRTOSなプリエンティブ、多段フィードバックキューやタイムスライスなど。

IT系の国家資格を持ってる人なら試験範囲の部分だし、自作OSの実装などでも触っている部分だしこの辺の事は大丈夫だろうと思って油断したのがARMコアのDMA転送。。

仕様上リングバッファ非対応だとか、ラウンドロビンで優先権を回す方式など、ある程度の仕組みを調べていざ動かしてみるとなぜかフリーズするんですよね。。

(海外サイトでも動かなくて解決案が無く、Githubでもコメントでここはそのうち・・みたいな感じになっていたり。PC向けARMって大丈夫?)

フリーズする理由でいくつか考えてみると、割込みが飛んでこないからっていう理由でコールバック処理されないなど色々模索してみたけど結果解決できず。。しかもレジスタを覗いてみるとラウンドロビンのFIFOキューは空っぽ、、静的な割り当てしても反応しない、、アクティブチャンネルを変えようと思っても切り替わらないしいったいどうなってるの状態。



さまざまな代替案やアプローチを考え試したけどうまくいかなくて、最終的にはPIOでカバーという非常手段を取っておきつつ、何度も1000ページ超える英文のドキュメントを読み直しては間違った解釈が無いか、抜け漏れがないか調べてようやく気付いた事がある。



ラウンドロビン・・・(; ・`д・´)?



あー・・・(悲しみ

通信周りに関して上位レイヤーから物理レイヤーまですべて精通してるつもりだったけど、そうでもなかった件について。。

ラウンドロビンって順番に優先権を渡して終わったら次!っていう感じに回していく仕組みだから、受信側のDMA転送は指定バイト数受信が終わるまで優先権を奪ってしまうんですよね。
つまり、タイムアウトなんて機能がないため
他のDMA転送を開始しない限り優先権は切り替わる事はなく、そのままフリーズする現象が起こる。
というのもバイト単位をビートという名称で括っていて、1ビート単位で受信したよ!って割込みを発生させることができれば解決するように思えるがうまくいかない。
割込みをやめてライトバックキャッシュをポーリングして自分で転送データ数をカウントしていこうと思っても割込みが発生しない=ライトバックキャッシュは更新されない。って現象。
では、参照するたびにサスペンド・リジュームしていけば割込み飛んでくるし解決?って思いきや、割込み入るまで16クロック程度かかったりするのでオーバーランのリスクが高まる。
以上の事から1ビートを1バイト単位に刻めば解決?って思うけどそれはそれでメモリ圧迫するからしたくないジレンマ。。

今日考えたのは、タイマー割込みをDMA転送にして割込み優先度を受信DMA転送より高くしてあげればいいんじゃない?って発想。
1ms割込みを無駄に消費するけど、バス効率が悪くなるだけでCPUの負担は少ないはず。。
これでもう一度DMA転送を試してみようと思う。

教訓:知っているからって油断するとハマる罠あり

0 件のコメント:

Androider