Skip to content

Commit 205ab41

Browse files
fhoedemakersclaude
andauthored
Zapper v2 (#216)
* Use a SNES pad's A and B in games, not its B and Y A SNES controller wired to a NES controller port shifts out B and Y where a NES pad has A and B, so those two buttons drove NES A and B while physical A did nothing at all. Every other input names its buttons instead: a USB pad's A reaches NES A through Button::A, and so does a Wii Classic pad's, whose bit0 is A. The GPIO port was the only place where the button that launches a ROM was dead once the game started. Its four face buttons are now named too, using the pad type that nespad_decode() records: physical A drives NES A, physical B drives NES B, and X/Y/L/R are ignored as they are on USB and Wii pads. Rapid fire and the SELECT+START+UP+A bootsel combo follow, since both work on the merged NES word. NES pads and SNES->NES adapter cables that report NES buttons keep the previous mapping, bit for bit. Bumps pico_shared for the matching menu fix, which also carries three earlier commits that had not been recorded here yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add NES Zapper (light gun) support on the custom PCB Reads NES controller port 2's two extra data lines into bits 3 and 4 of $4017, the way a real NES does: D3 (light sensor) on GPIO28, D4 (trigger) on GPIO27, as routed by PCB design v2.1 and later. Enabled for HW_CONFIG 2 only; every other board already uses one or both of those GPIOs, so the feature compiles away there. The levels are sampled inside the $4017 read rather than latched once per frame, because the games measure where in the frame light appears. Only bits 3 and 4 are overlaid, so the pad-2 serial data in bit 0 survives and a controller can share the port with the gun. The bits are deliberately kept out of InfoNES_PadState(), where bit 3 is START and bit 4 is UP and would fire the hotkey combinations on every shot. The light line is inverted in software and the trigger line is not. The NES inverts the light line between the connector and the CPU bus, so $4017 bit 3 reads 0 for "light detected" while the pin is high when the sensor sees light; the PCB wires the port straight to the Pico. Verified on hardware by covering the sensor. Both lines have ZAPPER_INVERT_* build options. Presence is detected automatically and latched sticky, since a Zapper holds its trigger line low while the trigger is released. Also adds two off-by-default diagnostics: ZAPPER_DEBUG (bit mask, 1 = UART trace, 2 = on-screen readout) and ZAPPER_MEASURE, which blacks out the picture, flashes it white and times the light line to measure end-to-end display lag. Both disturb light gun detection and are for bring-up only. Measured on RP2040/picoDVI with a Tomee Zapp Gun: 19-27 ms end-to-end lag, and a single white frame is detected only about half the time while three consecutive frames always are. Known limitation: verified on RP2040/picoDVI. On RP2350/HSTX the patched Duck Hunt menu advances on its own, which is still to be investigated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Update subproject commit reference in pico_lib * Add NES Zapper (light gun) support on the custom PCB Reads NES controller port 2's two extra data lines into bits 3 and 4 of $4017, the way a real NES does: D3 (light sensor) on GPIO28, D4 (trigger) on GPIO27, as routed by PCB design v2.1 and later. Enabled for HW_CONFIG 2 only; every other board already uses one or both of those GPIOs, so the feature compiles away there. The levels are sampled inside the $4017 read rather than latched once per frame, because the games measure where in the frame light appears. Only bits 3 and 4 are overlaid, so the pad-2 serial data in bit 0 survives and a controller can share the port with the gun. The bits are deliberately kept out of InfoNES_PadState(), where bit 3 is START and bit 4 is UP and would fire the hotkey combinations on every shot. The light line is inverted in software and the trigger line is not. The NES inverts the light line between the connector and the CPU bus, so $4017 bit 3 reads 0 for "light detected" while the pin is high when the sensor sees light; the PCB wires the port straight to the Pico. Verified on hardware by covering the sensor. Both lines have ZAPPER_INVERT_* build options. Presence is detected automatically and latched sticky, since a Zapper holds its trigger line low while the trigger is released. Also adds two off-by-default diagnostics. ZAPPER_DEBUG is a bit mask: 1 is a UART trace of the pin levels, how often the game reads $4016/$4017, what it was told, and hardware edge counts on both lines; 2 draws the same on screen. ZAPPER_MEASURE blacks out the picture, flashes it white and times the light line to measure end-to-end display lag. All of them disturb light gun detection and are for bring-up only. Verified on RP2040 with picoDVI and on RP2350 with both HSTX and DVI. Measured on RP2040 with a Tomee Zapp Gun: 19-27 ms end-to-end display lag, and a single white frame is detected only about half the time while three consecutive frames always are - the panel cannot reach full brightness in one frame, which is why screen brightness matters more than anything else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Correct the Zapper D3/D4 pin mapping and note board limitations The PCB routes port 2's D3 (light sensor) to GPIO27 and D4 (trigger) to GPIO28, not the other way round as the PCB README stated. That README was written from the v2.1 silkscreen, which labels the two pads the wrong way round: what is printed as D3 is the physical D4 line and vice versa. Only the printing is affected, so the routing is identical on v2.1 and v2.6 and one firmware default serves both. v2.6 corrects the labels. Swaps the HW_CONFIG 2 defaults to ZAPPER_D3=27 and ZAPPER_D4=28 and updates every place the mapping was documented. Line polarity is unchanged: the macros name the lines by function, so ZAPPER_INVERT_D3 still applies to the light line wherever it lands. Anyone who wired a breadboard the other way can build with -DZAPPER_D3=28 -DZAPPER_D4=27. Also records that the Zapper cannot be used on the Murmulator M1 and M2 boards, whose PCBs leave D3 and D4 of the controller ports unconnected, so the gun's lines never reach the board at all. Verified on a breadboard and on the PCB, on RP2040 with picoDVI and on RP2350 with HSTX. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Update subproject commit reference in pico_lib * Update subproject commit reference in pico_shared * update CHANGELOG * Update README * Update CHANGELOG --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 33e3548 commit 205ab41

13 files changed

Lines changed: 1176 additions & 94 deletions

File tree

CHANGELOG.md

Lines changed: 57 additions & 78 deletions
Large diffs are not rendered by default.

CMakeLists.txt

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ message("* Current build type is : ${CMAKE_BUILD_TYPE}")
4444
# Hardware / board selection (project-specific)
4545
# ---------------------------------------------------------------------------
4646
if(NOT HW_CONFIG)
47-
set(HW_CONFIG 8 CACHE STRING "Select the hardware configuration for your board")
47+
set(HW_CONFIG 2 CACHE STRING "Select the hardware configuration for your board")
4848
endif()
4949

5050
if(NOT USE_HSTX)
@@ -53,8 +53,78 @@ endif()
5353

5454
include("pico_shared/BoardConfigs.cmake")
5555

56+
# ---------------------------------------------------------------------------
57+
# NES Zapper (light gun) on NES controller port 2.
58+
#
59+
# Custom PCB design v2.1 and later route port 2 pin D3 -> GPIO27 (light sensor)
60+
# and pin D4 -> GPIO28 (trigger). Beware the v2.1 silkscreen, which labels these
61+
# two pads the wrong way round; the routing is the same on v2.1 and v2.6 and
62+
# needs no firmware difference. That is HW_CONFIG 2 (Adafruit DVI + SD breakout
63+
# / custom PCB), the only supported configuration. Every other HW_CONFIG gets -1 ("not present"), which compiles
64+
# the feature out entirely -- on most of them GPIO 27/28 are already taken by
65+
# I2S clock pins, NES port 2, DVI/TMDS pairs or the PIO USB DP pin.
66+
#
67+
# Kept here rather than in pico_shared/BoardConfigs.cmake because that file is a
68+
# submodule shared with the other emulators, which have no Zapper support.
69+
#
70+
# Note: this must come after BoardConfigs.cmake, which is where USE_I2S_AUDIO is
71+
# set. Its value is either the string "0" or a driver name, hence STREQUAL.
72+
# ---------------------------------------------------------------------------
73+
# These are plain variables guarded by `if(NOT DEFINED ...)` rather than cache
74+
# entries, so the board-dependent defaults are recomputed on every configure. A
75+
# cache default would be baked into existing build directories and would not
76+
# follow a change made here. An explicit -DZAPPER_...=x on the command line does
77+
# create a cache entry, so DEFINED sees it and the override still wins.
78+
if(NOT DEFINED ZAPPER_D3 AND NOT DEFINED ZAPPER_D4)
79+
if(HW_CONFIG EQUAL 2 AND "${USE_I2S_AUDIO}" STREQUAL "0")
80+
set(ZAPPER_D3 27) # light sensor
81+
set(ZAPPER_D4 28) # trigger
82+
else()
83+
# I2S audio on HW_CONFIG 2 claims GPIO 26 (data) and 27/28 (clock base
84+
# pair), so the Zapper pins have to give way if it is ever enabled there.
85+
set(ZAPPER_D3 -1)
86+
set(ZAPPER_D4 -1)
87+
endif()
88+
endif()
89+
90+
# Line polarity, see zapper.h. The light line arrives inverted with respect to
91+
# the value the NES puts on the bus: measured with a Tomee Zapp Gun, the light
92+
# pin reads low while the sensor is covered and high while it sees light,
93+
# whereas $4017 bit 3 is defined as 0 = light detected. The NES inverts this line
94+
# between the connector and the CPU; a direct GPIO wire does not, so it has to be
95+
# inverted in software. The trigger line needs no such correction.
96+
# Override on the command line if a gun behaves differently, for example:
97+
# cmake -DHW_CONFIG=2 -DZAPPER_INVERT_D3=0 -DZAPPER_DEBUG=1 ..
98+
if(NOT DEFINED ZAPPER_INVERT_D3)
99+
set(ZAPPER_INVERT_D3 1)
100+
endif()
101+
if(NOT DEFINED ZAPPER_INVERT_D4)
102+
set(ZAPPER_INVERT_D4 0)
103+
endif()
104+
if(NOT DEFINED ZAPPER_DEBUG)
105+
set(ZAPPER_DEBUG 0) # bit mask: 1 = UART trace, 2 = on-screen readout
106+
endif()
107+
# Display-lag measurement, see zapper.h. Replaces the picture with a black field
108+
# and periodic white flashes, so it is a measuring instrument, not a play mode.
109+
if(NOT DEFINED ZAPPER_MEASURE)
110+
set(ZAPPER_MEASURE 0)
111+
endif()
112+
if(NOT DEFINED ZAPPER_MEASURE_WHITE)
113+
set(ZAPPER_MEASURE_WHITE 1) # frames of white per flash
114+
endif()
115+
if(ZAPPER_D3 EQUAL -1 OR ZAPPER_D4 EQUAL -1)
116+
message("* Zapper support: disabled for HW_CONFIG ${HW_CONFIG}")
117+
else()
118+
message("* Zapper support: D3 (light) = GPIO${ZAPPER_D3}, D4 (trigger) = GPIO${ZAPPER_D4}, "
119+
"invert D3/D4 = ${ZAPPER_INVERT_D3}/${ZAPPER_INVERT_D4}, debug = ${ZAPPER_DEBUG}, "
120+
"measure = ${ZAPPER_MEASURE}")
121+
if(ZAPPER_MEASURE)
122+
message("* NOTE: ZAPPER_MEASURE replaces the picture with a black/white flash pattern.")
123+
endif()
124+
endif()
125+
56126
if(NOT PICO_BOARD)
57-
set(PICO_BOARD pico2 CACHE STRING "Board type")
127+
set(PICO_BOARD pico CACHE STRING "Board type")
58128
message("PICO_BOARD not set, using default: ${PICO_BOARD}")
59129
endif()
60130

@@ -113,6 +183,7 @@ add_executable(${projectname}
113183
DefaultSS444.c
114184
DefaultSS555.c
115185
state.cpp
186+
zapper.cpp
116187
)
117188

118189
# Optional: embed a NES ROM directly into the firmware.
@@ -185,6 +256,13 @@ target_compile_definitions(${projectname} PRIVATE
185256
NES_PIO_1=${NES_PIO_1}
186257
WII_PIN_SDA=${WII_SDA}
187258
WII_PIN_SCL=${WII_SCL}
259+
ZAPPER_D3=${ZAPPER_D3}
260+
ZAPPER_D4=${ZAPPER_D4}
261+
ZAPPER_INVERT_D3=${ZAPPER_INVERT_D3}
262+
ZAPPER_INVERT_D4=${ZAPPER_INVERT_D4}
263+
ZAPPER_DEBUG=${ZAPPER_DEBUG}
264+
ZAPPER_MEASURE=${ZAPPER_MEASURE}
265+
ZAPPER_MEASURE_WHITE=${ZAPPER_MEASURE_WHITE}
188266
LED_GPIO_PIN=${LED_GPIO_PIN}
189267
HW_CONFIG=${HW_CONFIG}
190268
WIIPAD_I2C=${WIIPAD_I2C}

HISTORY.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,90 @@
11
# History of changes
22

3+
# v0.43
4+
5+
## Audio
6+
7+
- Better audio mixing for NES games.
8+
- Fixed a DC offset on the I2S audio.
9+
- Added an alternative I2S audio driver based on the official pico-extras driver. This is an opt-in build option; the default driver is unchanged.
10+
11+
Special thanks go to [szuping](https://github.com/szuping) for his contribution to the audio fixes.
12+
13+
## Game fixes
14+
15+
- Fixed flickering on the bottom line of the top HUD in *Ganbare Goemon! - Karakuri Douchuu (Japan)*.
16+
17+
## HDMI
18+
19+
- More stable HDMI/DVI output on HSTX-based boards. Some monitors previously lost the picture intermittently and recovered with a visible glitch; the updated signal shape keeps the picture stable.
20+
21+
## Settings menu
22+
23+
- The options list is now scrollable, with up/down arrows when items extend beyond the visible window. SAVE/CANCEL/DEFAULT, the palette, and the help text stay anchored at fixed rows.
24+
- Note: the settings file format was bumped; existing `settings_nes.dat` files will be reset to defaults on first boot.
25+
26+
## Developer
27+
28+
- Added a headless Linux host harness for the InfoNES core, so PPU/CPU/mapper bugs can be reproduced on a PC without flashing a board.
29+
30+
31+
32+
# v0.42
33+
34+
## Features
35+
36+
**Famicom Disk System**
37+
38+
- PSRAM is no longer required to run Famicom Disk System games. The only requirement now is an RP2350-based board.
39+
- BIOS screen now displays correctly.
40+
- Added "FDS Auto Insert Disk 1 on Start" setting. When set to Off, the BIOS animation keeps playing until the user presses Button2 (A) to insert the disk.
41+
42+
**NSF Player**
43+
44+
- Fixed audio clipping.
45+
- Fixed pause/resume: elapsed time is preserved, and the player no longer skips to the next track when resuming.
46+
- Fixed audio delay on PicoDVI boards. Audio now starts in sync with playback right from the first track.
47+
48+
**HDMI**
49+
50+
- Added 8:7 pixel aspect ratio support for HSTX boards.
51+
- Added "Scanline Type" setting (HSTX boards only). Simple darkens odd lines; LCD adds a visible pixel-grid effect by also darkening alternating output columns. LCD is only available in 1:1 screen mode.
52+
- Screen mode and scanline settings now behave consistently across all HDMI boards.
53+
54+
**USB Controllers**
55+
56+
- Added two-player USB controller support. On the Adafruit Fruit Jam, two controllers can be connected directly to the board’s USB ports for multiplayer games.
57+
58+
This feature is confirmed working on the Adafruit Fruit Jam, Raspberry Pi Pico, and Pico 2. For the Raspberry Pi Pico and Pico 2, a USB Y-cable and USB hub are required.
59+
Currently, this does not yet work on the Waveshare RP2350-PiZero.
60+
61+
Other configurations may also work when using a USB hub, but these have not yet been tested.
62+
63+
**Other**
64+
65+
- Added support for mapper 210 [#200](https://github.com/fhoedemakers/pico-infonesPlus/issues/200)
66+
- Test builds (VX.X) now show the build date and time on the splash screen.
67+
- Built against the latest TinyUSB version.
68+
69+
70+
## Fixes
71+
72+
- Fixed external audio (PCM5000A) not working on RP2040 PicoDVI boards when enabled at boot, and resolved an intermittent audio glitch on the same boards.
73+
- Fixed audio distortion during loud sound effects on the Adafruit Fruit Jam.
74+
- Fixed volume imbalance between headphones and speaker on Adafruit Fruit Jam. Headphone volume is now automatically attenuated when headphones are inserted, so the volume control can be set for a comfortable speaker level without blasting headphones.
75+
- Better audio mixing for VRC6 games like Akumajou Densetsu (Castlevania III JP) [#199](https://github.com/fhoedemakers/pico-infonesPlus/issues/199)
76+
- Fixed background jitter in Akumajou Densetsu (Castlevania III JP) during vertical scroll sections. The playfield no longer shifts up and down by a pixel between frames.
77+
- Fixed HUD scroll glitches in Rush'n Attack, Galaxian (JP) and Robocop 3.
78+
- Fixed missing HUD in Alien 3.
79+
- Fixed crash when opening the settings menu.
80+
- Fixed a memory allocation bug in the HDMI driver on HSTX boards that wasted RAM.
81+
- Fixed mapper 19 not working correctly [#200](https://github.com/fhoedemakers/pico-infonesPlus/issues/200)
82+
- Improved display sync and fixed audio clipping on first launch by feeding blank frames.
83+
- Fixed settings menu always showing unsaved changes after the new scanline setting was added.
84+
- Updated the build configuration to be compatible with the latest TinyUSB version. [#202](https://github.com/fhoedemakers/pico-infonesPlus/issues/202) [#203](https://github.com/fhoedemakers/pico-infonesPlus/issues/203)
85+
86+
87+
388
# v0.41
489

590
## Features

PCB/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
> [!NOTE]
22
> The design files in this folder are no longer maintained here. The current PCB release, **pico_nesPCB_v2.6.zip**, and all other gerbers now live in the [PCB folder of the pico_shared repository](https://github.com/fhoedemakers/pico_shared/tree/main/PCB). They are also attached to the [releases](https://github.com/fhoedemakers/pico-infonesPlus/releases/latest) page. The files below are kept for reference only.
33
4-
**pico_nesPCB_v2.1.zip** is identical to v2.0, except that D3 and D4 of NES controller port 2 are mapped to GPIO28 (D3) and GPIO27 (D4). This is intended for possible zapper use, which is currently in beta.
4+
**pico_nesPCB_v2.1.zip** is identical to v2.0, except that D3 and D4 of NES controller port 2 are mapped to **GPIO27 (D3)** and **GPIO28 (D4)**. This is used by the NES Zapper support, which is currently in beta.
5+
6+
> [!NOTE]
7+
> The **v2.1 silkscreen labels these two pads the wrong way round**: what is printed as D3 is the physical D4 line, and what is printed as D4 is the physical D3 line. Only the printing is wrong - the routing is as stated above, and a controller port soldered into the footprint works correctly on both revisions. **v2.6 corrects the labels.** No firmware change is needed for either revision.
58
69
**Gerber_PicoNES_Mini_PCB_v2.0.zip** is for the PicoNES Mini with a Waveshare RP2040/RP2350 Zero board.
710

0 commit comments

Comments
 (0)