NAND型フラッシュの読み出し/書き出し操作
フラッシュのプログラムモデル
NAND型フラッシュの大きな特徴として、読み出しや書き込みを、シーケンシャルに実行する点があげられます。
メモリにアクセスするには、まず所定のコマンドを投入してから、メモリのアドレスを必要サイクル分投入します。
そのうえで必要なデータの読み出しや書き込みが実行できます。
NOR型フラッシュのようにメモリ空間上にメモリセルがマッピングされ、ランダムアクセスできる構造にはなっていません。
この点はメモリというより、むしろHDDなどに近いアクセス方式となっています。
フラッシュの読み書きはページと呼ばれる528 (512 + 16) バイト単位で実行します。
1ページは、512バイトのデータ部と16バイトの冗長部に分けられます。
データ部には通常のデータを格納し、冗長部にはECCデータや不良ブロックマーク、そのほかの管理情報を格納するのが一般的な使い方です。
ちなみにデータ部と冗長部のメモリセルには何ら違いはなく、このように使い分けると便利なように内部の制御回路が構成されており、それにあわせてコマンドが用意されているにすぎません。
データ部よりも冗長部のほうが不良率が低いといった差はありません。
ブロックはフラッシュの一括消去の単位で、32ページ (16Kバイト) で構成されています。
ページとブロックにはそれぞれアドレスとして0から番号が割り当てられています (図2)。

制御信号
フラッシュへの読み書きはすべて8ビットないしは16ビットのデータポートを経由して行われます。
データポートで読み書きされるデータを区別するために、入出力用の制御信号として _CLE (Command Latch Enable), _ALE (Address Latch Enable), _RE (Read Enable), _WE (Write Enable) があり、この組み合わせでコマンド、アドレス、データ (読み込み/書き込み) を区別します。
NAND型フラッシュの制御信号一覧を 表2に示します。
| _CE | チップイネーブル |
| _WE | ライトイネーブル |
| _RE | リードイネーブル |
| CLE | コマンドラッチイネーブル |
| ALE | アドレスラッチイネーブル |
| _WP | ライトプロテクト |
| RY/_BY | レディビジー出力 |
| I/O | コマンドアドレスデータ入出力 |
多くのデバイスと同様に _CE (Chip Enable) があり、バスマスタのフラッシュチップへのアクセスを明示します。
フラッシュの内部状態を示すRY/_BY信号もあり、ドライバソフトウェアでこの信号レベルを監視してチップの動作状態を判別します。
NAND型フラッシュは上記のとおり、CPUから見た場合にはメモリというよりもパラレルポート付きのI/Oデバイスのように見えます。
フラッシュをCPUに接続する場合には、何通りかの方法があります。
1) すべての制御信号、データポートをGPIOに接続
すべての制御線とデータポートをGPIOに接続し、チップの選択や読み込み/書き込みのタイミング制御などはすべてプログラムで実現します 〔図3 (a)〕。

2) メモリバスに接続
CPUのメモリへのリード/ライトでそのままデータポートを読み書きできるように、簡単なグルーロジックを介して接続する方法です。
メモリバスの制御信号で_ALE、_CLE、_RE、_WEを作り、_CEとRD/_BYのみをGPIOに接続します〔図3 (b)〕。

NAND型フラッシュには“CE Don’t Care”というタイプが存在します〔図3 (c)〕。
通常のNANDフラッシュでは、コマンド投入からデータの読み書き完了まで、_CEピンをアサートし続けていなければいけません。
このため_CEピンはGPIOにつなぐなどして、プログラムで明示的に制御しなければなりませんが、“CE Don’t Care”は_CEのレベルに関係なく読み書きの操作をできるようにしてあるので、メモリバスに出ている_CSなどを直接つないでNANDフラッシュを制御できるようになります。

