N64のコントローラと通信したい

N64のコントローラと通信したい

December 7, 2022
GameConsole, N64

参考 #

初めの一歩 #

M5Stack(ESP32, 240MHz)で全力で回してみる

なんかいけそうな気がする

setCpuFrequencyMhz(80);するとこんな感じ

1ms周期で何かの割り込みが入ってる(他の優先度高いタスクが動いてる)かで10nsぐらい待たされることがあるみたい

Raspberry Pi Pico + VSCode + PlatformIO on Windows #

  • picotoolでアップロードするにはドライバが必要
    • Using picotoolを参照
    • ZadigでRP2 Boot (Interface 1) (Driverが(NONE)になってる) に対してlibusb-win32WinUSBをインストール
      • WinUSBのほうがよさそう
  • “Unable to connect” in Windows (building with Git for Windows SDK) · Issue #20 · raspberrypi/picotool
  • PlatformIO Core CLIを開いてpio pkg exec -p tool-rp2040tools -c "picotool info"してNo accessible RP2040 devices in BOOTSEL mode were found.が出なければ成功
  • MicroPythonを入れていたPicoだとうまくアップロードできないかも
    • 一度BOOTSELモードにしてPlatformIOでビルドしたバイナリ(.pio/build/pico/firmware.uf2)を転送したらうまくいった

うまくいくとこんな感じでいちいちBOOTSELに切り替えず転送できる(一瞬フォルダが開くが)

Processing pico (platform: raspberrypi; board: pico; framework: arduino)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/raspberrypi/pico.html
PLATFORM: Raspberry Pi RP2040 (1.7.0) > Raspberry Pi Pico
HARDWARE: RP2040 133MHz, 264KB RAM, 2MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, jlink, raspberrypi-swd)
PACKAGES: 
 - framework-arduino-mbed @ 3.1.1 
 - tool-openocd-raspberrypi @ 2.1100.0 (11.0) 
 - tool-rp2040tools @ 1.0.2
 - toolchain-gccarmnoneeabi @ 1.90201.191206 (9.2.1)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 37 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\pico\src\main.cpp.o
Linking .pio\build\pico\firmware.elf
Generating UF2 image
elf2uf2 ".pio\build\pico\firmware.elf" ".pio\build\pico\firmware.uf2"
Checking size .pio\build\pico\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [==        ]  15.1% (used 40696 bytes from 270336 bytes)
Flash: [          ]   0.2% (used 4034 bytes from 2097152 bytes)
Configuring upload protocol...
AVAILABLE: cmsis-dap, jlink, picotool, raspberrypi-swd
CURRENT: upload_protocol = picotool
Looking for upload port...
Auto-detected: COM8
Forcing reset using 1200bps open/close on port COM8
Uploading .pio\build\pico\firmware.elf
rp2040load 1.0.1 - compiled with go1.15.8
.Loading into Flash: [                              ]  0%
Loading into Flash: [=                             ]  5%
Loading into Flash: [===                           ]  11%
Loading into Flash: [====                          ]  16%
Loading into Flash: [======                        ]  22%
Loading into Flash: [========                      ]  28%
Loading into Flash: [=========                     ]  33%
Loading into Flash: [===========                   ]  39%
Loading into Flash: [=============                 ]  44%
Loading into Flash: [===============               ]  50%
Loading into Flash: [================              ]  56%
Loading into Flash: [==================            ]  61%
Loading into Flash: [====================          ]  67%
Loading into Flash: [=====================         ]  72%
Loading into Flash: [=======================       ]  78%
Loading into Flash: [=========================     ]  84%
Loading into Flash: [==========================    ]  89%
Loading into Flash: [============================  ]  95%
Loading into Flash: [==============================]  100%

usec単位あるいはそれ以下のディレイを使って1us幅のパルスを生成するのが難しい

Raspberry Pi Pico + MicroPython + PIOで試してみる #

というかPIO凄くね?

from rp2 import PIO, StateMachine, asm_pio
from machine import Pin

@asm_pio(out_init=PIO.OUT_HIGH, out_shiftdir=PIO.SHIFT_RIGHT, pull_thresh=32)
def blink():
    pull(ifempty)
    out(pins, 1)

sm = StateMachine(0, blink, freq=2000000, out_base=Pin(0))
sm.active(1)
sm.put(0x88888888) # 0001 0001 0001 0001 0001 0001 0001 0001
sm.put(0xfffffffe) # 0111 1111 1111 1111 1111 1111 1111 1111
#sm.active(0)

while True:
    pass

Command 0x00 + Console Stop Bitを送っているつもり

良い感じでは?

コントローラを繋いでみるとなんとなくアンサー返してくれているような雰囲気

0000 0101 0000 0000 0000 0010 Identifier(0x0500)とCRC(たぶん)0x02: No Pak installed

とりあえずキー入力がなんとなく見えるやつを作った Communicate with N64 Controller using Raspberry Pi Pico with MicroPython

64GBパック(Transfer Pak)と通信したい #

概略 #

  • 実際にJoyBus経由で送るコマンドのアドレスは下位5ビットをチェックコードにして送る
  • 以下はチェックコード抜きのアドレス表記で記載
  • 8000h: FEhでパワーオフ、84hでパワーオン
  • B000h: 01hを書く 読むと89hが返ってくる(最初だけ8Dhのときがある) カートリッジ未挿入だと00h
  • A000h: Pakのバンク切り替え(読み/書き)
    • 00h: PakのC000h-FFFFhはGBの0000h-3FFFhにマップされる
    • 01h: PakのC000h-FFFFhはGBの4000h-7FFFhにマップされる
    • 02h: PakのC000h-FFFFhはGBの8000h-BFFFhにマップされる
    • 03h: PakのC000h-FFFFhはGBのC000h-FFFFhにマップされる (ROMの読み書きでは通常使わないはず)
  • C000h-FFFFh: 上記のとおり

GBメモリカートリッジとのやりとり #

Pak経由での読み書きは32バイト単位だが、GBメモリ固有のレジスタ(ここではNPレジスタと呼びます)の有効化(0120h-013Fhへの書き込み)は未使用部分を0にしてあげれば可能(0以外は未確認)

# CMD_09h: Wakeup
self.write_gbaddr(0x0120, [
    0x09, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5,
])

Flashコマンドの送信(5555h=AAh, 2AAAh=55h, 5555h=cmdのシーケンス)は上記32バイト単位での書き込みだと不可なので NPレジスタ経由で行う

# CMD_0Fh: Write Byte
self.write_gbaddr(0x0120, [
    0x0f, 0x00, 0x00, 0x00, 0x00, hiaddr, loaddr, cmd,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5,
])

Flashへのデータ書き込みは以下の手順で可能

  • MBCレジスタを無効化(CMD_10h)した状態で0000h-007Fhに128バイト(32×4)書き込む
  • MBCレジスタを有効化(CMD_11h)して書き込み先のバンクに切り替えた後
  • CMD_0FhでROMの書き込み先アドレス+7Fhに対してFFhを書く