V5.5: Reduce memory usage in Filebrowser

This commit is contained in:
sanni 2020-10-28 18:44:13 +01:00
parent 6ffd175e7b
commit 9eca87d975
9 changed files with 935 additions and 926 deletions

View File

@ -1,16 +1,17 @@
/********************************************************************************** /**********************************************************************************
Cartridge Reader for Arduino Mega2560 Cartridge Reader for Arduino Mega2560
Author: sanni Date: 28.10.2020
Date: 06.07.2020 Version: 5.5
Version: 5.4
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
Clockgen: https://github.com/etherkit/Si5351Arduino GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library
BusIO: https://github.com/adafruit/Adafruit_BusIO
RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools
SI5351 lib: https://github.com/etherkit/Si5351Arduino
Compiled with Arduino 1.8.12 Compiled with Arduino 1.8.13
Thanks to: Thanks to:
MichlK - ROM-Reader for Super Nintendo MichlK - ROM-Reader for Super Nintendo
@ -42,7 +43,7 @@
**********************************************************************************/ **********************************************************************************/
#include <SdFat.h> #include <SdFat.h>
char ver[5] = "5.4"; char ver[5] = "5.5";
#include "options.h" #include "options.h"
@ -192,7 +193,7 @@ boolean ignoreError = 0;
// File browser // File browser
#define FILENAME_LENGTH 32 #define FILENAME_LENGTH 32
#define FILEPATH_LENGTH 64 #define FILEPATH_LENGTH 64
#define FILEOPTS_LENGTH 20 #define FILEOPTS_LENGTH 18
char fileName[FILENAME_LENGTH]; char fileName[FILENAME_LENGTH];
char filePath[FILEPATH_LENGTH]; char filePath[FILEPATH_LENGTH];
@ -201,7 +202,6 @@ byte lastPage;
byte numPages; byte numPages;
boolean root = 0; boolean root = 0;
boolean filebrowse = 0; boolean filebrowse = 0;
char fileOptions[30][FILEOPTS_LENGTH];
// Common // Common
char romName[17]; char romName[17];
@ -1390,16 +1390,12 @@ browserstart:
else if (myFile.isDir()) { else if (myFile.isDir()) {
// Copy full dirname into fileNames // Copy full dirname into fileNames
snprintf(fileNames[currFile], FILENAME_LENGTH, "%s%s", "/", nameStr); snprintf(fileNames[currFile], FILENAME_LENGTH, "%s%s", "/", nameStr);
// Copy short string into fileOptions
snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s%s", "/", nameStr);
currFile++; currFile++;
} }
// It's just a file // It's just a file
else if (myFile.isFile()) { else if (myFile.isFile()) {
// Copy full filename into fileNames // Copy full filename into fileNames
snprintf(fileNames[currFile], FILENAME_LENGTH, "%s", nameStr); snprintf(fileNames[currFile], FILENAME_LENGTH, "%s", nameStr);
// Copy short string into fileOptions
snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s", nameStr);
currFile++; currFile++;
} }
myFile.close(); myFile.close();
@ -1451,7 +1447,7 @@ page:
for (byte i = 0; i < 8; i++ ) { for (byte i = 0; i < 8; i++ ) {
// Copy short string into fileOptions // Copy short string into fileOptions
snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileOptions[ ((currPage - 1) * 7 + i)] ); snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileNames[ ((currPage - 1) * 7 + i)] );
} }
// Create menu with title and 1-7 options to choose from // Create menu with title and 1-7 options to choose from

View File

@ -2060,8 +2060,13 @@ void idFlashrom_GBA() {
resetMX29GL128E_GBA(); resetMX29GL128E_GBA();
} }
else { else {
println_Msg(F("Error"));
println_Msg(F(""));
println_Msg(F("Unknown Flash"));
print_Msg(F("Flash ID: "));
println_Msg(flashid); println_Msg(flashid);
print_Error(F("Unknown Flashid"), true); println_Msg(F(""));
print_Error(F("Check voltage"), true);
} }
} }
} }
@ -2508,7 +2513,7 @@ void flashRepro_GBA() {
println_Msg(""); println_Msg("");
println_Msg(F("This will erase your")); println_Msg(F("This will erase your"));
println_Msg(F("Repro Cartridge.")); println_Msg(F("Repro Cartridge."));
println_Msg(F("Please use 3.3V!")); println_Msg(F(""));
println_Msg(""); println_Msg("");
println_Msg(F("Press Button")); println_Msg(F("Press Button"));
display_Update(); display_Update();
@ -2633,9 +2638,13 @@ void flashRepro_GBA() {
} }
} }
else { else {
print_Msg(F("ID: ")); println_Msg(F("Error"));
println_Msg(F(""));
println_Msg(F("Unknown Flash"));
print_Msg(F("Flash ID: "));
println_Msg(flashid); println_Msg(flashid);
print_Error(F("Unknown Flash ID"), true); println_Msg(F(""));
print_Error(F("Check voltage"), true);
} }
} }

886
Cart_Reader/GBM.ino Normal file
View File

