※このサイト内の情報は一切保証されません。参考にする際はすべて自己責任となります。
2023/07/02 Misskeyリンクの追加(内容に変更ありません)
2023/02/11 アクセスカウンタ・アクセス解析タグ入れ替え(内容に変更ありません)

目次

1. 概要
2. パーツ
3. TC584000の操作
4. 回路
5. 実験
6. あとがき
7. 参考にさせていただいたサイト・情報

1. 概要

いまやフラッシュメモリは、パーソナルコンピュータの補助記憶装置の立場をHDDに取って代わろうとするまでになった記憶装置となりました。
そのフラッシュメモリのうち、NAND型フラッシュメモリとして初の製品である、東芝の"4Mbit CMOS NAND EEPROM" TC584000をたまたま入手したので、実験してみました。

2. パーツ

実験であり、また、貴重なチップなのでブレッドボードを使います。
今回入手したのは、TC584000はPDIPのTC584000Pです。純粋な最初期のNAND型フラッシュメモリのベンチマーク(水準品の意味)で、4Mbit(512k-word x 8)で始まりました。
74HC161はアドレス生成用です。512KiBなので、アドレス空間は19bitですが、下位12bit+1bit(後述)を使用し、上位6bitは後述する基準に従って固定します。

3. TC584000の操作

TC584000には、19bitのアドレス線、8bitのデータ線、/WE(書込)、/OE(出力)、/CE(有効)の3本の制御線があり、見た目は4MbitのSRAMです。
読み出しにおいては、62256等のSRAMと同様に、アドレスを指定し、/OEをアクティブにすることで、TC584000内のデータが出力されます。

一方で、書き込みは複雑です。
SRAMのように、アドレスを指定し、データ線にデータを出力して/WEをアクティブにする・・・とは行きません。
TC584000への書き込みは、512Byte毎の「ページ」と8ページ毎の「ブロック」単位で行われ、なおかつ、「コマンド」を使用する必要があります。
コマンドの実行は、SRAMへのデータを書き込むときと同様に、データバスにコマンドを与え、/WEをH→L→Hにすることで行います。
コマンド 内容その後の制御
書込任意アドレスに40Hを書き込む上位10bitのページアドレスを固定し、
アドレス下位9bitを0からインクリメントしながら
512Byte連続データを書き込み後、
35-45μs後にベリファイコマンドを実行する
ベリファイ書込終了後、35-45μs間に
任意アドレスにC0Hを書き込む
上位10bitに書込時と同じページアドレスを固定し、
アドレス下位9bitを0からインクリメントしながら
512Byte連続データを読み込む
全消去任意アドレスに20Hを2回書き込む9.5-10.5ms後に読込コマンドを実行する
ブロック消去上位7bitのブロックを指定し
60Hを2回書き込む
9.5-10.5ms後に読込コマンドを実行する
読込任意アドレスに00Hを書き込む読込モードになる
(汎用のSRAMやROMの読み出しと同様)
リセット55555HにFFHを2回書き込む自動で読込コマンド実行後の状態となる

順番に書き込み方法をみていきます。

1.消去

まず、ブロック(8ページ = 4KiB)単位もしくは、チップ全体の内容を消去します。
電源投入直後は、読込モードになっているため、全消去コマンドあるいはブロック消去コマンドを与えます。
コマンドを与えたら、/WEをHにして、9.5-10.5ms待ち、読込コマンドを与えます。
読込コマンドを与えたら、/WEと/CEを10ns以上の間隔を空けて順にHにし、2ms待機することで、消去が終了します。
消去後は、消去したブロックあるいはチップ内のすべてのアドレスの内容がFFHになります。

消去コマンドを与えるだけではチップの消去は完了せず、その後の読込コマンドを与え、その際の/WEをHにするまでを確実に実行する必要があります。

2.書き込み

消去が完了したら、書き込みを実行します。書き込みはページ単位で行います。
/CEをLに戻し、まずは書き込みコマンドを与えます。
コマンドを与えたら、上位10bitでページのアドレスを指定し、下位9bitを000Hにして、その番地に対応するデータを書き込みます。
データの書き込みは、SRAM同様に、データバスにデータを与え、/WEをH→L→Hとすることで行います。
その後、下位9bitを1FFHまでインクリメントしながら、511Byte(最初の書き込みと合わせて512Byte)を書き込みます。
この際、/WEをLにしたままアドレスとデータのみを変えるといった横着はできません。
必ず、アドレスインクリメント→データを与える→/WEを50ns以上Lにする→/WEをHにする(次にLにするまでは50ns以上空ける)→アドレスインクリメント→...を繰り返す必要があります。

書き込むデータが512Byte未満しかない場合でも、必ず、512Byte分のデータ書き込みをしなければなりません。
これは、512Byte分のデータを内部レジスタに格納して初めて、NANDフラッシュメモリセルアレイに書き込みが行われる仕様のためです。適当なデータを付加して、512Byte丁度とします。

