gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > EEPROM Troubles

#20096 - jd - Sat May 01, 2004 11:51 pm

Hi all,

Sorry for the long post - I didn't want to leave out any vital information by mistake.

Anyway, I've written some code to read and write to EEPROM (see below). It reads from EEPROM first and displays the first byte as a number on screen (on VBA this is always zero when the EEPROM is uninitialised, but I would be surprised if I can rely on this in hardware). It then increments this number and writes it back. Then, it repeats the procedure. This allows the user to increment the counter an arbitrary number of times, with the last value stored in EEPROM. If the machine is switched off then the count should continue from its previous state.

Unfortunately, I only get this behaviour in VBA. On real hardware it hangs on the EEPROM write with a Flash Advance Xtreme 512M (presumeably because I'm not checking for timeouts yet), which I'm guessing means that cart doesn't support EEPROM saves. However, it's on a Flash2Advance 64M cart that things get really weird. Everything works exactly as it should, except for the counter goes up by 3 each time, rather than by 1.

Ok, here are my questions:

1) Does the Flash Advance Xtreme 512M support EEPROM?
2) Any ideas why the counter goes up by 1 with VBA but by 3 on hardware with a Flash2Advance 64M cart? (Any suggestions would be welcome - I'm completely stumped right now.)
3) Is there any way to detect if the EEPROM hasn't been written to before? At the moment, the only way I can think of to test this is to check for a magic value but that's a nasty kludge that I'd rather avoid if possible.

Thanks for any assistance you can offer!

Code:

#define EEPROM_ADDRESS (volatile u16*)0xD000000
#define REG_EEPROM  (*(volatile u16*)0xD000000)
#define REG_DM3SAD  (*(volatile u32*)0x40000D4)
#define REG_DM3DAD  (*(volatile u32*)0x40000D8)
#define REG_DM3CNT  (*(volatile u32*)0x40000DC)

void EEPROM_SendPacket( u16* packet, int size )
{
   REG_DM3SAD = (u32)packet;
   REG_DM3DAD = (u32)EEPROM_ADDRESS;
   REG_DM3CNT = 0x80000000 + size;
}

void EEPROM_ReceivePacket( u16* packet, int size )
{
   REG_DM3SAD = (u32)EEPROM_ADDRESS;
   REG_DM3DAD = (u32)packet;
   REG_DM3CNT = 0x80000000 + size;
}

void EEPROM_Read( int offset, u8* dest ) // dest must point to 8 bytes
{
   u16 packet[68];
   u8* out_pos;
   u16* in_pos;
   u8 out_byte;
   int byte, bit;
   
   // Read request
   packet[0] = 1;
   packet[1] = 1;
   
   // 6 bits eeprom address (MSB first)
   packet[2] = offset>>5;
   packet[3] = offset>>4;
   packet[4] = offset>>3;
   packet[5] = offset>>2;
   packet[6] = offset>>1;
   packet[7] = offset;
   
   // End of request
   packet[8] = 0;
   
   // Do transfers
   EEPROM_SendPacket( packet, 9 );
   EEPROM_ReceivePacket( packet, 68 );
   
   // Extract data
   in_pos = &packet[4];
   out_pos = dest;
   for( byte = 7; byte >= 0; --byte )
   {
      out_byte = 0;
      for( bit = 7; bit >= 0; --bit )
      {
         out_byte += (*in_pos++)<<bit;
      }
      *out_pos++ = out_byte;
   }
}

void EEPROM_Write( int offset, u8* source ) // source must point to 8 bytes
{
   u16 packet[73];
   u8* in_pos;
   u16* out_pos;
   u8 in_byte;
   int byte, bit;
   
   // Write request
   packet[0] = 1;
   packet[1] = 0;
   
   // 6 bits eeprom address (MSB first)
   packet[2] = offset>>5;
   packet[3] = offset>>4;
   packet[4] = offset>>3;
   packet[5] = offset>>2;
   packet[6] = offset>>1;
   packet[7] = offset;
   
   // Extract data
   in_pos = source;
   out_pos = &packet[8];
   for( byte = 7; byte >= 0; --byte )
   {
      in_byte = *in_pos++;
      for( bit = 7; bit >= 0; --bit )
      {
         *out_pos++ = in_byte>>bit;
      }
   }
   
   // End of request
   packet[72] = 0;
   
   // Do transfers
   EEPROM_SendPacket( packet, 73 );
   
   // Wait for EEPROM to finish (should timeout after 10 ms)
   while( (REG_EEPROM & 1) == 0 );
}