@ -0,0 +1,886 @@
/******************************************
GB MEMORY MODULE
******************************************/
#include "options.h"
#ifdef enable_GBX
/******************************************
Menu
*****************************************/
// GBM menu items
static const char gbmMenuItem1[] PROGMEM = "Read ID";
static const char gbmMenuItem2[] PROGMEM = "Read Flash";
static const char gbmMenuItem3[] PROGMEM = "Erase Flash";
static const char gbmMenuItem4[] PROGMEM = "Blankcheck";
static const char gbmMenuItem5[] PROGMEM = "Write Flash";
static const char gbmMenuItem6[] PROGMEM = "Read Mapping";
static const char gbmMenuItem7[] PROGMEM = "Write Mapping";
static const char* const menuOptionsGBM[] PROGMEM = {gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7};
void gbmMenu() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsGBM, 7);
mainMenu = question_box(F("GB Memory Menu"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu)
{
// Read Flash ID
case 0:
// Clear screen
display_Clear();
readFlashID_GBM();
break;
// Read Flash
case 1:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("Always power cycle"));
println_Msg(F("cartreader directly"));
println_Msg(F("before reading"));
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Clear screen
display_Clear();
// Reset to root directory
sd.chdir("/");
// Enable access to ports 0120h
send_GBM(0x09);
// Map entire flashrom
send_GBM(0x04);
// Disable ports 0x0120...
send_GBM(0x08);
// Read 1MB rom
readROM_GBM(64);
break;
// Erase Flash
case 2:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("This will erase your"));
println_Msg(F("NP Cartridge."));
println_Msg("");
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Clear screen
display_Clear();
eraseFlash_GBM();
break;
// Blankcheck Flash
case 3:
// Clear screen
display_Clear();
if (blankcheckFlash_GBM()) {
println_Msg(F("OK"));
display_Update();
}
else {
println_Msg(F("ERROR"));
display_Update();
}
break;
// Write Flash
case 4:
// Clear screen
display_Clear();
filePath[0] = '\0';
sd.chdir("/");
// Launch file browser
fileBrowser(F("Select 1MB file"));
display_Clear();
sprintf(filePath, "%s/%s", filePath, fileName);
// Write rom
writeFlash_GBM();
break;
// Read mapping
case 5:
// Clear screen
display_Clear();
// Reset to root directory
sd.chdir("/");
// Read mapping
readMapping_GBM();
break;
// Write mapping
case 6:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("This will erase your"));
println_Msg(F("NP Cartridge's"));
println_Msg(F("mapping data"));
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Reset to root directory
sd.chdir("/");
// Clear screen
display_Clear();
// Clear filepath
filePath[0] = '\0';
// Reset to root directory
sd.chdir("/");
// Launch file browser
fileBrowser(F("Select MAP file"));
display_Clear();
sprintf(filePath, "%s/%s", filePath, fileName);
display_Update();
// Clear screen
display_Clear();
// Erase mapping
eraseMapping_GBM();
if (blankcheckMapping_GBM()) {
println_Msg(F("OK"));
display_Update();
}
else {
print_Error(F("Erasing failed"), false);
break;
}
// Write mapping
writeMapping_GBM();
break;
}
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
void setup_GBM() {
// Set RST(PH0) to Input
DDRH &= ~(1 << 0);
// Activate Internal Pullup Resistors
PORTH |= (1 << 0);
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF;
//A8-A15
DDRK = 0xFF;
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
DDRH |= (1 << 3) | (1 << 5) | (1 << 6);
// Output a high signal on all pins, pins are active low therefore everything is disabled now
PORTH |= (1 << 3) | (1 << 5) | (1 << 6);
// Set Data Pins (D0-D7) to Input
DDRC = 0x00;
delay(400);
// Check for Nintendo Power GB Memory cart
byte timeout = 0;
// First byte of NP register is always 0x21
while (readByte_GBM(0x120) != 0x21) {
// Enable ports 0x120h (F2)
send_GBM(0x09);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
timeout++;
if (timeout > 10) {
println_Msg(F("Error: Time Out"));
print_Error(F("Please power cycle"), true);
}
}
}
/**********************
LOW LEVEL
**********************/
// Read one word out of the cartridge
byte readByte_GBM(word myAddress) {
// Set data pins to Input
DDRC = 0x0;
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Switch CS(PH3) and RD(PH6) to LOW
PORTH &= ~(1 << 3);
PORTH &= ~(1 << 6);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Read
byte tempByte = PINC;
// Switch CS(PH3) and RD(PH6) to HIGH
PORTH |= (1 << 6);
PORTH |= (1 << 3);
return tempByte;
}
// Write one word to data pins of the cartridge
void writeByte_GBM(word myAddress, byte myData) {
// Set data pins to Output
DDRC = 0xFF;
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTC = myData;
// Pull CS(PH3) and write(PH5) low
PORTH &= ~(1 << 3);
PORTH &= ~(1 << 5);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Pull CS(PH3) and write(PH5) high
PORTH |= (1 << 5);
PORTH |= (1 << 3);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Set data pins to Input (or read errors??!)
DDRC = 0x0;
}
/**********************
HELPER FUNCTIONS
**********************/
void printSdBuffer(word startByte, word numBytes) {
for (int currByte = 0; currByte < numBytes; currByte += 10) {
for (byte c = 0; c < 10; c++) {
// Convert to char array so we don't lose leading zeros
char currByteStr[2];
sprintf(currByteStr, "%02X", sdBuffer[startByte + currByte + c]);
print_Msg(currByteStr);
}
// Add a new line every 10 bytes
println_Msg("");
}
display_Update();
}
void readROM_GBM(word numBanks) {
println_Msg(F("Reading Rom..."));
display_Update();
// Get name, add extension and convert to char array for sd lib
EEPROM_readAnything(0, foldern);
sprintf(fileName, "GBM%d", foldern);
strcat(fileName, ".bin");
sd.mkdir("NP", true);
sd.chdir("NP");
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(0, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("Can't create file on SD"), true);
}
else {
// Read rom
word currAddress = 0;
for (word currBank = 1; currBank < numBanks; currBank++) {
// Set rom bank
writeByte_GBM(0x2100, currBank);
// Switch bank start address
if (currBank > 1) {
currAddress = 0x4000;
}
for (; currAddress < 0x7FFF; currAddress += 512) {
for (int currByte = 0; currByte < 512; currByte++) {
sdBuffer[currByte] = readByte_GBM(currAddress + currByte);
}
myFile.write(sdBuffer, 512);
}
}
// Close the file:
myFile.close();
// Signal end of process
print_Msg(F("Saved to NP/"));
println_Msg(fileName);
display_Update();
}
}
/**********************
GB Memory Functions
**********************/
void send_GBM(byte myCommand) {
switch (myCommand) {
case 0x01:
//CMD_01h -> ???
writeByte_GBM(0x0120, 0x01);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x02:
//CMD_02h -> Write enable Step 2
writeByte_GBM(0x0120, 0x02);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x03:
//CMD_03h -> Undo write Step 2
writeByte_GBM(0x0120, 0x03);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x04:
//CMD_04h -> Map entire flashrom (MBC4 mode)
writeByte_GBM(0x0120, 0x04);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x05:
//CMD_05h -> Map menu (MBC5 mode)
writeByte_GBM(0x0120, 0x05);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x08:
//CMD_08h -> disable writes/reads to/from special Nintendo Power registers (those at 0120h..013Fh)
writeByte_GBM(0x0120, 0x08);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x09:
//CMD_09h Wakeup -> re-enable access to ports 0120h..013Fh
writeByte_GBM(0x0120, 0x09);
writeByte_GBM(0x0121, 0xAA);
writeByte_GBM(0x0122, 0x55);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x0A:
//CMD_0Ah -> Write enable Step 1
writeByte_GBM(0x0120, 0x0A);
writeByte_GBM(0x0125, 0x62);
writeByte_GBM(0x0126, 0x04);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x10:
//CMD_10h -> disable writes to normal MBC registers (such like 2100h)
writeByte_GBM(0x0120, 0x10);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x11:
//CMD_11h -> re-enable access to MBC registers like 0x2100
writeByte_GBM(0x0120, 0x11);
writeByte_GBM(0x013F, 0xA5);
break;
default:
print_Error(F("Unknown Command"), true);
break;
}
}
void send_GBM(byte myCommand, word myAddress, byte myData) {
byte myAddrLow = myAddress & 0xFF;
byte myAddrHigh = (myAddress >> 8) & 0xFF;
switch (myCommand) {
case 0x0F:
// CMD_0Fh -> Write address/byte to flash
writeByte_GBM(0x0120, 0x0F);
writeByte_GBM(0x0125, myAddrHigh);
writeByte_GBM(0x0126, myAddrLow);
writeByte_GBM(0x0127, myData);
writeByte_GBM(0x013F, 0xA5);
break;
default:
print_Error(F("Unknown Command"), true);
break;
}
}
void switchGame_GBM(byte myData) {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
//CMD_C0h -> map selected game without reset
writeByte_GBM(0x0120, 0xC0 & myData);
writeByte_GBM(0x013F, 0xA5);
}
void resetFlash_GBM() {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
// Send reset command
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0xF0);
delay(100);
}
boolean readFlashID_GBM() {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
writeByte_GBM(0x2100, 0x01);
// Read ID command
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x90);
// Read the two id bytes into a string
sprintf(flashid, "%02X%02X", readByte_GBM(0), readByte_GBM(1));
if (strcmp(flashid, "C289") == 0) {
print_Msg(F("Flash ID: "));
println_Msg(flashid);
display_Update();
resetFlash_GBM();
return 1;
}
else {
print_Msg(F("Flash ID: "));
println_Msg(flashid);
print_Error(F("Unknown Flash ID"), true);
resetFlash_GBM();
return 0;
}
}
void eraseFlash_GBM() {
println_Msg(F("Erasing..."));
display_Update();
//enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Unprotect sector 0
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x40);
// Wait for unprotect to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Send erase command
send_GBM(0x0F, 0x5555, 0xaa);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x80);
send_GBM(0x0F, 0x5555, 0xaa);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x10);
// Wait for erase to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Reset flashrom
resetFlash_GBM();
}
boolean blankcheckFlash_GBM() {
print_Msg(F("Blankcheck..."));
display_Update();
//enable access to ports 0120h (F2)
send_GBM(0x09);
// Map entire flashrom
send_GBM(0x04);
// Disable ports 0x0120...
send_GBM(0x08);
// Read rom
word currAddress = 0;
for (byte currBank = 1; currBank < 64; currBank++) {
// Set rom bank
writeByte_GBM(0x2100, currBank);
// Switch bank start address
if (currBank > 1) {
currAddress = 0x4000;
}
for (; currAddress < 0x7FFF; currAddress++) {
if (readByte_GBM(currAddress) != 0xFF) {
return 0;
}
}
}
return 1;
}
void writeFlash_GBM() {
print_Msg(F("Writing..."));
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
// Get rom size from file
fileSize = myFile.fileSize();
if ((fileSize / 0x4000) > 64) {
print_Error(F("File is too big."), true);
}
// Enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Map entire flash rom
send_GBM(0x4);
// Set bank for unprotect command, writes to 0x5555 need odd bank number
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Unprotect sector 0
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x60);
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x40);
// Check if flashrom is ready for writing or busy
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// first bank: 0x0000-0x7FFF,
word currAddress = 0x0;
// Write 63 banks
for (byte currBank = 0x1; currBank < (fileSize / 0x4000); currBank++) {
// Blink led
PORTB ^= (1 << 4);
// all following banks: 0x4000-0x7FFF
if (currBank > 1) {
currAddress = 0x4000;
}
// Write single bank in 128 byte steps
for (; currAddress < 0x7FFF; currAddress += 128) {
// Fill SD buffer
myFile.read(sdBuffer, 128);
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Write flash buffer command
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xA0);
// Wait until flashrom is ready again
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, currBank);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Fill flash buffer
for (word currByte = 0; currByte < 128; currByte++) {
writeByte_GBM(currAddress + currByte, sdBuffer[currByte]);
}
// Execute write
writeByte_GBM(currAddress + 127, 0xFF);
// Wait for write to complete
while ((readByte_GBM(currAddress) & 0x80) != 0x80) {}
}
}
// Close the file:
myFile.close();
println_Msg(F("Done"));
}
else {
print_Error(F("Can't open file"), false);
}
}
void readMapping_GBM() {
// Enable ports 0x0120
send_GBM(0x09);
// Set WE and WP
send_GBM(0x0A);
send_GBM(0x2);
// Enable hidden mapping area
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
// Read mapping
println_Msg(F("Reading Mapping..."));
display_Update();
// Get name, add extension and convert to char array for sd lib
EEPROM_readAnything(0, foldern);
sprintf(fileName, "GBM%d", foldern);
strcat(fileName, ".map");
sd.mkdir("NP", true);
sd.chdir("NP");
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(0, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("Can't create file on SD"), true);
}
else {
for (byte currByte = 0; currByte < 128; currByte++) {
sdBuffer[currByte] = readByte_GBM(currByte);
}
myFile.write(sdBuffer, 128);
// Close the file:
myFile.close();
// Signal end of process
printSdBuffer(0, 20);
printSdBuffer(102, 20);
println_Msg("");
print_Msg(F("Saved to NP/"));
println_Msg(fileName);
display_Update();
}
// Reset flash to leave hidden mapping area
resetFlash_GBM();
}
void eraseMapping_GBM() {
println_Msg(F("Erasing..."));
display_Update();
//enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Unprotect sector 0
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x40);
// Wait for unprotect to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Send erase command
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x04);
// Wait for erase to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Reset flashrom
resetFlash_GBM();
}
boolean blankcheckMapping_GBM() {
print_Msg(F("Blankcheck..."));
display_Update();
// Enable ports 0x0120
send_GBM(0x09);
// Set WE and WP
send_GBM(0x0A);
send_GBM(0x2);
// Enable hidden mapping area
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
// Disable ports 0x0120...
send_GBM(0x08);
// Read rom
for (byte currByte = 0; currByte < 128; currByte++) {
if (readByte_GBM(currByte) != 0xFF) {
return 0;
}
}
return 1;
}
void writeMapping_GBM() {
print_Msg(F("Writing..."));
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
// Get map file size and check if it exceeds 128KByte
if (myFile.fileSize() > 0x80) {
print_Error(F("File is too big."), true);
}
// Enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Map entire flash rom
send_GBM(0x4);
// Set bank, writes to 0x5555 need odd bank number
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Unlock write to map area
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x60);
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xE0);
// Check if flashrom is ready for writing or busy
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Fill SD buffer
myFile.read(sdBuffer, 128);
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Write flash buffer command
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xA0);
// Wait until flashrom is ready again
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Fill flash buffer
for (word currByte = 0; currByte < 128; currByte++) {
// Blink led
PORTB ^= (1 << 4);
writeByte_GBM(currByte, sdBuffer[currByte]);
}
// Execute write
writeByte_GBM(127, 0xFF);
// Close the file:
myFile.close();
println_Msg(F("Done"));
}
else {
print_Error(F("Can't open file"), false);
}
}
#endif
//******************************************
// End of File
//******************************************

