5

STM32F3 mc (STM32F3-Discovery) の埋め込みコードを書いています。データを UART に出力する必要があり、これには DMA を使用しています。これにより、バイト送信の完了を待つのではなく、センサーの読み取りとデータ処理に集中できるからです。ただし、問題は、次のように組み合わせる必要があることです。

  1. フォーマットされた出力 (つまり、printf の一部)
  2. 連続印刷の数 (前の印刷が終了する前に発生する)

だから私は循環バッファについて考えています。しかし、バッファの最後を尊重してバッファの先頭への書き込みを続けるように sprintf を作成する方法を知っているとは思いません。もちろん、別の一時バッファを作成してそこに出力し、バイトごとにコピーすることもできますが、私にはエレガントに見えません。

4

2 に答える 2

2

sprintf解決策の 1 つは、リング バッファで動作する独自の実装を行うことです。残念ながら、これはより基本的な問題に関しては役に立ちません: リングバッファがいっぱいで を呼び出したらどうしますsprintfか?

メモリの状況に余裕がある場合は、この問題の別の解決策をお勧めします。

このアイデアは、バッファの 2 つのリンクされたリストに基づいています (1 つのリストはフリー バッファ用、もう 1 つのリストは送信キューとして)。バッファーは同じサイズであるため、最悪の場合の長さの文字列を格納できます。バッファは単純なヒープを構築します。割り当て/割り当て解除は、空きリストまたは転送リストから要素をデキュー/エンキューするだけです。

同じサイズのバッファーを使用すると、メモリを動的に割り当てる際に、"チェッカーボード" などの外側の断片化の影響を受けないことが保証されます。このジョブ用に独自のヒープを構築すると、送信タスクに使用できる合計バッファー サイズを完全に制御することもできます。

これが次のように実行されていると想像できます。

  1. フリー リストからバッファを割り当てて、データをレンダリングします。
  2. レンダリング関数 (sprintf など) を使用して、バッファー内のデータをレンダリングします。
  3. 送信するデータを送信キューに追加します (必要に応じて送信をトリガーします)。

DMA 転送の場合、転送終了 IRQ を処理します。そこで、転送されたバッファを「空きリスト」に移動し、キュー内の次のバッファの転送をセットアップします。

このソリューションはメモリ効率が最も高いわけではありませんが、メモリへの書き込みは1回だけで、割り当て/割り当て解除はどこかにポインタをフェッチ/保存するだけなので、ランタイム効率は良好です。もちろん、割り当て/割り当て解除のために、アプリケーションと IRQ の間で競合状態が発生しないようにする必要があります。

おそらく、このアイデアは、要件を解決するためのインスピレーションを与えるでしょう。

于 2013-02-17T22:35:27.790 に答える
1

これを概算する 1 つの方法は、printf バッファーをリングバッファーの 2 倍のサイズとして割り当て、前半をリングバッファーとして使用することです。オーバーフローを検出し、後半のオーバーフローを先頭(リング部分)にコピーします。このようなもの:

void xprintf(const char *format, ...)
{
  int written;
  va_list args;
  va_start(args, format);
  written = vsnprintf(buffer, HALF_BUFFER_SIZE, format, args);
  va_end(args);
  if (buffer + written > bufferStart + HALF_BUFFER_SIZE)
  { // time to wrap
    int overflow = (buffer + written) - (bufferStart + HALF_BUFFER_SIZE); 
    memmove(bufferStart, bufferStart + HALF_BUFFER_SIZE, overflow;
    buffer = bufferStart + overflow;
  }
}
于 2013-02-19T02:01:18.713 に答える