3) 専用のコントローラを介して接続
ECC回路やデータの読み書き、1ページ分の内部バッファなどを持ったコントローラに接続し、NANDの制御をこのコントローラで行う方法です。
プログラムからは、コントローラのレジスタへのアクセスと、内蔵SRAMバッファへのアクセスだけで済みます。
最近のアプリケーションプロセッサは、 NANDコントローラを内蔵したものがいろいろと出始めています。
フラッシュからの読み出し
フラッシュに格納されたデータを読み出す場合には、チップのレディ状態でデータポートに読み出しコマンド (0x00) と数バイトのアドレスを投入した後、デバイスのレディ状態を待ちます。
この間にフラッシュ内部では各セルの値がリードバッファに読み出されます。
528バイトすべて読み込まれるとRY/_BYピンのレベルがレディになります。
これを待ってからデータポートからのデータを読み込みます。
メモリセルからリードバッファへの読み出しには10~20μsかかりますが、この時間はリアルタイムOSのコンテキストスイッチの時間と大差ない非常に短い時間です。
そのため、コンテキストスイッチが起こるような手法、たとえばドライバプログラムで時間待ちの sleep() を入れたり、 RY/_BYを割り込みで受けるような手法は使わず、単純なbusy loopで待ち受ける実装がもっともシンプルで性能の出やすい実装方法ということになります。
フラッシュへの書き込み
フラッシュにデータを書き込む場合は、チップのレディ状態でデータ入力コマンド (0x80) を投入した後、数バイトのアドレスを投入し、引き続きデータを528バイト投入します。
投入したデータは内部のバッファに溜め込まれます。
データ投入後に書き込みコマンド (0x10) を投入すると、チップ内部で書き込み動作が開始されます。
書き込み動作中はRY/_BYピンがアサートされているので、GPIOポートでこれを監視するか、フラッシュにステータスコマンドを投入して内部のステータスを読み出して監視をし続けます。
データの書き込みにはおおよそ200μsかかります。
リードの場合と同様にこの間をbusy loopで待つか、もしくは sleep() などでいったんCPU時間をほかのタスクに回すかは、システムの特性によって決まるでしょう。
フラッシュの消去
フラッシュ上のブロックを消去する場合は、次のように操作します。
チップのレディ状態で消去コマンド (0x60) を投入し、その後ブロック番号をアドレスとして投入、最後に消去開始コマンド (0xD0) を投入します。
これで指定したブロックの消去が開始されます。
ブロックの消去には数msかかります。
消去終了は書き込みと同様にRY/_BYピンのレベルを確認するか、ステータスリードコマンド (0x70) でステータスを取得して確認します。
書き込み動作と消去動作完了後には、必ずステータスリードコマンド (0x70) を使って正常終了したかどうかを確認してください。
ステータスがビジーの間のチップステータスは意味がないので無視してください。
ステータスがレディになった時点で書き込みや消去の処理結果がチップステータスとして示されます。
これがPassならば処理完了ですが、 Failになっている場合には、書き込み不良や消去不良なので、そのブロックを不良ブロックと認定して、しかるべき退避処理を実施する必要があります。
消去時の不良ブロック発生については、対象ブロックに有効なデータはないので、そのブロックを不良ブロックとして管理情報を登録し、これ以降書き込みなどに使われないようにします。
書き込み時の不良ブロックの場合には、そのブロックを不良ブロックとして登録するだけではなく、すでにそのブロックに正しく書き終わっているデータを、別の正常な空きブロックに書き写したうえで再度正常に終わらなかったデータの書き込み処理を再実行します。
目次
- はじめに
- フラッシュとは
- NAND型フラッシュの読み出し/書き出し操作
- リード/ライトのパフォーマンス
- 不良ブロックの処理
- ビットエラーとECC
- メモリマッピング
- リクラメーション
- ウェアレベリング
- フラッシュファイルシステムと電源障害耐性
- FATファイルシステムの電源障害耐性
- 電源瞬断による破損
- 電源瞬断対策