View File

@ -54,8 +54,13 @@ GBSmartGameInfo gbSmartGames[GB_SMART_GAMES_PER_PAGE];
byte signature[48]; byte signature[48];
uint16_t gameMenuStartBank; uint16_t gameMenuStartBank;
#ifdef enable_NP
extern boolean hasMenu; extern boolean hasMenu;
extern byte numGames; extern byte numGames;
#else
boolean hasMenu;
byte numGames;
#endif
byte readByte_GBS(word myAddress) { byte readByte_GBS(word myAddress) {
PORTF = myAddress & 0xFF; PORTF = myAddress & 0xFF;

View File

@ -97,7 +97,7 @@ void mdLoadConf() {
char line[64]; char line[64];
int n; int n;
int i; int i;
while ((n = myFile.fgets(line, sizeof(line)-1)) > 0) { while ((n = myFile.fgets(line, sizeof(line) - 1)) > 0) {
// preprocess // preprocess
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (line[i] == ';') { if (line[i] == ';') {

View File

@ -1,15 +1,10 @@
//****************************************** //******************************************
// NINTENDO POWER MODULE // NINTENDO POWER SF MEMORY MODULE
//****************************************** //******************************************
// (GB Memory starts at around line 1740)
#include "options.h" #include "options.h"
#ifdef enable_NP #ifdef enable_NP
/******************************************
SF Memory Cassette
******************************************/
/****************************************** /******************************************
SF Memory Clock Source SF Memory Clock Source
******************************************/ ******************************************/
@ -1742,884 +1737,6 @@ void write_SFM(int startBank, uint32_t pos) {
} }
} }
/******************************************
GB Memory Cassette
******************************************/
/******************************************
Menu
*****************************************/
// GBM menu items
static const char gbmMenuItem1[] PROGMEM = "Read ID";
static const char gbmMenuItem2[] PROGMEM = "Read Flash";
static const char gbmMenuItem3[] PROGMEM = "Erase Flash";
static const char gbmMenuItem4[] PROGMEM = "Blankcheck";
static const char gbmMenuItem5[] PROGMEM = "Write Flash";
static const char gbmMenuItem6[] PROGMEM = "Read Mapping";
static const char gbmMenuItem7[] PROGMEM = "Write Mapping";
static const char* const menuOptionsGBM[] PROGMEM = {gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7};
void gbmMenu() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsGBM, 7);
mainMenu = question_box(F("GB Memory Menu"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu)
{
// Read Flash ID
case 0:
// Clear screen
display_Clear();
readFlashID_GBM();
break;
// Read Flash
case 1:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("Always power cycle"));
println_Msg(F("cartreader directly"));
println_Msg(F("before reading"));
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Clear screen
display_Clear();
// Reset to root directory
sd.chdir("/");
// Enable access to ports 0120h
send_GBM(0x09);
// Map entire flashrom
send_GBM(0x04);
// Disable ports 0x0120...
send_GBM(0x08);
// Read 1MB rom
readROM_GBM(64);
break;
// Erase Flash
case 2:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("This will erase your"));
println_Msg(F("NP Cartridge."));
println_Msg("");
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Clear screen
display_Clear();
eraseFlash_GBM();
break;
// Blankcheck Flash
case 3:
// Clear screen
display_Clear();
if (blankcheckFlash_GBM()) {
println_Msg(F("OK"));
display_Update();
}
else {
println_Msg(F("ERROR"));
display_Update();
}
break;
// Write Flash
case 4:
// Clear screen
display_Clear();
filePath[0] = '\0';
sd.chdir("/");
// Launch file browser
fileBrowser(F("Select 1MB file"));
display_Clear();
sprintf(filePath, "%s/%s", filePath, fileName);
// Write rom
writeFlash_GBM();
break;
// Read mapping
case 5:
// Clear screen
display_Clear();
// Reset to root directory
sd.chdir("/");
// Read mapping
readMapping_GBM();
break;
// Write mapping
case 6:
// Clear screen
display_Clear();
// Print warning
println_Msg(F("Attention"));
println_Msg(F("This will erase your"));
println_Msg(F("NP Cartridge's"));
println_Msg(F("mapping data"));
println_Msg("");
println_Msg(F("Press Button"));
println_Msg(F("to continue"));
display_Update();
wait();
// Reset to root directory
sd.chdir("/");
// Clear screen
display_Clear();
// Clear filepath
filePath[0] = '\0';
// Reset to root directory
sd.chdir("/");
// Launch file browser
fileBrowser(F("Select MAP file"));
display_Clear();
sprintf(filePath, "%s/%s", filePath, fileName);
display_Update();
// Clear screen
display_Clear();
// Erase mapping
eraseMapping_GBM();
if (blankcheckMapping_GBM()) {
println_Msg(F("OK"));
display_Update();
}
else {
print_Error(F("Erasing failed"), false);
break;
}
// Write mapping
writeMapping_GBM();
break;
}
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
void setup_GBM() {
// Set RST(PH0) to Input
DDRH &= ~(1 << 0);
// Activate Internal Pullup Resistors
PORTH |= (1 << 0);
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF;
//A8-A15
DDRK = 0xFF;
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
DDRH |= (1 << 3) | (1 << 5) | (1 << 6);
// Output a high signal on all pins, pins are active low therefore everything is disabled now
PORTH |= (1 << 3) | (1 << 5) | (1 << 6);
// Set Data Pins (D0-D7) to Input
DDRC = 0x00;
delay(400);
// Check for Nintendo Power GB Memory cart
byte timeout = 0;
// First byte of NP register is always 0x21
while (readByte_GBM(0x120) != 0x21) {
// Enable ports 0x120h (F2)
send_GBM(0x09);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
timeout++;
if (timeout > 10) {
println_Msg(F("Error: Time Out"));
print_Error(F("Please power cycle"), true);
}
}
}
/**********************
LOW LEVEL
**********************/
// Read one word out of the cartridge
byte readByte_GBM(word myAddress) {
// Set data pins to Input
DDRC = 0x0;
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Switch CS(PH3) and RD(PH6) to LOW
PORTH &= ~(1 << 3);
PORTH &= ~(1 << 6);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Read
byte tempByte = PINC;
// Switch CS(PH3) and RD(PH6) to HIGH
PORTH |= (1 << 6);
PORTH |= (1 << 3);
return tempByte;
}
// Write one word to data pins of the cartridge
void writeByte_GBM(word myAddress, byte myData) {
// Set data pins to Output
DDRC = 0xFF;
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTC = myData;
// Pull CS(PH3) and write(PH5) low
PORTH &= ~(1 << 3);
PORTH &= ~(1 << 5);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Pull CS(PH3) and write(PH5) high
PORTH |= (1 << 5);
PORTH |= (1 << 3);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Set data pins to Input (or read errors??!)
DDRC = 0x0;
}
/**********************
HELPER FUNCTIONS
**********************/
void printSdBuffer(word startByte, word numBytes) {
for (int currByte = 0; currByte < numBytes; currByte += 10) {
for (byte c = 0; c < 10; c++) {
// Convert to char array so we don't lose leading zeros
char currByteStr[2];
sprintf(currByteStr, "%02X", sdBuffer[startByte + currByte + c]);
print_Msg(currByteStr);
}
// Add a new line every 10 bytes
println_Msg("");
}
display_Update();
}
void readROM_GBM(word numBanks) {
println_Msg(F("Reading Rom..."));
display_Update();
// Get name, add extension and convert to char array for sd lib
EEPROM_readAnything(0, foldern);
sprintf(fileName, "GBM%d", foldern);
strcat(fileName, ".bin");
sd.mkdir("NP", true);
sd.chdir("NP");
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(0, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("Can't create file on SD"), true);
}
else {
// Read rom
word currAddress = 0;
for (word currBank = 1; currBank < numBanks; currBank++) {
// Set rom bank
writeByte_GBM(0x2100, currBank);
// Switch bank start address
if (currBank > 1) {
currAddress = 0x4000;
}
for (; currAddress < 0x7FFF; currAddress += 512) {
for (int currByte = 0; currByte < 512; currByte++) {
sdBuffer[currByte] = readByte_GBM(currAddress + currByte);
}
myFile.write(sdBuffer, 512);
}
}
// Close the file:
myFile.close();
// Signal end of process
print_Msg(F("Saved to NP/"));
println_Msg(fileName);
display_Update();
}
}
/**********************
GB Memory Functions
**********************/
void send_GBM(byte myCommand) {
switch (myCommand) {
case 0x01:
//CMD_01h -> ???
writeByte_GBM(0x0120, 0x01);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x02:
//CMD_02h -> Write enable Step 2
writeByte_GBM(0x0120, 0x02);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x03:
//CMD_03h -> Undo write Step 2
writeByte_GBM(0x0120, 0x03);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x04:
//CMD_04h -> Map entire flashrom (MBC4 mode)
writeByte_GBM(0x0120, 0x04);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x05:
//CMD_05h -> Map menu (MBC5 mode)
writeByte_GBM(0x0120, 0x05);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x08:
//CMD_08h -> disable writes/reads to/from special Nintendo Power registers (those at 0120h..013Fh)
writeByte_GBM(0x0120, 0x08);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x09:
//CMD_09h Wakeup -> re-enable access to ports 0120h..013Fh
writeByte_GBM(0x0120, 0x09);
writeByte_GBM(0x0121, 0xAA);
writeByte_GBM(0x0122, 0x55);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x0A:
//CMD_0Ah -> Write enable Step 1
writeByte_GBM(0x0120, 0x0A);
writeByte_GBM(0x0125, 0x62);
writeByte_GBM(0x0126, 0x04);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x10:
//CMD_10h -> disable writes to normal MBC registers (such like 2100h)
writeByte_GBM(0x0120, 0x10);
writeByte_GBM(0x013F, 0xA5);
break;
case 0x11:
//CMD_11h -> re-enable access to MBC registers like 0x2100
writeByte_GBM(0x0120, 0x11);
writeByte_GBM(0x013F, 0xA5);
break;
default:
print_Error(F("Unknown Command"), true);
break;
}
}
void send_GBM(byte myCommand, word myAddress, byte myData) {
byte myAddrLow = myAddress & 0xFF;
byte myAddrHigh = (myAddress >> 8) & 0xFF;
switch (myCommand) {
case 0x0F:
// CMD_0Fh -> Write address/byte to flash
writeByte_GBM(0x0120, 0x0F);
writeByte_GBM(0x0125, myAddrHigh);
writeByte_GBM(0x0126, myAddrLow);
writeByte_GBM(0x0127, myData);
writeByte_GBM(0x013F, 0xA5);
break;
default:
print_Error(F("Unknown Command"), true);
break;
}
}
void switchGame_GBM(byte myData) {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
//CMD_C0h -> map selected game without reset
writeByte_GBM(0x0120, 0xC0 & myData);
writeByte_GBM(0x013F, 0xA5);
}
void resetFlash_GBM() {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
// Send reset command
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0xF0);
delay(100);
}
boolean readFlashID_GBM() {
// Enable ports 0x0120 (F2)
send_GBM(0x09);
writeByte_GBM(0x2100, 0x01);
// Read ID command
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x90);
// Read the two id bytes into a string
sprintf(flashid, "%02X%02X", readByte_GBM(0), readByte_GBM(1));
if (strcmp(flashid, "C289") == 0) {
print_Msg(F("Flash ID: "));
println_Msg(flashid);
display_Update();
resetFlash_GBM();
return 1;
}
else {
print_Msg(F("Flash ID: "));
println_Msg(flashid);
print_Error(F("Unknown Flash ID"), true);
resetFlash_GBM();
return 0;
}
}
void eraseFlash_GBM() {
println_Msg(F("Erasing..."));
display_Update();
//enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Unprotect sector 0
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x40);
// Wait for unprotect to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Send erase command
send_GBM(0x0F, 0x5555, 0xaa);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x80);
send_GBM(0x0F, 0x5555, 0xaa);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x10);
// Wait for erase to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Reset flashrom
resetFlash_GBM();
}
boolean blankcheckFlash_GBM() {
print_Msg(F("Blankcheck..."));
display_Update();
//enable access to ports 0120h (F2)
send_GBM(0x09);
// Map entire flashrom
send_GBM(0x04);
// Disable ports 0x0120...
send_GBM(0x08);
// Read rom
word currAddress = 0;
for (byte currBank = 1; currBank < 64; currBank++) {
// Set rom bank
writeByte_GBM(0x2100, currBank);
// Switch bank start address
if (currBank > 1) {
currAddress = 0x4000;
}
for (; currAddress < 0x7FFF; currAddress++) {
if (readByte_GBM(currAddress) != 0xFF) {
return 0;
}
}
}
return 1;
}
void writeFlash_GBM() {
print_Msg(F("Writing..."));
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
// Get rom size from file
fileSize = myFile.fileSize();
if ((fileSize / 0x4000) > 64) {
print_Error(F("File is too big."), true);
}
// Enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Map entire flash rom
send_GBM(0x4);
// Set bank for unprotect command, writes to 0x5555 need odd bank number
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Unprotect sector 0
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x60);
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x40);
// Check if flashrom is ready for writing or busy
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// first bank: 0x0000-0x7FFF,
word currAddress = 0x0;
// Write 63 banks
for (byte currBank = 0x1; currBank < (fileSize / 0x4000); currBank++) {
// Blink led
PORTB ^= (1 << 4);
// all following banks: 0x4000-0x7FFF
if (currBank > 1) {
currAddress = 0x4000;
}
// Write single bank in 128 byte steps
for (; currAddress < 0x7FFF; currAddress += 128) {
// Fill SD buffer
myFile.read(sdBuffer, 128);
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Write flash buffer command
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xA0);
// Wait until flashrom is ready again
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, currBank);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Fill flash buffer
for (word currByte = 0; currByte < 128; currByte++) {
writeByte_GBM(currAddress + currByte, sdBuffer[currByte]);
}
// Execute write
writeByte_GBM(currAddress + 127, 0xFF);
// Wait for write to complete
while ((readByte_GBM(currAddress) & 0x80) != 0x80) {}
}
}
// Close the file:
myFile.close();
println_Msg(F("Done"));
}
else {
print_Error(F("Can't open file"), false);
}
}
void readMapping_GBM() {
// Enable ports 0x0120
send_GBM(0x09);
// Set WE and WP
send_GBM(0x0A);
send_GBM(0x2);
// Enable hidden mapping area
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
// Read mapping
println_Msg(F("Reading Mapping..."));
display_Update();
// Get name, add extension and convert to char array for sd lib
EEPROM_readAnything(0, foldern);
sprintf(fileName, "GBM%d", foldern);
strcat(fileName, ".map");
sd.mkdir("NP", true);
sd.chdir("NP");
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(0, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("Can't create file on SD"), true);
}
else {
for (byte currByte = 0; currByte < 128; currByte++) {
sdBuffer[currByte] = readByte_GBM(currByte);
}
myFile.write(sdBuffer, 128);
// Close the file:
myFile.close();
// Signal end of process
printSdBuffer(0, 20);
printSdBuffer(102, 20);
println_Msg("");
print_Msg(F("Saved to NP/"));
println_Msg(fileName);
display_Update();
}
// Reset flash to leave hidden mapping area
resetFlash_GBM();
}
void eraseMapping_GBM() {
println_Msg(F("Erasing..."));
display_Update();
//enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Unprotect sector 0
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x40);
// Wait for unprotect to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Send erase command
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x60);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x04);
// Wait for erase to complete
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Reset flashrom
resetFlash_GBM();
}
boolean blankcheckMapping_GBM() {
print_Msg(F("Blankcheck..."));
display_Update();
// Enable ports 0x0120
send_GBM(0x09);
// Set WE and WP
send_GBM(0x0A);
send_GBM(0x2);
// Enable hidden mapping area
writeByte_GBM(0x2100, 0x01);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
send_GBM(0x0F, 0x5555, 0xAA);
send_GBM(0x0F, 0x2AAA, 0x55);
send_GBM(0x0F, 0x5555, 0x77);
// Disable ports 0x0120...
send_GBM(0x08);
// Read rom
for (byte currByte = 0; currByte < 128; currByte++) {
if (readByte_GBM(currByte) != 0xFF) {
return 0;
}
}
return 1;
}
void writeMapping_GBM() {
print_Msg(F("Writing..."));
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
// Get map file size and check if it exceeds 128KByte
if (myFile.fileSize() > 0x80) {
print_Error(F("File is too big."), true);
}
// Enable access to ports 0120h
send_GBM(0x09);
// Enable write
send_GBM(0x0A);
send_GBM(0x2);
// Map entire flash rom
send_GBM(0x4);
// Set bank, writes to 0x5555 need odd bank number
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Unlock write to map area
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0x60);
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xE0);
// Check if flashrom is ready for writing or busy
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Fill SD buffer
myFile.read(sdBuffer, 128);
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0x1);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Write flash buffer command
writeByte_GBM(0x5555, 0xAA);
writeByte_GBM(0x2AAA, 0x55);
writeByte_GBM(0x5555, 0xA0);
// Wait until flashrom is ready again
while ((readByte_GBM(0) & 0x80) != 0x80) {}
// Enable access to ports 0x120 and 0x2100
send_GBM(0x09);
send_GBM(0x11);
// Set bank
writeByte_GBM(0x2100, 0);
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
send_GBM(0x10);
send_GBM(0x08);
// Fill flash buffer
for (word currByte = 0; currByte < 128; currByte++) {
// Blink led
PORTB ^= (1 << 4);
writeByte_GBM(currByte, sdBuffer[currByte]);
}
// Execute write
writeByte_GBM(127, 0xFF);
// Close the file:
myFile.close();
println_Msg(F("Done"));
}
else {
print_Error(F("Can't open file"), false);
}
}
#endif #endif
//****************************************** //******************************************

