2016/09/11

[nrf52]UARTのEasyDMAとはなんぞや

nRF52832には、EasyDMAという機構というかユニットがある。
DMAは、Direct Memory Accessで、CPUを介さずにメモリをアクセスするユニットだと思えばよいだろう。

だいたい、DMAを使うときにはこういうデータをセットする。

  • 転送元のアドレス
  • 転送元アドレスの進め方
  • 転送先のアドレス
  • 転送先アドレスの進め方
  • バスの扱い方

最近使っていないからちょっとあやしいが、だいたいこんなもんだろう。

メモリからメモリへの転送であれば、アドレスはアクセスごとに進めるなり戻るなりしたいだろうけど、片方がレジスタであれば同じアドレスをアクセスし続けたいはずだ。

また、DMAユニットがメモリのバスを使い続けると、そのバスを使いたい人は空くまで待たないといけない。
バースト転送だとそんな感じだけど、アクセスごとにバスを空ける方式もあったと思う。

転送が終わったら割込みが上がるか、転送完了フラグが立つか、というパターンであろう。


nRF52832のProduct Specでは、2ページ程度で説明されている。
レジスタ仕様などなく、こんな接続ですよ、というくらいだ。

EasyDMAは、メモリ-メモリ間の転送はできず、RAMといくつかの周辺機器間に限定しているようだ。
その分、使い方が簡単になっているのが「Easy」の意味か。

そして、周辺機器の相手は「メモリ」ではなく「RAM」なのだ。
たとえば、UARTドライバの送信nrf_drv_uart_tx()では、EasyDMAを使うルートにこういうコメントがある。

// EasyDMA requires that transfer buffers are placed in DataRAM,
// signal error if the are not.

渡されたアドレスがデータRAMかどうかをチェックして、違う場合はエラーにしているのだ。
チェックするマクロは、こうなっている。

#define IS_EASY_DMA_RAM_ADDRESS(addr) (((uint32_t)addr & 0xFFFF0000) == 0x20000000)

送信だからconstなデータを送ることもあるだろうけど、EasyDMAを使いたいのであれば一度RAMに移して、そのアドレスから送信してやらないといかんということだ。

 

EasyDMAがある場合のUART構成は、こうなっている。
Product Specでは「UARTE」となっている。

image

nRF51と同じ構成のUARTもある。

image

外から見ると、STARTRX, STOPRXや、PSELRXD, PSELTXDは同じなのだけど、それが内部でどうつながっているかが違うようだ。

 

app_uart_put()を使うと送信サイズが1なので、あまりEasyDMAを使ってもありがたみがなさそうな気がする。
だが、転送データは最終的に構造体に入れられてnrf_drv_uartに渡されるので、アドレスは心配しなくてよさそうだ。


 

ドライバのソースは、EasyDMAなのかどうかを、CODE_FOR_UARTE()とCODE_FOR_UART()で分けている。
分けているのだが、パターンとして

  • UARTのみ
  • UARTEのみ
  • UARTEとUART両方

を許容しているようだ。
EasyDMAだけだと、RAMに置けないような大きいデータをやりとりできなくなってしまうので、両方使えるようにもしてあるのだろうか。

 

nRF51でUARTの送信バイト間がやたらと空いてしまうことが有り、おそらくUART送信とSoftDeviceの処理が重なり、SoftDeviceが優先されたためだろうと思っている。
バイト間タイムアウトがあるデバイスを使っていたので問題になったけど、DMAもなく上手に回避できなかったのだ。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。