SPI Flashの使い方
組み込み工作でデータを格納したいときはFlashメモリを使うと便利です。
Flashメモリと言っても様々な種類があり、ざっくり以下のような分類ができます。
各社*1開発を行っており、微妙な違いで様々な製品があります。 例外もありますが型番の多くがメーカー名+数字で構成されておりカッコ内の示してあります。
- NAND Flash
- Parallel (_29)
- Address/Data組み合わせのコマンド方式
- Parallel (_29)
- NOR Flash
- Parallel (_29)
- Address/Data組み合わせのコマンド方式
- Serial
- SPI/QSPI/DSPI (_25)
- I2C (_24)
- Parallel (_29)
大容量のNAND Flashはお馴染みのUSBメモリなど、本当に大容量なデータの格納に使われています。 中・小規模なその他のFlashはプログラムの格納(外付けの場合)やFPGAのコンフィグデータの格納、ログデータやリソースの格納などに使われています。
LogiCloverでは
などで使用しました。
FPGAのコンフィグROMをPCから書き換える実験。
今回はSPIで制御するSerial NOR Flash(以下SPI Flash)の最低限の使い方について、FPGAのコンフィグで使用しているMicron社M25P40を例に説明します。 用意されているコマンドの種類やニーモニックが異なるだけで、基本的な使い方は各社同じです。
パッケージ
殆どのSPI FlashはSOIC8かSOIC16のようです。(1.27mmピッチ)
ピンアサイン
SOIC8のピンアサインは以下のとおりです (M25P40は対応していませんが、QSPIも含めた解説もしておきます。)
ピン名 | 方向 | SPI時 | QSPI時 |
---|---|---|---|
S# | 入力 | チップセレクト(CS) | チップセレクト(CS) |
C | 入力 | クロック入力(SCK) | クロック入力(SCK) |
DQ0 | 双方向 | データ入力(MOSI) | データ線0 |
DQ1 | 双方向 | データ出力(MISO) | データ線1 |
W#/DQ2 | 双方向 | 書き込み保護(使わなければH固定) | データ線2 |
HOLD#/DQ3 | 双方向 | 通信一時停止(使わなければH固定) | データ線3 |
SPIで使うときはW#/HOLD#はHigh固定で問題ないです。 QSPI時は帯域を増やすためにこの2つの信号線も通信に使用します。
インターフェース
電圧 : 2.3V ~ 3.6V
デバイスによっては1.8Vなど低い電圧までサポートしているものがありますが、5Vはほぼサポートしていないと見ていいでしょう。
もしArduinoの5V I/Oなどから使用する場合は必ずレベル変換してください。
通信周波数 : コマンドと電源電圧による
これがSPI Flashの厄介なところで、殆どのデバイスがコマンドと電源電圧によって最大周波数が異なります。 多くの場合Read命令とRead Fast命令が別れています。
Read Fastはダミーサイクルを挿入する代わりに(コマンドについては後述)最大周波数を上げています。 最近のデバイスでは100MHz超えも当たり前になっています。
M25P40を3.3Vで使った場合、下の表のとおりになります。
条件 | 周波数[MHz] |
---|---|
Read | 33 |
Read Fast | 75 |
それ以外 | 75 |
通信フォーマット
Master側のペリフェラル設定については割愛します。特殊なことは必要ありません。
クロック極性
立ち上がりエッジでキャプチャできるようにしてあれば大丈夫です。
CPHA,CPOLが(0, 0)か(1, 1)
ビットオーダー
MSBファーストで転送します。([D7, D6, D5, D4 … D0]の順に送る。)
送り方
命令によってデータの付け方が異なります。殆どの場合、データシートにまとめた表がだいたいあります。
送る順としては命令 + アドレス + モード + ダミー + データになっています。*2
アドレス、モード、ダミーなどは命令によって省略されるのでデータシートを確認してください。また最近のデバイスではアドレスに32bit指定可能なもの、ダミーサイクル数が指定可能なものなどもあります。
命令のみの場合
Write Enable, Write Disable, Bulk Erase, Deep Power-down など
命令1byte
例えば書き込み有効化のWrite Enableは、0x06を1byte送れば実行できます。
ステータス読み出しの場合
Read Identification, Read Status Register, Release from Deep Power-downなど
命令1byte + 読み出すデータ(IO1に出力される)
Masterから送るデータは最初の1byteに命令、あとは適当なダミーデータを送り、IO1のデータを読み取れば大丈夫です。
データ書き込みの場合
Page Programなど
命令1byte + 読み出しアドレス3byte + 書き込むデータ
指定したアドレスから順にデータを書き込んでいきます。
注意すべき点としては読み出しが一度に全部読み出せるのに対し、書き込みはページ単位(256byte)ごとに処理する必要があります。
データ読み出しの場合
Read Data Bytes, Read Data Bytes at Higher Speed など
命令1byte + 読み出しアドレス3byte + 読み出されたデータ(IO1に出力される。)
読み出したいデータ分だけ転送バイト数を増やすだけで大丈夫です。
通信速度を上げたい場合、代わりにat Higher Speed命令を送り、アドレスの後1byteは適当なデータを送っておけば大丈夫です。
制御方法
あとはコマンドをどう使うかだけ確認します。ここまでくれば後は送るだけです。
データ読み出し
Read Data Bytesで読み取りたい長さ分のSPI転送を行えば大丈夫です。
アドレス指定が出来るので任意アドレスのデータを読み出せます。
データ消去
消去命令は全領域消去を行うBulk Eraseと、特定セクター*3の消去を行うSector Eraseがあります。
Erase/Program系の命令他の命令と異なり別のコマンドと組み合わせが必要です。
- 実行前にWrite Enableを行う必要があります
- コマンド発行から完了まで時間がかかるためRead Status Registerでステータスを1byte読み出し、最下位ビットのWrite in Progress(WIP)が0になるまで待つ必要があります。
以下にフローを示します。
データ書き込み
PROGRAM命令を使って書き込み先を指定して書き込みます。
読み出しと異なりデータ長はページごと(M25P40の場合は256byteごと)に行います。
データ消去同様、Write Enableを事前に実行し書き込み後にWIPを待つ必要があります。
これは補足ですが一般的に書き込む前に事前にデータ消去を行います。
既にデータが書かれている場所にもう一度書き込んだ場合に正しく書き込めるかは保証されません。
終わりに
今回はSPI Flashの基本的な使い方についてまとめました。
PCからFlashやFPGAのコンフィグを行う実験のまとめになります。
後々需要があればツールは公開予定ですが、ご要望があれば優先度は考えます。
Arduinoでの制御例
2017/08/15 書きました、とりあえず動かしたい方はどうぞ。
※ Micron社 M25P40データシートより引用 https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf