diff --git a/CHANGELOG.md b/CHANGELOG.md index 5607aba..757940a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,21 @@ Binaries for each configuration are at the end of this page. # Release notes +## v0.13 + +Features: + +- Two player games can now be played. An extra NES controller port can be added to any configuration. Controller port 1 can be a USB or NES controller, controller 2 must be a NES controller. At the moment, no second USB controller can be connected. + +Fixes: + +- none + +Technical changes: + +- Pimoroni Pico DV Demo Base: uart output fore debug printf messages is disabled, because gpio1 is needed for the seconc NES controller port. + + ## v0.12 Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ee8152..9e5a607 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ if (NOT INFONES_PLUS_HW_CONFIG) set(INFONES_PLUS_HW_CONFIG 1 CACHE STRING "Select the hardware configuration for your board") endif() if ( INFONES_PLUS_HW_CONFIG EQUAL 1 ) - # This default Config is for Pimoroni Pico DV Demo Base + # This default Config is for Pimoroni Pico DV Demo Base, note uart is disabled because gpio 1 is used for NES controller set(DVICONFIG "dviConfig_PimoroniDemoDVSock" CACHE STRING "Select a default pin configuration from common_dvi_pin_configs.h") set(LED_GPIO_PIN "25" CACHE STRING "Select the GPIO pin for LED") @@ -72,11 +72,17 @@ if ( INFONES_PLUS_HW_CONFIG EQUAL 1 ) set(NES_CLK "14" CACHE STRING "Select the Clock GPIO pin for NES controller") set(NES_DATA "15" CACHE STRING "Select the Data GPIO pin for NES controller") set(NES_LAT "16" CACHE STRING "Select the Latch GPIO pin for NES controller") + set(NES_PIO "pio0" CACHE STRING "Select the PIO for NES controller") + set(NES_CLK_1 "1" CACHE STRING "Select the Clock GPIO pin for second NES controller") + set(NES_DATA_1 "21" CACHE STRING "Select the Data GPIO pin for second NES controller") + set(NES_LAT_1 "20" CACHE STRING "Select the Latch GPIO pin for second NES controller") + set(NES_PIO_1 "pio1" CACHE STRING "Select the PIO for second NES controller") set(WII_SDA "-1" CACHE STRING "Select the SDA GPIO pin for Wii Classic controller") set(WII_SCL "-1" CACHE STRING "Select the SCL GPIO pin for Wii Classic controller") elseif ( INFONES_PLUS_HW_CONFIG EQUAL 2 ) # -------------------------------------------------------------------- # Alternate config for use with different SDcard reader and HDMI board + # Use also for Printed Circuit Board (PCB) version. # -------------------------------------------------------------------- # Adafruit DVI Breakout For HDMI Source Devices https://www.adafruit.com/product/4984 set(DVICONFIG "dviConfig_PicoDVISock" CACHE STRING @@ -90,6 +96,11 @@ elseif ( INFONES_PLUS_HW_CONFIG EQUAL 2 ) set(NES_CLK "6" CACHE STRING "Select the Clock GPIO pin for NES controller") set(NES_DATA "7" CACHE STRING "Select the Data GPIO pin for NES controller") set(NES_LAT "8" CACHE STRING "Select the Latch GPIO pin for NES controller") + set(NES_PIO "pio0" CACHE STRING "Select the PIO for NES controller") + set(NES_CLK_1 "9" CACHE STRING "Select the Clock GPIO pin for second NES controller") + set(NES_DATA_1 "10" CACHE STRING "Select the Data GPIO pin for second NES controller") + set(NES_LAT_1 "11" CACHE STRING "Select the Latch GPIO pin for second NES controller") + set(NES_PIO_1 "pio1" CACHE STRING "Select the PIO for second NES controller") set(WII_SDA "-1" CACHE STRING "Select the SDA GPIO pin for Wii Classic controller") set(WII_SCL "-1" CACHE STRING "Select the SCL GPIO pin for Wii Classic controller") elseif ( INFONES_PLUS_HW_CONFIG EQUAL 3 ) @@ -106,6 +117,11 @@ elseif ( INFONES_PLUS_HW_CONFIG EQUAL 3 ) set(NES_CLK "5" CACHE STRING "Select the Clock GPIO pin for NES controller") set(NES_DATA "6" CACHE STRING "Select the Data GPIO pin for NES controller") set(NES_LAT "9" CACHE STRING "Select the Latch GPIO pin for NES controller") + set(NES_PIO "pio0" CACHE STRING "Select the PIO for NES controller") + set(NES_CLK_1 "26" CACHE STRING "Select the Clock GPIO pin for second NES controller") + set(NES_DATA_1 "28" CACHE STRING "Select the Data GPIO pin for second NES controller") + set(NES_LAT_1 "27" CACHE STRING "Select the Latch GPIO pin for second NES controller") + set(NES_PIO_1 "pio1" CACHE STRING "Select the PIO for second NES controller") set(WII_SDA "2" CACHE STRING "Select the SDA GPIO pin for Wii Classic controller") set(WII_SCL "3" CACHE STRING "Select the SCL GPIO pin for Wii Classic controller") elseif ( INFONES_PLUS_HW_CONFIG EQUAL 4 ) @@ -122,22 +138,32 @@ elseif ( INFONES_PLUS_HW_CONFIG EQUAL 4 ) set(NES_CLK "5" CACHE STRING "Select the Clock GPIO pin for NES controller") set(NES_DATA "6" CACHE STRING "Select the Data GPIO pin for NES controller") set(NES_LAT "9" CACHE STRING "Select the Latch GPIO pin for NES controller") + set(NES_PIO "pio0" CACHE STRING "Select the PIO for NES controller") + set(NES_CLK_1 "10" CACHE STRING "Select the Clock GPIO pin for second NES controller") + set(NES_DATA_1 "12" CACHE STRING "Select the Data GPIO pin for second NES controller") + set(NES_LAT_1 "11" CACHE STRING "Select the Latch GPIO pin for second NES controller") + set(NES_PIO_1 "pio1" CACHE STRING "Select the PIO for second NES controller") set(WII_SDA "-1" CACHE STRING "Select the SDA GPIO pin for Wii Classic controller") set(WII_SCL "-1" CACHE STRING "Select the SCL GPIO pin for Wii Classic controller") endif ( ) # -------------------------------------------------------------------- -message("HDMI board type : ${DVICONFIG}") -message("SD card CS : ${SD_CS}") -message("SD card SCK : ${SD_SCK}") -message("SD card MOSI : ${SD_MOSI}") -message("SD card MISO : ${SD_MISO}") -message("NES controller CLK : ${NES_CLK}") -message("NES controller DATA : ${NES_DATA}") -message("NES controller LAT : ${NES_LAT}") -message("Wii controller SDA : ${WII_SDA}") -message("Wii controller SCL : ${WII_SCL}") -message("LED pin : ${LED_GPIO_PIN}") +message("HDMI board type : ${DVICONFIG}") +message("SD card CS : ${SD_CS}") +message("SD card SCK : ${SD_SCK}") +message("SD card MOSI : ${SD_MOSI}") +message("SD card MISO : ${SD_MISO}") +message("NES controller 0 CLK : ${NES_CLK}") +message("NES controller 0 DATA : ${NES_DATA}") +message("NES controller 0 LAT : ${NES_LAT}") +message("NES controller 0 PIO : ${NES_PIO}") +message("NES controller 1 CLK : ${NES_CLK_1}") +message("NES controller 1 DATA : ${NES_DATA_1}") +message("NES controller 1 LAT : ${NES_LAT_1}") +message("NES controller 1 PIO : ${NES_PIO_1}") +message("Wii controller SDA : ${WII_SDA}") +message("Wii controller SCL : ${WII_SCL}") +message("LED pin : ${LED_GPIO_PIN}") add_executable(piconesPlus main.cpp @@ -154,7 +180,15 @@ add_executable(piconesPlus pico_set_program_name(piconesPlus "piconesPlus") pico_set_program_version(piconesPlus "0.8") -pico_enable_stdio_uart(piconesPlus 1) +# disable uart output for Pimoronis Pico DV Demo Base, as gpio 1 is used for NES controller +# so debug messages will not be visible on the serial console. +if ( INFONES_PLUS_HW_CONFIG EQUAL 1 ) + message("Disabling UART output for Pimoroni Pico DV Demo Base") + pico_enable_stdio_uart(piconesPlus 0) +else() + pico_enable_stdio_uart(piconesPlus 1) +endif() + pico_enable_stdio_usb(piconesPlus 0) # tinyusb @@ -171,10 +205,15 @@ target_compile_definitions(piconesPlus PRIVATE SDCARD_PIN_SPI0_MOSI=${SD_MOSI} SDCARD_PIN_SPI0_MISO=${SD_MISO} SDCARD_PIO=pio1 - SDCARD_PIO_SM=0 +# SDCARD_PIO_SM=1 # Let the driver decide what state machine to use. NES_PIN_CLK=${NES_CLK} NES_PIN_DATA=${NES_DATA} NES_PIN_LAT=${NES_LAT} + NES_PIO=${NES_PIO} + NES_PIN_CLK_1=${NES_CLK_1} + NES_PIN_DATA_1=${NES_DATA_1} + NES_PIN_LAT_1=${NES_LAT_1} + NES_PIO_1=${NES_PIO_1} WII_PIN_SDA=${WII_SDA} WII_PIN_SCL=${WII_SCL} LED_GPIO_PIN=${LED_GPIO_PIN} diff --git a/README.md b/README.md index 748707e..6b3a0f6 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # pico-infonesPlus. -> [A more comprehensive guide from Adafruit can be found here](https://learn.adafruit.com/nes-emulator-for-rp2040-dvi-boards) +## Introduction + A NES (Nintendo Entertainment System) emulator for RP2040 based microcontrollers with SD card and menu support. Uses HDMI for display. -> There is also an emulator port for the Sega Master System/Sega Game Gear. You can find it here [https://github.com/fhoedemakers/pico-smsplus](https://github.com/fhoedemakers/pico-smsplus) +Supports two controllers for two player games. [See "about two player games" below for specifics and limitations](#about-two-player-games) The emulator used is [Infones by Jay Kumogata](https://github.com/jay-kumogata/InfoNES) which was ported to the [Raspberry Pi Pico by Shuichi Takano](https://github.com/shuichitakano/pico-infones) with changes done by me to accomodate the SD card menu. @@ -12,6 +13,21 @@ In stead of flashing a NES rom to the Pico using picotool, you create a FAT32 fo A menu is added to the emulator, which reads the roms from the SD card and shows them on screen for the user to select, flash and play. +[See also the Adafruit guide](https://learn.adafruit.com/nes-emulator-for-rp2040-dvi-boards) although it is somewhat outdated now. (No two player) + +> There is also an emulator port for the Sega Master System/Sega Game Gear. You can find it here [https://github.com/fhoedemakers/pico-smsplus](https://github.com/fhoedemakers/pico-smsplus) + +*** + +## Video +Click on image below to see a demo video. + +[![Video](https://img.youtube.com/vi/OEcpNMNzZCQ/0.jpg)](https://www.youtube.com/watch?v=OEcpNMNzZCQ) + +*** + +## Possible configurations + You can use it with these RP2040 boards and configurations: - Raspberry Pi Pico. Requires one of these addons: @@ -37,6 +53,8 @@ You can use it with these RP2040 boards and configurations: [See below to see how to setup your specific configuration.](#Setup) +*** + ## Gamecontroller support Depending on the hardware configuration, the emulator supports these gamecontrollers: @@ -46,8 +64,8 @@ Depending on the hardware configuration, the emulator supports these gamecontrol - Sony Dual Sense - BUFFALO BGC-FC801 connected to USB - not tested - Legacy Controllers - - An original NES controller. Requires soldering when using Pico DV Demo Base. - - An original SNES controller. PCB Only + - One or optional two original NES controllers. Requires soldering when using Pico DV Demo Base or Printed Circuit Board. + - An original SNES controller. PCB Only. Connects to controller port 1. - WII-classic controller. Breadboard only. Not tested - should work - Adafruit Feather RP2040 with DVI (HDMI) - USB controllers @@ -55,7 +73,7 @@ Depending on the hardware configuration, the emulator supports these gamecontrol - Sony Dual Sense - BUFFALO BGC-FC801 connected to USB - not tested - Legacy Controllers - - An original NES controller. + - One or optional two original NES controllers. - WII-classic controller. - Waveshare RP2040-PiZero Development Board - USB controllers @@ -63,26 +81,33 @@ Depending on the hardware configuration, the emulator supports these gamecontrol - Sony Dual Sense - BUFFALO BGC-FC801 connected to USB - not tested - Legacy Controllers - - An original NES controller. + - One or optional two original NES controllers. -When using Legacy Controllers, you need these additional items: - * NES Controller +When using Legacy Controllers, you can choose between: + * NES Controller. (Second controller port and controller is optional and only needed if you want to play two player games) * [NES controller port](https://www.zedlabz.com/products/controller-connector-port-for-nintendo-nes-console-7-pin-90-degree-replacement-2-pack-black-zedlabz) * [An original NES controller](https://www.amazon.com/s?k=NES+controller&crid=1CX7W9NQQDF8H&sprefix=nes+controller%2Caps%2C174&ref=nb_sb_noss_1) - * SNES Controller (PCB only) + * SNES Controller (PCB only, connects to controller port 1) * [SNES controller port](https://www.zedlabz.com/products/zedlabz-7-pin-90-degree-female-controller-connector-port-for-nintendo-snes-console-2-pack-grey) - * [An original SNES controller](https://www.amazon.com/s?k=original+snes+controller&sprefix=original+SNES+%2Caps%2C174&ref=nb_sb_ss_ts-doa-p_1_14) + * [An original SNES controller](https://www.amazon.com/s?k=original+snes+controller&sprefix=original+SNES+%2Caps%2C174&ref=nb_sb_ss_ts-doa-p_1_14). + * WII-Classic controller * [Adafruit Wii Nunchuck Breakout Adapter - Qwiic / STEMMA QT](https://www.adafruit.com/product/4836) * [Adafruit STEMMA QT / Qwiic JST SH 4-pin Cable](https://www.adafruit.com/product/4210) * [WII Classic wired controller](https://www.amazon.com/Classic-Controller-Nintendo-Wii-Remote-Console/dp/B0BYNHWS1V/ref=sr_1_1_sspa?crid=1I66OX5L05507&keywords=Wired+WII+Classic+controller&qid=1688119981&sprefix=wired+wii+classic+controller%2Caps%2C150&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1) - -## Video -Click on image below to see a demo video. -[![Video](https://img.youtube.com/vi/OEcpNMNzZCQ/0.jpg)](https://www.youtube.com/watch?v=OEcpNMNzZCQ) +*** + +## About two player games +The emulator supports two player games using two NES controllers or an USB gamecontroller and a NES controller connected to controller port of player 2. The USB controller is always player 1. +> [!NOTE] +> You cannot use two USB controllers for two player mode. +> At the moment only one USB controller is recognized by the driver. +> The second controller must be a NES controller. In this config the NES controller port must be wired up to the GPIO pins of player 2. See configurations below. + +*** ## Warning Repeatedly flashing your Pico will eventually wear out the flash memory. @@ -93,6 +118,8 @@ Use this software at your own risk! I will not be responsible in any way for any I also do not take responsability in any way when damage is caused to the Pico or display due to incorrect wiring or voltages. +*** + # Setup Click on the link below for your specific board configuration: @@ -102,6 +129,9 @@ Click on the link below for your specific board configuration: - [Adafruit Feather RP2040 with DVI (HDMI) Output Port setup](#adafruit-feather-rp2040-with-dvi-hdmi-output-port-setup) - [Waveshare RP2040-PiZero Development Board](#waveshare-rp2040-pizero-development-board) - [Printed Circuit Board with Raspberry Pi Pico](#pcb-with-raspberry-pi-pico) +- [3D printed case](#3d-printed-case-one-player-only) + +*** ## Raspberry Pi Pico, setup for Pimoroni Pico DV Demo Base. @@ -114,6 +144,7 @@ Click on the link below for your specific board configuration: - NES Controller: - [NES controller port](https://www.zedlabz.com/products/controller-connector-port-for-nintendo-nes-console-7-pin-90-degree-replacement-2-pack-black-zedlabz). Requires soldering. - [An original NES controller](https://www.amazon.com/s?k=NES+controller&crid=1CX7W9NQQDF8H&sprefix=nes+controller%2Caps%2C174&ref=nb_sb_noss_1) + - Optional: A sconde NES controller port and controller if you want to play two player games. - [Dupont wires](https://a.co/d/cJVmnQO) - [Mail or female headers to be soldered on the board](https://a.co/d/dSNPuyo) - HDMI Cable. @@ -130,17 +161,26 @@ Click on the link below for your specific board configuration: ### Pinout -#### NES controller port (if you want to use a NES controller). +#### NES controller port(s) (if you want to use legacy NES controllers). -> Note: This requires soldering! -| Port | GPIO | Pin number | -| ------------- | ---- | ---------- | -| GND | | GND on base | -| VCC (Power) | | 3V3 on base | -| NES Clock | GP14 | 19 | -| NES LATCH | GP16 | 21 | -| NES Data | GP15 | 20 | +| | Port 1 | Port 2 (optional) |Note | +| ------------- | ------------- | ------------- | ----------- | +| GND | | | GND (- on board) | +| VCC (Power) | | | Connect to 3V3 | +| NES Clock | GPIO14 | GPIO1 | | +| NES LATCH | GPIO16 | GPIO20 | | +| NES Data | GPIO15 | GPIO21 | | + +> [!NOTE] +> Soldering is required. +> There is only one 3v3 pin header on the board, the other 3V3 must be soldered directly onto pin 36 (3V3 OUT) of the Pico. +> For GND there are two pin headers available on the board. +> Clock Data and Latch for controller one must be soldered directly onto the Pico. +> The Clock, Data and Latch for the second controller can be soldered on the available pin headers on the board, no need to solder them directly onto the Pico. + +![PinHeadersPimoroniDV](https://github.com/user-attachments/assets/4e2ee8e1-13dd-44d6-a5a0-908771872c11) + ![Image](assets/nes-controller-pinout.png) @@ -151,13 +191,31 @@ Click on the link below for your specific board configuration: - Connect the usb OTG cable to the Pico's usb port. - Depending which controller you want to use: - Connect the controller to the other end of the usb OTG. - - Connect legacy NES controller to NES controller port. + - Connect legacy NES controller(s) to NES controller port(s). - Insert the SD card into the SD card slot. -- Connect the usb power adapter to the usb port of the Demo base. +- Connect the usb power adapter to the usb port of the Demo base. (USB POWER) - Power on the monitor and the Pico +### Image: Usb controller only + ![Image](assets/PicoInfoNesPlusPimoroni.jpeg) +### Image: two player setup, usb controller and NES controller port + +USB controller is player 1, NES controller is player two and must be wired to controller port 2. + +![Image](assets/2plpimoronidv.png) + +### Image: Two player setup using NES controllers +(You can also connect an USB controller and a NES controller to port 2) + +Controller Port 1 pins must be soldered directly onto the Pico + +Controller Port 2 pins can be soldered to the available headers of the Pimoroni DV. + +TODO + +*** ## Raspberry Pi Pico, setup with Adafruit hardware and breadboard @@ -198,42 +256,42 @@ Use the breadboard to connect all together: #### Adafruit Micro-SD breakout board+ -| Breakout | GPIO | Pin number | +| Breakout | GPIO | Note | | ------------- | ------ | -------------- | -| CS | GP5 | 7 | -| CLK (SCK) | GP2 | 4 | -| DI (MOSI) | GP3 | 5 | -| DO (MISO) | GP4 | 6 | -| 3V | | 36 (3v3 OUT) | +| CS | GPIO5 | | +| CLK (SCK) | GPIO2 | | +| DI (MOSI) | GPIO3 | | +| DO (MISO) | GPIO4 | | +| 3V | | Pin 36 (3v3 OUT) | | GND | | Ground on breadboard (-) | #### Adafruit DVI Breakout For HDMI Source Devices -| Breakout | GPIO | Pin number | +| Breakout | GPIO | Note| | ------------- | ---- | ---------- | -| D0+ | GP12 | 16 | -| D0- | GP13 | 17 | -| CK+ | GP14 | 19 | -| CK- | GP15 | 20 | -| D2+ | GP16 | 21 | -| D2- | GP17 | 22 | -| D1+ | GP18 | 24 | -| D1- | GP19 | 25 | -| 5 (*) | VBUS | 40 (5volt) | +| D0+ | GPIO12 | | +| D0- | GPIO13 | | +| CK+ | GPIO14 | | +| CK- | GPIO15 | | +| D2+ | GPIO16 | | +| D2- | GPIO17 | | +| D1+ | GPIO18 | | +| D1- | GPIO19 | | +| 5 (*) | VBUS | Pin 40 (5volt) | | GND (3x) | | Ground on breadboard (-) | (*) This is the via on the side of the board marked 5. (next to via D and C). ![Image](assets/DVIBreakout.jpg) -#### NES controller port. (If you want to use a NES controller) -| Port | GPIO | Pin number | -| ------------- | ---- | ---------- | -| GND | | Ground on breadboard (-) | -| VCC (Power) | | 36 (3v3 OUT) | -| NES Clock | GP6 | 9 | -| NES LATCH | GP8 | 11 | -| NES Data | GP7 | 10 | +#### NES controller port(s). (if you want to use legacy NES controllers). +| | Port1 | Port 2 (optional) | Note | +| ------------- | ---- | -------- |---------- | +| GND | | | |Ground on breadboard (-) | +| VCC (Power) | | |(3v3 OUT) | +| NES Clock | GPIO6 | GPIO9 | | +| NES LATCH | GPIO8 | GPIO11 | | +| NES Data | GPIO7 | GPIO10 | | ![Image](assets/nes-controller-pinout.png) @@ -251,11 +309,27 @@ Use the breadboard to connect all together: - Power on the monitor and the Pico See image below. -> Note. The Shotky Diode (VSYS - Pin 39 to breadboard + column) and the wire on breadboard left (+) to right (+) are not necessary, but recommended when powering the Pico from a Raspberry Pi. -[See Chapter 4.6 - Powering the Board of the Raspberry Pi Pico Getting Started guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf) + +> [!NOTE] +> The Shotky Diode (VSYS - Pin 39 to breadboard + column) and the wire on breadboard left (+) to right (+) are not necessary, but recommended when powering the Pico from a Raspberry Pi. +> [See Chapter 4.6 - Powering the Board of the Raspberry Pi Pico Getting Started guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf) + +### Image: One player setup only + +USB controller and NES controller ar both player 1 ![Image](assets/PicoBreadBoard.jpg) +### Image: Two player setup using NES controllers +(You can also connect an USB controller and a NES controller to port 2) + +> [!NOTE] +> The device on the left is a Pico Debug probe used for debugging. This is optional + +![Image](assets/2plpicobreadb.png) + +*** + ## Adafruit Feather RP2040 with DVI (HDMI) Output Port setup ### materials needed @@ -311,10 +385,10 @@ Use the breadboard to connect all together: | Breakout | GPIO | | | ------------- | ------ | -------------- | -| CS | GP10 | | -| CLK (SCK) | GP14 | | -| DI (MOSI) | GP15 | | -| DO (MISO) | GP8 | | +| CS | GPIO10 | | +| CLK (SCK) | GPIO14 | | +| DI (MOSI) | GPIO15 | | +| DO (MISO) | GPIO8 | | | 3V | | + column on breadboard connected to feather 3.3V pin | | GND | | - column on breadboard connected to feather ground pin| @@ -322,14 +396,15 @@ Use the breadboard to connect all together: Connect the nunchuck breakout adapter to the Feather DVI using the STEMMA QT cable. -#### NES controller port. -| Port | GPIO | | -| ------------- | ---- | ---------- | -| GND | | - column on breadboard connected to feather ground pin | -| VCC (Power) | | + column on breadboard connected to feather 3.3V pin | -| NES Clock | 5 | | -| NES LATCH | 9 | | -| NES Data | 6 | | +#### NES controller port(s). (if you want to use legacy NES controllers). + +| | Port 1 | Port 2 (optional) | Note | +| ------------- | ---- | ------ | ---------- | +| GND | | | - column on breadboard connected to feather ground pin | +| VCC (Power) | | | + column on breadboard connected to feather 3.3V pin | +| NES Clock | GPIO5 | GPIO26 | | +| NES LATCH | GPIO9 | GPIO27 | | +| NES Data | GPIO6 | GPIO28 | | ![Image](assets/nes-controller-pinout.png) @@ -351,8 +426,20 @@ Connect the nunchuck breakout adapter to the Feather DVI using the STEMMA QT cab * Connect the Micro usb power adapter to the female Micro usb connecter of the OTG Y-Cable. - Power on the monitor and the Pico +### Image: One player setup only + +USB, NES and WII-Classic are player 1 + ![Image](assets/featherDVI.jpg) +### Image: Two player setup using NES controllers + +(You can also connect an USB controller and a NES controller to port 2) + +![Image](assets/2plfeatherdv.png) + +*** + ## Waveshare RP2040-PiZero Development Board ### materials needed @@ -364,6 +451,7 @@ Connect the nunchuck breakout adapter to the Feather DVI using the STEMMA QT cab - [Mini HDMI to HDMI Cable](https://a.co/d/5BZg3Z6). - FAT 32 formatted Micro SD card with roms you legally own. Roms must have the .nes extension. You can organise your roms into different folders. +> [!NOTE] > When using an USB controller, connect the controller and the power adapter to the Y cable. Connect the Y-cable to the port on the board labelled USB. I do not recommend powering the board via the PIO-USB port. This caused some weird behaviour. #### NES controller port. @@ -374,15 +462,19 @@ When using a original NES controller you need: - [An original NES controller](https://www.amazon.com/s?k=NES+controller&crid=1CX7W9NQQDF8H&sprefix=nes+controller%2Caps%2C174&ref=nb_sb_noss_1) - [Dupont female to female wires](https://a.co/d/cJVmnQO) -| Port | GPIO | | -| ------------- | ---- | ---------- | -| GND | | Any ground pin | -| VCC (Power) | | 5Volt pin | -| NES Clock | 5 | | -| NES LATCH | 9 | | -| NES Data | 6 | | +For two player games you need an extra NES controller port, controller and wire + + +| | Port 1 | Port 2 (Optional) | Note | +| ------------- | ---- | ----- | ---------- | +| GND | | | Any ground pin | +| VCC (Power) | | | 5Volt pin | +| NES Clock | GPIO5 | GPIO10 | | +| NES LATCH | GPIO9 | GPIO11| | +| NES Data | GPIO6 | GPIO12| | -> Note: Contrary to other configurations where VCC is connected to 3Volt, VCC should be connected to a 5Volt pin. Otherwise the NES controller could possibly not work. +> [!NOTE] +> Contrary to other configurations where VCC is connected to 3Volt, VCC should be connected to a 5Volt pin. Otherwise the NES controller could possibly not work. ![Image](assets/nes-controller-pinout.png) @@ -396,10 +488,22 @@ When using a original NES controller you need: > Note: When the emulator won't start and the screen shows "No signal", press the run button once again. The emulator will now boot. +### Image: One player setup only + +USB and NES are player 1 + ![Image](assets/WaveShareRP2040_1.jpg) ![Image](assets/WaveShareRP2040_2.jpg) +### Image: Two player setup using NES controllers + +(You can also connect an USB controller and a NES controller to port 2) + +![Image](assets/2plwsrp2040.png) + +*** + ## PCB with Raspberry Pi Pico > Note: Soldering skills are required. @@ -407,6 +511,9 @@ When using a original NES controller you need: Create your own little Pico Based NES console and play with an orginal (S)NES controller. The PCB design files can be found in the [assets/pcb](https://github.com/fhoedemakers/pico-infonesPlus/tree/main/assets/pcb) folder. Several Companies can make these PCBs for you. +> [!NOTE] +> The pcb is not designed for a second NES controller port for player 2, but the second port can be added without much hassle. You need to solder the gpio pins directly on to the Pico. + I personally recommend [PCBWay](https://www.pcbway.com/). The boards i ordered from them are of excellent quality. [![Image](assets/pcbw.png)](https://www.pcbway.com/) @@ -423,23 +530,53 @@ Other materials needed: * NES Controller * [NES controller port](https://www.zedlabz.com/products/controller-connector-port-for-nintendo-nes-console-7-pin-90-degree-replacement-2-pack-black-zedlabz) * [An original NES controller](https://www.amazon.com/s?k=NES+controller&crid=1CX7W9NQQDF8H&sprefix=nes+controller%2Caps%2C174&ref=nb_sb_noss_1) - * SNES Controller + * SNES Controller (This connects to player 1) * [SNES controller port](https://www.zedlabz.com/products/zedlabz-7-pin-90-degree-female-controller-connector-port-for-nintendo-snes-console-2-pack-grey). * [An original SNES controller](https://www.amazon.com/s?k=original+snes+controller&sprefix=original+SNES+%2Caps%2C174&ref=nb_sb_ss_ts-doa-p_1_14) +- (Optional) a second NES controller and controller port if you want to play two player games. - [Micro usb to OTG Y-Cable](https://a.co/d/b9t11rl) if you want to use a Dualshock/Dualsense controller. - Micro USB power supply. +For two player setup you need an extra NES controller port. You must solder the GPIO connections directly onto the pico. + +| | Port 2 (Optional) | Note | +| ------------- | ---- | ---------- | +| GND | | ground via on PCB | +| VCC (Power) | | VCC via on PCB | +| NES Clock | GPIO9 | | +| NES LATCH | GPIO11| | +| NES Data | GPIO10| | + Flash the Pico with **piconesPlusAdaFruitDVISD.uf2** from the [releases page](https://github.com/fhoedemakers/pico-infonesPlus/releases/latest). + +### Image: One player setup only + +NES, SNES and USB controller are alle player 1 + ![Image](assets/picones.jpg) -[DynaMight1124](https://github.com/DynaMight1124) designed a NES-like case you can 3d-print as enclosure for this pcb. [Click here for the design](https://www.thingiverse.com/thing:6689537). Please contact the creator on his thingiverse page if you have any questions about this case. +### Image: Two player setup using NES controllers + +(You can also connect an USB controller and a NES controller to port 2) + +clock, data and latch soldered directly on the Pico. Ground and vcc soldered on the pcb. + +![Todo](assets/2plpcb.png) + +### 3D printed case (One player only) + +[DynaMight1124](https://github.com/DynaMight1124) designed a NES-like case you can 3d-print as enclosure for this pcb. This enclosure is suitable for one NES controller port. [Click here for the design](https://www.thingiverse.com/thing:6689537). Please contact the creator on his thingiverse page if you have any questions about this case. ![image](assets/3d1.jpg) ![image](assets/3d2.jpg) -## Menu Usage + +*** + + +# Menu Usage Gamepad buttons: - UP/DOWN: Next/previous item in the menu. - LEFT/RIGHT: next/previous page. @@ -447,23 +584,29 @@ Gamepad buttons: - B (X): Back to parent folder. - START: Starts game currently loaded in flash. -## Emulator (in game) +# Emulator (in game) Gamepad buttons: - SELECT + START: Resets back to the SD Card menu. Game saves are saved to the SD card. - SELECT + UP/SELECT + DOWN: switches screen modes. - SELECT + A/B: toggle rapid-fire. - START + A : Toggle framerate display -## Save games +*** + +# Save games For games which support it, saves will be stored in the /SAVES folder of the SD card. Caution: the save ram will only be saved back to the SD card when quitting the game via (START + SELECT) -## Raspberry Pico W support +*** + +# Raspberry Pico W support The emulator works with the Pico W, but without the onboard blinking led. In order for the led to work on the Pico W, the cyw43 driver needs to be initialised. This causes the emulator to stop with an out of memory panic. -## USB game Controllers latency +*** + +# USB game Controllers latency Using a USB gamecontroller introduces some latency. The legacy controllers ((S)NES, WII-classic) have less latency. -## Troubleshooting no image on TV or monitor +# Troubleshooting no image on TV or monitor - Make sure the board is directly connected to your display. Do not connect through a HDMI splitter. - Some displays need 5V in order to work: @@ -471,13 +614,17 @@ Using a USB gamecontroller introduces some latency. The legacy controllers ((S)N ![Image](assets/DVIBreakout.jpg) -## Known Issues and limitations +*** + +# Known Issues and limitations - Pimoroni Pico DV: Audio through the audio out jack is not supported, audio only works over hdmi. - Due to the Pico's memory limitations, not all games will work. Games not working will show a "Mapper n is unsupported." (n is a number). For example starting Castlevania III will show the "Mapper 5 is unsupported." message. - tar file support is removed. - Pico W: The onboard led does not blink every 60 frames. -## Building from source +*** + +# Building from source Best is to use the included build script [buildAll.sh](buildAll.sh). You can then copy the correct .uf2 to your Pico via the bootsel option. The script builds three .uf2 files and puts them in the releases folder. @@ -485,12 +632,15 @@ Best is to use the included build script [buildAll.sh](buildAll.sh). You can the git clone https://github.com/fhoedemakers/pico-infonesPlus.git cd pico-infonesPlus git submodule update --init +chmod +x build*.sh ./buildAll.sh ``` -When using Visual Studio code, choose the Release or the Debug build variant. +When using Visual Studio code, choose the Release or the RelWithDebuginfo build variant. -## Credits +*** + +# Credits InfoNes is programmed by [Jay Kumogata](https://github.com/jay-kumogata/InfoNES) and ported to the Raspberry Pi Pico by [Shuichi Takano](https://github.com/shuichitakano/pico-infones). I contributed by adding SD card and menu support. For this reasons I made code changes to the emulator for accommodating the menu and SD card. @@ -503,7 +653,9 @@ WII-Classic controller support by [PaintYourDragon](https://github.com/PaintYour Adafruit Feather DVI - RP2040 support by [PaintYourDragon](https://github.com/PaintYourDragon) & [Adafruit](https://github.com/adafruit). -## Other versions +*** + +# Other versions [There is also a version available for the Pimoroni PicoSystem handheld](https://github.com/fhoedemakers/PicoSystem_InfoNes). ![Image](https://github.com/fhoedemakers/PicoSystem_InfoNes/blob/master/assets/gamescreen.jpeg) diff --git a/assets/2plfeatherdv.png b/assets/2plfeatherdv.png new file mode 100644 index 0000000..e184eaf Binary files /dev/null and b/assets/2plfeatherdv.png differ diff --git a/assets/2plpcb.png b/assets/2plpcb.png new file mode 100644 index 0000000..fdd8404 Binary files /dev/null and b/assets/2plpcb.png differ diff --git a/assets/2plpicobreadb.png b/assets/2plpicobreadb.png new file mode 100644 index 0000000..6a93ae8 Binary files /dev/null and b/assets/2plpicobreadb.png differ diff --git a/assets/2plpimoronidv.png b/assets/2plpimoronidv.png new file mode 100644 index 0000000..f3ecfd1 Binary files /dev/null and b/assets/2plpimoronidv.png differ diff --git a/assets/2plwsrp2040.png b/assets/2plwsrp2040.png new file mode 100644 index 0000000..338333d Binary files /dev/null and b/assets/2plwsrp2040.png differ diff --git a/assets/PinHeadersPimoroniDV.png b/assets/PinHeadersPimoroniDV.png new file mode 100644 index 0000000..f23d38c Binary files /dev/null and b/assets/PinHeadersPimoroniDV.png differ diff --git a/drivers/sdcard/sdcard.c b/drivers/sdcard/sdcard.c index 754a82f..2fce082 100644 --- a/drivers/sdcard/sdcard.c +++ b/drivers/sdcard/sdcard.c @@ -13,7 +13,7 @@ #include "ff.h" #include "diskio.h" - +#include /*-------------------------------------------------------------------------- @@ -62,7 +62,7 @@ BYTE CardType; /* Card type flags */ #ifdef SDCARD_PIO pio_spi_inst_t pio_spi = { .pio = SDCARD_PIO, - .sm = SDCARD_PIO_SM + .sm = -1 // SDCARD_PIO_SM }; #endif @@ -164,6 +164,8 @@ void init_spi(void) int cpol = 0; int cpha = 0; uint cpha0_prog_offs = pio_add_program(pio_spi.pio, &spi_cpha0_program); + // Let the driver decide which state machine to use, and claim it. + pio_spi.sm = pio_claim_unused_sm(pio_spi.pio, true); pio_spi_init(pio_spi.pio, pio_spi.sm, cpha0_prog_offs, 8, // 8 bits per SPI frame diff --git a/main.cpp b/main.cpp index b9a10b3..067e2d2 100644 --- a/main.cpp +++ b/main.cpp @@ -376,11 +376,12 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) (gp.buttons & io::GamePadState::Button::SELECT ? SELECT : 0) | (gp.buttons & io::GamePadState::Button::START ? START : 0) | 0; - if (i == 0) - { #if NES_PIN_CLK != -1 - v |= nespad_state; + v |= nespad_states[i]; #endif + if (i == 0) + { + #if WII_PIN_SDA >= 0 and WII_PIN_SCL >= 0 v |= wiipad_read(); #endif @@ -1018,7 +1019,10 @@ int main() applyScreenMode(settings.screenMode); #if NES_PIN_CLK != -1 - nespad_begin(CPUFreqKHz, NES_PIN_CLK, NES_PIN_DATA, NES_PIN_LAT); + nespad_begin(0, CPUFreqKHz, NES_PIN_CLK, NES_PIN_DATA, NES_PIN_LAT, NES_PIO); +#endif +#if NES_PIN_CLK_1 != -1 + nespad_begin(1, CPUFreqKHz, NES_PIN_CLK_1, NES_PIN_DATA_1, NES_PIN_LAT_1, NES_PIO_1); #endif #if WII_PIN_SDA >= 0 and WII_PIN_SCL >= 0 wiipad_begin(); diff --git a/menu.cpp b/menu.cpp index 7901289..3e9c1e9 100644 --- a/menu.cpp +++ b/menu.cpp @@ -96,7 +96,10 @@ void RomSelect_PadState(DWORD *pdwPad1, bool ignorepushed = false) (gp.buttons & io::GamePadState::Button::Y ? Y : 0) | 0; #if NES_PIN_CLK != -1 - v |= nespad_state; + v |= nespad_states[0]; +#endif +#if NES_PIN_CLK_1 != -1 + v |= nespad_states[1]; #endif #if WII_PIN_SDA >= 0 and WII_PIN_SCL >= 0 v |= wiipad_read(); diff --git a/nespad.cpp b/nespad.cpp index 922f785..ba08f03 100644 --- a/nespad.cpp +++ b/nespad.cpp @@ -21,47 +21,58 @@ static const struct pio_program nespad_program = { .origin = -1, }; -static inline pio_sm_config nespad_program_get_default_config(uint offset) { +static inline pio_sm_config nespad_program_get_default_config(uint offset) +{ pio_sm_config c = pio_get_default_sm_config(); sm_config_set_wrap(&c, offset + nespad_wrap_target, offset + nespad_wrap); sm_config_set_sideset(&c, 1, false, false); return c; } -static PIO pio = pio0; -static uint8_t sm = -1; +static PIO pio[2]; +static int8_t sm[2] = {-1, -1}; +static bool second_pad = false; +uint8_t nespad_states[2] = {0, 0}; uint8_t nespad_state = 0; - -bool nespad_begin(uint32_t cpu_khz, uint8_t clkPin, uint8_t dataPin, - uint8_t latPin) { - if (pio_can_add_program(pio, &nespad_program) && - ((sm = pio_claim_unused_sm(pio, true)) >= 0)) { - uint offset = pio_add_program(pio, &nespad_program); +bool nespad_begin(uint8_t padnum, uint32_t cpu_khz, uint8_t clkPin, uint8_t dataPin, + uint8_t latPin, PIO _pio) +{ + if (padnum > 1) { + return false; // Only 2 pads supported + } + if ( padnum == 1 ) { + second_pad = true; + } + pio[padnum] = _pio; + if (pio_can_add_program(pio[padnum], &nespad_program) && + ((sm[padnum] = pio_claim_unused_sm(pio[padnum], true)) >= 0)) + { + uint offset = pio_add_program(pio[padnum], &nespad_program); pio_sm_config c = nespad_program_get_default_config(offset); sm_config_set_sideset_pins(&c, clkPin); sm_config_set_in_pins(&c, dataPin); sm_config_set_set_pins(&c, latPin, 1); - pio_gpio_init(pio, clkPin); - pio_gpio_init(pio, dataPin); - pio_gpio_init(pio, latPin); + pio_gpio_init(pio[padnum], clkPin); + pio_gpio_init(pio[padnum], dataPin); + pio_gpio_init(pio[padnum], latPin); gpio_set_pulls(dataPin, true, false); // Pull data high, 0xFF if unplugged - pio_sm_set_pindirs_with_mask(pio, sm, + pio_sm_set_pindirs_with_mask(pio[padnum], sm[padnum], (1 << clkPin) | (1 << latPin), // Outputs (1 << clkPin) | (1 << dataPin) | (1 << latPin)); // All pins - sm_config_set_in_shift(&c, true, true, 8); // R shift, autopush @ 8 bits + sm_config_set_in_shift(&c, true, true, 8); // R shift, autopush @ 8 bits sm_config_set_clkdiv_int_frac(&c, cpu_khz / 1000, 0); // 1 MHz clock // IRQ is just a 'go' flag, don't assert a system interrupt pio_set_irq0_source_enabled( - pio, (pio_interrupt_source)(pis_interrupt0 + sm), false); + pio[padnum], (pio_interrupt_source)(pis_interrupt0 + sm[padnum]), false); - pio_sm_clear_fifos(pio, sm); + pio_sm_clear_fifos(pio[padnum], sm[padnum]); - pio_sm_init(pio, sm, offset, &c); - pio_sm_set_enabled(pio, sm, true); + pio_sm_init(pio[padnum], sm[padnum], offset, &c); + pio_sm_set_enabled(pio[padnum], sm[padnum], true); return true; // Success } @@ -70,7 +81,7 @@ bool nespad_begin(uint32_t cpu_khz, uint8_t clkPin, uint8_t dataPin, // Initiate nespad read. Non-blocking; result will be available in ~100 uS // via nespad_read_finish(). Must first call nespad_begin() once to set up PIO. -void nespad_read_start(void) { pio_interrupt_clear(pio, 0); } +void nespad_read_start(void) { pio_interrupt_clear(pio[0], 0); if ( second_pad ) { pio_interrupt_clear(pio[1], 0);}} // Finish nespad read. Ideally should be called ~100 uS after // nespad_read_start(), but can be sooner (will block until ready), or later @@ -79,8 +90,14 @@ void nespad_read_start(void) { pio_interrupt_clear(pio, 0); } // 0x04=Down, 0x08=Up, 0x10=Start, 0x20=Select, 0x40=B, 0x80=A. Must first // call nespad_begin() once to set up PIO. Result will be 0 if PIO failed to // init (e.g. no free state machine). -void nespad_read_finish(void) { +void nespad_read_finish(void) +{ // Right-shift was used in sm config so bit order matches NES controller // bits used elsewhere in picones, but does require shifting down... - nespad_state = (sm >= 0) ? ((pio_sm_get_blocking(pio, sm) >> 24) ^ 0xFF) : 0; + nespad_states[0] = (sm[0] >= 0) ? ((pio_sm_get_blocking(pio[0], sm[0]) >> 24) ^ 0xFF) : 0; + if (second_pad) { + nespad_states[1] = (sm[1] >= 0) ? ((pio_sm_get_blocking(pio[1], sm[1]) >> 24) ^ 0xFF) : 0; + } else { + nespad_states[1] = 0; + } } diff --git a/nespad.h b/nespad.h index 6934b7b..779ba73 100644 --- a/nespad.h +++ b/nespad.h @@ -1,8 +1,10 @@ #pragma once -extern uint8_t nespad_state; +#include "hardware/pio.h" -extern bool nespad_begin(uint32_t cpu_khz, uint8_t clkPin, uint8_t dataPin, - uint8_t latPin); +//extern uint8_t nespad_state; +extern uint8_t nespad_states[2]; +extern bool nespad_begin(uint8_t padnum, uint32_t cpu_khz, uint8_t clkPin, uint8_t dataPin, + uint8_t latPin, PIO _pio); extern void nespad_read_start(void); extern void nespad_read_finish(void);