View File

@ -585,7 +585,7 @@ void read_tennokoe_bank_PCE(int bank_index)
println_Msg(F("RAM bank size: 2KB")); println_Msg(F("RAM bank size: 2KB"));
// Get name, add extension and convert to char array for sd lib // Get name, add extension and convert to char array for sd lib
sprintf(fileName, "BANKRAM%d.sav", bank_index+1); sprintf(fileName, "BANKRAM%d.sav", bank_index + 1);
// create a new folder for the save file // create a new folder for the save file
EEPROM_readAnything(0, foldern); EEPROM_readAnything(0, foldern);
@ -620,7 +620,7 @@ void read_tennokoe_bank_PCE(int bank_index)
data_input_PCE(); data_input_PCE();
//Read Tennokoe bank RAM //Read Tennokoe bank RAM
read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index); read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index);
//Lock Tennokoe Bank RAM //Lock Tennokoe Bank RAM
data_output_PCE(); data_output_PCE();
@ -726,7 +726,7 @@ void write_tennokoe_bank_PCE(int bank_index)
unlock_tennokoe_bank_RAM(); unlock_tennokoe_bank_RAM();
data_input_PCE(); data_input_PCE();
//Read Tennokoe bank RAM //Read Tennokoe bank RAM
read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index); read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index);
//Lock Tennokoe Bank RAM //Lock Tennokoe Bank RAM
data_output_PCE(); data_output_PCE();
lock_tennokoe_bank_RAM(); lock_tennokoe_bank_RAM();
@ -862,8 +862,8 @@ void pceMenu() {
if (pce_internal_mode == HUCARD || pce_internal_mode == HUCARD_NOSWAP) if (pce_internal_mode == HUCARD || pce_internal_mode == HUCARD_NOSWAP)
{ {
sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index+1); sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index + 1);
sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index+1); sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index + 1);
strcpy(menuOptionspceCart[0], pceCartMenuItem1); strcpy(menuOptionspceCart[0], pceCartMenuItem1);
strcpy(menuOptionspceCart[1], pceCartMenuItem2); strcpy(menuOptionspceCart[1], pceCartMenuItem2);
strcpy(menuOptionspceCart[2], pceCartMenuItem3); strcpy(menuOptionspceCart[2], pceCartMenuItem3);

View File

@ -60,5 +60,6 @@ Needed libraries(already included in the portable Arduino IDE under Releases)
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
GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library
BusIO: https://github.com/adafruit/Adafruit_BusIO
RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools
SI5351 lib: https://github.com/etherkit/Si5351Arduino SI5351 lib: https://github.com/etherkit/Si5351Arduino

View File

@ -16,20 +16,15 @@
#define enable_Button2 #define enable_Button2
// define enable_XXX to enable // define enable_XXX to enable
#define enable_FLASH
#define enable_GBX
#define enable_MD #define enable_MD
#define enable_SMS #define enable_N64
#define enable_PCE
#define enable_NES #define enable_NES
#define enable_NGP
#define enable_NP
#define enable_PCE
#define enable_SMS
#define enable_SNES #define enable_SNES
#define enable_SV #define enable_SV
#define enable_NP
#define enable_GBX
#define enable_N64
#define enable_WS #define enable_WS
#define enable_NGP
#define enable_FLASH