Code:

int AgbMain(void)
{
   u8 buffer[8];

   // Edited out some set up stuff here

   // Set up waitstates for EEPROM access etc.
   *(volatile unsigned short *)0x04000204 = 0x4317;

   do
   {
        EEPROM_Read( 0, buffer );
        printf_special( "%d\n", buffer[0] );
        ++buffer[0];
        EEPROM_Write( 0, buffer );
   }
   while( 1 );

   return 1;
}


(printf_special is a routine which outputs text to the screen and waits for user input - it's been tested thoroughly so the problem definitely isn't there.)

#20101 - dagamer34 - Sun May 02, 2004 1:16 am

I made a test on my EZFA to see what happens. Your code seems to hang on reading because I flashed over a VBA save file but I still ended up with zero being displayed when run. It did successfully work in VBA though.

By the way, the EZFA fully supports all save types, so my guess leans more towards code than the flash cart being the problem.
_________________
Little kids and Playstation 2's don't mix. :(

#20102 - jd - Sun May 02, 2004 1:37 am

dagamer34 wrote:
I made a test on my EZFA to see what happens. Your code seems to hang on reading because I flashed over a VBA save file but I still ended up with zero being displayed when run.


If it displayed something then the code can't have hung on reading (the display is done after the read). Did the number increment as it should when you pressed a button?

#20103 - dagamer34 - Sun May 02, 2004 2:13 am

Whoops.

I checked again, printing after every operation, and the code hangs on writing. It's funny, though, it doesn't display the number it should anyway because I flashed over a .sav file just to make sure it's loading something.
_________________
Little kids and Playstation 2's don't mix. :(

#20104 - jd - Sun May 02, 2004 2:19 am

dagamer34 wrote:
Whoops.

I checked again, printing after every operation, and the code hangs on writing. It's funny, though, because it doesn't display the number it should anyway.


Yes, it could well be that it's not reading properly either, it just doesn't actually hang until the write - almost certainly because it waits indefinitely for the EEPROM to be ready, but it never is. (I'll add a timeout in the final code, although of course that doesn't fix the current problem.)

#20105 - dagamer34 - Sun May 02, 2004 2:46 am

jd wrote:
dagamer34 wrote:
Whoops.

I checked again, printing after every operation, and the code hangs on writing. It's funny, though, because it doesn't display the number it should anyway.


Yes, it could well be that it's not reading properly either, it just doesn't actually hang until the write - almost certainly because it waits indefinitely for the EEPROM to be ready, but it never is. (I'll add a timeout in the final code, although of course that doesn't fix the current problem.)


Hope you post the finished code so no one else will go through what you did!
_________________
Little kids and Playstation 2's don't mix. :(

#20106 - jd - Sun May 02, 2004 3:51 am

dagamer34 wrote:

Hope you post the finished code so no one else will go through what you did!


Sure, no problem. Now I just need to actually get it to work. :)

#20110 - phonymike - Sun May 02, 2004 8:11 am

I have a flash xtreme 512, and I think its eeprom function is broke. I have another 128 xtreme card, and a turbo, and certain games save fine on those, but not at all on the 512. Maybe your card broke too.

#20114 - jd - Sun May 02, 2004 12:46 pm

phonymike wrote:
I have a flash xtreme 512, and I think its eeprom function is broke. I have another 128 xtreme card, and a turbo, and certain games save fine on those, but not at all on the 512. Maybe your card broke too.


That could well be the case, but since the code also fails completely on an EZFA and partially on an F2A, I'm pretty sure there's something wrong with the code as well.

#20116 - sajiimori - Sun May 02, 2004 4:30 pm

Code:

out_byte += (*in_pos++)<<bit;

Forgive my ignorance (I've never used EEPROM before), but are the high bits of incoming packet halfwords guaranteed to be 0?

#20119 - jd - Sun May 02, 2004 5:11 pm

sajiimori wrote:

Forgive my ignorance (I've never used EEPROM before), but are the high bits of incoming packet halfwords guaranteed to be 0?


Sajiimori, you are a god! I changed the code you quoted to..

Code:

out_byte += ((*in_pos++)&1)<<bit;


..and now it works perfectly on both VBA and the F2A cart! Thanks! Dagamer34, does this new code work on the EZFA?

There are a couple of things that are still puzzling me though:

1) The code doesn't work properly on BatGBA. The read seems to work but the write seems to always write 0. Any ideas what's going wrong there?

2) Is there an official way to check if the EEPROM has been written to before?

#20126 - dagamer34 - Sun May 02, 2004 7:07 pm

I have tested it again with the new code and found out that the new code doesn't hang on writes, but it doesn't read or write correctly either. I don't know why. :(

Should have gotten a F2A.
_________________
Little kids and Playstation 2's don't mix. :(

#20138 - jd - Mon May 03, 2004 12:12 am

dagamer34 wrote:
I have tested it again with the new code and found out that the new code doesn't hang on writes, but it doesn't read or write correctly either. I don't know why. :(


Try adding the following to the end of EEPROM_Read() and EEPROM_Write():

Code:

// Waste some clock cycles
REG_DISPCNT = REG_DISPCNT;
   
// Wait for transfer to finish (add timeout?)
while( REG_DM3CNT_H & 0x8000 );


This has no noticeable effect for me, but it's possible that the DMA transfers act differently on the EZFA.

dagamer34 wrote:

Should have gotten a F2A.


Right now it looks likely that the problem is still with the code rather than the cart.

#20140 - dagamer34 - Mon May 03, 2004 1:25 am

I did some MORE testing, and I found out that it actually writes the data correctly (1 down, 1 to go), but doesn't read it properly. That is why it appears as if nothing happened.

If you want to know what I did:

1) I created a sav file in VBA with a certain value (I had 85).
2) I then flashed over the sav file to my cart
3) Then on my EZFA, I pressed the A button 5 times (the screen showed showed 20)
4) Then I extracted the sav file and tested it in VBA. And the number 90 appeared, yay!

