組み込み

【組み込み】DMA転送の活用方法

DMA転送についての説明と、DMA転送を活用すべき理由について説明します。

DMA転送は使用しなくても実装できますが、活用することによってパフォーマンス改善につなげることができます。
DMA転送の特徴と活用すべき場面をおさえて、設計時の選択肢としていつでも出せるようにしておきましょう。

DMA転送の概要

DMAとは「Direct Memory Access」の略です。
その名前が意味する通り、CPUを介さず直接メモリ同士でデータの受け渡しができるという機能です。

この「CPUを介さない」というのが非常に重要で、CPUが一つ一つデータ転送処理をするはずだった処理をDMA転送が肩代わりしてくれるので、その空いた時間で別の処理をすることができます。

つまり、CPUリソースを減らすための手段となる、ということですね。

DMA転送の設定と動作

DMA転送で設定する内容を見つつ、動作について確認します。

DMA転送で設定する内容は主に以下の項目になります。

  • 転送元/転送先のアドレス
  • 転送元/転送先のアドレスのインクリメントの有無
  • 転送サイズ
  • 連続転送モード or 転送要求信号モード
  • 要求信号の選択(転送要求信号モードの場合)

1つ目の設定は、どこのアドレスからどこのアドレスに転送するか、という基本的な設定です。

2つ目のインクリメントの有無、というのは、2byte以降のアドレスをインクリメントするかどうかの設定となります。
例えば、転送元アドレスのインクリメントはなしで転送先アドレスのインクリメントがありの場合、

  • 1byte目:(転送元アドレス+0) ⇒ (転送先アドレス+0)
  • 2byte目:(転送元アドレス+0) ⇒ (転送先アドレス+1)
  • 3byte目:(転送元アドレス+0) ⇒ (転送先アドレス+2)

といった形でデータの転送を行うことになります。

3つ目の転送サイズは、何byte送った時点でDMA転送を終了するか、という設定です。

4つ目の設定は、転送するタイミングを決めるモードの設定です。
連続転送モードの場合、1つの転送が完了したら隙間なく次々とデータの転送を実施するモードです。
転送要求信号モードの場合、何かしらの要求信号(トリガ)を受けたタイミングで次の転送を実施するモードです。
(モード名は私の命名なので、いろいろな表現があると思います)
どういった場合に使い分けるのかは、このあと具体例で見ていきます。

5つ目は、要求信号モードを選択した場合に、どのトリガが発生した場合に転送を実施するかを設定する必要があります。

基本的な機能は以上となります。

マイコンによっては、転送モードが他にもあったり、1回に何byte送るかという設定があったりなど、他にも機能がある場合がありますが、ここまでの基本機能を押さえておけば問題なく理解ができると思います。

DMA転送を活用すべき場面

それでは、具体例を用いてDMA転送を活用すべき場面とそのときの設定・動作を見ていきましょう。

大量データの転送

まずは最も単純な例として、大量データを転送する例を見ていきましょう。

設定を

  • 転送元/転送先ともにインクリメントあり
  • 送信データは100byte
  • 連続転送モード

としたときの動作が以下の図のようになります。

CPUからDMA転送開始の命令(ソフトウェアトリガ)を送ると、転送元アドレス(SA:Source Address)から転送先アドレス(DA:Destination Address)へのデータ転送が自動的に始まります。
インクリメントありとしているので、2byte目はSA+1からDA+1への転送となり、最終的にはSA+99からDA+99への転送となります。
すべての割り込みが完了すると、DMA転送完了割り込みがCPUに通知されます。

この例の転送をするときに、通常のCPUによる転送ではなくDMA転送を使用すると判断するポイントは、

  • 大量データであること
  • 同じアドレスへの転送を頻繁に行うこと

です。

少量だったりDMA転送の設定変更が多い場合、DMA転送の設定変更のCPUリソース分が無駄になり、メリットが得られない場合があるからです。
また、DMA転送中に別の処理を行う場合、ディスパッチも発生するので、その分のディレイを考える必要もあります。
(DMA転送中にポーリングで待たせる方法ではDMA転送を使用するメリットがあまり得られません)

memcpyを使っていればそこまで転送が遅いわけではないはずなので、データサイズが大きくなければ実装の簡単さや不具合の発生しにくさを考えればmemcpyを使用すればよいと思います。

ですので、使用する場合は、memcpyの処理時間とDMA転送によって浮くCPUリソースを見積もって判断するようにしてください。

シリアル通信の自動送受信

次はシリアル通信の自動送受信に使用する例です。
組み込みで使用する場合は、こちらの例で使用するパターンの方が多いでしょう。

動作としては、受信割り込みや送信割り込みが入ったことをトリガとして、自動で受信データを受け取ったり次の送信データを設定したりできるというものになります。

