Appearance
Arduino Mega 2560 フラッシュライター(SST39SF040 / MX29F040)
自作 NES カートリッジ用の 5V パラレル NOR フラッシュ SST39SF040(DIP-32, 512KB。 互換品 MX29F040 も可)へ、Arduino Mega 2560 経由で .nes ROM の PRG 部を 書き込むための構成。Mega は 5V ロジックなのでレベル変換なしで GPIO 直結できる。
- ファームウェア:
firmware/mega-writer/mega-writer.ino - ホスト CLI (macOS):
tools/flashnes.py(Python 3 + pyserial)
ブレッドボード配線表
フラッシュは DIP-32(JEDEC 標準ピン配置)。ノッチ(半月の切り欠き)を上にして、 左上が 1 番ピン、反時計回りに 32 番まで。
| フラッシュ DIP-32 ピン | 信号 | Mega 2560 ピン |
|---|---|---|
| 1 | A18 | D40 |
| 2 | A16 | D38 |
| 3 | A15 | D37 |
| 4 | A12 | D34 |
| 5 | A7 | D29 |
| 6 | A6 | D28 |
| 7 | A5 | D27 |
| 8 | A4 | D26 |
| 9 | A3 | D25 |
| 10 | A2 | D24 |
| 11 | A1 | D23 |
| 12 | A0 | D22 |
| 13 | DQ0 | D42 |
| 14 | DQ1 | D43 |
| 15 | DQ2 | D44 |
| 16 | VSS | GND |
| 17 | DQ3 | D45 |
| 18 | DQ4 | D46 |
| 19 | DQ5 | D47 |
| 20 | DQ6 | D48 |
| 21 | DQ7 | D49 |
| 22 | /CE | D50 |
| 23 | A10 | D32 |
| 24 | /OE | D51 |
| 25 | A11 | D33 |
| 26 | A9 | D31 |
| 27 | A8 | D30 |
| 28 | A13 | D35 |
| 29 | A14 | D36 |
| 30 | A17 | D39 |
| 31 | /WE | D52 |
| 32 | VDD | 5V |
規則性: A0..A18 → D22..D40(番号順)、DQ0..DQ7 → D42..D49、 /CE → D50、/OE → D51、/WE → D52。Mega の 2×18 ピンヘッダ(D22–D53)だけで 完結する割り当てなので、リボンケーブルでも配線しやすい。
補足:
- 電源は Mega の 5V / GND ピンから供給する(書き込み電流は数十 mA 程度)。
- VDD–VSS 間にパスコン 0.1µF を(できるだけチップの近くに)入れると安定する。
- /CE・/OE・/WE はファームウェアが常時駆動するためプルアップは必須ではないが、 10kΩ で 5V にプルアップしておくとリセット中の誤書き込み保護になる。
セットアップ
ファームウェア書き込み(Arduino IDE でも arduino-cli でも可)
bashbrew install arduino-cli # 未導入なら arduino-cli core install arduino:avr arduino-cli compile --fqbn arduino:avr:mega firmware/mega-writer arduino-cli upload -p /dev/tty.usbmodem1101 --fqbn arduino:avr:mega firmware/mega-writerホスト側の準備
bashpip install pyserialポート名は
ls /dev/tty.usbmodem*で確認する。
使い方
bash
PORT=/dev/tty.usbmodem1101
# 1. チップ ID の確認(配線チェックを兼ねる。必ず最初に実行する)
python3 tools/flashnes.py --port $PORT id
# → ID 0xBF 0xB7 SST39SF040 (MX29F040 なら ID 0xC2 0xA4 MX29F040)
# 2. .nes から PRG 部を抽出して 消去→書き込み→ベリファイ を一括実行
python3 tools/flashnes.py --port $PORT write game.nes --ines
# 生バイナリの一部だけ書く場合
python3 tools/flashnes.py --port $PORT write prg.bin --offset 0 --length 32768
# 書き込み済み内容の照合のみ
python3 tools/flashnes.py --port $PORT verify game.nes --ines
# フラッシュ全体の吸い出し
python3 tools/flashnes.py --port $PORT dump readback.bin --length 524288writeは既定でチップ消去→書き込み→リードバックベリファイまで自動実行する (消去を飛ばす場合は--no-erase)。--inesは iNES ヘッダ 16 バイトをスキップし、PRG サイズ(ヘッダ 4 バイト目 × 16KB)だけを抽出する。トレーナー(512B)があれば自動でスキップする。- チップ消去は SST39SF040 で 1 秒未満、MX29F040 では数十秒かかることがある。
シリアルプロトコル(参考)
115200bps・行ベース。V(バージョン)、I(ID 読み出し)、E(チップ消去)、 W <addr> <len>(バイナリ書き込み、256 バイトごとに ACK、完了で OK <checksum>)、R <addr> <len>(バイナリ読み出し)。詳細は firmware/mega-writer/mega-writer.ino 冒頭のコメントを参照。
トラブルシュート: ID が読めない時の確認順
id が ID 0xFF 0xFF UNKNOWN や ID 0x00 0x00 UNKNOWN を返す場合、 以下の順で切り分ける。
- 電源: フラッシュ pin 32 (VDD)–pin 16 (VSS) 間をテスターで実測して 約 5V あるか。ブレッドボードの電源レール分割(中央で分かれているタイプ)に注意。
- チップの向き: ノッチ位置を再確認。逆挿しは発熱するので即座に外す。
- 制御 3 線: /CE(pin22)→D50、/OE(pin24)→D51、/WE(pin31)→D52 の 3 本を 最優先で確認する。ここが 1 本でも違うと ID は絶対に読めない。
0xFF 0xFF→ チップが応答していない(/CE か /OE の配線・電源を疑う)。0x00 0x00→ バスが駆動されていない/短絡の可能性。
- データバス 8 本: DQ0..DQ7(pin13,14,15,17,18,19,20,21)→ D42..D49 の 順序ずれ。ID の値が「毎回同じだが期待値と違う」ならビット順の入れ替わりを疑う (例: 0xBF がビット逆転で 0xFD に見える等)。
- アドレスバス: ID コマンドは $5555/$2AAA への書き込みを使うため、 A0..A14 のどれかが違っていてもコマンドが届かず
0xFFになる。 配線表と 1 本ずつ突き合わせる(特に pin 1=A18 / pin 2=A16 / pin 30=A17 / pin 31=/WE の並びは間違えやすい)。 - 接触不良: ブレッドボードとジャンパワイヤの品質。チップを軽く押さえながら
idを再実行して値が変わるなら接触不良。 - チップ自体: 別の個体に差し替えて再確認。3.3V 版の SST39VF040 は 5V では使用不可(ID も読めないか、読めても書けない)。
上記でも解決しない場合は、V コマンド(python3 -c 等でシリアルに直接送信)で ファームウェアが応答するかを確認し、応答がなければ USB ケーブル・ポート名・ ファームウェア書き込み自体を疑う。
実機検証の残タスク
部品到着後にユーザーが実施:
idで ID 読み出し(配線検証)erase→dumpで全バイト 0xFF 確認write <rom>.nes --ines→ 自動ベリファイ一致- 書き込んだチップをカートリッジに装着して実機起動確認