mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-26 21:11:54 +01:00
V5.0: Add suport for NeoGeo Pocket
Many thanks to splash5
This commit is contained in:
parent
61ff6cff34
commit
615ef8d68c
@ -2,8 +2,8 @@
|
|||||||
Cartridge Reader for Arduino Mega2560
|
Cartridge Reader for Arduino Mega2560
|
||||||
|
|
||||||
Author: sanni
|
Author: sanni
|
||||||
Date: 20.04.2020
|
Date: 12.05.2020
|
||||||
Version: 4.9
|
Version: 5.0
|
||||||
|
|
||||||
SD lib: https://github.com/greiman/SdFat
|
SD lib: https://github.com/greiman/SdFat
|
||||||
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||||
@ -38,12 +38,12 @@
|
|||||||
rama - code speedup & improvements
|
rama - code speedup & improvements
|
||||||
Gens-gs - Megadrive checksum
|
Gens-gs - Megadrive checksum
|
||||||
Modman - N64 checksum comparison fix
|
Modman - N64 checksum comparison fix
|
||||||
splash5 - EMS GB Smart cart support, Wonderswan module
|
splash5 - EMS GB Smart cart support, Wonderswan module, NGP module
|
||||||
|
|
||||||
**********************************************************************************/
|
**********************************************************************************/
|
||||||
#include <SdFat.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
char ver[5] = "4.9";
|
char ver[5] = "5.0";
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
Options
|
Options
|
||||||
@ -155,6 +155,7 @@ typedef enum COLOR_T {
|
|||||||
#define mode_GB_GBSmart_Flash 19
|
#define mode_GB_GBSmart_Flash 19
|
||||||
#define mode_GB_GBSmart_Game 20
|
#define mode_GB_GBSmart_Game 20
|
||||||
#define mode_WS 21
|
#define mode_WS 21
|
||||||
|
#define mode_NGP 22
|
||||||
|
|
||||||
// optimization-safe nop delay
|
// optimization-safe nop delay
|
||||||
#define NOP __asm__ __volatile__ ("nop\n\t")
|
#define NOP __asm__ __volatile__ ("nop\n\t")
|
||||||
@ -382,9 +383,10 @@ static const char addonsItem1[] PROGMEM = "NES/Famicom";
|
|||||||
static const char addonsItem2[] PROGMEM = "Flashrom Programmer";
|
static const char addonsItem2[] PROGMEM = "Flashrom Programmer";
|
||||||
static const char addonsItem3[] PROGMEM = "PC Engine/TG16";
|
static const char addonsItem3[] PROGMEM = "PC Engine/TG16";
|
||||||
static const char addonsItem4[] PROGMEM = "Sega Master System";
|
static const char addonsItem4[] PROGMEM = "Sega Master System";
|
||||||
static const char addonsItem6[] PROGMEM = "WonderSwan";
|
static const char addonsItem5[] PROGMEM = "WonderSwan";
|
||||||
static const char addonsItem5[] PROGMEM = "Reset";
|
static const char addonsItem6[] PROGMEM = "NeoGeo Pocket";
|
||||||
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem6, addonsItem5};
|
static const char addonsItem7[] PROGMEM = "Reset";
|
||||||
|
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem5, addonsItem6, addonsItem7};
|
||||||
|
|
||||||
// Info Screen
|
// Info Screen
|
||||||
void aboutScreen() {
|
void aboutScreen() {
|
||||||
@ -479,11 +481,11 @@ void mainMenu() {
|
|||||||
|
|
||||||
// Everything that needs an adapter
|
// Everything that needs an adapter
|
||||||
void addonsMenu() {
|
void addonsMenu() {
|
||||||
// create menu with title and 5 options to choose from
|
// create menu with title and 7 options to choose from
|
||||||
unsigned char addonsMenu;
|
unsigned char addonsMenu;
|
||||||
// Copy menuOptions out of progmem
|
// Copy menuOptions out of progmem
|
||||||
convertPgm(addonsOptions, 6);
|
convertPgm(addonsOptions, 7);
|
||||||
addonsMenu = question_box(F("Choose Adapter"), menuOptions, 6, 0);
|
addonsMenu = question_box(F("Choose Adapter"), menuOptions, 7, 0);
|
||||||
|
|
||||||
// wait for user choice to come back from the question box menu
|
// wait for user choice to come back from the question box menu
|
||||||
switch (addonsMenu)
|
switch (addonsMenu)
|
||||||
@ -505,10 +507,20 @@ void addonsMenu() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
|
display_Clear();
|
||||||
|
display_Update();
|
||||||
setup_WS();
|
setup_WS();
|
||||||
|
mode = mode_WS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case 5:
|
||||||
|
display_Clear();
|
||||||
|
display_Update();
|
||||||
|
setup_NGP();
|
||||||
|
mode = mode_NGP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
resetArduino();
|
resetArduino();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1509,6 +1521,9 @@ void loop() {
|
|||||||
else if (mode == mode_WS) {
|
else if (mode == mode_WS) {
|
||||||
wsMenu();
|
wsMenu();
|
||||||
}
|
}
|
||||||
|
else if (mode == mode_NGP) {
|
||||||
|
ngpMenu();
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
display_Clear();
|
display_Clear();
|
||||||
println_Msg(F("Menu Error"));
|
println_Msg(F("Menu Error"));
|
||||||
|
238
Cart_Reader/NGP.ino
Normal file
238
Cart_Reader/NGP.ino
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
//******************************************
|
||||||
|
// NGP MODULE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
static const char ngpMenuItem1[] PROGMEM = "Read Rom";
|
||||||
|
static const char ngpMenuItemReset[] PROGMEM = "Reset";
|
||||||
|
static const char* const menuOptionsNGP[] PROGMEM = {ngpMenuItem1, ngpMenuItemReset};
|
||||||
|
|
||||||
|
char ngpRomVersion[5];
|
||||||
|
|
||||||
|
void setup_NGP() {
|
||||||
|
// A0 - A7
|
||||||
|
DDRF = 0xff;
|
||||||
|
// A8 - A15
|
||||||
|
DDRK = 0xff;
|
||||||
|
// A16 - A20
|
||||||
|
DDRL = 0xff;
|
||||||
|
|
||||||
|
// D0 - D7
|
||||||
|
DDRC = 0x00;
|
||||||
|
|
||||||
|
// controls
|
||||||
|
// /CE0: PH3
|
||||||
|
// /CE1: PH0
|
||||||
|
// /OE: PH6
|
||||||
|
// /WE: PH5
|
||||||
|
// PWR: PH4
|
||||||
|
DDRH |= ((1 << 0) | (1 << 3) | (1 << 5) | (1 << 6));
|
||||||
|
DDRH &= ~(1 << 4);
|
||||||
|
|
||||||
|
PORTH |= ((1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6));
|
||||||
|
|
||||||
|
if (getCartInfo_NGP())
|
||||||
|
{
|
||||||
|
showCartInfo_NGP();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println_Msg(F("NeoGeo Pocket"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Rom Size Error"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngpMenu() {
|
||||||
|
|
||||||
|
uint8_t mainMenu;
|
||||||
|
|
||||||
|
convertPgm(menuOptionsNGP, 2);
|
||||||
|
mainMenu = question_box(F("NGP Menu"), menuOptions, 2, 0);
|
||||||
|
|
||||||
|
switch (mainMenu)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
sd.chdir("/");
|
||||||
|
readROM_NGP(filePath, FILEPATH_LENGTH);
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCartInfo_NGP() {
|
||||||
|
uint8_t *tmp;
|
||||||
|
|
||||||
|
// enter autoselect mode
|
||||||
|
dataOut();
|
||||||
|
writeByte_NGP(0x555, 0xaa);
|
||||||
|
writeByte_NGP(0x2aa, 0x55);
|
||||||
|
writeByte_NGP(0x555, 0x90);
|
||||||
|
|
||||||
|
dataIn();
|
||||||
|
|
||||||
|
cartSize = 0;
|
||||||
|
tmp = (uint8_t*)&romSize;
|
||||||
|
*(tmp + 0) = readByte_NGP(0);
|
||||||
|
*(tmp + 1) = readByte_NGP(1);
|
||||||
|
|
||||||
|
switch (romSize)
|
||||||
|
{
|
||||||
|
case 0x2c98:
|
||||||
|
cartSize = 1048576;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset to read mode
|
||||||
|
dataOut();
|
||||||
|
writeByte_NGP(0x000000, 0xf0);
|
||||||
|
|
||||||
|
if (cartSize == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dataIn();
|
||||||
|
|
||||||
|
for (uint32_t addr = 0; addr < 28; addr++)
|
||||||
|
sdBuffer[addr] = readByte_NGP(addr);
|
||||||
|
|
||||||
|
if (memcmp_P(sdBuffer, PSTR("COPYRIGHT BY SNK CORPORATION"), 28) != 0 && memcmp_P(sdBuffer, PSTR(" LICENSED BY SNK CORPORATION"), 28) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
snprintf(cartID, 5, "%02X%02X", readByte_NGP(0x000021), readByte_NGP(0x000020));
|
||||||
|
snprintf(ngpRomVersion, 5, "%02X%02X", readByte_NGP(0x000023), readByte_NGP(0x000022));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 17; i++)
|
||||||
|
romName[i] = readByte_NGP(0x24 + i);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showCartInfo_NGP() {
|
||||||
|
display_Clear();
|
||||||
|
|
||||||
|
println_Msg(F("NGP Cart Info"));
|
||||||
|
|
||||||
|
print_Msg(F("Game: "));
|
||||||
|
println_Msg(romName);
|
||||||
|
|
||||||
|
print_Msg(F("GameID: "));
|
||||||
|
println_Msg(cartID);
|
||||||
|
|
||||||
|
print_Msg(F("Rom Size: "));
|
||||||
|
print_Msg((cartSize >> 17));
|
||||||
|
println_Msg(F(" Mb"));
|
||||||
|
|
||||||
|
print_Msg(F("Version: "));
|
||||||
|
println_Msg(ngpRomVersion);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readROM_NGP(char *outPathBuf, size_t bufferSize) {
|
||||||
|
// generate fullname of rom file
|
||||||
|
snprintf(fileName, FILENAME_LENGTH, "%s.ngp", romName);
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
snprintf(folder, sizeof(folder), "NGP/ROM/%s/%d", romName, foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
// filling output file path to buffer
|
||||||
|
if (outPathBuf != NULL && bufferSize > 0)
|
||||||
|
snprintf(outPathBuf, bufferSize, "%s/%s", folder, fileName);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT))
|
||||||
|
print_Error(F("Can't create file on SD"), true);
|
||||||
|
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
// back to read mode
|
||||||
|
dataOut();
|
||||||
|
writeByte_NGP(0x0, 0xf0);
|
||||||
|
|
||||||
|
dataIn();
|
||||||
|
for (uint32_t addr = 0; addr < cartSize; addr += 512) {
|
||||||
|
|
||||||
|
// blink LED
|
||||||
|
if ((addr & ((1 << 14) - 1)) == 0)
|
||||||
|
PORTB ^= (1 << 4);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 512; i++)
|
||||||
|
sdBuffer[i] = readByte_NGP(addr + i);
|
||||||
|
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
myFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeByte_NGP(uint32_t addr, uint8_t data) {
|
||||||
|
PORTF = addr & 0xff;
|
||||||
|
PORTK = (addr >> 8) & 0xff;
|
||||||
|
PORTL = (addr >> 16) & 0x1f;
|
||||||
|
PORTC = data;
|
||||||
|
|
||||||
|
// which chip to select
|
||||||
|
// 0x000000 - 0x1fffff -> /CE0
|
||||||
|
// 0x200000 - 0x3fffff -> /CE1
|
||||||
|
data = (addr & 0x00200000 ? (1 << 0) : (1 << 3));
|
||||||
|
|
||||||
|
PORTH &= ~data;
|
||||||
|
PORTH &= ~(1 << 5);
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTH |= data;
|
||||||
|
PORTH |= (1 << 5);
|
||||||
|
NOP; NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readByte_NGP(uint32_t addr) {
|
||||||
|
uint8_t data;
|
||||||
|
|
||||||
|
PORTF = addr & 0xff;
|
||||||
|
PORTK = (addr >> 8) & 0xff;
|
||||||
|
PORTL = (addr >> 16) & 0x1f;
|
||||||
|
|
||||||
|
// which chip to select
|
||||||
|
// 0x000000 - 0x1fffff -> /CE0
|
||||||
|
// 0x200000 - 0x3fffff -> /CE1
|
||||||
|
data = (addr & 0x00200000 ? (1 << 0) : (1 << 3));
|
||||||
|
|
||||||
|
PORTH &= ~data;
|
||||||
|
PORTH &= ~(1 << 6);
|
||||||
|
NOP; NOP; NOP;
|
||||||
|
|
||||||
|
data = PINC;
|
||||||
|
|
||||||
|
PORTH |= data;
|
||||||
|
PORTH |= (1 << 6);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
@ -69,8 +69,6 @@ void setup_WS()
|
|||||||
DDRG &= ~(1 << 5);
|
DDRG &= ~(1 << 5);
|
||||||
PORTG |= (1 << 5);
|
PORTG |= (1 << 5);
|
||||||
|
|
||||||
display_Clear();
|
|
||||||
|
|
||||||
// unlock MMC
|
// unlock MMC
|
||||||
// if (!unlockMMC2003_WS())
|
// if (!unlockMMC2003_WS())
|
||||||
// print_Error(F("Can't initial MMC"), true);
|
// print_Error(F("Can't initial MMC"), true);
|
||||||
@ -78,8 +76,8 @@ void setup_WS()
|
|||||||
// if (getCartInfo_WS() != 0xea)
|
// if (getCartInfo_WS() != 0xea)
|
||||||
// print_Error(F("Rom header read error"), true);
|
// print_Error(F("Rom header read error"), true);
|
||||||
|
|
||||||
display.println("Initializing...");
|
println_Msg(F("Initializing..."));
|
||||||
display.display();
|
display_Update();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
unlockMMC2003_WS();
|
unlockMMC2003_WS();
|
||||||
@ -89,7 +87,6 @@ void setup_WS()
|
|||||||
getCartInfo_WS();
|
getCartInfo_WS();
|
||||||
|
|
||||||
showCartInfo_WS();
|
showCartInfo_WS();
|
||||||
mode = mode_WS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean headerCheck() {
|
boolean headerCheck() {
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
|
|
||||||
![image](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1)
|
![image](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1)
|
||||||
|
|
||||||
|
#### ngp_adapter.zip is an add-on for reading NeoGeo Pocket carts. [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1), this is very important or else it won't fit into the SNES slot.
|
||||||
|
|
||||||
|
![image](https://dl.dropboxusercontent.com/s/yvutwme8n7d4tiy/ngp_adapter.png?dl=1)
|
||||||
|
|
||||||
#### flash_adapter.zip is an add-on for writing flashroms like the 29F032, 29L3211, 29LV160, [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/va1c72073cqfy90/pcb12.jpg?dl=1), this is very important or else it won't fit into the SNES slot.
|
#### flash_adapter.zip is an add-on for writing flashroms like the 29F032, 29L3211, 29LV160, [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/va1c72073cqfy90/pcb12.jpg?dl=1), this is very important or else it won't fit into the SNES slot.
|
||||||
|
|
||||||
![image](https://dl.dropboxusercontent.com/s/afrfmiuwvmvg9px/flash_adapter.png?dl=1)
|
![image](https://dl.dropboxusercontent.com/s/afrfmiuwvmvg9px/flash_adapter.png?dl=1)
|
||||||
|
BIN
pcb/adapters/ngp_adapter.zip
Normal file
BIN
pcb/adapters/ngp_adapter.zip
Normal file
Binary file not shown.
BIN
pcb/adapters/ngp_adapter_schematic.png
Normal file
BIN
pcb/adapters/ngp_adapter_schematic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Loading…
Reference in New Issue
Block a user