7

さまざまな長さのアイテムをフラッシュチップの循環キューに格納する必要があります。各アイテムにはカプセル化されているので、アイテムの大きさと次のアイテムの始まりを把握できます。バッファに十分なアイテムがある場合、最初にラップされます。

フラッシュチップに循環キューを格納するための良い方法は何ですか?

何万ものアイテムを保管したい可能性があります。したがって、バッファの最初から最後まで読み取ることは、最後まで検索するのに時間がかかるため、理想的ではありません。

また、円形なので、最初のアイテムと最後のアイテムを区別できるようにする必要があります。

最後の問題は、これがフラッシュに保存されることです。そのため、各ブロックの消去には時間がかかり、各ブロックに対して設定された回数しか実行できません。

4

5 に答える 5

14

まず、ブロック管理:

各ブロックの先頭に小さいヘッダーを配置します。「最も古い」と「最も新しい」を追跡する必要がある主なものは、kを法として単純にインクリメントするブロック番号です。kは、ブロックの総数よりも大きくする必要があります。理想的には、kをMAX値(たとえば0xFFFF)より小さくして、消去されたブロックが何であるかを簡単に見分けられるようにします。

起動時に、コードは各ブロックのヘッダーを順番に読み取り、n i + 1 =(n i + 1)MODULOkであるシーケンスの最初と最後のブロックを見つけます。消去されたブロック(ブロック番号は0xFFFFなど)または何らかの理由で破損したデータ(不完全な消去など)によって混乱しないように注意してください。

各ブロック内

各ブロックは最初は空で始まります(各バイトは0xFFです)。各レコードは、単純に次々に書き込まれます。固定サイズのレコードがある場合は、単純なインデックスを使用してアクセスできます。可変サイズのレコードがある場合、それを読み取るには、ブロックの先頭からリンクリストスタイルでスキャンする必要があります。

可変サイズのレコードが必要であるが、線形スキャンを避けたい場合は、各レコードに明確に定義されたヘッダーを設定できます。たとえば、レコード区切り文字として0を使用し、各レコードをCOBSエンコード(またはCOBS / Rエンコード)します。または、選択したバイトを区切り文字として使用し、各レコードで発生する場合はそのバイトを「エスケープ」します(PPPプロトコルと同様)。

起動時に、最新のブロックがわかったら、最新のレコードの線形スキャンを実行できます。または、固定サイズのレコードまたはレコード区切り文字がある場合は、バイナリ検索を実行できます。

スケジュールを消去する

一部のフラッシュメモリチップでは、ブロックの消去にかなりの時間がかかる場合があります(例:5秒)。少し「前もって」バックグラウンドタスクとして消去をスケジュールすることを検討してください。たとえば、現在のブロックがx%いっぱいになったら、次のブロックの消去を開始します。

レコード番号

レコードに番号を付けることをお勧めします。私が過去に行った方法は、各ブロックのヘッダーに最初のレコードのレコード番号を入れることです。次に、ソフトウェアはブロック内の各レコードの数をカウントし続ける必要があります。

チェックサムまたはCRC

破損したデータ(予期しない電源障害による不完全な書き込みまたは消去など)を検出する場合は、各レコードに、場合によってはブロックヘッダーにチェックサムまたはCRCを追加できます。ブロックヘッダーCRCは、新しいレコードが書き込まれるたびに再書き込みできないため、レコードではなくヘッダー自体のみをカバーすることに注意してください。

于 2009-11-03T23:58:12.303 に答える
2

最初のレコードの開始と最後のレコードの終了へのポインターを含む別のブロックを保持します。レコードの総数など、より多くの情報を保持することもできます。

最初にスペースが不足するまで、レコードの追加は、レコードをバッファーの最後に書き込んでテールポインターを更新するのと同じくらい簡単です。

スペースを再利用する必要があるため、現在のレコードに収まるように十分なレコードを削除してください。レコードを削除するときにヘッドポインタを更新します。

解放された余分なスペースの量を追跡する必要があります。最後のレコードの終わりへのポインターを保持している場合、次にレコードを追加する必要があるときに、それを最初のレコードへのポインターと比較して、さらにレコードを削除する必要があるかどうかを判断できます。

また、これがNANDの場合、ユーザーまたはフラッシュコントローラーは非ブロック化とウェアレベリングを実行する必要がありますが、これらはすべて、循環バッファーにスペースを割り当てるよりも下位層にある必要があります。

于 2009-11-03T22:59:26.050 に答える
1

私は今それを手に入れていると思います。あなたの最大の問題は、録音に利用できるスペースを埋めた後、次に何が起こるかということのようです。新しいデータは最も古いデータを上書きする必要があります。これは、循環バッファの意味を信じています。ただし、データは固定長ではないため、複数のレコードを上書きする可能性があります。

長さの変動の量は十分に大きいので、すべてを固定長にパディングすることはオプションではないと思います。

