cartreader/Cart_Reader/LEAP.ino
2024-07-08 19:25:29 +02:00

1053 lines
25 KiB
C++

//******************************************
// LEAP MODULE
//******************************************
#ifdef ENABLE_LEAP
// Leapster
// Cartridge pinout
// 60P 1.27mm pitch connector
//
// FRONT BACK
// SIDE SIDE
// +---------+
// VCC -| 1B 1A |- VCC
// nc -| 2B 2A |- GND
// D11 -| 3B 3A |- D4
// D3 -| 4B 4A |- D12
// D10 -| 5B 5A |- D5
// GND -| 6B 6A |- D2
// D13 -| 7B 7A |- D9
// nc -| 8B 8A |- nc
// D6 -| 9B 9A |- D1
// D14 -| 10B 10A |- D8
// |---------|
// D7 -| 11B 11A |- GND
// D0 -| 12B 12A |- D15
// BYTE -| 13B 13A |- OE
// nc -| 14B 14A |- A22
// FLA_CE -| 15B 15A |- A23
// CE -| 16B 16A |- A16
// A0 -| 17B 17A |- A15
// A1 -| 18B 18A |- A14
// A2 -| 19B 19A |- A13
// GND -| 20B 20A |- A3
// A12 -| 21B 21A |- A4
// A11 -| 22B 22A |- A5
// A10 -| 23B 23A |- A6
// A9 -| 24B 24A |- A7
// A8 -| 25B 25A |- A17
// A19 -| 26B 26A |- A18
// A20 -| 27B 27A |- A21
// WE -| 28B 28A |- GND
// EEP_SDA -| 29B 29A |- EEP_WP
// nc -| 30B 30A |- EEP_SCL
// +---------+
//
// CONTROL PINS:
// EEPROM WP (PH0) - SNES /RESET
// EEPROM SCL (PH1) - SNES CPUCLK
// EEPROM SDA (PH4) - SNES /IRQ
// OE (PH3) - SNES /CART
// WE (PH5) - SNES /WR
// CE (PH6) - SNES /RD
// BYTE (PE5) - SNES REFRESH
// FLASH CE (PJ0) - SNES /PARD
//******************************************
// DEFINES
//******************************************
// CONTROL PINS - OE/WE/CE
#define OE_HIGH PORTH |= (1<<3)
#define OE_LOW PORTH &= ~(1<<3)
#define WE_HIGH PORTH |= (1<<5)
#define WE_LOW PORTH &= ~(1<<5)
#define CE_HIGH PORTH |= (1<<6)
#define CE_LOW PORTH &= ~(1<<6)
// BYTE PIN IS A0 IN BYTE MODE - SHIFT ADDRESS >> 1
#define BYTE_HIGH PORTE |= (1<<5)
#define BYTE_LOW PORTE &= ~(1<<5)
// SERIAL I2C EEPROM PINS 24LC02B 2K
// PIN 5 - SDA
// PIN 6 - SCL
// PIN 7 - WP
// CART B30 = SDA
// CART A31 = SCL
// CART A30 = WP
#define WP_HIGH PORTH |= (1<<0)
#define WP_LOW PORTH &= ~(1<<0)
#define SCL_HIGH PORTH |= (1<<1)
#define SCL_LOW PORTH &= ~(1<<1)
#define SDA_HIGH PORTH |= (1<<4)
#define SDA_LOW PORTH &= ~(1<<4)
// FLASH 39VF040 512K
// CART B16 = CE#
#define FL_CE_HIGH PORTJ |= (1<<0)
#define FL_CE_LOW PORTJ &= ~(1<<0)
#define DATA_C_READ { DDRC = 0; PORTC = 0xFF; } // [INPUT PULLUP]
#define DATA_A_READ { DDRA = 0; PORTA = 0xFF; } // [INPUT PULLUP]
//******************************************
// VARIABLES
//******************************************
// ROM File = LEAP.bin
// RAM File = SAVE.eep
// FLASH File = SAVE.fla
byte LEAPSTER[] = {4,8,16};
byte leaplo = 0; // Lowest Entry
byte leaphi = 2; // Highest Entry
byte leapsize;
byte newleapsize;
byte tempbyte;
char tempword;
word ptrword;
word tempcheck;
// EEPROM MAPPING
// 08 ROM SIZE
//******************************************
// ROM STRUCTURE
//******************************************
char LEAP[] = {0x4C,0x45,0x41,0x50}; // "LEAP" MARKER AT 0x00 OR 0x144 (WORD 0xA2)
char TBL[] = {0x01,0x00,0x00,0x01}; // TABLE START
char TXT[] = {0x04,0x00,0x00,0x01}; // NEXT DWORD IS TEXT BLOCK [5 SENTENCES] START
char VER[] = {0x0A,0x00,0x00,0x01}; // NEXT DWORD IS ROM VERSION LOCATION
char TTL[] = {0x0B,0x00,0x00,0x01}; // NEXT DWORD IS ROM TITLE LOCATION
char END[] = {0x10,0x00,0x00,0x01}; // LAST BLOCK - END SEARCH
word sentenceAddr = 0; // Sentence Block Start Address
word versionAddr = 0; // Version Address
word titleAddr = 0; // Title Address
char ROMVersion[20]; // Fosters [20] "155-11172 152-11808"
char ROMTitle[50]; // "Mr. Pencils Learn to Draw and Write." [37]
// "Thomas and Friends Calling All Engines" [39]
// "The Letter Factory.v1.0 - Initial Release JBM3" [47]
//******************************************
// DATA INTEGRITY BLOCK
//******************************************
// 5 Sentences - 172 bytes
// Location not static between ROMs
static const unsigned char LeapCheck [] = {
0x4C,0x69,0x6C,0x20,0x64,0x75,0x63,0x6B,0x65,0x64,0x2E,0x20,0x20,0x54,0x68,0x65,
0x20,0x6A,0x65,0x74,0x20,0x7A,0x69,0x70,0x70,0x65,0x64,0x20,0x70,0x61,0x73,0x74,
0x20,0x68,0x65,0x72,0x20,0x68,0x65,0x61,0x64,0x2E,0x20,0x20,0x44,0x75,0x73,0x74,
0x20,0x66,0x6C,0x65,0x77,0x2C,0x20,0x4C,0x69,0x6C,0x20,0x73,0x6E,0x65,0x65,0x7A,
0x65,0x64,0x2C,0x20,0x61,0x6E,0x64,0x20,0x4C,0x65,0x61,0x70,0x20,0x74,0x75,0x72,
0x6E,0x65,0x64,0x20,0x72,0x65,0x64,0x2E,0x20,0x20,0x54,0x68,0x65,0x6E,0x20,0x4C,
0x69,0x6C,0x20,0x67,0x6F,0x74,0x20,0x75,0x70,0x2C,0x20,0x61,0x62,0x6F,0x75,0x74,
0x20,0x74,0x6F,0x20,0x79,0x65,0x6C,0x6C,0x2E,0x20,0x20,0x4C,0x65,0x61,0x70,0x20,
0x67,0x61,0x73,0x70,0x65,0x64,0x2C,0x20,0x22,0x4C,0x6F,0x6F,0x6B,0x2C,0x20,0x4C,
0x69,0x6C,0x21,0x20,0x20,0x59,0x6F,0x75,0x72,0x20,0x74,0x6F,0x6F,0x74,0x68,0x21,
0x20,0x20,0x49,0x74,0x20,0x66,0x65,0x6C,0x6C,0x21,0x22,0x00
};
//******************************************
// MENU
//******************************************
// Base Menu
static const char leapmenuItem4[] PROGMEM = "Read EEPROM";
static const char leapmenuItem5[] PROGMEM = "Write EEPROM";
static const char leapmenuItem6[] PROGMEM = "Read FLASH";
static const char leapmenuItem7[] PROGMEM = "Write FLASH";
static const char* const menuOptionsLEAP[] PROGMEM = { FSTRING_SELECT_CART, FSTRING_READ_ROM, FSTRING_SET_SIZE, leapmenuItem4, leapmenuItem5, leapmenuItem6, leapmenuItem7 };
void leapMenu()
{
convertPgm(menuOptionsLEAP, 7);
uint8_t mainMenu = question_box(F("LEAPSTER MENU"), menuOptions, 7, 0);
switch (mainMenu)
{
// Select Cart
case 0:
setCart_LEAP();
setup_LEAP();
break;
// Read ROM
case 1:
sd.chdir("/");
readROM_LEAP();
sd.chdir("/");
break;
// Set Size
case 2:
setROMSize_LEAP();
break;
// Read EEPROM
case 3:
sd.chdir("/");
readEEP_LEAP();
sd.chdir("/");
break;
// Write EEPROM
case 4:
writeEEP_LEAP();
break;
// Read FLASH
case 5:
idFLASH_LEAP();
if (strcmp(flashid_str, "BFD7") == 0) {
sd.chdir("/");
readFLASH_LEAP();
sd.chdir("/");
}
break;
// Write FLASH
case 6:
idFLASH_LEAP();
if (strcmp(flashid_str, "BFD7") == 0)
writeFLASH_LEAP();
break;
}
}
//******************************************
// SETUP
//******************************************
void setup_LEAP()
{
// Request 3.3V
setVoltage(VOLTS_SET_3V3);
// Control Pins PH0..PH1, PH3..PH6 BYTE, OE, CE, WE
DDRH = 0x7B; // 0b01111011 - CE, WE, SDA, OE, SCL, WP [OUTPUT] - Unused Pins [INPUT]
PORTH = 0xFF; // 0b11111111 - CE, WE, SDA, OE, SCL, WP [HIGH] - Unused Pins [HIGH]
// Address Pins
DDRF = 0xFF; // Address A0-A7 [OUTPUT]
DDRK = 0xFF; // Address A8-A15 [OUTPUT]
DDRL = 0xFF; // Address A16-A23 [OUTPUT]
// Data Pins
DDRC = 0x00; // D0-D7 [INPUT]
DDRA = 0x00; // D8-D15 [INPUT]
// BYTE Pin PE5
DDRE = 0x20; // 0b00100000 BYTE [OUTPUT] - Unused Pins [INPUT]
PORTE = 0xFF; // 0b11111111 BYTE [HIGH] - Unused Pins [HIGH]
// Flash Pin PJ0
DDRJ = 0x01; // 0b00000001 - FLA_CE [OUTPUT] - Unused Pins [INPUT]
PORTJ = 0xFF; // 0b11111111 - FLA_CE [HIGH] - Unused Pins {HIGH]
// Check Start for "LEAP" marker
// Read ROM Version & Title
checkStart_LEAP();
// 39VF040 Flash Check
// idFLASH();
checkStatus_LEAP();
strncpy(romName, ROMTitle, 16); // Truncate ROMTitle to fit
mode = CORE_LEAP;
}
//******************************************
// READ FUNCTIONS
//******************************************
// Max ROM Size 0x1000000 (Highest Address = 0xFFFFFF) - FF FFFF
word read_rom_word_LEAP(unsigned long address) // OLD TIMING #1
{
PORTL = (address >> 16) & 0xFF;
PORTK = (address >> 8) & 0xFF;
PORTF = address & 0xFF;
CE_LOW;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
OE_LOW;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
unsigned char data1 = PINC;
unsigned char data2 = PINA;
word data = (data1 << 8) | (data2);
OE_HIGH;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
CE_HIGH;
return data;
}
byte read_flash_byte_LEAP(unsigned long address) // CE HIGH, OE LOW, FL_CE LOW
{
PORTL = (address >> 17) & 0x7F;
PORTK = (address >> 9) & 0xFF;
PORTF = (address >> 1) & 0xFF;
if (address & 0x1) // BYTE = A0
BYTE_HIGH;
else
BYTE_LOW;
CE_HIGH;
OE_LOW;
FL_CE_LOW;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
unsigned char data = PINC;
FL_CE_HIGH;
OE_HIGH;
return data;
}
//******************************************
// WRITE FUNCTION
//******************************************
void write_flash_byte_LEAP(unsigned long address, unsigned char data)
{
PORTL = (address >> 17) & 0x7F;
PORTK = (address >> 9) & 0xFF;
PORTF = (address >> 1) & 0xFF;
if (address & 0x1) // BYTE = A0
BYTE_HIGH;
else
BYTE_LOW;
OE_HIGH;
FL_CE_LOW;
NOP;
NOP;
NOP;
NOP;
NOP;
PORTC = data;
WE_LOW;
WE_HIGH;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
FL_CE_HIGH;
OE_LOW;
}
//******************************************
// DATA INTEGRITY FUNCTIONS
//******************************************
void checkStart_LEAP()
{
delay(500);
OE_LOW;
CE_LOW;
BYTE_HIGH;
tempword = read_rom_word_LEAP(0x0);
if ((LEAP[0] == ((tempword >> 0x8) & 0xFF)) && (LEAP[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(0x1);
findTable_LEAP(0x4, 0xA2);
}
else {
delay(500);
tempword = read_rom_word_LEAP(0xA2);
if ((LEAP[0] == ((tempword >> 0x8) & 0xFF)) && (LEAP[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(0xA3);
findTable_LEAP(0xA4, 0x146);
}
}
CE_HIGH;
OE_HIGH;
}
void findTable_LEAP(unsigned long startAddr, unsigned long endAddr)
{
delay(500);
CE_LOW;
for (unsigned long addr = startAddr; addr < endAddr; addr +=2) {
tempword = read_rom_word_LEAP(addr);
if ((TBL[0] == ((tempword >> 0x8) & 0xFF))&&(TBL[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(addr + 1);
if ((TBL[2] == ((tempword >> 0x8) & 0xFF))&&(TBL[3] == (tempword & 0xFF))) {
readTable_LEAP(startAddr, endAddr);
break;
}
}
}
CE_HIGH;
}
void readTable_LEAP(unsigned long startAddr, unsigned long endAddr)
{
delay(500);
CE_LOW;
for (unsigned long addr = startAddr; addr < endAddr; addr++) {
tempword = read_rom_word_LEAP(addr);
if ((TXT[0] == ((tempword >> 0x8) & 0xFF))&&(TXT[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(addr + 1);
if ((TXT[2] == ((tempword >> 0x8) & 0xFF))&&(TXT[3] == (tempword & 0xFF))) { // Text Block Marker Found
ptrword = read_rom_word_LEAP(addr + 2);
sentenceAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
}
}
else if ((VER[0] == ((tempword >> 0x8) & 0xFF))&&(VER[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(addr + 1);
if ((VER[2] == ((tempword >> 0x8) & 0xFF))&&(VER[3] == (tempword & 0xFF))) { // Version Marker Found
ptrword = read_rom_word_LEAP(addr + 2);
versionAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
}
}
else if ((TTL[0] == ((tempword >> 0x8) & 0xFF))&&(TTL[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(addr + 1);
if ((TTL[2] == ((tempword >> 0x8) & 0xFF))&&(TTL[3] == (tempword & 0xFF))) { // Title Marker Found
ptrword = read_rom_word_LEAP(addr + 2);
titleAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
}
}
else if ((END[0] == ((tempword >> 0x8) & 0xFF))&&(END[1] == (tempword & 0xFF))) {
tempword = read_rom_word_LEAP(addr + 1);
if ((END[2] == ((tempword >> 0x8) & 0xFF))&&(END[3] == (tempword & 0xFF))) { // END OF TABLE
break;
}
}
}
CE_HIGH;
// print_Msg(F("Text Addr: "));
// println_Msg(sentenceAddr, HEX);
// print_Msg(F("Version Addr: "));
// println_Msg(versionAddr, HEX);
// print_Msg(F("Title Addr: "));
// println_Msg(titleAddr, HEX);
// display_Update();
delay(500);
CE_LOW;
for (int x = 0; x < 10; x++) {
tempword = read_rom_word_LEAP((versionAddr / 2) + x);
ROMVersion[x * 2] = (tempword >> 0x8) & 0xFF;
ROMVersion[(x * 2) + 1] = tempword & 0xFF;
}
delay(500);
CE_LOW;
for (int x = 0; x < 25; x++) {
tempword = read_rom_word_LEAP((titleAddr / 2) + x);
ROMTitle[x * 2] = (tempword >> 0x8) & 0xFF;
ROMTitle[(x * 2) + 1] = tempword & 0xFF;
}
}
//******************************************
// READ ROM
//******************************************
void readROM_LEAP()
{
createFolderAndOpenFile("LEAP", "ROM", romName, "bin");
for (unsigned long address = 0; address < 0x200000; address += 256) { // 4MB
for (unsigned int x = 0; x < 256; x++) {
tempword = read_rom_word_LEAP(address + x);
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
}
myFile.write(sdBuffer, 512);
}
if (leapsize > 0) {
for (unsigned long address = 0x200000; address < 0x400000; address += 256) { // +4MB = 8MB
for (unsigned int x = 0; x < 256; x++) {
tempword = read_rom_word_LEAP(address + x);
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
}
myFile.write(sdBuffer, 512);
}
if (leapsize > 1) {
for (unsigned long address = 0x400000; address < 0x800000; address += 256) { // +8MB = 16MB
for (unsigned int x = 0; x < 256; x++) {
tempword = read_rom_word_LEAP(address + x);
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
}
myFile.write(sdBuffer, 512);
}
}
}
myFile.close();
printCRC(fileName, NULL, 0);
println_Msg(FS(FSTRING_EMPTY));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
//******************************************
// ROM SIZE
//******************************************
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
void printRomSize_LEAP(int index)
{
display_Clear();
print_Msg(FS(FSTRING_ROM_SIZE));
println_Msg(LEAPSTER[index]);
}
#endif
void setROMSize_LEAP()
{
byte newleapsize;
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
display_Clear();
if (leaplo == leaphi)
newleapsize = leaplo;
else {
newleapsize = navigateMenu(leaplo, leaphi, &printRomSize_LEAP);
display.setCursor(0, 56); // Display selection at bottom
}
print_Msg(FS(FSTRING_ROM_SIZE));
print_Msg(LEAPSTER[newleapsize]);
println_Msg(F("KB"));
display_Update();
delay(1000);
#else
if (leaplo == leaphi)
newleapsize = leaplo;
else {
setrom:
String sizeROM;
for (int i = 0; i < (leaphi - leaplo + 1); i++) {
Serial.print(F("Select ROM Size: "));
Serial.print(i);
Serial.print(F(" = "));
Serial.print(LEAPSTER[i + leaplo]);
Serial.println(F("KB"));
}
Serial.print(F("Enter ROM Size: "));
while (Serial.available() == 0) {}
sizeROM = Serial.readStringUntil('\n');
Serial.println(sizeROM);
newleapsize = sizeROM.toInt() + leaplo;
if (newleapsize > leaphi) {
Serial.println(F("SIZE NOT SUPPORTED"));
Serial.println(FS(FSTRING_EMPTY));
goto setrom;
}
}
Serial.print(F("ROM Size = "));
Serial.print(LEAPSTER[newleapsize]);
Serial.println(F("KB"));
#endif
EEPROM_writeAnything(8, newleapsize);
leapsize = newleapsize;
}
void checkStatus_LEAP()
{
EEPROM_readAnything(8, leapsize);
if (leapsize > leaphi) {
leapsize = 1; // default 8M
EEPROM_writeAnything(8, leapsize);
}
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
display_Clear();
println_Msg(F("LEAPSTER READER"));
println_Msg(FS(FSTRING_CURRENT_SETTINGS));
println_Msg(FS(FSTRING_EMPTY));
print_Msg(F("TITLE: "));
println_Msg(ROMTitle);
print_Msg(F("VER: "));
println_Msg(ROMVersion);
print_Msg(FS(FSTRING_ROM_SIZE));
print_Msg(LEAPSTER[leapsize]);
println_Msg(F("MB"));
display_Update();
wait();
#else
Serial.print(F("TITLE: "));
Serial.println(ROMTitle);
Serial.print(F("VER: "));
Serial.println(ROMVersion);
Serial.print(FS(FSTRING_ROM_SIZE));
Serial.print(LEAPSTER[leapsize]);
Serial.println(F("MB"));
Serial.println(FS(FSTRING_EMPTY));
#endif
}
//******************************************
// FLASH SAVES
//******************************************
// FLASH 39VF040
// MR. PENCIL'S LEARN TO DRAW & WRITE
// TOP SECRET - PERSONAL BEESWAX
// FLASH IS BYTE MODE
// BYTE PIN IS A0 - SHIFT ADDRESS >> 1
void dataOut_LEAP()
{
DDRC = 0xFF;
DDRA = 0xFF;
}
void dataIn_LEAP()
{
DDRC = 0x00;
DDRA = 0x00;
}
void idFLASH_LEAP() // "BFD7" = 39VF040
{
int ID1 = 0;
int ID2 = 0;
dataOut_LEAP();
resetFLASH_LEAP();
write_flash_byte_LEAP(0x5555, 0xAA);
write_flash_byte_LEAP(0x2AAA, 0x55);
write_flash_byte_LEAP(0x5555, 0x90);
dataIn_LEAP();
ID1 = read_flash_byte_LEAP(0x0000);
ID2 = read_flash_byte_LEAP(0x0001);
dataOut_LEAP();
resetFLASH_LEAP();
dataIn_LEAP();
sprintf(flashid_str, "%02X%02X", ID1, ID2);
display_Clear();
print_Msg(F("Flash ID: "));
println_Msg(flashid_str);
display_Update();
}
void resetFLASH_LEAP()
{
write_flash_byte_LEAP(0x5555, 0xF0);
}
void eraseFLASH_LEAP()
{
write_flash_byte_LEAP(0x5555, 0xAA);
write_flash_byte_LEAP(0x2AAA, 0x55);
write_flash_byte_LEAP(0x5555, 0x80);
write_flash_byte_LEAP(0x5555, 0xAA);
write_flash_byte_LEAP(0x2AAA, 0x55);
write_flash_byte_LEAP(0x5555, 0x10);
}
void programFLASH_LEAP()
{
write_flash_byte_LEAP(0x5555, 0xAA);
write_flash_byte_LEAP(0x2AAA, 0x55);
write_flash_byte_LEAP(0x5555, 0xA0);
}
void statusFLASH_LEAP()
{
byte flashStatus = 1;
do {
flashStatus = ((PORTA & 0x80) >> 7); // D7 = PORTA7
_delay_us(4);
}
while (flashStatus == 1);
}
void readFLASH_LEAP()
{
createFolderAndOpenFile("LEAP", "SAVE", romName, "fla");
if(myFile) {
CE_HIGH;
OE_LOW;
FL_CE_LOW;
for (unsigned long address = 0x0; address < 0x80000; address += 512) { // 512K
if ((address % 0x8000) == 0) {
print_Msg(F("*"));
display_Update();
}
for (unsigned int x = 0; x < 512; x++) {
// CONSOLE READS ADDRESS 4X
do {
tempbyte = read_flash_byte_LEAP(address + x);
tempcheck = read_flash_byte_LEAP(address + x);
}
while (tempbyte != tempcheck);
sdBuffer[x] = tempbyte;
}
myFile.write(sdBuffer, 512);
}
myFile.flush();
myFile.close();
FL_CE_HIGH;
OE_HIGH;
println_Msg(FS(FSTRING_EMPTY));
printCRC(fileName, NULL, 0); // 512K
}
println_Msg(FS(FSTRING_EMPTY));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
void writeFLASH_LEAP()
{
fileBrowser(F("Select FLASH File"));
sd.chdir();
sprintf(filePath, "%s/%s", filePath, fileName);
display_Clear();
println_Msg(F("Writing File: "));
println_Msg(filePath);
println_Msg(fileName);
display_Update();
//open file on sd card
if (myFile.open(filePath, O_READ)) {
CE_HIGH;
dataOut_LEAP();
eraseFLASH_LEAP();
statusFLASH_LEAP();
delay(100); // WORKS ~75 OK
for (unsigned long address = 0x0; address < 0x80000; address += 512) { // 512K
myFile.read(sdBuffer, 512);
if ((address % 0x10000) == 0) {
print_Msg(F("*"));
display_Update();
}
for (unsigned int x = 0; x < 512; x++) {
programFLASH_LEAP();
write_flash_byte_LEAP(address + x, sdBuffer[x]);
}
}
dataIn_LEAP();
myFile.close();
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("FLASH FILE WRITTEN!"));
display_Update();
}
else {
println_Msg(F("SD ERROR"));
display_Update();
}
sd.chdir(); // root
filePath[0] = '\0'; // Reset filePath
}
//******************************************
// EEPROM SAVES
//******************************************
// EEPROM 24LC02/24LC16
// 24LC02B = 256 BYTES
// 24LC16B = 2048 BYTES
// DORA THE EXPLORER - WILDLIFE RESCUE 24LC16B
// SCHOLASTIC MATH MISSIONS 24LC16B
// MODIFIED FOR COMPATIBILITY WITH ISSI EEPROM
// PET PALS ISSI 416A-2GLI = 24C16A
// START - SDA HIGH TO LOW WHEN SCL HIGH
void eepromStart_LEAP()
{
SCL_LOW;
SDA_LOW;
SCL_HIGH;
_delay_us(2);
SDA_HIGH;
_delay_us(2);
SDA_LOW;
_delay_us(2);
SCL_LOW;
_delay_us(2);
}
void eepromSet0_LEAP()
{
SCL_LOW;
SDA_LOW;
_delay_us(2);
SCL_HIGH;
_delay_us(5);
SCL_LOW;
_delay_us(2);
}
void eepromSet1_LEAP()
{
SCL_LOW;
SDA_LOW;
_delay_us(2);
SDA_HIGH;
_delay_us(2);
SCL_HIGH;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP; // ~500ns
SCL_LOW;
SDA_LOW;
_delay_us(2);
}
void eepromDevice_LEAP()
{
eepromSet1_LEAP();
eepromSet0_LEAP();
eepromSet1_LEAP();
eepromSet0_LEAP();
}
void eepromSetDeviceAddress_LEAP(unsigned long addrhi)
{
for (int i = 0; i < 3; i++) {
if ((addrhi >> 2) & 0x1) // Bit is HIGH
eepromSet1_LEAP();
else // Bit is LOW
eepromSet0_LEAP();
addrhi <<= 1; // rotate to the next bit
}
}
void eepromStatus_LEAP() // ACK
{
byte eepStatus = 1;
DDRH &= ~(1 << 4); // SDA to INPUT
SCL_LOW;
_delay_us(2);
SCL_HIGH;
_delay_us(5);
SCL_LOW;
do {
eepStatus = ((PINH & 0x10) >> 4); // SDA = PORTH4
}
while (eepStatus == 1);
DDRH |= (1 << 4); // SDA to OUTPUT
}
void eepromReadMode_LEAP()
{
eepromSet1_LEAP(); // READ
eepromStatus_LEAP(); // ACK
}
void eepromWriteMode_LEAP()
{
eepromSet0_LEAP(); // WRITE
eepromStatus_LEAP(); // ACK
}
void eepromReadData_LEAP()
{
DDRH &= ~(1 << 4); // SDA to INPUT
for (int i = 0; i < 8; i++) {
SCL_LOW;
SDA_LOW;
_delay_us(2);
SCL_HIGH;
eepbit[i] = ((PINH & 0x10) >> 4); // SDA = PORTH4
if (eepbit[i] == 1) {
SCL_LOW;
_delay_us(4);
}
else {
_delay_us(4);
SCL_LOW;
}
_delay_us(2);
}
DDRH |= (1 << 4); // SDA to OUTPUT
}
void eepromWriteData_LEAP(byte data)
{
for (int i = 0; i < 8; i++) {
if ((data >> 7) & 0x1) // Bit is HIGH
eepromSet1_LEAP();
else // Bit is LOW
eepromSet0_LEAP();
data <<= 1; // rotate to the next bit
}
eepromStatus_LEAP(); // ACK
}
// STOP - SDA LOW TO HIGH WHEN SCL HIGH
void eepromStop_LEAP()
{
SCL_LOW;
SDA_LOW;
_delay_us(1);
SCL_HIGH;
_delay_us(2);
SDA_HIGH;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP; // ~500nS
SCL_LOW;
SDA_LOW;
}
void eepromSetAddress_LEAP(word address)
{
for (int i = 0; i < 8; i++) {
if ((address >> 7) & 0x1) // Bit is HIGH
eepromSet1_LEAP();
else // Bit is LOW
eepromSet0_LEAP();
address <<= 1; // rotate to the next bit
}
eepromStatus_LEAP(); // ACK
}
void readEepromByte_LEAP(word address)
{
word addrhi = address >> 8;
word addrlo = address & 0xFF;
eepromStart_LEAP(); // START
eepromDevice_LEAP(); // DEVICE [1010]
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10..A8]
eepromWriteMode_LEAP();
eepromSetAddress_LEAP(addrlo);
eepromStart_LEAP(); // START
eepromDevice_LEAP(); // DEVICE [1010]
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10..A8]
eepromReadMode_LEAP();
eepromReadData_LEAP();
eepromStop_LEAP(); // STOP
// OR 8 bits into byte
eeptemp = eepbit[0] << 7 | eepbit[1] << 6 | eepbit[2] << 5 | eepbit[3] << 4 | eepbit[4] << 3 | eepbit[5] << 2 | eepbit[6] << 1 | eepbit[7];
sdBuffer[addrlo] = eeptemp;
}
void writeEepromByte_LEAP(word address)
{
word addrhi = address >> 8;
word addrlo = address & 0xFF;
eeptemp = sdBuffer[addrlo];
eepromStart_LEAP(); // START
eepromDevice_LEAP(); // DEVICE [1010]
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10-A8]
eepromWriteMode_LEAP(); // WRITE
eepromSetAddress_LEAP(addrlo);
eepromWriteData_LEAP(eeptemp);
eepromStop_LEAP(); // STOP
}
// Read EEPROM and save to the SD card
void readEEP_LEAP()
{
createFolderAndOpenFile("LEAP", "SAVE", romName, "eep");
if (myFile) {
for (word currByte = 0; currByte < 2048; currByte += 256) {
for (int i = 0; i < 256; i++) {
readEepromByte_LEAP(currByte + i);
}
myFile.write(sdBuffer, 256);
}
// 24LC02
// for (word currByte = 0; currByte < 256; currByte++) {
// readEepromByte_LEAP(currByte);
// }
// myFile.write(sdBuffer, 256);
myFile.close();
printCRC(fileName, NULL, 0); // 2048
}
println_Msg(FS(FSTRING_EMPTY));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
void writeEEP_LEAP()
{
fileBrowser(F("Select EEPROM File"));
sd.chdir();
sprintf(filePath, "%s/%s", filePath, fileName);
display_Clear();
println_Msg(F("Writing File: "));
// println_Msg(filePath);
println_Msg(fileName);
display_Update();
//open file on sd card
if (myFile.open(filePath, O_READ)) {
WP_LOW;
for (word currByte = 0; currByte < 2048; currByte += 256) {
myFile.read(sdBuffer, 256);
for (int i = 0; i < 256; i++) {
writeEepromByte_LEAP(currByte + i);
delay(50);
}
print_Msg(F("*"));
display_Update();
}
WP_HIGH;
myFile.close();
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("EEPROM FILE WRITTEN!"));
display_Update();
}
else {
println_Msg(F("SD ERROR"));
display_Update();
}
sd.chdir(); // root
filePath[0] = '\0'; // Reset filePath
}
//******************************************
// CART SELECT CODE
//******************************************
void setCart_LEAP()
{
//go to root
sd.chdir();
byte gameSize;
// Select starting letter
//byte myLetter = starting_letter();
// Open database
if (myFile.open("leapster.txt", O_READ)) {
// seek_first_letter_in_database(myFile, myLetter);
if(checkCartSelection(myFile, &readDataLineSingleDigit, &gameSize)) {
EEPROM_writeAnything(8, gameSize);
}
} else {
print_FatalError(FS(FSTRING_DATABASE_FILE_NOT_FOUND));
}
}
#endif