I keep playing around with your code to see what is wrong.
_________________
Little kids and Playstation 2's don't mix. :(

#20141 - jd - Mon May 03, 2004 1:36 am

dagamer34 wrote:

1) I created a sav file in VBA with a certain value (I had 85).
2) I then flashed over the sav file to my cart
3) Then on my EZFA, I pressed the A button 5 times (the screen showed showed 20)


So it started at a displayed value of 15 and incremented by 1 each time you pressed A?

dagamer34 wrote:

4) Then I extracted the sav file and tested it in VBA. And the number 90 appeared, yay!


Interesting. So is the value it reads/displays on EZFA always 70 less than the true value saved on the cart?

This would imply either:

a) It mangles the data when it reads it, then exactly unmangles it when it writes it.

or

b) There's something wrong with the way the value is being displayed.

By the way, did the DMA thing I mentioned above make any difference?

#20187 - jd - Tue May 04, 2004 4:34 am

I guess not many people around here use EEPROM then?

#20197 - tepples - Tue May 04, 2004 4:45 pm

Most "people around here" seem to develop on flash carts, which have SRAM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#20202 - Miked0801 - Tue May 04, 2004 6:51 pm

Or the people who are forced to use them use the Nintendo libs to access them :)

#20216 - jd - Tue May 04, 2004 10:16 pm

tepples wrote:
Most "people around here" seem to develop on flash carts, which have SRAM.


Miked0801 wrote:
Or the people who are forced to use them use the Nintendo libs to access them :)


True. Ah well, it was worth a shot.