Raspberry PI PIO で NANDアクセスを高速化する
登壇する機会があったのでその際の資料。RP2040 に搭載されている Programmable IO を用いて、Parallel Command I/F である NAND IC へのアクセスを高速化検討した話。
資料は marp を使用して作成したので、以後は元になった資料の markdown 移植版
背景
最近 SSD 自作キット JISC-SSD で 時折放置してますが 遊んでいます。
途中まで C++で書いていましたが、気まぐれで Rust 再実装中...
RPi Pico: RP2040 Cortex-M0+ DualCore @133MHz NAND Flash: KIOXIA TC58NVG0S3HTA00 1Gbit SLC ECC なし
| 外観 | 回路図抜粋 | RP2040 Block Diagram | 
|---|---|---|
|  |  |  | 
| GPIO で NAND と直結 | 
課題
NAND IC へのアクセスをもう少しいい感じにしたい
GPIO 直叩きでの通信は遅い (当然と言えばそう) SIO (Single Cycle IO) もあるが、転送中 CPU Resouce 占有してしまう PIO (Programmable IO) という小規模なシーケンサのような HW が乗っている
| SIO | PIO Overview | 
|---|---|
|  |  | 
| bus fabric 経由せず GPIO 叩ける | State Machine 4 機 | 
PIO 概要
- 動作周波数はデフォルトで 125MHz, uCode は 32 命令まで
- 命令セットはデータ入出力+入出力時の bitshift、分岐命令 あたり
- GPIO の Read/Write/PinDir 変更、FIFO 経由で CPU/DMA とやりとりできる
- 命令実行と同時に固定サイクル遅延 (Delay)、もしくは特定ピンの H/L を変更できる (Sideset)
- この 2 機能に割り当てられる bit は合わせて 5bit まで
 
| 命令セット | Shift Register | 
|---|---|
|  | TX FIFO -> Output Shift Reg  Input Shift Reg -> RX FIFO  | 
| Delay/sideset の bit 割り振りは起動前に設定 | 
NAND IC との通信
GPIO 複数ピンによるコマンド入力 + 双方向データ転送が必要
| Pin | Function | 
|---|---|
| /CS | Chip Enable | 
| /WE, /RE | Write/Read Enable。転送クロック相当 | 
| ALE, CLE | Address/Command Latch Enable。入力データ区別 | 
| RY//BY | Ready/Busy: Busy なら Low | 
| IO[7:0] | データ線。双方向 | 
| Logic & Command Table | Read Operation | 
|---|---|
|  |  | 
| Cmd In (0x00)-> Addr In -> Cmd In (0x30) -> Wait RY/BY -> Data Out... | 
Simulation/Debug 環境
デバッガがないため、 Jupyter 上に論理検証環境構築 adafruit_pioasm + pioemu + pandas + wavedrom

設計
DMA で流すデータ上に独自コマンドセットを定義
CmdId を指定し、各シーケンスごとのルーチンを実装。CPU は Buffer 上にシーケンスを組む (流すデータの順番があっていればよいので、連続領域に確保しなくても DMA を Chain で良い)
| Data[0] assign | Field | Description | 
|---|---|---|
| [31:28] | CmdId | コマンド指定 | 
| [27:16] | TransferCount | (AddrLatch/DataIn/DataOut のみ) 転送 byte 数指定 | 
| [15:0] | PinDirection | GPIO の入出力設定 | 
| CmdId | Data[1, ...] | Description | 
|---|---|---|
| Bitbang | PinData | そのまま GPIO に流す | 
| CmdLatch | NandCmdId | CLE 有効で Data 入力 | 
| AddrLatch | NandAddr | ALE 有効で Data 入力 | 
| DataOutput | - | 指定回数 Data 出力 + GPIO Read | 
| DataInput | TransferDatas | 指定回数 Data 入力 | 
| WaitRbb | - | RB/BY pin が Ready になるまでループ | 
| SetIrq | - | 割り込み通知(転送完了を CPU に知らせる用) | 
| PIO Process Diagram | Sequence | 
|---|---|
|  | 
性能 (Data Input の例)
$f_{Max}$ で動かすと Data の Setup 満たさないので 83MHz (12ns) より下げて動かす必要あり。 GPIO Toggle よりはだいぶ速くなったが、AC 特性 Spec と比べるともうひと声。

まとめ
所感
PIO は小規模ながら色々できて面白い System Clock (Max 133MHz) で動くのでホビー用途なら十分速い 実機デバッグはしんどいので Sim 環境作っておいてよかった 続きもぼちぼち実装します → 整理しました wipeseals/nandio.pio
出典
JISC-SSD(Jisaku In-Storage Computation SSD 学習ボード) - 株式会社クレイン電子 RP2040 Datasheet - Raspberry Pi Ltd TC58NVG0S3HTA00 Datasheet - KIOXIA
Fin.