STM32上のUARTでの割り込みを優先して、常にDMAを使用しないのはなぜですか?[閉まっている]


9

先月、割り込みを使用してUART(MIDI用)をSTM(STM32F103C8T6)と連携させるのに多くの時間を費やしましたが、あまり成功しませんでした。

ただし、DMAを使用した今晩は非常に高速に動作しました。

私が読む限りDMAはより高速でCPUを解放するので、なぜ割り込みを優先して常にDMAを使用しないのですか?特にSTM32ではかなりの問題があるようです。

STM32CubeMx / HALを使用しています。


2
何故なの?それは意見の問題、どちらの可能性のある技術的理由についての推測を求めている人、または同じように広すぎるため、ここに属する問題ではありません。ランダムな例を挙げれば、DMAは、特に複数の文字の収集を許可しない限り実際のメリットを得られないため、データを要求する際の待機時間が長くなります。多くの場合、それは問題ないかもしれませんが、そうでない場合もあります。
Chris Stratton

6
割り込みが機能するまでに数週間かかる場合は、タスクに間違った方法でアプローチしたことが原因です。DMAの動作を開始するには時間がかかる可能性があります。実際にはより複雑なタスクであるため、単純なタスクよりも複雑なタスクを簡単に実行できることは、メカニズム自体ではなく、それぞれのガイダンスに使用したリソースに起因すると考えられます。
Chris Stratton

5
dmaがcpuを解放すると仮定しないでください。はい、cpuは続行します。dmaエンジンのバスを保持するためにプロセッサがフリーズしない場合もあります。armの実装でこれを行うのは簡単です。したがって、すべてのarmがこの方法であり、すべてのx86がその方法であるとは言えません。それはそれほど単純ではなく、常にシステム設計を調べて、おそらく少しハッキングする必要があります。あなたが持っているチップは腕のコアをかなり解放するかもしれません、これはdmaへのコメントです。あなたの質問に関しては、あなたが追いつくことができなかった意味がありません、そしてあなたが単にポーリングできない場合、dma + intがおそらく完全な解決策です。
old_timer 2017年

5
STM32Fシリアルポートでは、割り込みは非常に簡単です。コードを使って質問を投稿して、私たちの一部があなたが間違っているところを見つけようとしないのはなぜですか?根本的な問題が何であるかを理解せずに機能するまで、コードをハッキングすることは決して良い考えではありません。
2017年

7
私の(そうではない)控えめな意見では、これはひどく膨れ上がったCubeを使用することの欠点の1つです。ソフトウェアを最初から作成します。UARTがどのように機能するかを正確に学習します(必要なため)。ペリフェラルをはるかによく理解し、長期的に見れば、時間を大幅に節約できます。
DiBosco 2017年

回答:


24

DMAはCPUを解放するため、同じコアで実行されている他の割り込み駆動型アプリケーションのレイテンシを削減する可能性がありますが、それに関連するコストがあります。

  • 唯一の存在であるDMAチャネルの限られた量は、これらのチャネルが異なる周辺機器とやり取りする方法には制限があります。同じチャネル上の別のペリフェラルは、DMAの使用により適している場合があります。

    たとえば、5msごとに大量のI2C転送がある場合、これは、UART2に時々到着するデバッグコマンドよりもDMAのより良い候補のようです。

  • DMAの設定と維持はそれ自体コストがかかります。(通常、DMAの設定は、通常の文字単位の割り込み駆動型転送の設定よりも複雑であると考えられます。これは、メモリ管理、関連する周辺機器、割り込み自体を使用するDMA、およびDMAの外側で最初の数文字を解析する必要があるためです。とにかく、以下を参照してください。)

  • DMAは、クロックを供給する必要があるコアのドメインであるため、追加の電力を使用する場合があります。一方、コアがサポートしている場合は、DMA転送の進行中にCPUを一時停止できます。

  • DMAを使用するには、メモリバッファーが必要です(周辺機器間DMAを実行している場合を除く)。そのため、それに関連するメモリコストが発生します。

    (メモリコスト、文字ごとの割り込みを使用する場合にも存在する可能性がありますが、メッセージが割り込み内ですぐに解釈される場合は、はるかに小さくなるか、まったくなくなる場合があります。)

  • 転送が完了または半分完了したときにのみCPUに通知されるため、DMAはレイテンシを生成します(他の回答を参照)。

  • リングバッファーとの間でデータをストリーミングする場合を除いて、受信/送信するデータの量を事前に知っおく必要があります。

    • これは、文字ごとの割り込みを使用してメッセージの最初の文字を処理する必要があることを意味する場合があります。たとえば、XBeeとのインターフェースをとるときは、最初にパケットタイプとサイズを読み取ってから、割り当てられたバッファーへのDMA転送をトリガーします。

    • 他のプロトコルでは、メッセージの終わりの区切り文字のみを使用する場合、これはまったく不可能である可能性があります。たとえば、'\n'区切り文字として使用するテキストベースのプロトコル。(DMAペリフェラルが文字のマッチングをサポートしていない場合)。

ご覧のとおり、ここでは考慮すべき多くのトレードオフがあります。一部はハードウェアの制限(チャネル数、他の周辺機器との競合、文字の一致)に関連し、一部は使用するプロトコル(区切り文字、既知の長さ、メモリバッファー)に基づいています。

事例証拠を追加するために、私は非常に異なるプロトコルで多くの異なる周辺機器を使用する趣味のプロジェクトでこれらのトレードオフのすべてに直面しました。主に「転送するデータの量と転送する頻度」という質問に基づいて、いくつかのトレードオフがありました。これは基本的に、CPUに対する単純な割り込み駆動型転送の影響の大まかな見積もりを提供します。このため、同じDMAチャネルを使用するUART転送を数秒ごとに行うよりも、5msごとに前述のI2C転送を優先しました。別のUART転送がより頻繁に行われ、その一方でより多くのデータを使用すると、まれにしか発生しない別のI2C転送よりも優先されます。それはすべてトレードオフです。

もちろん、DMAを使用することにも利点がありますが、それはあなたが要求したものではありません。


詳しい回答ありがとうございます。MIDIが最も重要な部分になるので、DMAが適していると思います(ただし、速度は低速ですが、31250ボー)。十分なDMAチャネルがあるので、4つのUSARTを使用するときに、別のSTM32を使用します。5V USB電力が供給されるため、CPUを一時停止する必要はありません。また、メッセージ間で処理を行う必要があります(メインループでメッセージを処理するため)。256バイトの読み取りと256バイトの送信バッファーがあります。必要に応じて後で増やすことができます。STM32f103c8t6には20 KBのRAMがあり、最終的に使用するSTMには192 KBがあります。
ミシェルケイツァー2017年

そして、あなたは私に改善する方法を非常に良いアイデアを与えてくれます。これまでは、常に1バイトを読み取り、完全な(MIDI)メッセージが受信されたときに継続的にチェックしていました。しかし、私は最初のバイトを読み取ることができ、それに応じてほとんどの場合サイズがわかっており、残りを要求できます。これにより、別の小さなバッファが必要になりましたが、それでも問題ありません。
ミシェルケイツァー2017年

DMAを使用した単一バイトの読み取りは非常に非効率的です。レイテンシを短縮して効率を上げるには、サイズがわかるまで文字ごとの割り込みを使用してから、DMAに切り替えると効果的です。
JonasSchäfer2017年

さて、割り込み(DMAなし)の使用には多くの問題がありました。1バイトのDMA受信を使用すると思います。その後、予想されるバイト数がわかって、DMAリクエストを実行してさらに多くのデータを取得します。
ミシェルケイツァー2017年

6
それはおそらく間違いだ-あなたは、あなたの簡単な割り込みコードを修正する必要なしに DMA。
クリスストラットン

10

通常、DMAを使用すると、すべての文字で割り込みが発生するのではなく、文字の「バッファーフル」が受信(または送信)された後でのみ、割り込みが発生します。これにより、これらの文字の処理のレイテンシが増加します。最初の文字は、バッファ内の最後の文字が受信されるまで処理されません。

このレイテンシは、特にMIDIなどのレイテンシの影響を受けやすいアプリケーションでは、数ミリ秒かかるため、ライブパフォーマンスで深刻な演奏性の問題が発生する可能性があるため、好ましくない場合があります。


私がしていることは、一度に1バイト(つまり、1バイトの「DMA」バッファー)を受信し、その1バイトのDMAコールバックごとに、手動で処理するリングバッファーに格納することです。メインループでは、完全なMIDIメッセージをチェックして処理するつもりです。
ミシェルケイツァー2017年

3
DMAは通常、複数のバイトを取得するために使用され、それらがすべて受信されたときにのみ割り込みます。DMAを使用していない場合、1バイトだけの割り込みは正常ですので、DMAを使用することでさらに複雑になる点は何でしょうか。
スティーブメルニコフ2017年

5
@MichelKeijzers次に行うことは、純粋な割り込み駆動型の実装で行う場合とほとんど同じです。したがって、この場合はDMAを使用してもメリットはなく、元の問題はおそらくDMAでは解決されず、(ISR、セットアップ)コードの書き換えによって解決されます。
JimmyB 2017年

@JimmyB ...感謝...ただし、以下のジョナスの回答により、メッセージが長いため、その多くのバイトを読み取るように改善します。(ほとんどの場合)最初のバイトを受信した後でこれがわかります。割り込みよりもDMAを使用する方がメリットがあります。
ミシェルケイツァー2017年

8

DMAは割り込みの代わりにはなりません-それらは通常一緒に使用されます!たとえば、DMAを使用してUART経由でデータを送信している場合でも、送信が完了したことを通知する割り込みが必要です。


確かに、おそらくSTM32だけで(DMA以外の)割り込みメカニズムは、直接DMAに比べて少し扱いに​​くいです。
ミシェルケイツァー2017年

2
@duskwuff本当にそうではありません。あなたは、DMAが完了したときに見にポーリングすることができ、あなたはよくありますしたい主な理由の1ので、利用するためのプログラムがそれを受け取った上で行動することが可能な状態になるまでDMAシリアルポートを気にする必要はないことですデータ。または、送信DMAの場合は、単にポーリングして、送信バッファーにさらに追加できるかどうかを確認できます。
Chris Stratton

1
@MichelKeijzers:特定のチップをIDKしますが、通常、DMAに代わるものは文字通りの割り込みではなく、プログラムされたIOです(CPU命令を使用して、I / Oレジスタとの間でデータを読み書きします)。割り込みハンドラーでは、通常、1つの読み取りを行い、最初の読み取り中に文字が入った場合に備えて、おそらく別の割り込みをトリガーしない場合は特に別の読み取りを行います。または、そのようなバッファーがある場合は、内部バッファーが空になるまで読み取ります。明らかに、PIOにはさらに多くの割り込みが必要であり、それらを異なる方法で設定します。
Peter Cordes 2017年

@ChrisStratton良い点...これまでのところ、送信が可能かどうかはチェックしていません。何かを送信するだけで、問題がないかどうかはチェックしません。もしそうでなければ、後でもう一度やり直します。
ミシェルケイツァー2017年

@PeterCordes STM32にはDMAのための十分な割り込みがあるようで、毎回1バイトしか読み取っていません。最も単純なSTM32(F103c8t6)でも十分なDMAポート/割り込みが利用できます。
ミシェルケイツァー2017年

5

DMAを使用すると、UARTペリフェラルの使用に関する他のすべての考慮事項を超える興味深い質問と課題が生じます。いくつか例を挙げましょう。あなたのuCが他のデバイスと一緒にRS485(または何でも)バスに座っていると仮定します。バス上には多くのメッセージがあり、いくつかはあなたのuCを対象としていますが、そうでないものもあります。さらに、これらのバスネイバーはすべて異なるデータプロトコルを話すと想定します。これは、メッセージ長が異なることを意味します。

DMAを使用するときにのみ出てくるいくつかの質問は次のとおりです。

  • いつ割り込みますか?
    • DMAは、事前に設定された量のデータを転送したときにのみ割り込みを行います。
    • DMA割り込みをトリガーするのに十分なデータを受信しない場合はどうしますか?
  • DMAの割り込み時に部分的なメッセージしか受信しない場合はどうなりますか?
  • RXバッファーはどのように見えますか?それらは直線ですか、それとも円形ですか?
    • DMAは、アドレス境界に従うだけという意味で、手に負えない循環バッファの参加者になる可能性がありますが、循環バッファシステム内の他のポインタを超えて問題が発生することはありません。

