diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index 598ba92..c128984 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: 2017-06-25 - Version: V26 + Date: 2017-06-26 + Version: V27 SD lib: https://github.com/greiman/SdFat LCD lib: https://github.com/adafruit/Adafruit_SSD1306 @@ -34,7 +34,7 @@ YamaArashi - GBA flashrom bank switch command **********************************************************************************/ -char ver[5] = "V26"; +char ver[5] = "V27"; /****************************************** Define Output @@ -124,6 +124,7 @@ SdFile myFile; #define mode_FLASH16 8 #define mode_GBA 9 #define mode_GBM 10 +#define mode_MD 11 /****************************************** Variables @@ -179,10 +180,10 @@ char fileOptions[30][20]; // Common char romName[17]; -int sramSize = 0; +unsigned long sramSize = 0; int romType = 0; byte saveType; -int romSize = 0; +word romSize = 0; byte numBanks = 128; char checksumStr[5]; bool errorLvl = 0; @@ -324,9 +325,10 @@ static const char modeItem1[] PROGMEM = "Nintendo 64"; static const char modeItem2[] PROGMEM = "Super Nintendo"; static const char modeItem3[] PROGMEM = "Nintendo Power"; static const char modeItem4[] PROGMEM = "Game Boy"; -static const char modeItem5[] PROGMEM = "Flashrom Programmer"; -static const char modeItem6[] PROGMEM = "About"; -static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6}; +static const char modeItem5[] PROGMEM = "Mega Drive"; +static const char modeItem6[] PROGMEM = "Flashrom Programmer"; +static const char modeItem7[] PROGMEM = "About"; +static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7}; // N64 Submenu static const char n64MenuItem1[] PROGMEM = "Cart Slot"; @@ -353,8 +355,8 @@ void mainMenu() { // create menu with title and 6 options to choose from unsigned char modeMenu; // Copy menuOptions out of progmem - convertPgm(modeOptions, 6); - modeMenu = question_box("Cartridge Reader", menuOptions, 6, 0); + convertPgm(modeOptions, 7); + modeMenu = question_box("Cartridge Reader", menuOptions, 7, 0); // wait for user choice to come back from the question box menu switch (modeMenu) @@ -456,6 +458,13 @@ void mainMenu() { break; case 4: + display_Clear(); + display_Update(); + setup_MD(); + mode = mode_MD; + break; + + case 5: // create menu with title and 2 options to choose from unsigned char flashSlot; // Copy menuOptions out of progmem @@ -481,7 +490,7 @@ void mainMenu() { } break; - case 5: + case 6: display_Clear(); // Draw the Logo display.drawBitmap(0, 0, sig, 128, 64, 1); @@ -1308,6 +1317,9 @@ void loop() { else if (mode == mode_GBM) { gbmMenu(); } + else if (mode == mode_MD) { + mdMenu(); + } else { display_Clear(); println_Msg(F("Menu Error")); diff --git a/Cart_Reader/MD.ino b/Cart_Reader/MD.ino new file mode 100644 index 0000000..08d5529 --- /dev/null +++ b/Cart_Reader/MD.ino @@ -0,0 +1,282 @@ +//****************************************** +// SEGA MEGA DRIVE +//****************************************** + +/****************************************** + Menu + *****************************************/ +// MD menu items +static const char MDMenuItem1[] PROGMEM = "Read Rom"; +static const char MDMenuItem2[] PROGMEM = "Read Save"; +static const char MDMenuItem3[] PROGMEM = "Write Save"; +static const char MDMenuItem4[] PROGMEM = "Write Flashcart"; +static const char MDMenuItem5[] PROGMEM = "Reset"; +static const char* const menuOptionsMD[] PROGMEM = {MDMenuItem1, MDMenuItem2, MDMenuItem3, MDMenuItem4, MDMenuItem5}; + +void mdMenu() { + // create menu with title and 5 options to choose from + unsigned char mainMenu; + // Copy menuOptions out of progmem + convertPgm(menuOptionsMD, 5); + mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 1, 0); + + // wait for user choice to come back from the question box menu + switch (mainMenu) + { + case 0: + display_Clear(); + // Change working dir to root + sd.chdir("/"); + readROM_MD(); + //compare_checksum_MD(); + break; + + /*case 1: + display_Clear(); + // Does cartridge have SRAM + if () { + // Change working dir to root + sd.chdir("/"); + readSRAM_MD(); + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; + + case 2: + display_Clear(); + // Does cartridge have SRAM + if () { + // Change working dir to root + sd.chdir("/"); + writeSRAM_MD(); + unsigned long wrErrors; + wrErrors = verifySRAM_MD(); + if (wrErrors == 0) { + println_Msg(F("Verified OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(wrErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; + + case 3: + // Change working dir to root + sd.chdir("/"); + writeFlash_MD(); + // Reset + wait(); + asm volatile (" jmp 0"); + break; + + case 4: + asm volatile (" jmp 0"); + break;*/ + } + println_Msg(F("")); + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + +/****************************************** + Setup + *****************************************/ +void setup_MD() { + // Set Address Pins to Output + //A0-A7 + DDRF = 0xFF; + //A8-A15 + DDRK = 0xFF; + //A16-A23 + DDRL = 0xFF; + + // Set Control Pins to Output CS(PH3) WR(PH5) OE(PH6) + DDRH |= (1 << 3) | (1 << 5) | (1 << 6); + + // Set Data Pins (D0-D15) to Input + DDRC = 0x00; + DDRA = 0x00; + + // Setting WR(PH5) OE(PH6) HIGH + PORTH |= (1 << 5) | (1 << 6); + // Setting CS(PH3) LOW + PORTH &= ~(1 << 3); + + delay(200); + + // Print all the info + getCartInfo_MD(); +} + +/****************************************** + I/O Functions + *****************************************/ + +/****************************************** + Low level functions +*****************************************/ +void writeWord_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 WR(PH5) to LOW + PORTH &= ~(1 << 5); + + // Leave WR low for at least 60ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Switch WR(PH5) to HIGH + PORTH |= (1 << 5); + + // Leave WR high for at least 50ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); +} + +word readWord_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""nop\n\t""nop\n\t""nop\n\t""nop\n\t""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"); + + // Read + word tempWord = ( ( PINA & 0xFF ) << 8 ) | ( PINC & 0xFF ); + + // 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"); + + return tempWord; +} + +// Switch data pins to write +void dataOut_MD() { + DDRC = 0xFF; + DDRA = 0xFF; +} + +// Switch data pins to read +void dataIn_MD() { + DDRC = 0x00; + DDRA = 0x00; +} + +/****************************************** + MEGA DRIVE functions +*****************************************/ +void getCartInfo_MD() { + cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1; + sramSize = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD)) - ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB)) + 2; + + // Get name + for (byte c = 0; c < 48; c += 2) { + // split word + word myWord = readWord_MD((0x150 + c) / 2); + byte loByte = myWord & 0xFF; + byte hiByte = myWord >> 8; + + // write to buffer + sdBuffer[c] = hiByte; + sdBuffer[c + 1] = loByte; + } + byte myLength = 0; + for (unsigned int i = 0; i < 48; i++) { + if (((char(sdBuffer[i]) >= 48 && char(sdBuffer[i]) <= 57) || (char(sdBuffer[i]) >= 65 && char(sdBuffer[i]) <= 122)) && myLength < 15) { + romName[myLength] = char(sdBuffer[i]); + myLength++; + } + } + + display_Clear(); + println_Msg(F("Cart Info")); + println_Msg(F(" ")); + print_Msg(F("Name: ")); + println_Msg(romName); + print_Msg(F("Size: ")); + print_Msg(cartSize / 1024 / 1024); + println_Msg(F("MB")); + print_Msg(F("Sram: ")); + print_Msg(sramSize / 1024); + println_Msg(F("KB")); + + // Wait for user input + if (enable_OLED) { + println_Msg(F(" ")); + println_Msg(F("Press Button...")); + display_Update(); + wait(); + } +} + +// Read rom and save to the SD card +void readROM_MD() { + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".MD"); + + // create a new folder + EEPROM_readAnything(10, foldern); + sprintf(folder, "MD/ROM/%s/%d", romName, foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + display_Clear(); + print_Msg(F("Saving to ")); + print_Msg(folder); + println_Msg(F("/...")); + display_Update(); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(10, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + print_Error(F("SD Error"), true); + } + + word d = 0; + for (unsigned long currBuffer = 0; currBuffer < cartSize / 2; currBuffer += 256) { + // Blink led + if (currBuffer % 16384 == 0) + PORTB ^= (1 << 4); + + for (int currWord = 0; currWord < 256; currWord++) { + word myWord = readWord_MD(currBuffer + currWord); + // Split word into two bytes + // Left + sdBuffer[d] = (( myWord >> 8 ) & 0xFF); + // Right + sdBuffer[d + 1] = (myWord & 0xFF); + d += 2; + } + myFile.write(sdBuffer, 512); + d = 0; + } + // Close the file: + myFile.close(); +} +