diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index cef8c98..47c1eac 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -2,8 +2,8 @@ Cartridge Reader for Arduino Mega2560 Author: sanni - Date: 22-10-2018 - Version: 2.2 + Date: 30-10-2018 + Version: 2.3 SD lib: https://github.com/greiman/SdFat LCD lib: https://github.com/adafruit/Adafruit_SSD1306 @@ -37,7 +37,7 @@ vogelfreiheit - N64 flashram fix **********************************************************************************/ -char ver[5] = "2.2"; +char ver[5] = "2.3"; /****************************************** Define Starting Point @@ -71,6 +71,8 @@ char ver[5] = "2.2"; ******************************************/ // If set to 1 then the crc32 checksum will be calculated after reading a N64 rom boolean n64crc = 1; +// Enable 16bit flash adapter menu +//#define enable_flash16 /****************************************** Libraries @@ -1379,4 +1381,4 @@ void loop() { //****************************************** // End of File -//****************************************** +//****************************************** diff --git a/Cart_Reader/FLASH.ino b/Cart_Reader/FLASH.ino index ae09325..760b8f2 100644 --- a/Cart_Reader/FLASH.ino +++ b/Cart_Reader/FLASH.ino @@ -19,9 +19,9 @@ boolean hiROM = 1; Menu *****************************************/ // Flash start menu -static const char flashMenuItem1[] PROGMEM = "8bit adapter"; -static const char flashMenuItem2[] PROGMEM = "16bit adapter(old)"; -static const char flashMenuItem3[] PROGMEM = "Eprom adapter(beta)"; +static const char flashMenuItem1[] PROGMEM = "8bit Flash adapter"; +static const char flashMenuItem2[] PROGMEM = "Eprom adapter(beta)"; +static const char flashMenuItem3[] PROGMEM = "16bit Flash adapter"; static const char* const menuOptionsFlash[] PROGMEM = {flashMenuItem1, flashMenuItem2, flashMenuItem3}; // 8bit Flash menu items @@ -57,8 +57,13 @@ void flashMenu() { // create menu with title and 3 options to choose from unsigned char flashSlot; // Copy menuOptions out of progmem +#ifdef enable_flash16 convertPgm(menuOptionsFlash, 3); flashSlot = question_box("Select adapter PCB", menuOptions, 3, 0); +#else + convertPgm(menuOptionsFlash, 2); + flashSlot = question_box("Select adapter PCB", menuOptions, 2, 0); +#endif // wait for user choice to come back from the question box menu switch (flashSlot) @@ -76,17 +81,17 @@ void flashMenu() { case 1: display_Clear(); display_Update(); - setup_Flash16(); - id_Flash16(); - wait(); - mode = mode_FLASH16; + setup_Eprom(); + mode = mode_EPROM; break; case 2: display_Clear(); display_Update(); - setup_Eprom(); - mode = mode_EPROM; + setup_Flash16(); + id_Flash16(); + wait(); + mode = mode_FLASH16; break; } } diff --git a/Cart_Reader/MD.ino b/Cart_Reader/MD.ino index ea63991..ef198ca 100644 --- a/Cart_Reader/MD.ino +++ b/Cart_Reader/MD.ino @@ -31,7 +31,7 @@ void mdMenu() { unsigned char mainMenu; // Copy menuOptions out of progmem convertPgm(menuOptionsMD, 5); - mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 3, 0); + mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 5, 0); // wait for user choice to come back from the question box menu switch (mainMenu) @@ -90,18 +90,47 @@ void mdMenu() { } break; - /*case 3: - // Change working dir to root - sd.chdir("/"); - writeFlash_MD(); - // Reset - wait(); - asm volatile (" jmp 0"); - break; + case 3: + // Change working dir to root + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser("Select file"); + display_Clear(); + // Setting CS(PH3) LOW + PORTH &= ~(1 << 3); - case 4: - asm volatile (" jmp 0"); - break;*/ + // ID flash + resetFlash_MD(); + idFlash_MD(); + resetFlash_MD(); + print_Msg("Flash ID: "); + println_Msg(flashid); + if (strcmp(flashid, "C2F1") == 0) { + println_Msg("MX29F1610 detected"); + flashSize = 2097152; + } + else { + print_Error(F("Error: Unknown flashrom"), true); + } + display_Update(); + + eraseFlash_MD(); + resetFlash_MD(); + blankcheck_MD(); + write29F1610_MD(); + resetFlash_MD(); + delay(1000); + resetFlash_MD(); + delay(1000); + verifyFlash_MD(); + // Set CS(PH3) HIGH + PORTH |= (1 << 3); + break; + + case 4: + // Reset + asm volatile (" jmp 0"); + break; } println_Msg(F("")); println_Msg(F("Press Button...")); @@ -206,6 +235,55 @@ word readWord_MD(unsigned long myAddress) { return tempWord; } +void writeFlash_MD(unsigned long myAddress, word myData) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTL = (myAddress >> 16) & 0xFF; + PORTC = myData; + PORTA = (myData >> 8) & 0xFF; + + // Arduino running at 16Mhz -> one nop = 62.5ns + // Wait till output is stable + __asm__("nop\n\t"); + + // Switch WE(PH5) to LOW + PORTH &= ~(1 << 5); + + // Leave WE low for at least 60ns + __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"); + + // Switch WE(PH5)to HIGH + PORTH |= (1 << 5); + + // Leave WE high for at least 50ns + __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"); +} + +word readFlash_MD(unsigned long myAddress) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTL = (myAddress >> 16) & 0xFF; + + // Arduino running at 16Mhz -> one nop = 62.5ns + __asm__("nop\n\t"); + + // Setting OE(PH6) LOW + PORTH &= ~(1 << 6); + + __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"); + + // Read + word tempWord = ( ( PINA & 0xFF ) << 8 ) | ( PINC & 0xFF ); + + __asm__("nop\n\t"); + + // Setting OE(PH6) HIGH + PORTH |= (1 << 6); + __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"); + + return tempWord; +} + // Switch data pins to write void dataOut_MD() { DDRC = 0xFF; @@ -494,6 +572,209 @@ unsigned long verifySram_MD() { return writeErrors; } +//****************************************** +// Flashrom Functions +//****************************************** +void resetFlash_MD() { + // Set data pins to output + dataOut_MD(); + + // Reset command sequence + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0xf0); + + // Set data pins to input again + dataIn_MD(); +} + +void write29F1610_MD() { + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + print_Msg(F("Flashing file ")); + print_Msg(filePath); + println_Msg(F("...")); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + fileSize = myFile.fileSize(); + if (fileSize > flashSize) { + print_Error(F("File size exceeds flash size."), true); + } + // Set data pins to output + dataOut_MD(); + + // Fill sdBuffer with 1 page at a time then write it repeat until all bytes are written + int d = 0; + for (unsigned long currByte = 0; currByte < fileSize / 2; currByte += 64) { + myFile.read(sdBuffer, 128); + + // Blink led + if (currByte % 4096 == 0) { + PORTB ^= (1 << 4); + } + + // Write command sequence + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0xa0); + + // Write one full page at a time + for (byte c = 0; c < 64; c++) { + word currWord = ( ( sdBuffer[d] & 0xFF ) << 8 ) | ( sdBuffer[d + 1] & 0xFF ); + writeFlash_MD(currByte + c, currWord); + d += 2; + } + d = 0; + + // Check if write is complete + delayMicroseconds(100); + busyCheck_MD(); + } + + // Set data pins to input again + dataIn_MD(); + + // Close the file: + myFile.close(); + } + else { + println_Msg(F("Can't open file")); + display_Update(); + } +} + +void idFlash_MD() { + // Set data pins to output + dataOut_MD(); + + // ID command sequence + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0x90); + + // Set data pins to input again + dataIn_MD(); + + // Read the two id bytes into a string + sprintf(flashid, "%02X%02X", readFlash_MD(0) & 0xFF, readFlash_MD(1) & 0xFF); +} + +byte readStatusReg_MD() { + // Set data pins to output + dataOut_MD(); + + // Status reg command sequence + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0x70); + + // Set data pins to input again + dataIn_MD(); + + // Read the status register + byte statusReg = readFlash_MD(0); + return statusReg; +} + +void eraseFlash_MD() { + // Set data pins to output + dataOut_MD(); + + // Erase command sequence + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0x80); + writeFlash_MD(0x5555, 0xaa); + writeFlash_MD(0x2aaa, 0x55); + writeFlash_MD(0x5555, 0x10); + + // Set data pins to input again + dataIn_MD(); + + busyCheck_MD(); +} + +void blankcheck_MD() { + blank = 1; + for (unsigned long currByte = 0; currByte < flashSize / 2; currByte++) { + if (readFlash_MD(currByte) != 0xFFFF) { + currByte = flashSize / 2; + blank = 0; + } + if (currByte % 4096 == 0) { + PORTB ^= (1 << 4); + } + } + if (!blank) { + print_Error(F("Error: Not blank"), false); + } +} + +void verifyFlash_MD() { + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + fileSize = myFile.fileSize(); + if (fileSize > flashSize) { + print_Error(F("File size exceeds flash size."), true); + } + + blank = 0; + word d = 0; + for (unsigned long currByte = 0; currByte < fileSize / 2; currByte += 256) { + if (currByte % 4096 == 0) { + PORTB ^= (1 << 4); + } + //fill sdBuffer + myFile.read(sdBuffer, 512); + for (int c = 0; c < 256; c++) { + word currWord = ((sdBuffer[d] << 8) | sdBuffer[d + 1]); + + if (readFlash_MD(currByte + c) != currWord) { + blank++; + } + d += 2; + } + d = 0; + } + if (blank == 0) { + println_Msg(F("Flashrom verified OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(blank); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + // Close the file: + myFile.close(); + } + else { + println_Msg(F("Can't open file")); + display_Update(); + } +} + +// Delay between write operations based on status register +void busyCheck_MD() { + // Set data pins to input + dataIn_MD(); + + // Read the status register + word statusReg = readFlash_MD(0); + + while ((statusReg | 0xFF7F) != 0xFFFF) { + statusReg = readFlash_MD(0); + } + + // Set data pins to output + dataOut_MD(); +} + //****************************************** // End of File //****************************************** diff --git a/Cart_Reader/SNES.ino b/Cart_Reader/SNES.ino index 1d64c2f..10b7c10 100644 --- a/Cart_Reader/SNES.ino +++ b/Cart_Reader/SNES.ino @@ -1932,4 +1932,4 @@ boolean eraseSRAM (byte b) { //****************************************** // End of File -//****************************************** +//****************************************** diff --git a/Cart_Reader/SV.ino b/Cart_Reader/SV.ino index 423cae4..a9fd7b0 100644 --- a/Cart_Reader/SV.ino +++ b/Cart_Reader/SV.ino @@ -43,7 +43,7 @@ void svMenu() { // Copy menuOptions out of progmem convertPgm(menuOptionsSVFlash, 3); mainMenu = question_box("Satellaview 8M Memory", menuOptions, 3, 0); - + // wait for user choice to come back from the question box menu switch (mainMenu) { @@ -205,7 +205,7 @@ void writeROM_SV (void) { sprintf(checksumStr, "%02X%02X", readBank_SNES(0, 65503), readBank_SNES(0, 65502)); //if CRC is not 8B86, BS-X cart is not inserted. Display error and reset - if(strcmp("8B86", checksumStr) != 0) + if (strcmp("8B86", checksumStr) != 0) { display_Clear(); print_Error(F("Error: Must use BS-X cart"), true); @@ -241,7 +241,7 @@ void writeROM_SV (void) { println_Msg(F("Erasing pack...")); display_Update(); eraseAll_SV(); - + //Blank check //Set pins to input dataIn(); @@ -251,7 +251,7 @@ void writeROM_SV (void) { for (int currBank = 0xC0; currBank < 0xD0; currBank++) { draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000); for (long currByte = 0; currByte < 65536; currByte++) { - if(0xFF != readBank_SNES(currBank, currByte)) + if (0xFF != readBank_SNES(currBank, currByte)) { println_Msg(F("")); println_Msg(F("Erase failed")); @@ -272,7 +272,7 @@ void writeROM_SV (void) { for (int currBank = 0xC0; currBank < 0xD0; currBank++) { draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000); for (long currByte = 0; currByte < 65536; currByte++) { - + writeBank_SNES(0xC0, 0x0000, 0x10); //Program Byte writeBank_SNES(currBank, currByte, myFile.read()); writeBank_SNES(0xC0, 0x0000, 0x70); //Status Mode @@ -285,7 +285,7 @@ void writeROM_SV (void) { writeBank_SNES(0xC0, 0x0000, 0xFF); //Terminate write draw_progressbar(0x100000, 0x100000); - + //Verify dataIn(); //Set pins to input controlIn_SNES(); @@ -295,7 +295,7 @@ void writeROM_SV (void) { for (int currBank = 0xC0; currBank < 0xD0; currBank++) { draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000); for (long currByte = 0; currByte < 65536; currByte++) { - if(myFile.read() != readBank_SNES(currBank, currByte)) + if (myFile.read() != readBank_SNES(currBank, currByte)) { println_Msg(F("")); println_Msg(F("Verify failed")); @@ -306,7 +306,7 @@ void writeROM_SV (void) { } } } - + // Close the file: myFile.close(); draw_progressbar(0x100000, 0x100000); @@ -327,7 +327,7 @@ void eraseCheck_SV(void) { // Read register ret = readBank_SNES(0xC0, 0x0004); - + // CE or OE must be toggled with each subsequent status read or the // completion of a program or erase operation will not be evident. while ((ret & 0x80) == 0x00) { //Wait until X.bit7 = 1 @@ -354,7 +354,7 @@ void supplyCheck_SV(void) { // Read register ret = readBank_SNES(0xC0, 0x0004); - + // CE or OE must be toggled with each subsequent status read or the // completion of a program or erase operation will not be evident. while ((ret & 0x08) == 0x08) { //Wait until X.bit3 = 0 @@ -381,7 +381,7 @@ void writeCheck_SV(void) { // Read register ret = readBank_SNES(0xC0, 0x0000); - + // CE or OE must be toggled with each subsequent status read or the // completion of a program or erase operation will not be evident. while ((ret & 0x80) == 0x00) { @@ -410,12 +410,12 @@ void detectCheck_SV(void) { // Read register ret = readBank_SNES(0xC0, 0x0002); - + // CE or OE must be toggled with each subsequent status read or the // completion of a program or erase operation will not be evident. while ((ret & 0x80) == 0x00) { i++; - if( i > 10000) + if ( i > 10000) { //timeout break; @@ -454,4 +454,3 @@ void eraseAll_SV(void) //****************************************** // End of File //****************************************** -