とにかく、ただ考えるための食べ物。


それらの考慮をありがとう。私のメッセージ(MIDI)は実際には長さが異なり、次に何を取得するかわからないため、現在は常に1バイトを受信して​​リングバッファーに格納しています。メインループで、メッセージを処理するための完全なメッセージをチェックします(完了した場合は、リングバッファーから削除します)。そのため、常に十分なデータを受信します(バイトを逃すことがない限り、チェックする必要があります)。RXバッファーは1バイトしかありませんが、リング/循環バッファーにコピーします。いっぱいかどうかを確認しませんでした(追加する必要があります)。
ミシェルケイツァー2017年

おい、心配しない。あなたのアプリケーションはきちんとプログラムされるでしょう。他の人が述べたように、DMAは素晴らしいですが、無料ではありません。それを使用せずに逃げることができる場合、存在しないシステムへの追加の考慮事項が導入されます。
pgvoorhees 2017年

まあ、私はまだ初心者だと思います。
ミシェルケイツァー2017年

3

(私が思い出すように)受信側では、DMAは文字の一致またはターミナルカウントで終了します。一部のプロトコルと多くの対話型アプリケーションはこのモデルに簡単に適合せず、実際にキャラクターごとに処理する必要があります。また、通信リンクが信頼できない場合、DMAテクニックは不安定になる可能性があり、ストリーム内の1つの文字を失うと、DMAステートマシンを簡単に混乱させる可能性があります。


私は実際にバイト単位で受信し、それを後で処理するためにリングバッファーに手動でコピーします。
ミシェルケイツァー2017年

1

いくつかのプロジェクトでSTM32CubeMx / HALを使用していて、それが生成するUART処理ソフトウェアには受信側に明確な欠点があることがわかりました。

送信時には、通常、データブロックまたはテキスト行を送信します。この場合、データ転送の長さを前もって知っているので、DMAを使用することは明らかな解決策です。転送が完了すると割り込みが発生し、UART TX完了コールバック関数を使用して、送信が完了したことをメインコードに示し、別のデータブロックを送信できます。

データ受信に関しては、STが提供する機能はすべて、送信デバイスが送信を開始する前に送信する文字数を知っていることを前提としています。通常、これは不明です。割り込み機能は、受信したデータをバッファに格納し、事前定義された数の文字を受信したときに使用可能なデータがあることのみを示します。DMAまたは割り込み機能を使用して、順次単一文字転送をセットアップすることによりデータを受信しようとすると、これらのそれぞれのセットアップ時間は、最も遅いデータレート(ボーレート)以外で文字を失うことを意味します。データが失われ始めると、プロセッサーのクロック速度に依存します)、プロセッサーに過度の負荷がかかり、他の処理のための命令サイクルがなくなります

これを回避するために、小さなローカルサーキュラーバッファーにデータを格納し、メインコード(RTOSカウントセマフォ)によって読み取られるカウントを設定する独自の割り込みハンドラー関数を記述して、受信データの準備ができていることを示します。その後、メインコードはこのバッファからデータを自由に収集できます。データが収集される前にローカルバッファがオーバーフローしない限り、データの収集に遅延があっても問題ありません。


私はまったく同じです(私は思います)。一度に1バイトを読み取り、それを循環バッファーに保管します。メインループで完全なメッセージをチェックするつもりです。少し強化することもできます。
ミシェルケイツァー2017年

DMAを毎回セットアップすると、プロセッサーに過負荷がかかる/ 31,250ボーで文字が欠落するという問題に遭遇する可能性があると思いますか?
ミシェルケイツァー2017年

1
一度に複数の文字を転送するようにDMAを設定している限り、これは問題にはなりません。115200以上を実行する4つのUARTとDMAを使用して問題なくI2Cを使用しています。UART送信はすべて〜20バイト以上です。問題は、UARTでの受信にDMAを使用していた(80MHz、9600ボーのL4プロセッサ)。
uɐɪ

現在、一度に1バイトに設定していますが、それを改善することができます(最初のバイトを実行してから、さらに必要なバイト数を確認することにより)。
ミシェルケイツァー2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.