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 > Saving to EEPROM

#10604 - mash - Wed Sep 10, 2003 2:43 pm

I'm in big trouble. I would like to save my game data on a 4kbit (512 byte) EEPROM. Could you send me source examples how can I do that?
Thanks!

Mash

#10611 - niltsair - Wed Sep 10, 2003 3:26 pm

If you mean the gamepak memory used for save games, then you can take a look at the Faq in the beginner section. It's really easy, but i had a hard time finding doc about it some time ago.
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)

#10644 - mash - Thu Sep 11, 2003 2:56 pm

I can't use SRAM. I need to use a 4kbit EEPROM. As I know it uses the DMA to transfer data but I don't know how.

Bye!
Mash

#10719 - mash - Sat Sep 13, 2003 10:29 am

Anybody else? Please! :)

#10724 - Burton Radons - Sat Sep 13, 2003 12:58 pm

EEPROM isn't in the CowBite spec, but it is in the no$gba spec here.

I know this isn't helpful as a tutorial - I don't grok how to do it myself. But it looks like it has the necessary raw information.

For writing, what it appears you need to do is to generate a packet and then transfer that through DMA to the EEPROM at 0xD000000. You transfer eight bytes at a time. The packet starts with 2 bits, valued 2, then 6 or 14 bits (6 for a 512-byte EEPROM, 14 for an 8kb EEPROM) indicating the EEPROM address to write to times eight. Then it is followed by the eight bytes to store, then stash a 0 byte at the end. Copy that over.

Then you need to keep reading from 0xD000000 until the first bit reads 1. This will not take more than 10 ms, unless if the chip has gone screwy.

For reading, you send a request packet and then get the response in two DMA transfers. The request packet is composed of two bits with a value of 3, then 6 or 14 bits with the address times eight, and then a zero byte. Once you've sent that through DMA, transfer 9 bytes from the EEPROM through DMA; the first four bits are junk, the next 64 bits are the eight bytes of data you requested.

What a mess! Here's a blind try at converting that to code (blind as in I'm programming it in this message and haven't done any DMA transfers). Accept that it might be so far off that it'll decrease your understanding of the issue rather than increase it. At least it'll be well-documented disinformation. :-)

Code:

/** Setup the waitstate for an EEPROM.  This must be done before any transfer operations with the EEPROM. */
void initializeEEPROM ()
{
    REG_WAITCNT &= ~(7 << 8); /* Clear bits 8, 9, 10. */
    REG_WAITCNT |= 3 << 8; /* Set bits 8 and 9. */
}

/** Attempt to write an eight-byte packet to EEPROM.
  * @param size The EEPROM size.  This must be 512 or 8192.
  * @param offset The EEPROM offset to store into.  These are in pages of eight, so zero and one indicate separate pages.
  * @param data The data to store.
  * @return Returns zero on success or negative on failure.  -1 means that the chip was initially not OK.  -2 means that the chip timed out after the write.
  */

int writeToEEPROM (int size, int offset, u8 data [8])
{
    volatile u8 *eeprom = (u8 *) 0xD000000; /* EEPROM pointer. */
    u8 packet [12]; /* Packet content to transfer. */
    int start; /* Starting offset for the data. */
    int c; /* Loop counter. */

    assert (size == 512 || size == 8192);

    /* Initially check that the EEPROM is ready. */
    if (!(*eeprom & 1))
        return -1;

    /* Write the address into the packet. */
    if (size == 512)
    {
        assert (offset >= 0 && offset < 64);
        packet [0] = 2 | (offset << 2);
        start = 1;
    }
    else
    {
        assert (offset >= 0 && offset < 1024);
        packet [0] = 2 | (offset << 2);
        packet [1] = offset >> 6;
        start = 2;
    }

    packet [start + 8] = 0; /* Store the end-of-transfer indicator. */

    /* Copy the data over. */
    for (c = 0; c < 8; c ++)
        packet [start + c] = data [c];

    /* Make the DMA transfer. */
    REG_DM3SAD = (u32) &packet [0]; /* Starting address. */
    REG_DM3DAD = (u32) eeprom; /* Destination address. */
    REG_DM3CNT_L = (start + 8 + 2) / 2; /* Number of 16-bit words to transfer, either 5 or 6. */
    REG_DM3CNT_H = 1 << 15; /* Control bits and fire the DMA. */
    REG_DISPCNT = REG_DISPCNT; /* Waste some clock cycles. */
    while (REG_DM3CNT_H & (1 << 15)); /* Wait out the transfer. */

    /* Now wait until the EEPROM is back to ready.
     * Each cycle here must take at least one clock cycle. */
    for (c = 0; c < 150000; c ++)
        if (*eeprom & 1)
            return 1;

    return -2; /* Ass! */
}