512Byte分の書き込みが終了し次第、自動的に内部レジスタからNANDフラッシュメモリセルアレイへの書き込みが始まります。
内部レジスタからNANDフラッシュメモリセルアレイへの書き込みは、ベリファイコマンドの実行によって終了します。
しかし、内部レジスタからNANDフラッシュメモリセルアレイへの書き込みが45μsを超えると、正常にデータの読み出しができなくなる恐れがあります(オーバープログラミング)。
そのため、512Byte分の書き込みが終了したら、35-45μs以内に任意のアドレスにC0Hを書き込み、/WEをHにするまでを確実に実行します。
もし、ベリファイをするつもりがなくても、ベリファイコマンドの実行は、書き込みに必須です。
ベリファイコマンドを与えたら、/WEと/CEを10ns以上の間隔を空けて順にHにし、5μs待機することで、書き込みが終了します。

3.ベリファイ

ベリファイで行うことは、シーケンシャルな読み出しだけです。チップ内部で書き込んだデータとページ内容を比較している訳ではありません。
/CEをLに戻し、上位10bitで書き込み時と同一のページアドレスを指定し、下位9bitを000Hにして、/OEをLにします。
あとは、下位9bitをインクリメントして、512ByteをTC584000が出力すればベリファイは終了です。
ベリファイが不要であれば、/CEをLに戻した後、リセットコマンドを与えることで、スキップして読込モードに即移行できます。

...と、書き込みタイミングがシビアだったり、512Byteや4KiBの縛りがあったり、/CEまで制御に必要だったりと、なかなか面倒です。
もっとも、最近のNAND型フラッシュメモリ(パラレルバス)は、1ページが2KiB、1ブロックが64ページ(=128KiB)とさらに大きな単位になっていますが(_ _;

この一連の消去・書き込み操作をして、中身を読み出す実験を、Arduinoのシリアルモニタを使って行います。

4. 回路

実験用の回路図です。


74HC161でアドレスを生成し、IOエキスパンダを使用せずにデータバスをArduinoと直結させるお手軽回路です。
SIPOシフトレジスタ74HC595を使えば、もっと配線量は減るのでしょうが、手持ちがなかったので力業です。しんぷる・いず・べすと
足りないアドレスバスは、リセットコマンド書き込みのための55555Hを与えられるように、偶数ビットをVccへ、奇数ビットをGNDへ直結しています。
前述の通り、TC584000は書き込みを512Byte単位で行うため、1回の書き込みの間に9bitのアドレスを必要とします。
74HC161x2では1bit不足するため、この1bitはArduinoから直接制御しています。
もう一つの74HC161はページ指定のために使用しています。16ページ切り替え可能です。
また、ATmega328PはPD0とPD1がU(S)ARTとして用いられるため、PD2-7およびPB0-1を8bitデータバスとして使用しました。8bitデータを左2bitシフトしたものと右6bitシフトしたものを、それぞれPORTDとPORTBに与えることになります。

...で、この力業回路のブレッドボード実装がこちらです。

(左:ジャンパワイヤの茂み 右:TC584000P)

19bitのアドレスバスと8bitのデータバス、それに未使用ピンの処理もしているため、ブレッドボードがジャンパワイヤで埋まってしまいました。
なんとか主役のTC584000Pを隙間から撮影したのが右の写真です(^^;

5. 実験

実験にはプログラムが必要になります。わざわざ別ページをつくるほどのものでもないので、こちらに。
内容をArduino IDEにそのままペーストしてArduino UNOにコンパイル・書き込みしてください。型変換エラーが出ますが無視してください。動けばいいんです、動けば(`・ω・´)
使用は自己責任でどうぞ。詳しくはソースコード内の「東雲保管庫ライセンス」を参照してください。
やっていることは、全消去・文字列データの書き込み・読み取りです。ベリファイはコマンドだけ与えて、直後にリセットしています。

書き込んだら、シリアルモニタを立ち上げ、1152000bps, LFのみに設定します。
シリアルモニタに「Send String Data(1-255 bytes):」と表示されたら、1文字以上255文字以内の半角英数字をシリアルモニタに入力します。
入力すると、最初に現在のTC584000の内容を256Byte読みこみ、次にTC584000の内容を全消去し、シリアルモニタから入力された内容をTC584000に書き込みます。
最後に、書き込み前に読み込んだ内容・書き込んだ内容・書き込み後に読み込んだ内容がシリアルモニタに表示されます。

(左:送信前 右:送信後)

入力した文字列が、「Read Data:」の後に表示され、「Write Data:」の後の文字列と一致すれば成功です。
なお、無効データチェックは最低限しかしていないため、極端なデータを入力すると実験は失敗します。

6. あとがき

回路製作は山盛りの配線になっただけで、すぐにできましたが、ソフトウェアはArduino もとい AVRのプログラミングが未熟なために、試行錯誤をかなり繰り返しました。
デバッグを繰り返す度に、TC584000だけでなくAVRのフラッシュメモリもすり減って行きました(_ _;

ちなみに、各ページ内512Byte毎の読み出しであれば、各バイトのアクセスタイムは120nsと、EPROM程度のアクセスタイムが得られますが、ページをまたいだ途端、15000nsまで跳ね上がります。
そのため、たとえばZ80のプログラムROMとして用いるには遅すぎます。SSDのような補助記憶装置としては十分な速度かもしれませんが、主記憶装置の代替にはなりません。

東芝よ...どうしてこうなってしまったんだ...

7. 参考にさせていただいたサイト・情報


上へ
戻る