ROM-Reader for Super Nintendo / Super Famicom Game Cartridges

Yes it's inside gb.ino, right now WE/WR is set to PH5.

void setup_GB() {
// 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 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);

void writeByte_GB(int myAddress, uint8_t myData) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTC = myData;

// Arduino running at 16Mhz -> one nop = 62.5ns
// Wait till output is stable
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");

// Pull WR(PH5) low
PORTH &= ~(1 << 5);

// Leave WE low for at least 60ns
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");

// Pull WR(PH5) HIGH
PORTH |= (1 << 5);

// Leave WE high for at least 50ns
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}

The pinout.xls from the github will help you with figuring out what Arduino pin is connected to which GB cart slot pin.

Perfect, I will give it a shot and see what happens.

sanni:
I don't know exactly why this fixed it but I updated the code on github anyway. :slight_smile:
The added slot on the design idea I posted is a NES slot but ofc there is no code written for it.

Oh wow, I'm surprised you added an NES slot to the cart reader sanni.

Just wondering if you're working on code for it? I think I remember seeing another device which can backup/restore NES saves, although I believe it's in the beta stage (as tempting as it is to buy this device, I think I'm gonna stick with the Arduino). I'm looking forward to hearing more news about the new NES slot in the future.

Well, I would love to order the new PCB but it's $50 or more just to see if I made any mistakes designing it so I'm probably not going to place the order since there are better alternatives to read NES carts with the new infinitneslives dumper.

The goal of the new PCB design was to make building the Cart Reader cheaper but since a 150x100mm PCB is so much more expensive than a 100x100mm PCB that didn't really happen.
Maybe when PCBs get cheaper in the future I'll build it just for fun.

In terms of the pcb redesign, would doing an nes adapter be feasible as an alternative? The other item that might be attractive to people is a gamegear adapter.

Tried the bennvenn cart, but after making the changes it gets past the “Blankcheck” and erase phase but then stops at the flashing stage. On the plus side, it didn’t actually erase the cart, so it still functions as before.

Any additional suggestions?

Edit: Could the fact that MBM29F033C expects 256 bank be an issue? Or does the flashing effectively ignore that and just use whatever it detects the cartridge has (it correctly detects the cart is 128 bank)

Hey, new here, really like the project you made Sanni. Having bought a SFC not too long ago with a few games on ebay, I wanted to read and patch some of my Japanese games.

The github page / wiki has all the links necessary to buy everything you need to build one of these, thanks for that!

My advice, as you mentioned yourself, is to try and keep the PCB to 10x10cm, unless some other PCB fab has a better deal than JLPCB.

Now, I've put the dimensions of your new board (15x10cm) into PCB shopper and JLPCB is still the cheapest at 20$ for 5, https://pcbshopper.com/

I do want to build one, but I'd like to know if and when you're going to update the current design to the new one?
Should I just wait for the new board or go ahead and buy the current version ?

I'm not planning to update the PCB on github any time soon so you can go ahead and build the current version.

sanni:
I'm not planning to update the PCB on github any time soon so you can go ahead and build the current version.

All right, just bought the essentials for the SNES.
Some of the components from the BOM list are unavailable, but I found replacements pretty easily.

Hope nothing gets lost in transit from China.

Newbie2:
Any additional suggestions?

First, you should make sure that the cart gets erased properly.
So you could, for example, add while(1); into the function void writeFlash_GB:

delay(100);
println_Msg(F("Erasing flash"));
display_Update();

// Erase flash
writeByte_GB(0x555, 0xaa);
writeByte_GB(0x2aa, 0x55);
writeByte_GB(0x555, 0x80);
writeByte_GB(0x555, 0xaa);
writeByte_GB(0x2aa, 0x55);
writeByte_GB(0x555, 0x10);

dataIn_GB();

// Read the status register
byte statusReg = readByte_GB(0);

// After a completed erase D7 will output 1
while ((statusReg & 0x80) != 0x80) {
// Blink led
PORTB ^= (1 << 4);
delay(100);
// Update Status
statusReg = readByte_GB(0);
}

// Blankcheck
println_Msg(F("Blankcheck"));
display_Update();

to:

delay(100);
println_Msg(F("Erasing flash"));
display_Update();

// Erase flash
writeByte_GB(0x555, 0xaa);
writeByte_GB(0x2aa, 0x55);
writeByte_GB(0x555, 0x80);
writeByte_GB(0x555, 0xaa);
writeByte_GB(0x2aa, 0x55);
writeByte_GB(0x555, 0x10);

dataIn_GB();

// Read the status register
byte statusReg = readByte_GB(0);

// After a completed erase D7 will output 1
while ((statusReg & 0x80) != 0x80) {
// Blink led
PORTB ^= (1 << 4);
delay(100);
// Update Status
statusReg = readByte_GB(0);
}

// Blankcheck
println_Msg(F("Blankcheck"));
display_Update();
while(1);

The while(1); will make sure that after the erase nothing will be written to the cartridge. Then once "Blankcheck" is displayed you can switch the Cart Reader off and then on again and try to dump the cartridge and then check with a hex editor like HxD if the whole file you dumped consists out of 0xFF, meaning it erased fully.

If it did not erase then you need to change the code according to the datasheet of the used flashrom until it is erased.

If it is fully erased you can remove the while(1); again and write a rom to the cartridge, then dump the cartridge again and compare the dump in HxD to the file you wanted to write and see where exactly the writing failed.

sanni, can I use this card reader to mount the cartreader?
https://pt.aliexpress.com/item/FREE-SHIPPING-1PCS-LOT-Reading-and-writing-module-SD-Card-Module-Slot-Socket-Reader/32262829840.html?spm=a2g0s.9042311.0.0.6acfb90aEdyPlI

Or can I use it directly from your tutorial without converting to SD?

I would like to save on these pcb.

Yes, you can use both directly:
https://www.aliexpress.com/item/FREE-SHIPPING-1PCS-LOT-Reading-and-writing-module-SD-Card-Module-Slot-Socket-Reader/32262829840.html
https://www.aliexpress.com/item/Micro-SD-card-mini-TF-card-reader-module-SPI-interfaces-with-level-converter-chip/1000001126725.html

Thank you sanni!

sanni:
Yes, you can use both directly:
https://www.aliexpress.com/item/FREE-SHIPPING-1PCS-LOT-Reading-and-writing-module-SD-Card-Module-Slot-Socket-Reader/32262829840.html
https://www.aliexpress.com/item/Micro-SD-card-mini-TF-card-reader-module-SPI-interfaces-with-level-converter-chip/1000001126725.html

Thank you!

Sanni, really appreciate your guidance in response to my questions. The erase didn’t work, I am going to reach out to BennVenn to see if he has thoughts on what actions are necessary to get it to erase. Irregardless of whether I suceed, I very much appreciate your assistance.

Hi There! I am looking into building my own 64 rom reader and was excited to see this project! I was looking at the github for the code and the specs and noticed there was no pcb file for 64 hardware variant.

This is the cart reader variant I want to build:

Am I missing something? Thanks

Newbie2:
The erase didn’t work

Try to replace the erase command block with this, basically just adding the " << 1":
// Erase flash
writeByte_GB(0x555 << 1, 0xaa);
writeByte_GB(0x2aa << 1, 0x55);
writeByte_GB(0x555 << 1, 0x80);
writeByte_GB(0x555 << 1, 0xaa);
writeByte_GB(0x2aa << 1, 0x55);
writeByte_GB(0x555 << 1, 0x10);

Then check if it gets erased now.

Merix347:
This is the cart reader variant I want to build:
Home · sanni/cartreader Wiki · GitHub

That is a very old design. Only the newest PCB with the 4 slots is available on github. If you only need N64 just leave the other slots off.

Okay, that makes sense, Thank You!

sanni:
Try to replace the erase command block with this, basically just adding the " << 1":
// Erase flash
writeByte_GB(0x555 << 1, 0xaa);
writeByte_GB(0x2aa << 1, 0x55);
writeByte_GB(0x555 << 1, 0x80);
writeByte_GB(0x555 << 1, 0xaa);
writeByte_GB(0x2aa << 1, 0x55);
writeByte_GB(0x555 << 1, 0x10);

Then check if it gets erased now.

No change, and the erase happens very quick, which to me suggests nothing is actually happening. I emailed BennVenn to see if he had any thoughts and he stated that the standard WE pin on the cart edge is for bank control and whatnot, but any flash commands to be issued are using the Audio pin. To me it seemed the code that had the PH5 portions were only about issuing the flash commands, but is that not the case (ie does changing from the WR pin to the Audio pin in those sections also change what pin is used for bank control)?

Edit: He also suggested that using both pins at the same time wouldn’t upset the IC and thus might be an option, if bank control and the write commands are tied to the same pin in your code

That makes sense, in this case in setup_GB leave WR(PH5) as is and add WE(PH4):

// Set Control Pins to Output CS(PH3) WE(PH4) WR(PH5) RD(PH6)
DDRH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
// Output a high signal on all pins, pins are active low therefore everything is disabled now
PORTH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);

