メモリに非常に制約のある組み込みシステムで大規模なデータ転送をどのように処理しますか?

StackOverflow https://stackoverflow.com/questions/359745

質問

大きなファイルを PC シリアル ポート (115200 ボー) からダウンロードし、SPI (~2 MHz) 経由でシリアル フラッシュ メモリに書き込む必要があるマイクロコントローラーがあります。フラッシュ書き込みは 256 バイト ブロック内で行われ、その前に書き込みコマンドとページ アドレスが続く必要があります。システムで利用可能な合計 RAM は 1 kB、スタック サイズは 80 バイトです。

これは現在、UART から 256 バイトのバッファを埋めてから、フラッシュがビジー書き込みで書き込まれている間に、RX バッファレディ信号の割り込みによって埋められている別の 256 バイトのバッファにピンポンすることで動作しています。バッファのスワップは、操作が完了するまで繰り返されます。

個別の循環バッファ上で動作する SPI ポートと UART ポートの両方に TX/RX 割り込みハンドラをセットアップしたいと考えています。したがって、新しいバイトをポーリングして操作が完了するのを待つ代わりに、単純に TX バッファを埋めて割り込みを有効にするか、バッファに受信データがないかチェックするだけで済みます。これにより、ペリフェラルを待機する代わりに、実際の作業に多くのクロック サイクルが与えられます。

128 バイトの循環バッファを使用して IRQ を実装した後、UART RX バッファでデータをポーリングし、すぐにそれを SPI TX バッファに配置してファイル転送を実行します。このアプローチで発生している問題は、バッファ用の十分な RAM がなく、フラッシュ送信バッファにデータを送信するよりも早く PC 受信バッファがいっぱいになってしまうことです。明らかに、送信速度は問題ではありません (入力 115.2 kHz、出力 2 MHz) が、256 バイトのページが送信されるたびに書き込みサイクルの待機が発生します。


頻繁な SPI 割り込みが一部の UART 割り込みをブロックし、バイトの欠落を引き起こしていたようです。私が選択した解決策は、UART 受信割り込みにリング バッファを使用し、データを 256 バイトのページ バッファに送り、バイト転送と書き込み完了をポーリングすることでシリアル フラッシュに送信することでした。128 リング バッファは、SPI 書き込み中のオーバーフローを防ぐのに十分な大きさです。

役に立ちましたか?

解決

PC上でスキャッターギャザーみたいなことをやってみます。次のような構造体のリンク リストを作成します。

typedef struct data_buffer {
    char flags;
    char[128] data;
}

フラグ内のビットの 1 つは「ReadyToFlash」を意味し、もう 1 つは「Flashing」を意味します。リンク リスト内のバッファの数を調整して、フラッシュが書き込み時に UART をキャッチしないように、またはその逆を防ぐことができる必要があります。

フラッシュが「ReadyToFlash」ではないバッファ ブロックに到達すると停止するため、UART IRQ でフラッシュを再起動する必要があります。UART が「ReadyToFlash」または「Flashing」のブロックに到達した場合、そのブロックは急速に埋まっており、別のバッファが必要になる可能性があります。動的メモリがある場合は、実行時にこの調整を行って、オンザフライでリストにバッファを追加できます。そうでない場合は、いくつかの実証的テストを行う必要があります。

他のヒント

UART とアプリケーションの PC 側は RS-232 ハンドシェイク (フロー制御) をサポートしていますか?その場合、受信バッファがいっぱいに近づいたときに、ISR に CTS ラインをドロップさせます。PC 側がハードウェア フロー制御を尊重するように設定されている場合は、この状態を検出したときに送信を停止する必要があります。受信バッファを空にした(またはほぼ空にした)後、CTS を再度アサートすると、PC は再び送信を開始します。

これにより、組み込みデバイス上のソフトウェアがかなり複雑になることに注意してください。それがトレードオフになるかどうかは、あなたとあなたのマネージャー、チームが分析する必要があります。

これはまさにフロー制御が作成された目的です。セットアップが非常に面倒であることは承知していますが、シリアル回線でフロー制御を有効にすると、問題は過去のものになるでしょう。

バイナリ ファイルを転送していると仮定しているため、XON-XOFF は最良の解決策ではなく、ハードウェア フロー制御が残されています。

もう 1 つのオプションは、XModem などのフロー制御が組み込まれたプロトコルを使用することです。フラッシュが 128 バイトのページに書かれている同様の埋め込みプロジェクトがあります。XModem が 128 バイトのチャンクでデータを送信し、ACK を待ってから次のデータを送信するというのは、何と偶然でしょう。

ここで何が欠けているのかわかりませんが、PC から送信されるデータの平均速度がフラッシュに書き込むことができる平均速度よりも高いという事実がある場合は、大量の RAM が必要になるかのどちらかです。そうでない場合は、フロー制御が必要になります。

しかし、ブロック バッファーがあったときは機能していたが、バイト バッファーがある今では機能しなくなった、ということでしょうか?

UART RX 割り込みによって埋められるブロック バッファーをそのまま使用し、各バッファーがいっぱいになったら、SPI/フラッシュ コードに渡して、SPI 割り込みを使用してそのバッファーを空にすることはできますか?これにより、各バイトをコピーする手間が省け、循環バッファ ロジックをバイトごとに 2 回実行する必要がなくなり、ブロックごとに実行するだけで済みます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top