受信の場合の動作例

具体例として、UARTの送受信のときの使用例を見ましょう。
まずはUARTの受信の場合です。

受信の場合、設定は以下の通りになります。

  • 転送元アドレスは受信データバッファアドレスで、インクリメントなし
  • 転送先アドレスは転送先のRAMアドレスで、インクリメントあり
  • サイズは受信サイズ(例として100byte)
  • 転送モードは転送要求信号モード
  • トリガは受信割り込み

この条件で図示すると以下のようになります。

受信割り込みが発生するたびに、受信レジスタに入っているデータをRAMに転送していく動作となります。

UARTの受信の場合、受信が開始するタイミングや受信サイズがわからない場合も多いので、少し活用が難しく、そこまで使用される頻度は多くありません。

送信の場合の動作例

次に送信の例を見ていきましょう。
送信の場合の設定は以下の通りとなります。

  • 転送元アドレスは転送元のRAMアドレスで、インクリメントあり
  • 転送先アドレスは送信バッファアドレスで、インクリメントなし
  • サイズは送信サイズ
  • 転送モードは転送要求信号モード
  • トリガは送信データレジスタエンプティ割り込み

この設定を図示すると以下のようになります。

送信レジスタが空になるたびにデータを転送し、連続で送信を行うことができます。
ただし、1byte目のみまだ送信しておらず割り込みが発生しないので、最初はソフトウェアトリガで転送を開始する必要があります。

送信時にDMA転送を使用する場合は2点注意点があります。

1点目は、トリガとして「送信データレジスタエンプティ割り込み」を使用することです。

送信時の割り込みには、送信完了割り込みと送信データレジスタエンプティ割り込みの2種類あることが多いです。
送信完了割り込みは、実際にデータの送信が完了した時点で割り込みが発生し、送信データレジスタエンプティ割り込みは、データの送信が開始された時点(送信データレジスタのデータが空になった時点)で割り込みが発生します。
前者の割り込みを使用すると、送信が完了してから送信データレジスタへのデータ転送を行うことになるので、その時間分送信のタイミングが遅れることになります。
ですので、必ず送信データレジスタエンプティ割り込みを使用するようにしてください。

2点目は、DMA転送割り込みが発生した時点では送信が完了していない点です。

DMA転送割り込みが発生するタイミングは、最後のデータの送信を開始した時点となりますので、まだ送信自体は完了していません。
送信が完了したことを前提とした処理をしていると問題が発生する可能性があるので注意してください。

シリアル通信でDMA転送を使用するメリット

シリアル通信の自動送受信のためにDMA転送をしようするメリットは、以下の2つがあります。

  • 割り込みによるディスパッチが減らせる
  • 送信時にディレイなく送信することができる

100byteの受信を1byteずつ割り込みで処理をした場合、1回の割り込み当たり割り込みに入るときと出るときの2回ディスパッチが発生するので、200回ものディスパッチが発生することになります。

OS管理外割り込みを使用している場合は切り替え処理にそこまで時間がかかりませんが、OS管理割り込みの場合はそこそこの時間がかかります。
(OSやクロックによって変わるので、気になる方は測定してみてください)

そこそこの時間、といっても大きな時間ではないですが、それが200回にもなると馬鹿にできない時間になることもあります。
DMA転送を使用すれば、そのディスパッチ処理を発生させずに送受信の処理をすることができるので、大きなメリットとなります。

このメリットも、大きなデータの送受信の場合によく効いてきますので、使用するかどうかはデータの大きさで判断するようにしてください。

「送信時にディレイなく送信することができる」については、送信データレジスタエンプティ割り込みを使用すればそこまで気にしなくても問題が発生しない場合が多いですが、確認は必要です。

例えば、ボーレートが115200bpsで1byteが11bitの場合、エンプティ割り込みが発生してから次のデータ送信までの時間が、

11bit/115200bps ≒ 95.5us

なので、割り込みが発生してから95.5us以内に次のデータをセットしないと送信が遅れることになります。

通常は問題なくても、他の割り込みとタイミングが被った時に動作できなくて遅れるということも発生します。
(送信データが遅れると、相手に正しくデータを受け取ってもらえない可能性があります。)

ですが、DMA転送を使用すれば、エンプティ割り込みが発生したときに自動で次の送信データをセットしてくれるので、問題が発生しません。

まとめ

DMA転送の動作・設定と具体例を見てきました。

今回DMA転送を活用できる例としてあげたのは以下の2つです。

  • 大量データの転送
  • シリアル通信の自動送受信

このうち、特にシリアル通信の自動送信において大きなメリットがあることを見てきました。

また、見てきた通りDMA転送のメリットが大きくなるのは大きなデータを扱うときなので、扱うデータのサイズによって活用すべきかどうかを検討していただけると良いでしょう。

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA