Skip to content

Commit 46af956

Browse files
authored
Merge pull request #34 from fhoedemakers/pico_hdmi
Refactor audio handling, fix save state regression, and update changelog
2 parents 39569cd + e9b4e72 commit 46af956

11 files changed

Lines changed: 208 additions & 47 deletions

File tree

CHANGELOG.md

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,93 @@
11
# CHANGELOG
22

3+
> **HSTX replaces PicoDVI** on more boards, **HSTX now has picture and sound over HDMI**, in-game game reset, automatic headphone detection on Fruit Jam, and a save-state crash fix.
4+
35
# General Info
46

7+
58
[Binaries for each configuration and PCB design are at the end of this page](#downloads___).
69

710

811
[See setup section in in Pico-infoNesPlus readme how to install and wire up](https://github.com/fhoedemakers/pico-infonesPlus#pico-setup)
912

10-
# v0.24 Release Notes
13+
# v0.25 Release notes
14+
15+
This release replaces PicoDVI with HSTX on more boards, HSTX now also carries audio over HDMI,
16+
adds smoother on-screen motion, a few new in-game conveniences, and a
17+
handful of fixes that make the emulator more reliable in everyday use.
18+
19+
A huge thank you to [@fliperama86](https://github.com/fliperama86) for the
20+
excellent [pico_hdmi](https://github.com/fliperama86/pico_hdmi) driver that
21+
made the new HDMI output possible, and for all the help along the way.
22+
23+
## What's new
24+
25+
### Video and sound over a single HDMI cable
26+
27+
On the technical side, several RP2350 board configurations have switched
28+
from the **PicoDVI** software-driven video output to **HSTX**, the
29+
RP2350's dedicated High-Speed Serial Transmit hardware (GPIO 12 – 19).
30+
HSTX has been used for video on some boards before, but in this release
31+
it also carries **audio embedded in the HDMI stream** for the first
32+
time — that's the new capability HSTX gains here. (PicoDVI has always
33+
been able to embed audio; HSTX is just catching up on that front while
34+
offloading the work from the CPU to dedicated hardware.)
35+
36+
In practice, on these boards picture and sound now travel together over a
37+
single HDMI cable — no separate audio jack needed:
38+
39+
- Adafruit Fruit Jam
40+
- Murmulator M2
41+
42+
These RP2350 boards have also been switched from PicoDVI to HSTX. They
43+
keep using a separate audio output for now, but picture quality should
44+
look the same and the change frees up CPU cycles for future improvements:
45+
46+
- [Breadboard build](https://github.com/fhoedemakers/pico-infonesPlus?tab=readme-ov-file#raspberry-pi-pico-or-pico-2-setup-with-adafruit-hardware-and-breadboard)
47+
- [PCB build](https://github.com/fhoedemakers/pico-infonesPlus?tab=readme-ov-file#pcb-with-raspberry-pi-pico-or-pico-2)
48+
- [Adafruit Metro RP2350](https://github.com/fhoedemakers/pico-infonesPlus?tab=readme-ov-file#adafruit-metro-rp2350)
49+
50+
All other boards continue to use PicoDVI and work as before.
51+
52+
### Smoother gameplay
53+
54+
Frame timing now follows the display's own refresh signal, which removes
55+
small stutters and gives the picture a more consistent, smooth feel.
56+
57+
### New options and conveniences
58+
59+
- **Reset the running game** from the in-game menu — no need to power-cycle
60+
the device to restart.
61+
- **Enter flashing mode from the settings menu**, so you can update the
62+
firmware without having to unplug the device and hold the BOOTSEL button.
63+
- **Scanline effect for HDMI boards** — turn on the classic CRT scanline
64+
look from the settings menu when running on an HDMI-capable board.
65+
66+
### Adafruit Fruit Jam
67+
68+
- **Automatic headphone detection.** Plug headphones in and the built-in
69+
speaker mutes itself; unplug them and the speaker comes back. The old
70+
manual mute setting and pushbutton-1 mute shortcut have been removed —
71+
they are no longer needed.
1172

1273
## Fixes
1374

14-
- Emulator buffers are now allocated dynmically.
15-
- Pimoroni Pico DV Demo base: Settings are accessible from within the menu again.
16-
- ENding a game will now go back to the menu instead of rebooting the board.
75+
- **Save states work again.** A bug introduced in v0.24 could crash the
76+
emulator when loading a saved game. This is now fixed. Note: save state
77+
files created by earlier v0.25 development builds are not compatible
78+
with this fix and will need to be re-created.
79+
- **Picture-loss recovery.** On the new HSTX output when set to
80+
video-only (DVI) mode, the monitor could occasionally lose the picture.
81+
The emulator now detects this and automatically restores the signal
82+
without needing a restart. (Not observed in full HDMI mode, but the
83+
same safety net is enabled there too just in case.)
84+
- **Screen cropping fix.** A small visual glitch where part of the game
85+
picture was being cut off incorrectly has been corrected.
86+
87+
## Credits
88+
89+
Updated to acknowledge new contributors — see the splash screen on
90+
startup.
1791

1892
# previous changes
1993

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ message("* Current build type is : ${CMAKE_BUILD_TYPE}")
1414

1515

1616
if (NOT HW_CONFIG)
17-
set(HW_CONFIG 1 CACHE STRING "Select the hardware configuration for your board")
17+
set(HW_CONFIG 8 CACHE STRING "Select the hardware configuration for your board")
1818
endif()
1919
if (NOT USE_HSTX)
2020
set(USE_HSTX 1 CACHE STRING "Use HSTX for display output when possible")
2121
endif()
2222
include("pico_shared/BoardConfigs.cmake")
2323
if (NOT PICO_BOARD )
24-
set(PICO_BOARD pico CACHE STRING "Board type")
24+
set(PICO_BOARD pico2 CACHE STRING "Board type")
2525
message("PICO_BOARD not set, using default: ${PICO_BOARD}")
2626
endif()
2727
add_definitions( -DNDEBUG )
@@ -100,6 +100,8 @@ target_compile_definitions(${projectname} PUBLIC
100100
GPIOHSTXINVERTED=${GPIOHSTXINVERTED} # Set to 1 if HSTX pins are inverted: D- = D+ -1
101101
ENABLE_VU_METER=${ENABLE_VU_METER} # Enable VU meter (fruitjam NeoPixel leds)
102102
WIIPAD_DELAYED_START=${WIIPAD_DELAYED_START}
103+
#HSTX_DEBUG=1
104+
ENABLEDVI=1
103105
#PICO_DEBUG_MALLOC=1
104106
)
105107
if(NOT PICO_PLATFORM STREQUAL "rp2040")

HISTORY.md

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

3+
# v0.24 Release Notes
4+
5+
## Fixes
6+
7+
- Emulator buffers are now allocated dynmically.
8+
- Pimoroni Pico DV Demo base: Settings are accessible from within the menu again.
9+
- Ending a game will now go back to the menu instead of rebooting the board.
10+
311
# v0.23 Release Notes
412

513
- Implemented savestates [#140](https://github.com/fhoedemakers/pico-infonesPlus/issues/140)

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ You can organize the roms in directories. A menu is displayed on which you can s
99

1010
Supports two controllers for two player Master System games. [See "about two player games" below for specifics and limitations](#about-two-player-games)
1111

12+
Save and load state possible.
13+
14+
Battery backed saves stored on SD for games that support this.
15+
1216
See the [releases](https://github.com/fhoedemakers/pico-smsplus/releases/latest) page for the supported RP2040/RP2350 boards.
1317

1418
***
@@ -77,6 +81,8 @@ These boards already contain an RP2040 cpu, a separate Raspberry Pi Pico is not
7781
- [Pimoroni Pico Plus 2](https://shop.pimoroni.com/products/pimoroni-pico-plus-2?variant=42092668289107)
7882
Use the breadboard config or Pimoroni Pico DV Demo base. This board does not fit the PCB because of the SP/CE connector on back of the board.
7983
The PSRAM on the board is used in stead of flash to load the roms from SD.
84+
- [Waveshare RP2350-PiZero](https://www.waveshare.com/rp2350-pizero.htm)
85+
8086

8187
## Waveshare RP2040 & RP2350 Zero
8288

main.cpp

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,25 @@ static uint32_t CPUFreqKHz = EMULATOR_CLOCKFREQ_KHZ;
5858
// Order must match enum in menu_options.h
5959
const int8_t g_settings_visibility_sms[MOPT_COUNT] = {
6060
0, // Exit Game, or back to menu. Always visible when in-game.
61+
0, // Reset Game. Always visible when in-game.
6162
0, // Save / Restore State
6263
!HSTX, // Screen Mode (only when not HSTX)
6364
HSTX, // Scanlines toggle (only when HSTX)
6465
1, // FPS Overlay
6566
0, // Audio Enable
6667
0, // Frame Skip
67-
(EXT_AUDIO_IS_ENABLED && !HSTX), // External Audio
68+
(HSTX && ENABLEDVI), // Display Mode HDMI or DVI
69+
(EXT_AUDIO_IS_ENABLED), // External Audio
6870
1, // Font Color
6971
1, // Font Back Color
7072
ENABLE_VU_METER, // VU Meter
71-
(HW_CONFIG == 8), // Fruit Jam Internal Speaker
73+
//(HW_CONFIG == 8), // Fruit Jam Internal Speaker
7274
(HW_CONFIG == 8), // Fruit Jam Volume Control
7375
0, // DMG Palette (SMS/Game Gear emulator does not use GameBoy palettes)
7476
0, // Border Mode (Super Gameboy style borders not applicable for SMS/Game Gear)
7577
0, // Rapid Fire on A
7678
0, // Rapid Fire on B
79+
1 // Enter bootsel mode
7780
};
7881
const uint8_t g_available_screen_modes_sms[] = {
7982
#if PICO_RP2350
@@ -99,7 +102,8 @@ const uint8_t g_available_screen_modes_sms[] = {
99102
#define FPSSTART (((MARGINTOP + 7) / 8) * 8)
100103
#define FPSEND ((FPSSTART) + 8)
101104

102-
bool reset = false;
105+
static bool reset = false;
106+
static bool resetGame = false;
103107

104108
#if WII_PIN_SDA >= 0 and WII_PIN_SCL >= 0
105109
// Cached Wii pad state updated once per frame in ProcessAfterFrameIsRendered()
@@ -289,7 +293,22 @@ static void inline processaudioPerFrameDVI()
289293
written += n;
290294
}
291295
}
292-
#endif // !HSTX
296+
#else // !HSTX
297+
static void inline processaudioPerFrameHSTX() {
298+
for (int i = 0; i < snd.bufsize; i++)
299+
{
300+
short l = snd.buffer[0][i];
301+
short r = snd.buffer[1][i];
302+
hstx_push_audio_sample(l >> 2, r >> 2);
303+
#if ENABLE_VU_METER
304+
if (settings.flags.enableVUMeter)
305+
{
306+
addSampleToVUMeter(l);
307+
}
308+
#endif
309+
}
310+
}
311+
#endif
293312
static void inline processaudioPerFrameI2S()
294313
{
295314
for (int i = 0; i < snd.bufsize; i++)
@@ -479,7 +498,7 @@ extern "C" void in_ram(sms_render_line)(int line, const uint8_t *buffer)
479498
sbuffer = currentLineBuf + 32 + (IS_GG ? 48 : 0);
480499
if (buffer)
481500
{
482-
for (int i = screenCropX + (IS_GG ? 0 : 8); i < BMP_WIDTH - screenCropX; i++)
501+
for (int i = screenCropX ; i < BMP_WIDTH - screenCropX; i++)
483502
{
484503
sbuffer[i - screenCropX] = palette444[(buffer[i + BMP_X_OFFSET]) & 31];
485504
}
@@ -508,7 +527,7 @@ extern "C" void in_ram(sms_render_line)(int line, const uint8_t *buffer)
508527
sbuffer = currentLineBuf + 32 + (IS_GG ? 48 : 0);
509528
if (buffer)
510529
{
511-
for (int i = screenCropX + (IS_GG ? 0 : 8); i < BMP_WIDTH - screenCropX; i++)
530+
for (int i = screenCropX ; i < BMP_WIDTH - screenCropX; i++)
512531
{
513532
sbuffer[i - screenCropX] = palette444[(buffer[i + BMP_X_OFFSET]) & 31];
514533
}
@@ -709,7 +728,9 @@ void loadoverlay()
709728

710729
static inline int ProcessAfterFrameIsRendered()
711730
{
731+
Frens::pollHeadPhoneJack();
712732
Frens::PaceFrames60fps(false);
733+
//Frens::waitForVSync();
713734
#if NES_PIN_CLK != -1
714735
nespad_read_start();
715736
#endif
@@ -767,6 +788,10 @@ static inline int ProcessAfterFrameIsRendered()
767788
loadSaveStateMenu = true;
768789
quickSaveAction = SaveStateTypes::NONE;
769790
}
791+
if ( rval == 5)
792+
{
793+
reset = resetGame = true;
794+
}
770795
loadoverlay();
771796
}
772797
if (loadSaveStateMenu)
@@ -1055,22 +1080,20 @@ void in_ram(process)(void)
10551080
{
10561081
processinput(&pdwPad1, &pdwPad2, &pdwSystem, false, nullptr);
10571082
sms_frame(0);
1058-
#if !HSTX
10591083
#if EXT_AUDIO_IS_ENABLED
1060-
if (settings.flags.useExtAudio == 1)
1084+
if (settings.flags.useExtAudio == 1 || Frens::isHeadPhoneJackConnected())
10611085
{
10621086
processaudioPerFrameI2S();
1063-
}
1064-
else
1087+
} else
1088+
#endif
10651089
{
1090+
#if !HSTX
10661091
processaudioPerFrameDVI();
1067-
}
10681092
#else
1069-
processaudioPerFrameDVI();
1070-
#endif
1071-
#else
1072-
processaudioPerFrameI2S();
1073-
#endif // !HSTX
1093+
1094+
processaudioPerFrameHSTX();
1095+
#endif
1096+
}
10741097
ProcessAfterFrameIsRendered();
10751098
}
10761099
}
@@ -1106,6 +1129,8 @@ int main()
11061129
isFatalError = !Frens::initAll(selectedRom, CPUFreqKHz, MARGINTOP, MARGINBOTTOM, AUDIOBUFFERSIZE, false, true);
11071130
#if !HSTX
11081131
scaleMode8_7_ = Frens::applyScreenMode(settings.screenMode);
1132+
#else
1133+
hstx_setScanLines(settings.flags.scanlineOn);
11091134
#endif
11101135
bool showSplash = true;
11111136
g_settings_visibility = g_settings_visibility_sms;
@@ -1123,7 +1148,7 @@ int main()
11231148
reset = false;
11241149
fileSize = 0;
11251150
isGameGear = false;
1126-
EXT_AUDIO_MUTE_INTERNAL_SPEAKER(settings.flags.fruitJamEnableInternalSpeaker == 0);
1151+
//EXT_AUDIO_MUTE_INTERNAL_SPEAKER(settings.flags.fruitJamEnableInternalSpeaker == 0);
11271152
if (Frens::isPsramEnabled())
11281153
{
11291154
// Detect rom type from memory
@@ -1184,17 +1209,20 @@ int main()
11841209
{
11851210
printf("No auto-save configured for this ROM.\n");
11861211
}
1187-
loadoverlay();
1188-
load_rom(ROM_FILE_ADDR, fileSize, isGameGear);
1189-
// Initialize all systems and power on
1190-
system_init(SMS_AUD_RATE);
1191-
// load state if any
1192-
// system_load_state();
1193-
1194-
system_reset();
1195-
printf("Starting game\n");
1196-
process();
1197-
system_shutdown();
1212+
do {
1213+
reset = resetGame = false;
1214+
loadoverlay();
1215+
load_rom(ROM_FILE_ADDR, fileSize, isGameGear);
1216+
// Initialize all systems and power on
1217+
system_init(SMS_AUD_RATE);
1218+
// load state if any
1219+
// system_load_state();
1220+
system_reset();
1221+
printf("Starting game\n");
1222+
Frens::PaceFrames60fps(true);
1223+
process();
1224+
system_shutdown();
1225+
} while (resetGame);
11981226
selectedRom[0] = 0;
11991227
showSplash = false;
12001228
#if ENABLE_VU_METER

smsplus/loadrom.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ typedef struct
9595

9696
// return 1;
9797
// }
98-
void *frens_f_malloc(size_t size);
9998
int load_rom(uintptr_t addr, int size, bool isGameGear)
10099
{
101100
uint8_t *start = (uint8_t *)addr;
@@ -106,8 +105,6 @@ int load_rom(uintptr_t addr, int size, bool isGameGear)
106105
}
107106
sms.use_fm = 0;
108107
sms.country = TYPE_OVERSEAS;
109-
sms.ram = (uint8 *)frens_f_malloc(RAMSIZEBYTES);
110-
sms.sram = (uint8 *)frens_f_malloc(SRAMSIZEBYTES);
111108
sms.dummy = smsBufferLine;
112109
bitmap.data = smsBufferLine;
113110
bitmap.width = BMP_WIDTH;

smsplus/shared.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ extern "C" {
2929
#define strcasecmp stricmp
3030
#endif
3131
#endif
32-
32+
#if PICO_RP2350
33+
#define in_ram
34+
#endif
3335
#ifndef in_ram
3436
#ifdef PICO_BOARD
3537
#include <pico.h>

0 commit comments

Comments
 (0)