Skip to content

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 ピン
1A18D40
2A16D38
3A15D37
4A12D34
5A7D29
6A6D28
7A5D27
8A4D26
9A3D25
10A2D24
11A1D23
12A0D22
13DQ0D42
14DQ1D43
15DQ2D44
16VSSGND
17DQ3D45
18DQ4D46
19DQ5D47
20DQ6D48
21DQ7D49
22/CED50
23A10D32
24/OED51
25A11D33
26A9D31
27A8D30
28A13D35
29A14D36
30A17D39
31/WED52
32VDD5V

規則性: 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 にプルアップしておくとリセット中の誤書き込み保護になる。

セットアップ

  1. ファームウェア書き込み(Arduino IDE でも arduino-cli でも可)

    bash
    brew 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
  2. ホスト側の準備

    bash
    pip install pyserial
  3. ポート名は 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 524288
  • write は既定でチップ消去→書き込み→リードバックベリファイまで自動実行する (消去を飛ばす場合は --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 が読めない時の確認順

idID 0xFF 0xFF UNKNOWNID 0x00 0x00 UNKNOWN を返す場合、 以下の順で切り分ける。

  1. 電源: フラッシュ pin 32 (VDD)–pin 16 (VSS) 間をテスターで実測して 約 5V あるか。ブレッドボードの電源レール分割(中央で分かれているタイプ)に注意。
  2. チップの向き: ノッチ位置を再確認。逆挿しは発熱するので即座に外す。
  3. 制御 3 線: /CE(pin22)→D50、/OE(pin24)→D51、/WE(pin31)→D52 の 3 本を 最優先で確認する。ここが 1 本でも違うと ID は絶対に読めない。
    • 0xFF 0xFF → チップが応答していない(/CE か /OE の配線・電源を疑う)。
    • 0x00 0x00 → バスが駆動されていない/短絡の可能性。
  4. データバス 8 本: DQ0..DQ7(pin13,14,15,17,18,19,20,21)→ D42..D49 の 順序ずれ。ID の値が「毎回同じだが期待値と違う」ならビット順の入れ替わりを疑う (例: 0xBF がビット逆転で 0xFD に見える等)。
  5. アドレスバス: ID コマンドは $5555/$2AAA への書き込みを使うため、 A0..A14 のどれかが違っていてもコマンドが届かず 0xFF になる。 配線表と 1 本ずつ突き合わせる(特に pin 1=A18 / pin 2=A16 / pin 30=A17 / pin 31=/WE の並びは間違えやすい)。
  6. 接触不良: ブレッドボードとジャンパワイヤの品質。チップを軽く押さえながら id を再実行して値が変わるなら接触不良。
  7. チップ自体: 別の個体に差し替えて再確認。3.3V 版の SST39VF040 は 5V では使用不可(ID も読めないか、読めても書けない)。

上記でも解決しない場合は、V コマンド(python3 -c 等でシリアルに直接送信)で ファームウェアが応答するかを確認し、応答がなければ USB ケーブル・ポート名・ ファームウェア書き込み自体を疑う。

実機検証の残タスク

部品到着後にユーザーが実施:

  1. id で ID 読み出し(配線検証)
  2. erasedump で全バイト 0xFF 確認
  3. write <rom>.nes --ines → 自動ベリファイ一致
  4. 書き込んだチップをカートリッジに装着して実機起動確認