In writeByte_GB toggle both WE(PH4) and WR(PH5)

void writeByte_GB(int myAddress, uint8_t myData) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8 ) & 0xFF;
PORTC = myData;

// Arduino running at 16Mhz -> one nop = 62.5ns
// Wait till output is stable
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");

// Pull WE(PH4) WR(PH5) low
PORTH &= ~((1 << 4) | (1 << 5));

// Leave WE/WR low for at least 60ns
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");

// Pull WE(PH4) WR(PH5) HIGH
PORTH |= (1 << 4) | (1 << 5);

// Leave WE/WR high for at least 50ns
asm("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}

Hey sanni,

I've been working on a project based off of your reader for a few weeks now and I'm struggling to get it working. The end goal is to use a dedicated ATMEGA2560 with all accompanying hardware such as the power regulators, battery, screen, switches, etc and just have some edge connectors to hook up to the cart reader modules such as Game Boy, N64, etc. I just made my first prototype using the embed version of the Arduino Mega 2560 and I can't get it to read any Game Boy games. GB/C games are partially recognized but the title is wrong and I am unable to get a clean dump. ROM dumps are invalid and do not boot in an emulator and the checksum fails when dumping. GBA games just report cartridge error. All the other hardware seems to work just fine, including power management, voltage switching, charging, screen, buttons, SD reader, etc. I used the spreadsheet with the pinouts to make the schematic for this.

At this point, I think it's just a silly mistake but I still cannot find the error. I know it's not the SD card or the carts themselves because my other, unmodifed reader can handle both with no issues. If I post the schematic or board files, can you help out?

Thanks

Seemingly random errors like this are often caused by either dirty/corroded cartridge pins, a bad solder joint, a shorted address or data line, too tight timings or a bug in the code.
So there might either be a hardware problem with your PCB or you encountered a bug in the code that only gets triggered in edge cases and your PCB made this bug more "visible".

Hardware:
So first I would make sure the cartridge's contacts look like new and if not clean them.
Then I would check with a multimeter that none of the GB slot pins are shorted to GND which can happen if the solder mask got misaligned in the factory by a tiny bit.
Then I would check that none of the GB slot pins are shorted to another GB slot pin.
Then I would measure the resistance of the power switch, I had slide switches with several Ohms resistance in the past that produced a similar error, although only with the 3.3V systems.
And finally, I would use a multimeter to measure each address/data pin's resistance from the Arduino to the GB slot to check for a cold solder joint. I had several of those in the past, they look like a good joint but if you measure the resistance it's higher than on the other lines.

Code:
In the code I would try if enabling/disabling the internal pullups for the data line in setup_GB() and in dataIn_GB() makes any difference.
Then in readByte_GB() I would double the amount of "nop\n\t" to slow down the code. And I would also check if switching CS(PH3) and RD(PH6) high/low one at the time instead of at the same time does make any difference.