書き込みセグメントは、次に書き込むレコードの開始を表すアドレスを追跡する必要があります。事前に書き込むブロックのサイズがわかっている場合は、論理バッファーの最後で終了し、「0」からやり直すかどうかを判断できます。レコードを最後にいくつか、最初にいくつかで分割することはしません。

別のレジスターで開始を追跡できます。これは、まだ上書きされていない最も古いデータです。データを読みに行った場合は、ここから始めます。

次に、データライターは、書き込み開始アドレスとコミットしようとしているデータの長さを指定して、読み取りレジスターをバンプする必要があるかどうかを確認します。読み取りレジスターは、最初のブロックを調べて長さを確認し、次のレコードに進みます。データが何であれ、書き込むのに十分な余地があります。おそらく、書き込まれたデータの終わりと最も古いデータの始まりの間に存在するジャンクデータのギャップがあります。ただし、この方法では、ブロックを再配置するのではなく、1つまたは2つのアドレスをオーバーヘッドとして書き込むことができます。

少なくとも、それはおそらく私がすることです。HTH

于 2009-11-03T20:02:57.070 に答える
1

フラッシュの「循環」は、ブロックサイズに基づいて実行できます。つまり、このバッファに割り当てるフラッシュのブロック数を宣言する必要があります。

バッファの実際のサイズは、n-1(nはブロック数)とnの間の特定の時間ごとになります。

各ブロックは、どのブロックが他のブロックより古いかを判別するために使用できる連続番号またはタイムスタンプを含むヘッダーで開始する必要があります。

ヘッダーとフッターでカプセル化された各アイテム。デフォルトのヘッダーには必要なものがすべて含まれていますが、このヘッダーによると、アイテムのサイズを知っている必要があります。デフォルトのフッターは0xFFFFFFFFです。この値は、ヌル終了を示します。

RAMには、最も古いブロックと最新のブロックへのポインターと、最も古いアイテムと最新のアイテムへのポインターを保存する必要があります。電源を入れると、すべてのブロックを調べて、関連するブロックを見つけ、このメンバーをロードします。

新しいアイテムを保存するときは、最新のブロックにこのアイテム用の十分なスペースが含まれているかどうかを確認します。その場合は、前のアイテムの最後にアイテムを保存し、前のフッターを変更してこのアイテムを指すようにします。十分なスペースが含まれていない場合は、最も古いブロックを消去する必要があります。このブロックを消去する前に、最も古いブロックメンバー(RAM)を次のブロックを指すように変更し、最も古いアイテムをこのブロックの最初のアイテムを指すように変更します。次に、このブロックに新しいアイテムを保存し、このアイテムを指すように最新のアイテムのフッターを変更できます。

説明は複雑に聞こえるかもしれませんが、プロセスは非常に単純であり、正しく記述すれば、電源フェイルセーフにすることもできます(書き込みの順序を常に念頭に置いてください)。

バッファの循環性はフラッシュに保存されませんが、フラッシュには、ブロックヘッダーとアイテムヘッダーに従ってこれらのアイテムの順序を決定できるアイテムを含むブロックのみが含まれていることに注意してください。

于 2009-11-04T08:29:29.277 に答える
0

3つのオプションがあります。

オプション1:すべてを同じサイズにパディングすることです。これは簡単です。バッファの先頭と末尾へのポインタを格納して、書き込み先と読み取り開始先がわかるようにします。各オブジェクトのサイズを使用してオフセットを取得します。次に、これは、リンクリストと同じようにバッファを横断する必要があることを意味します。アイテム5000が必要な場合は低速です。

option2:循環バッファに実際のデータへのポインタのみを格納することです。これにより、ループするときにサイズの不一致に対処する必要がなくなります。実際のデータを循環バッファに格納し、それを埋めない場合、1つの新しいデータオブジェクトで複数のアイテムを過剰に処理する状況に遭遇する可能性があります。これは問題ないと思います。

実際のデータをフラッシュの他の場所に保存します。ほとんどのフラッシュには、ある種のウェアレベリングが組み込まれています。同じ場所を何度も上書きすることを心配する必要がない場合、ICは実際にチップ上のどこにデータを保存するかを判断します。次に利用可能な空き領域に書き込むだけです。

これは、循環バッファの最大サイズを選択する必要があることを意味します。これを行う方法は、データの変動性によって異なります。データのサイズが大きく変化する場合、たとえば数バイトだけの場合は、データを埋めてオプション1を使用する必要があります。サイズが大きく変化し、予測できない場合は、可能な最大サイズを選択して、オブジェクトの数を計算します。そのサイズのがフラッシュに収まるので、それをバッファ内のエントリの最大数として使用します。これは、大量のスペースを浪費することを意味します。

オプション3:オブジェクトが実際に任意のサイズである可能性がある場合は、ファイルシステムを使用する必要がある時点で、ファイルに順番に名前を付け、新しいエントリが大きい場合は削除する必要がある場合があることを念頭に置いて、ループバックします。オプション2は多くの点で単純なファイルシステムであるため、これは実際にはオプション2の単なる拡張です。

于 2009-11-03T22:02:23.930 に答える