SDカードの動作が遅い-誰が責任を負い、何をすべきか?

長い間、私はHabrに関する記事を書くことを考えていましたが、どういうわけかそれは決定されませんでした。 コミュニティにとって関心のない考えがあるように見えますが、それは、この「見かけ」が過度の自尊心から生じるという仮定を止めます。 それにもかかわらず、私はしようとします。 私は電子工学、特にマイクロコントローラーのプログラミングにかなり長い間従事しているので(おそらく、Habrの読者のほとんどよりも長いかもしれませんが、Habrの読者のほとんどよりも長いと思います)、この間に多くの興味深い事例が蓄積されています。 私はそれらのうちの1つについてのストーリーをコミュニティ裁判所に提示します。



そのため、ある開発では、ネットワークを介して処理センターに送信するために、大量の情報を保存する必要がありました。 結果として得られたデバイスは大量生産を目的としていたため、比較的安価なコンポーネント、特にシステムの中心要素としてマイクロコントローラーを使用するバリアントが選択されました。 その瞬間(2012年半ば)にボード上にイーサネットPHYを備えたマイクロコントローラーの提供に違いはなかったので(そして今では状況はそれほど良くありません)、特にデバッグボードをすでに持っているので、私はStellarisファミリー、特にLM3S8962からTI会社を選びましたありました。 当時のMKは比較的新しく、TIによって積極的に推進されていました(2013年の終わりにシリーズ全体をNRNDカテゴリに突然移行しました)。この問題を解決するのに十分なパラメーターがあります。 情報を保存するために、主に可用性と安さのために、またデバッグボード上に連絡先デバイスがあり、デバッグカードに付属するCDに多数の例があったため、SDカードのオプションが選択されました。 SDカード。 カードへのインターフェイスは最も簡単な方法で実装されました-SPI、提案された例はすぐに機能し、デバイスからPCカードリーダーにカードを転送するだけでインターフェイスを書き込む前にデータを処理することが決定されたため、制御オブジェクトとの相互作用アルゴリズムの初期デバッグは問題を引き起こしませんでした少なくともプロジェクトのこの部分では。 誰もが理解しているように、後で問題が発生しました...





アルゴリズムがデバッグされ、デバイス全体が機能するようになると、テスト実行が開始されました。 そして、SDカードは制御オブジェクトが配信するペースで情報を記録することができず、速度差は数倍であり、ストレージユニットのサイズ(2.7メガバイト)を考慮して、手頃な価格で中間バッファを作成することは不可能であることがわかります。 特定の数字に目を向けると、1.6秒以内に2.7メガバイトのサイズのファイルをSDカードに記録する必要がありましたが、実際にはデータは30秒で記録され、カードはクラス10で購入されました。つまり、記録速度は10 MB / sでした。 スピードをめぐる戦いはいくつかの段階を経ており、対戦相手はマイクロコントローラー、標準ライブラリ(ちなみにTIの専有)、または実際にはSDカードでした。



最初の段階-記録のタイミングを調べて、情報のさまざまなセクションの記録にはさまざまな時間がかかり、同じ情報ブロックの記録時間は(時々)大きく異なることをすぐに見つけます。 さまざまなサイズの記録ブロックで実験することで、単純なパターンを確立します。記録する情報のブロックが多いほど、そのサイズに関連する記録時間が短くなります。 ライブラリモジュールはFATをサポートし、セクターごとに情報を書き込むため、それらをやり直す意味がありません。32KBのセクターサイズにカードを再フォーマットし、14秒-1 SDポイントの記録時間を取得します。



第2段階-SPIインターフェースの動作を確認し、12.5 MHzの周波数で動作することを確認しますが、説明では送信周波数を25 MHz(50 MHzのプロセッサクロック速度の半分)に設定できます。 ライブラリからSPIモジュールの周波数を設定するためのルーチンは、可能な最大周波数を12.5 MHzに制限しており、マイクロコントローラインターフェイスモジュールのドキュメントにはそのような制限はありません。
i = ROM_SysCtlClockGet() / 2; if(i > 12500000) { i = 12500000; }
      
      





コードを変更すると、記録時間が2倍に短縮され、7秒-1 TIポイントになります。



3番目の段階-SDカードを使用して交換モジュールを調べ、低レベルの手順で非常に非生産的な時間の無駄を見つけます。つまり、マイクロコントローラーのSPIモジュールには8バイトのFIFOバッファーが組み込まれているため、作業を高速化できます。 出力モジュールは、次のバイトを転送する前に「転送バッファーがいっぱいではありません」フラグをチェックして、次のバイトを転送する可能性を待ちます。 しかし、バイト転送の後、バイト受信モジュールが呼び出され(実際、SPIインターフェースで送信する場合、受信も同時に実行されます)、受信バッファーからこれらの不要な受信バイトを選択する必要があります。 そして、このプロシージャは「受信バッファが空ではありません」というフラグをポーリングします。つまり、バッファの最後のバイトのシリアル化が完了するのを待ちます。 つまり、現在のバイトが完全に送信されるまで待機してから、次のバイトを準備します。

 void xmit_spi(BYTE dat) { uint32_t ui32RcvDat; SSIDataPut(SDC_SSI_BASE, dat); /* Write */ SSIDataGet(SDC_SSI_BASE, &ui32RcvDat); /* flush data */ }
      
      