/** Read a packet from EEPROM.
  *
  * @param size The EEPROM size.  This must be 512 or 8192.
  * @param offset The EEPROM offset to read from.  These are in pages of eight, so zero and one indicate separate pages.
  * @param data The data pointer to read into.
  * @return Returns zero if the operation is successful, or -1 if the EEPROM initially reported that it was not ready.
  */

int readFromEEPROM (int size, int offset, u8 *data)
{
    volatile u8 *eeprom = (u8 *) 0xD000000; /* EEPROM pointer. */
    u8 packet [10]; /* Transfer packet to and from. */
    int packetSize; /* Size of the send packet in 16-bit words. */
    int c;

    assert (size == 512 || size == 8192);

    /* Check that the EEPROM is good to go. */
    if (!(*eeprom & 1))
        return -1;
   
    /* Write the address into the packet. */
    if (size == 512)
    {
        assert (offset >= 0 && offset < 64);
        packet [0] = 3 | (offset << 2);
        packet [1] = 0;
        packetSize = 1;
    }
    else
    {
        assert (offset >= 0 && offset < 1024);
        packet [0] = 3 | (offset << 2);
        packet [1] = offset >> 6;
        packet [2] = 0;
        packetSize = 2;
    }

    /* Send the packet through DMA. */
    REG_DM3SAD = (u32) &packet [0]; /* Starting address. */
    REG_DM3DAD = (u32) eeprom; /* Destination address. */
    REG_DM3CNT_L = packetSize; /* Number of 16-bit words to transfer. */
    REG_DM3CNT_H = 1 << 15; /* Control bits and fire the DMA. */
    REG_DISPCNT = REG_DISPCNT; /* Waste some clock cycles. */
    while (REG_DM3CNT_H & (1 << 15)); /* Wait out the transfer. */

    /* Get the return packet. */
    REG_DM3SAD = (u32) eeprom; /* Starting address. */
    REG_DM3DAD = (u32) &packet [0]; /* Destination address. */
    REG_DM3CNT_L = 5; /* Number of 16-bit words to transfer. */
    REG_DM3CNT_H = 1 << 15; /* Control bits and fire the DMA. */
    REG_DISPCNT = REG_DISPCNT; /* Waste some clock cycles. */
    while (REG_DM3CNT_H & (1 << 15)); /* Wait out the transfer. */

    /* Unpack the return packet. */
    for (c = 0; c < 8; c ++)
        data [c] = (packet [c] >> 4) | (packet [c + 1] << 4);

    return 0; /* Woot. */
}

#10761 - mash - Sun Sep 14, 2003 11:23 pm

Hi Burton,

You are great!
Thanks a lot!!!!

Bye!
Mash

#16314 - dagamer34 - Thu Feb 12, 2004 7:09 am

Just wanted to know, does this code work? I can't seem to get it to work on VBA.
_________________
Little kids and Playstation 2's don't mix. :(

#16324 - FluBBa - Thu Feb 12, 2004 3:01 pm

You probably has to set the savetype to EEPROM in VBA and not automatic.
_________________
I probably suck, my not is a programmer.

#16342 - dagamer34 - Fri Feb 13, 2004 12:44 am

So its supposed to be set to EEPROM? It still doesn't work.

Here's some that i have:
Code:

EEPROMInit ();
   
   u8 data[8];
   if (EEPROMreadData (EEPROM_SIZE_64KB, 1, (u8*)&data) == -1)
   {
       DrawText (0, 0, "ERROR1_");
   }
   if (data[0] == 10)
   {
       DrawText (0, 0, "Hello!!!_");
   }

   data[0] = 10;
  if (EEPROMwriteData (EEPROM_SIZE_64KB, 1, data) == 1)
   {
       DrawText (0, 5, "ERROR2_");
   }
   DrawText (0, 1, "GoodBye_");
   while (1)
   {
      
   }


The first time it's run, it should display "ERROR", since there isn't any save data, but the second time it should display "Hello!!!"

Any ideas?
_________________
Little kids and Playstation 2's don't mix. :(

#16394 - dagamer34 - Sat Feb 14, 2004 9:38 pm

Does this code work? I can't get it to work in VBA. Can somebody make a demo that uses EEPROM for me to look at?
_________________
Little kids and Playstation 2's don't mix. :(

#16503 - dagamer34 - Wed Feb 18, 2004 2:27 am

Anyone?
_________________
Little kids and Playstation 2's don't mix. :(

#16524 - gb_feedback - Wed Feb 18, 2004 7:53 pm

To be fair I think Burton said that it was untested code. This means making any necessary changes to get it to work. I think it was brave to present the code in the first place. I'm interested to know what cartridge is envisaged for testing this - presumably an official Nintendo one?

I would be inclined to connect an oscilloscope to the eeprom pins on the cart to see what might be going wrong.
_________________
http://www.bookreader.co.uk/

#16535 - dagamer34 - Thu Feb 19, 2004 12:52 am

mash made it seem as if the code worked, he didn't ask any questions.
_________________
Little kids and Playstation 2's don't mix. :(