Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78527c8fc9 | ||
|
|
84d29789d5 | ||
|
|
f1c4685df7 | ||
|
|
f7d1affeff | ||
|
|
c248d5dd78 | ||
|
|
b3b74fd922 | ||
|
|
f3125a2b0b | ||
|
|
7e7bc68519 | ||
|
|
e14faf7df7 | ||
|
|
b5532392b7 |
@@ -3,3 +3,6 @@ uf2
|
||||
.pio
|
||||
.vscode
|
||||
*_bin.h
|
||||
*.bin
|
||||
*.gb
|
||||
*.gbc
|
||||
|
||||
@@ -1,74 +1,128 @@
|
||||
# About this fork
|
||||
|
||||
This is a fork of [tobigun's fork of the Pico-GB Game Boy emulator](https://github.com/tobigun/Pico-GB). I only changed very few things to make it easy to use for a display addition to Lego's official Game Boy set as I describe it in my blog post at [there.oughta.be/a/lego-game-boy](https://there.oughta.be/a/lego-game-boy).
|
||||
|
||||
My modifications are trivial:
|
||||
* Disable sound and SD card features
|
||||
* Disable input by setting all inputs to the unused GPIO 0
|
||||
* Set display driver and pinout according to the display used in my post (see [there.oughta.be/a/lego-game-boy](https://there.oughta.be/a/lego-game-boy) ).
|
||||
* Change default to stretched scaling
|
||||
* Set the grayscale color palette
|
||||
|
||||
Below is the original readme.
|
||||
|
||||
---
|
||||
|
||||
# RP2040-GB for Pico-GB
|
||||
|
||||
This is a fork of the [RP2040-GB Game Boy (DMG) emulator from deltabeard](https://github.com/deltabeard/RP2040-GB). RP2040-GB is a Game Boy (DMG) emulator Peanut-GB on the Raspberry Pi RP2040 microcontroller, using an ILI9225 screen. Runs at more than 70 fps without audio emulation. With frame skip and interlacing, can run at up to 120 fps.
|
||||
This is a fork of [YouMakeTech's Pico-GB Game Boy emulator](https://github.com/YouMakeTech/Pico-GB) which again is a fork of the [Peanut-GB based RP2040-GB Game Boy (DMG) emulator from deltabeard](https://github.com/deltabeard/Peanut-GB).
|
||||
In addition to YouMakeTech and Deltabeards amazing work, this fork adds some improvements to the emulator like
|
||||
* support for a larger variety of displays by using [Bodmer TFT_eSPI library](https://github.com/Bodmer/TFT_eSPI)
|
||||
* scaling modes that can be toggled with `Select` + `B`. Note that no integer scaling is possible on this low resolution screens. The modes are:
|
||||
* full height with stretching to screen's width. Some columns/lines are doubled in this mode
|
||||
* full height with width scaled to original aspect ratio. Some columns/lines are doubled in this mode
|
||||
* original size (160x144 px, no scaling/stretching)
|
||||
<div style="display: flex; flex-direction: row; margin: 2em">
|
||||
<div style="width: 50%; text-align: center;">
|
||||
<div><img src="doc/mode-scaled-aspect.jpg" height="300" alt="Scaled with correct aspect ratio)"></div>
|
||||
<span>Scaled with correct aspect ratio</span>
|
||||
</div>
|
||||
<div style="width: 50%; text-align: center;">
|
||||
<div><img src="doc/mode-stretched.jpg" height="200" alt="Stretched"></div>
|
||||
<span>Stretched</span>
|
||||
</div>
|
||||
<div style="width: 50%; text-align: center;">
|
||||
<div><img src="doc/mode-original.jpg" height="200" alt="Original size (160x144 px, no scaling/stretching)"></div>
|
||||
<span>Original size (160x144 px, no scaling/stretching)</span>
|
||||
</div>
|
||||
</div>
|
||||
* gamma correction (value hard-coded but changeable in source-code) for color correction of the used display
|
||||
* support for Game Boy Color games, thanks to (froggestspirit's CGB branch of Peanut-GB)[https://github.com/deltabeard/Peanut-GB/tree/cgb] that unfortunately is not merged yet to Peanut-GB main branch
|
||||
<div style="width: 50%; text-align: center;">
|
||||
<div><img src="doc/color.jpg" height="200" alt="Color"></div>
|
||||
</div>
|
||||
* migration to [PlatformIO](https://platformio.org/) for easier development and integration of third-party libraries
|
||||
* support for I2C IO expanders in case you want to use a fast 16-bit LCD display
|
||||
|
||||
This fork includes changes done by me for [Pico-GB](https://www.youmaketech.com/pico-gb-gameboy-emulator-handheld-for-raspberry-pi-pico/):
|
||||
It also includes the changes done by [YouMakeTech](https://github.com/YouMakeTech/Pico-GB):
|
||||
* push buttons support
|
||||
* overclocking to 266MHz for more accurate framerate (~60 FPS)
|
||||
* I2S sound support (44.1kHz 16 bits stereo audio)
|
||||
* SD card support (store roms and save games) + game selection menu
|
||||
* automatic color palette selection for some games (emulation of Game Boy Color Bootstrap ROM) + manual color palette selection
|
||||
|
||||
Pico-GB is a [3d-printed Game Boy emulator handheld gaming console for Raspberry Pi Pico](https://www.youmaketech.com/pico-gb-gameboy-emulator-handheld-for-raspberry-pi-pico/) that ressembles to the original Nintendo Game Boy released in 1989.
|
||||
|
||||
# Videos
|
||||
# Videos by YouMakeTech
|
||||
* [Let's build a Game Boy Emulator on a Breadboard!](https://youtu.be/ThmwXpIsGWs)
|
||||
* [Build the ULTIMATE GameBoy Emulator for Raspberry Pi Pico](https://youtu.be/yauNQSS6nC4)
|
||||
|
||||
# Hardware
|
||||
## What you need
|
||||
* (1x) [Raspberry Pi Pico](https://amzn.to/3rAcmDy)
|
||||
* (1x) [2.2inch ILI9225 176×220 LCD Display Module](https://amzn.to/3aNAMD7)
|
||||
* (1x) [FAT 32 formatted Micro SD card + adapter](https://amzn.to/3ICKzcm) with roms you legally own. Roms must have the .gb extension and must be copied to the root folder.
|
||||
* (1x) [MAX98357A amplifier](https://www.youmaketech.com/max98357)
|
||||
* (1x) [2W 8ohms speaker](https://amzn.to/3ikDy6S)
|
||||
* (8x) [Micro Push Button Switch, Momentary Tactile Tact Touch, 6x6x6 mm, 4 pins](https://amzn.to/3dyXBsx)
|
||||
* (1x) [Solderable Breadboard](https://amzn.to/3lwvfDi)
|
||||
* [Dupont Wires Assorted Kit (Male to Female + Male to Male + Female to Female)](https://amzn.to/3HtbvdO)
|
||||
* [Preformed Breadboard Jumper Wires](https://amzn.to/3rxwVjM)
|
||||
* (1x) Raspberry Pi Pico 2
|
||||
* Note: a Pico 1 should also work as long as you do not want to use GB Color games. As the price difference is so small, I would not recommend to use a Pico 1 for this project
|
||||
* (1x) An LCD screen, e.g. an 2.8" 320x240 ILI9341-based LCD Display Module works nicely.
|
||||
* Note that SPI displays might be too slow at this size. You might be better off with an 8-bit or 16-bit parallel display, where 8-bit might be the perfect tradeoff between speed and number of pins used.
|
||||
* At least you will not be able to use a 16-bit parallel display without an I2C IO expander, e.g. PCF8574.
|
||||
* smaller LCDs like the 176x220 one used in YouMakeTech's original project also work, but I did not implement any scaling for it
|
||||
* larger ones like 480x320 screens should also work. They might be interesting as they allow integer scaling (2x native resolution: 320x288 pixels). No scaling mode was implemented for this so far.
|
||||
* Do yourself a favor and do not use one with an SPI controller as the framerate might be really low. I tried a 3.5" SPI one that was designed for the Raspberry Pi and only got 20 FSP out of it.
|
||||
* 8-bit or 16-bit parallel should be fine and should easily give 60fps (probably 100 FPS without audio enabled).
|
||||
* (1x) SD card reader, like [this one](https://www.androegg.de/shop/esp8266-stm-32-arduino-spi-kartenleser-33v/) - if the LCD board does not already have one built in
|
||||
* (1x) FAT 32 formatted Micro SD card with roms you legally own. Roms must have the .gb or .gbc extension and must be copied to the root folder.
|
||||
* (1x) MAX98357A amplifier
|
||||
* (1x) 2W 8ohms speaker
|
||||
* (8x) Micro Push Button Switch, Momentary Tactile Tact Touch, 6x6x6 mm, 4 pins
|
||||
* (optional - 1x) I2C IO expander (PCF8574) for the buttons if you use a 16-bit parallel LCD
|
||||
* (1x) PCB or Breadboard
|
||||
* Dupont Wires Assorted Kit (Male to Female + Male to Male + Female to Female)
|
||||
* Preformed Breadboard Jumper Wires
|
||||
|
||||
DISCLAIMER: Some links are affiliate links. As an Amazon Associate I receive a small commission (at no extra cost to you) if you make a purchase after clicking one of the affiliate links. Thanks for your support!
|
||||
|
||||
## Setting up the hardware
|
||||
[Pico-GB assembly instructions, circuit diagrams, 3d printed files etc.](https://www.youmaketech.com/pico-gb-gameboy-emulator-handheld-for-raspberry-pi-pico/)
|
||||
Last but not least: you might want a shell.
|
||||
* You might like the one from YouMakeTech: [Pico-GB 3d-printed Game Boy emulator handheld gaming console for Raspberry Pi Pico](https://www.youmaketech.com/pico-gb-gameboy-emulator-handheld-for-raspberry-pi-pico/) that ressembles to the original Nintendo Game Boy released in 1989.
|
||||
* See [Pico-GB assembly instructions, circuit diagrams, 3d printed files etc.](https://www.youmaketech.com/pico-gb-gameboy-emulator-handheld-for-raspberry-pi-pico/)
|
||||
* Or just build your own like I did (I just modified a cheap retro arcade with "homebrew" games)
|
||||
|
||||
# Pinout
|
||||
* UP = GP2
|
||||
* DOWN = GP3
|
||||
* LEFT = GP4
|
||||
* RIGHT = GP5
|
||||
* BUTTON A = GP6
|
||||
* BUTTON B = GP7
|
||||
* SELECT = GP8
|
||||
* START = GP9
|
||||
* SD MISO = GP12
|
||||
* SD CS = GP13
|
||||
* SD CSK = GP14
|
||||
* SD MOSI = GP15
|
||||
* LCD CS = GP17
|
||||
* LCD CLK = GP18
|
||||
* LCD SDI = GP19
|
||||
* LCD RS = GP20
|
||||
* LCD RST = GP21
|
||||
* LCD LED = GP22
|
||||
* MAX98357A DIN = GP26
|
||||
* MAX98357A BCLK = GP27
|
||||
* MAX98357A LRC = GP28
|
||||
You must select your pinout via the tft-espi-config/tft_setup.h (for the display) and common.h (audio, input, sd-card) files.
|
||||
For my 16-bit display with IO expander I use the following pins:
|
||||
|
||||
* I2C IO Expander (PCF8574)
|
||||
* SDA = 20
|
||||
* SCL = 21
|
||||
* UP / DOWN / LEFT / RIGHT / BUTTON A + B / SELECT / START = I2C IO Expander pins 0-7
|
||||
* SD:
|
||||
* CS = GP17
|
||||
* CSK = GP18 (shared with LCD WR)
|
||||
* MOSI = GP19 (shared with LCD DC/RS)
|
||||
* MISO = GP16
|
||||
* LCD (16-bit parallel)
|
||||
* D0-D15 = GP0 - GP15
|
||||
* CS = GP22
|
||||
* DC/RS = GP19 (shared with SD MOSI)
|
||||
* WR = GP18 (shared with SD CSK)
|
||||
* RST = not connected, pull high to 3.3V instead
|
||||
* LED = not connected, connect to 3.3V instead (could be connected to GP25 for PWM, but not implemented yet)
|
||||
* I2S Audio (MAX98357A)
|
||||
* DIN = GP26
|
||||
* BCLK = GP27
|
||||
* LRC = GP28
|
||||
|
||||
As there is no pin left, reading the Display for VSYNC is not possible, so screen tearing might occur.
|
||||
An 8-bit parallel LCD might be better suited for this project.
|
||||
Maybe with 16-bit, the read pin can be shared with SD MISO(?) but at the moment no VSYNC support is enabled so far. The tearing is only visible slightly when the screen scrolls to the left or right.
|
||||
|
||||
# Flashing the firmware
|
||||
* Download RP2040_GB.uf2 from the [releases page](https://github.com/YouMakeTech/Pico-GB/releases)
|
||||
* Push and hold the BOOTSEL button on the Pico, then connect to your computer using a micro USB cable. Release BOOTSEL once the drive RPI-RP2 appears on your computer.
|
||||
* Drag and drop the UF2 file on to the RPI-RP2 drive. The Raspberry Pi Pico will reboot and will now run the emulator.
|
||||
As the project has to be configured to the display you want to use, there is no precompiled binary or UF2. You have to config the project first and then build and flash the firmware on your own with PlatformIO. See the next section.
|
||||
|
||||
# Building from source
|
||||
PlatformIO is required to build this project. It can be installed as an extension to Visual Studio Code.
|
||||
When PlatformIO is installed, just open the project in Visual Studio Code. It should be detected as a PlatformIO project. Now select the "pico2" environment. Then build and flash it.
|
||||
|
||||
# Preparing the SD card
|
||||
The SD card is used to store game roms and save game progress. For this project, you will need a FAT 32 formatted Micro SD card with roms you legally own. Roms must have the .gb extension.
|
||||
|
||||
* Insert your SD card in a Windows computer and format it as FAT 32
|
||||
* Copy your .gb files to the SD card root folder (subfolders are not supported at this time)
|
||||
* Insert the SD card into the ILI9225 SD card slot using a Micro SD adapter
|
||||
|
||||
# Building from source
|
||||
The [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk) is required to build this project. Make sure you are able to compile an [example project](https://github.com/raspberrypi/pico-examples#first--examples) before continuing.
|
||||
* Copy your .gb and/or .gbc files to the SD card root folder (subfolders are not supported at this time)
|
||||
* Insert the SD card into the SD card slot
|
||||
|
||||
# Known issues and limitations
|
||||
* No copyrighted games are included with Pico-GB / RP2040-GB. For this project, you will need a FAT 32 formatted Micro SD card with roms you legally own. Roms must have the .gb extension.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
+174
-351
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -827,10 +827,11 @@ uint8_t __gb_read(struct gb_s *gb, uint16_t addr)
|
||||
case 0x0:
|
||||
/* IO_BOOT is only set to 1 if gb->gb_bootrom_read was not NULL
|
||||
* on reset. */
|
||||
if(gb->hram_io[IO_BOOT] == 0 && addr < 0x0100)
|
||||
{
|
||||
if(gb->hram_io[IO_BOOT] == 0) {
|
||||
if ((gb->cgb.cgbMode && addr < 0x0900) || (!gb->cgb.cgbMode && addr < 0x0100)) {
|
||||
return gb->gb_bootrom_read(gb, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallthrough */
|
||||
case 0x1:
|
||||
|
||||
+3
-2
@@ -25,9 +25,10 @@ build_flags =
|
||||
-I.
|
||||
-Isrc/tft-espi-config
|
||||
-Ilib
|
||||
-DENABLE_SOUND=1
|
||||
-DENABLE_SOUND=0
|
||||
-DENABLE_LCD=1
|
||||
-DENABLE_SDCARD=1
|
||||
-DENABLE_SDCARD=0
|
||||
-DENABLE_INPUT=1
|
||||
-DENABLE_LCD_DMA=1
|
||||
-DENABLE_LCD_FRAMEBUFFER=1
|
||||
-DENABLE_FRAMEBUFFER_FLIP_X_Y=1
|
||||
|
||||
+4
-4
@@ -34,10 +34,10 @@ gpio_function_t UseSDPinFunctionScope::sd_mosi_pin_func = GPIO_FUNC_NULL;
|
||||
bool init_sdcard_hardware() {
|
||||
auto scope = UseSDPinFunctionScope();
|
||||
|
||||
SPI.setMISO(SD_MISO_PIN);
|
||||
SPI.setMOSI(SD_MOSI_PIN);
|
||||
SPI.setSCK(SD_SCK_PIN);
|
||||
bool success = sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50), &SPI));
|
||||
SD_SPI.setMISO(SD_MISO_PIN);
|
||||
SD_SPI.setMOSI(SD_MOSI_PIN);
|
||||
SD_SPI.setSCK(SD_SCK_PIN);
|
||||
bool success = sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50), &SD_SPI));
|
||||
if (success) {
|
||||
UseSDPinFunctionScope::init();
|
||||
}
|
||||
|
||||
+19
-19
@@ -7,9 +7,12 @@
|
||||
#include <SdFat.h>
|
||||
#include "gb.h"
|
||||
|
||||
#define INPUT_GPIO 1
|
||||
#define INPUT_PCF8574 2
|
||||
|
||||
/* Joypad Pins. */
|
||||
#define USE_JOYPAD_I2C_IO_EXPANDER
|
||||
#ifdef USE_JOYPAD_I2C_IO_EXPANDER
|
||||
//#define USE_JOYPAD_I2C_IO_EXPANDER
|
||||
#if ENABLE_INPUT == INPUT_PCF8574
|
||||
// Use PCF8574 for Joypad. Only required if an LCD with 16-bit parallel bus is used,
|
||||
// as Pico does not have enough pins for all peripherals. With 8-bit parallel or SPI LCDs this should not be necessary.
|
||||
#define PCF8574_ADDR 0x20
|
||||
@@ -24,16 +27,16 @@
|
||||
#define PIN_B 4
|
||||
#define PIN_SELECT 6
|
||||
#define PIN_START 7
|
||||
#else
|
||||
#elif ENABLE_INPUT == INPUT_GPIO
|
||||
// Use GPIOs directly on Pico for Joypad
|
||||
#define PIN_UP 2
|
||||
#define PIN_DOWN 3
|
||||
#define PIN_LEFT 4
|
||||
#define PIN_RIGHT 5
|
||||
#define PIN_A 6
|
||||
#define PIN_B 7
|
||||
#define PIN_SELECT 8
|
||||
#define PIN_START 9
|
||||
#define PIN_UP 0
|
||||
#define PIN_DOWN 0
|
||||
#define PIN_LEFT 0
|
||||
#define PIN_RIGHT 0
|
||||
#define PIN_A 0
|
||||
#define PIN_B 0
|
||||
#define PIN_SELECT 0
|
||||
#define PIN_START 0
|
||||
#endif
|
||||
|
||||
#if ENABLE_SOUND
|
||||
@@ -42,10 +45,11 @@
|
||||
#endif
|
||||
|
||||
#if ENABLE_SDCARD
|
||||
#define SD_CS_PIN 17
|
||||
#define SD_SCK_PIN 18
|
||||
#define SD_MOSI_PIN 19
|
||||
#define SD_MISO_PIN 16
|
||||
#define SD_SPI SPI
|
||||
#define SD_CS_PIN 13
|
||||
#define SD_SCK_PIN 14
|
||||
#define SD_MOSI_PIN 15
|
||||
#define SD_MISO_PIN 12
|
||||
|
||||
extern uint8_t _FS_start;
|
||||
extern uint8_t _FS_end;
|
||||
@@ -92,10 +96,6 @@ union core_cmd {
|
||||
uint32_t full;
|
||||
};
|
||||
|
||||
void nextPalette();
|
||||
|
||||
void prevPalette();
|
||||
|
||||
void lcd_init(bool isCore1);
|
||||
void lcd_draw_line(struct gb_s* gb, const uint8_t* pixels, const uint_fast8_t line);
|
||||
|
||||
|
||||
+25
-4
@@ -63,8 +63,29 @@ static void gb_error(struct gb_s* gb, const enum gb_error_e gb_err, const uint16
|
||||
error(String("Error ") + gb_err + " occurred: " + gb_err_str[gb_err] + " at 0x" + String(addr, 16));
|
||||
}
|
||||
|
||||
gb_init_error_e initGbContext() {
|
||||
memcpy(rom_bank0, rom, sizeof(rom_bank0));
|
||||
return gb_init(&gb, &gb_rom_read, &gb_cart_ram_read,
|
||||
&gb_cart_ram_write, &gb_error, NULL);
|
||||
#ifdef USE_BOOT_ROM
|
||||
#include "boot_cgb_bin.h"
|
||||
#include "boot_gb_bin.h"
|
||||
static uint8_t gb_bootrom_read(struct gb_s* gb, const uint_fast16_t addr) {
|
||||
if (gb->cgb.cgbMode) {
|
||||
return CGB_BOOT_ROM[addr];
|
||||
} else {
|
||||
return GB_BOOT_ROM[addr];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void initGbContext() {
|
||||
memcpy(rom_bank0, rom, sizeof(rom_bank0));
|
||||
|
||||
auto ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read, &gb_cart_ram_write, &gb_error, NULL);
|
||||
if (ret != GB_INIT_NO_ERROR) {
|
||||
error(String("Error initializing emulator: ") + ret);
|
||||
}
|
||||
|
||||
#ifdef USE_BOOT_ROM
|
||||
// gb_bootrom_read has to be set after gb_init(), as it sets it to NULL
|
||||
gb_set_bootrom(&gb, &gb_bootrom_read);
|
||||
gb_reset(&gb);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,4 +13,4 @@ extern const uint8_t* rom;
|
||||
#define RAM_SIZE 32768
|
||||
extern uint8_t ram[RAM_SIZE];
|
||||
|
||||
gb_init_error_e initGbContext();
|
||||
void initGbContext();
|
||||
|
||||
+53
-37
@@ -28,6 +28,8 @@ extern i2s_config_t i2s_config;
|
||||
|
||||
extern uint8_t gamma_int;
|
||||
|
||||
static uint8_t palette_selected = 0;
|
||||
|
||||
static struct
|
||||
{
|
||||
unsigned a : 1;
|
||||
@@ -40,7 +42,7 @@ static struct
|
||||
unsigned down : 1;
|
||||
} prev_joypad_bits;
|
||||
|
||||
#ifdef USE_JOYPAD_I2C_IO_EXPANDER
|
||||
#if ENABLE_INPUT == INPUT_PCF8574
|
||||
|
||||
static PCF8574 pcf8574(PCF8574_ADDR, PCF8574_SDA, PCF8574_SCL);
|
||||
|
||||
@@ -61,35 +63,35 @@ bool readJoypad(uint8_t pin) {
|
||||
return pcf8574.digitalRead(pin);
|
||||
}
|
||||
|
||||
#else
|
||||
#elif ENABLE_INPUT == INPUT_GPIO
|
||||
|
||||
static void initJoypadGpios() {
|
||||
gpio_set_function(GPIO_UP, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_DOWN, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_LEFT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_RIGHT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_A, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_B, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_SELECT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_START, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_UP, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_DOWN, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_LEFT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_RIGHT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_A, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_B, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_SELECT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PIN_START, GPIO_FUNC_SIO);
|
||||
|
||||
gpio_set_dir(GPIO_UP, false);
|
||||
gpio_set_dir(GPIO_DOWN, false);
|
||||
gpio_set_dir(GPIO_LEFT, false);
|
||||
gpio_set_dir(GPIO_RIGHT, false);
|
||||
gpio_set_dir(GPIO_A, false);
|
||||
gpio_set_dir(GPIO_B, false);
|
||||
gpio_set_dir(GPIO_SELECT, false);
|
||||
gpio_set_dir(GPIO_START, false);
|
||||
gpio_set_dir(PIN_UP, false);
|
||||
gpio_set_dir(PIN_DOWN, false);
|
||||
gpio_set_dir(PIN_LEFT, false);
|
||||
gpio_set_dir(PIN_RIGHT, false);
|
||||
gpio_set_dir(PIN_A, false);
|
||||
gpio_set_dir(PIN_B, false);
|
||||
gpio_set_dir(PIN_SELECT, false);
|
||||
gpio_set_dir(PIN_START, false);
|
||||
|
||||
gpio_pull_up(GPIO_UP);
|
||||
gpio_pull_up(GPIO_DOWN);
|
||||
gpio_pull_up(GPIO_LEFT);
|
||||
gpio_pull_up(GPIO_RIGHT);
|
||||
gpio_pull_up(GPIO_A);
|
||||
gpio_pull_up(GPIO_B);
|
||||
gpio_pull_up(GPIO_SELECT);
|
||||
gpio_pull_up(GPIO_START);
|
||||
gpio_pull_up(PIN_UP);
|
||||
gpio_pull_up(PIN_DOWN);
|
||||
gpio_pull_up(PIN_LEFT);
|
||||
gpio_pull_up(PIN_RIGHT);
|
||||
gpio_pull_up(PIN_A);
|
||||
gpio_pull_up(PIN_B);
|
||||
gpio_pull_up(PIN_SELECT);
|
||||
gpio_pull_up(PIN_START);
|
||||
}
|
||||
|
||||
bool readJoypad(uint8_t pin) {
|
||||
@@ -100,14 +102,35 @@ bool readJoypad(uint8_t pin) {
|
||||
|
||||
void initJoypad() {
|
||||
Serial.println("Init Joypad IOs ...");
|
||||
#ifdef USE_JOYPAD_I2C_IO_EXPANDER
|
||||
#if ENABLE_INPUT == INPUT_PCF8574
|
||||
initJoypadI2CIoExpander();
|
||||
#else
|
||||
#elif ENABLE_INPUT == INPUT_GPIO
|
||||
initJoypadGpios();
|
||||
#endif
|
||||
Serial.println("Joypad IOs initialized");
|
||||
}
|
||||
|
||||
#define PALETTE_COUNT 15
|
||||
|
||||
void updatePalette() {
|
||||
if (palette_selected == 0) {
|
||||
char rom_title[16];
|
||||
auto_assign_palette(palette, gb_colour_hash(&gb), gb_get_rom_name(&gb, rom_title));
|
||||
} else {
|
||||
manual_assign_palette(palette, palette_selected - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void nextPalette() {
|
||||
palette_selected = (palette_selected + 1) % PALETTE_COUNT;
|
||||
updatePalette();
|
||||
}
|
||||
|
||||
void prevPalette() {
|
||||
palette_selected = (palette_selected + PALETTE_COUNT - 1) % PALETTE_COUNT;
|
||||
updatePalette();
|
||||
}
|
||||
|
||||
void handleSerial() {
|
||||
static uint64_t start_time = time_us_64();
|
||||
|
||||
@@ -208,15 +231,7 @@ void handleJoypad() {
|
||||
prev_joypad_bits.select = gb.direct.joypad_bits.select;
|
||||
prev_joypad_bits.start = gb.direct.joypad_bits.start;
|
||||
|
||||
#if 0
|
||||
Serial.printf("pins:\n");
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
int in = pcf8574.digitalRead(i);
|
||||
Serial.printf(" %d", in);
|
||||
}
|
||||
Serial.printf("\n");
|
||||
#endif
|
||||
|
||||
#if ENABLE_INPUT != 0
|
||||
gb.direct.joypad_bits.up = readJoypad(PIN_UP);
|
||||
gb.direct.joypad_bits.down = readJoypad(PIN_DOWN);
|
||||
gb.direct.joypad_bits.left = readJoypad(PIN_LEFT);
|
||||
@@ -225,6 +240,7 @@ void handleJoypad() {
|
||||
gb.direct.joypad_bits.b = readJoypad(PIN_B);
|
||||
gb.direct.joypad_bits.select = readJoypad(PIN_SELECT);
|
||||
gb.direct.joypad_bits.start = readJoypad(PIN_START);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!gb.direct.joypad_bits.up) {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ static uint8_t scaledLineOffsetTable[LCD_HEIGHT]; // scaled to 240 lines
|
||||
/* Pixel data is stored in here. */
|
||||
static uint8_t pixels_buffer[LCD_WIDTH];
|
||||
|
||||
volatile ScalingMode scalingMode = ScalingMode::STRETCH_KEEP_ASPECT;
|
||||
volatile ScalingMode scalingMode = ScalingMode::STRETCH;
|
||||
|
||||
static int lcd_line_busy = 0;
|
||||
|
||||
|
||||
+3
-19
@@ -53,8 +53,6 @@ uint16_t* stream;
|
||||
i2s_config_t i2s_config;
|
||||
#endif
|
||||
|
||||
static uint8_t manual_palette_selected = 0;
|
||||
|
||||
uint_fast32_t frames = 0;
|
||||
|
||||
void startEmulator() {
|
||||
@@ -66,15 +64,12 @@ void startEmulator() {
|
||||
#endif
|
||||
|
||||
Serial.println("Init GB context ...");
|
||||
auto ret = initGbContext();
|
||||
if (ret != GB_INIT_NO_ERROR) {
|
||||
Serial.printf("Error: %d\n", ret);
|
||||
reset();
|
||||
}
|
||||
initGbContext();
|
||||
|
||||
/* Automatically assign a colour palette to the game */
|
||||
char rom_title[16];
|
||||
auto_assign_palette(palette, gb_colour_hash(&gb), gb_get_rom_name(&gb, rom_title));
|
||||
//auto_assign_palette(palette, gb_colour_hash(&gb), gb_get_rom_name(&gb, rom_title));
|
||||
get_colour_palette(palette, 0x16, 0x00);
|
||||
|
||||
#if ENABLE_LCD
|
||||
gb_init_lcd(&gb, &lcd_draw_line);
|
||||
@@ -170,19 +165,8 @@ void setup() {
|
||||
startEmulator();
|
||||
}
|
||||
|
||||
void nextPalette() {
|
||||
manual_palette_selected = manual_palette_selected < 12 ? manual_palette_selected + 1 : 0;
|
||||
manual_assign_palette(palette, manual_palette_selected);
|
||||
}
|
||||
|
||||
void prevPalette() {
|
||||
manual_palette_selected = manual_palette_selected > 0 ? manual_palette_selected - 1 : 12;
|
||||
manual_assign_palette(palette, manual_palette_selected);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
gb.gb_frame = 0;
|
||||
|
||||
do {
|
||||
__gb_step_cpu(&gb);
|
||||
tight_loop_contents();
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
// Tell the library to use parallel mode (otherwise SPI is assumed)
|
||||
//#define TFT_PARALLEL_8_BIT
|
||||
#define TFT_PARALLEL_16_BIT // **** 16-bit parallel ONLY for RP2040 processor ****
|
||||
//#define TFT_PARALLEL_16_BIT // **** 16-bit parallel ONLY for RP2040 processor ****
|
||||
|
||||
// Only define one driver, the other ones must be commented out
|
||||
#define ILI9341_DRIVER // Generic driver for common displays
|
||||
//#define ILI9341_DRIVER // Generic driver for common displays
|
||||
//#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
|
||||
//#define ST7735_DRIVER // Define additional parameters below for this display
|
||||
//#define ILI9163_DRIVER // Define additional parameters below for this display
|
||||
@@ -35,7 +35,7 @@
|
||||
//#define ILI9481_DRIVER
|
||||
//#define ILI9486_DRIVER
|
||||
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
|
||||
//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
|
||||
#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
|
||||
//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
|
||||
//#define R61581_DRIVER
|
||||
//#define RM68140_DRIVER
|
||||
@@ -100,22 +100,15 @@
|
||||
// driven with a PWM signal or turned OFF/ON then this must be handled by the user
|
||||
// sketch. e.g. with digitalWrite(TFT_BL, LOW);
|
||||
|
||||
// #define TFT_BL 32 // LED back-light control pin
|
||||
// #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
|
||||
#define TFT_BL 14 // LED back-light control pin
|
||||
#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
|
||||
|
||||
#define TFT_D0 0
|
||||
#define TFT_D1 1
|
||||
#define TFT_D2 2
|
||||
#define TFT_D3 3
|
||||
#define TFT_D4 4
|
||||
#define TFT_D5 5
|
||||
#define TFT_D6 6
|
||||
#define TFT_D7 7
|
||||
#define TFT_WR 18 // Write strobe for modified Raspberry Pi TFT only
|
||||
#define TFT_DC 19 // Data Command control pin
|
||||
#define TFT_CS 22 // Chip select control pin D8
|
||||
//#define TFT_RST 22 // Reset pin (could connect to NodeMCU RST, see next line)
|
||||
#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
||||
#define TFT_MOSI 9
|
||||
#define TFT_SCLK 10
|
||||
#define TFT_DC 13 // Data Command control pin
|
||||
#define TFT_CS 11 // Chip select control pin D8
|
||||
#define TFT_RST 12 // Reset pin (could connect to NodeMCU RST, see next line)
|
||||
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
||||
|
||||
// ##################################################################################
|
||||
//
|
||||
@@ -150,7 +143,7 @@
|
||||
// ##################################################################################
|
||||
|
||||
// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
|
||||
//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
|
||||
#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
|
||||
|
||||
// For RP2040 processor and 8 or 16-bit parallel displays:
|
||||
// The parallel interface write cycle period is derived from a division of the CPU clock
|
||||
|
||||
Reference in New Issue
Block a user