検出されたエラーを修正します(他に何と呼べますか?)そして、ファイル転送時間を3秒-1 TIポイントにします。

そして、タスクの機能を考慮に入れない最適化の結果として起こったことは次のとおりです。

 static void xmit_spi_my (BYTE const *dst, int length) { int i, *p, *d; d=(int*)(SDC_SSI_BASE+SSI_O_DR); p=(int*)(SDC_SSI_BASE+SSI_O_SR); do { while (!(*p & SSI_SR_TNF)) {} *d=*dst++; } while (--length); while (*p & SSI_SR_RNE) i=*d; }
      
      





第4段階-上位モジュールを調査し、インターフェイスへのデータ転送はメモリからのみ提供されるため、二重のジョブを実行する必要があることを確認します-最初に制御オブジェクトからデータストリームを読み取り、それをマイクロコントローラのRAMに送信します(ところで、これは32キロバイトですバッファ)、メモリからSPIレジスタへ。 レジスタ間で直接データを転送するための独自のモジュールを作成していますが、記録時間は1.6秒になります。 同時に、32キロバイトが転送されることをファイルシステムが認識するように、標準呼び出し内でモジュールへの呼び出しをマスクしています-1 TIポイント。



5番目のステージ。 設定された目標はすでに達成されていますが、最適化プロセスは慣性によって継続されます。 インターフェイスの信号を再度調べてみると、実際には送信されるのは連続したクロックパルスシーケンスではなく、8データビットと2クロックサイクルの休止であることがわかります。 まあ、まあ、9番目のビットは同期信号を送信するために必要です(クロック信号と混同しないでください)。私はまったく必要ありませんが、なぜ10番目ですか? さまざまなSPIモードを使用した実験の結果、ギャップのない実際の8ビットの送信信号と、それに対応する1.3秒の記録時間(1ポイントのステラリス)が得られました。



第六段階。 すべてがうまくいくように見えますが、完全に予想外に別の1つの問題が発生します-複数のファイルをストリーミング記録する場合、最初の3つは必要な間隔に収まり、わずかなマージンがあっても、4番目のファイルは記録時間をより長く示します-最大1.8-2.0秒、したがって、違反しますシーケンス。 フラッシュメモリレコードのページを通過することを想定して、明白な解決策を試しています。これらの場所を処理から除外します。 これで、以前に適切に書き込まれたファイルが長時間記録され始めます。 数多くの実験により、FLASHの動作は内部組織の機能に何らかの形で関連しているという結論に至ります。 録音用の内部高電圧発生器(その存在は疑いありません)は、長期間の動作中に必要な電圧レベルを維持することができず、充電を回復するために一定の時間を要すると思います。 同時に、全体的な平均速度は維持されますが、平均速度は必要ありませんが、各ファイルの瞬間的な書き込み速度は必要です。 ここでは、負荷分散のためのデータバッファの導入が役立ちますが、別の解決策が見つかりました-さまざまな企業のSDカードが購入され、その中に顕著なばらつきなく1.4秒の一定の記録時間を与えるものがありました。 記事の広告が見つからないように、カードメーカーの特定の名前は付けません-1ポイントSD。



結論-問題は解決され、デバイスは消費者に出荷され、障害なく動作します。検出された問題と修正された問題の合計スコア:SDカード-2、TIのライブラリ-3、マイクロコントローラー機能-1 上記から、次の結論を導き出すことができます。

1.アプリケーションの例とともに、標準プログラムの既存のライブラリに特に注意を払う必要があります。 原則として、それらは機能し、場合によってはエラーなしでも機能しますが、パフォーマンスが最適化されることはありません。 そのため、ソースコード(残念ながらそうです)を見て、創造的に修正します。 さらに、私は、そのような自由に配布されたライブラリは、有料のアナログの獲得を刺激するために、意図的に最適化されていないと考えていました。

2.さまざまなデバイスのパフォーマンスに関する仕様に注意を払っています。つまり、パラメーターの1〜2桁だけでなく、それらに適したものを決定するのではなく、モードと数値が達成される仕様を注意深く読みます。

3.マイクロコントローラモジュールのドキュメントを注意深く読み、その内部構造を理解し、オシロスコープが実際のボード上の実際のプロセスを研究することを忘れないでください。



そして、記事の終わりに、1つの小さなコメントがあります。新しいTIVA-Cタイプのマイクロコントローラーサポートパッケージ(TivaWare_C_Series-2.0.1.11577)での同様の手順の実装で、物事がどのように進行するかを確認することにしました。 まあ私たちは何を言うことができます-伝統は壊れていません。 まったく同じレーキがすべて同じ場所にあり、もう1つ追加されました-関数はFLASHメモリから直接呼び出されるのではなく、ダブルインデックスを使用するいわゆるROMライブラリから呼び出されるため、パフォーマンスは向上しません。 ミハイル・ズヴァネツキーが言ったように、「私たちはうまく生きるか、私の作品が常に関連するか」。 これまでのところ、2番目は真実です。



All Articles