• Home
  • News
  • Software
  • Articles / Guides
  • Forums
  • Links
  • Saving to EEPROM

    Please post all non-HAM GBA development topics here

    Saving to EEPROM

    Postby dagamer34 on Sun Feb 22, 2004 1:00 am

    Does anybody know how to save to EEPROM without HAM code (even if it was supported once)?

    I don't need to use all 256 kb of SRAM and EEPROM is just perfect for what I need to use.

    I have tried to code what the no$gba tech reference says but I don't get a thing saved. VBA doesn't even create a save file for it.

    Any help here? Some code snippets would help. Working EEPROM code would be even better!!!
    while (your_engine >= my_engine)
    my_engine++; :P
    User avatar
    dagamer34
    Expert
    Expert
     
    Posts: 143
    Joined: Tue Oct 07, 2003 11:00 pm
    Location: Dallas, Tx

    Postby Peter on Sun Feb 22, 2004 1:22 am

    Hi,

    staringmonkey released his saving routines on gbadev.org, it's in the source | gba section.

    Title of it is Sm's Library v6

    Hope it helps
    Kind Regards,
    Peter / HEL, Katie and VisualHAM author
    User avatar
    Peter
    Professional
    Professional
     
    Posts: 1281
    Joined: Thu Jan 30, 2003 12:00 am
    Location: Germany

    Postby dagamer34 on Mon Feb 23, 2004 1:21 am

    I'm sorry Peter, but I already have SRAM saving routines. What I need is EEPROM saving routines. Here is what I have so far:
    Code: Select all
    // Initializes EEPROM for reading and writing (sets up wait states)
    void EEPROMInit (void)
    {
        // Clear bits 8, 9, 10
        REG_WAITCNT &= ~(7 << 8);
        // Set bits 8 and 9
        REG_WAITCNT |= 3 << 8;
    }

    // Writes a block of 8 bytes to EEPROM
    s16 EEPROMwriteData (u32 size, u32 offset, u8 data[8])
    {
         // EEPROM pointer
         volatile u8* EEPROMpointer = EEPROM;
         
         // Packet to transfer
         u8 packet[12];
         // Starting offset for the data
         u32 start;
         // Loop counter
         u32 c;
         
         if (size != EEPROM_SIZE_4KB && size != EEPROM_SIZE_64KB)
            return -1;
           
         // Check that the EEPROM is good to go
         if (!(*EEPROMpointer & 1))
            return -1;
           
         // Write the address into the packet
         if (size == EEPROM_SIZE_4KB)
         {
             if (offset <= 0 || offset > 64)
                 return -1;
             packet [0] = 2 | (offset << 2);
             start = 1;
         }
         else
         {
             if (offset <= 0 || offset > 1024)
                 return -1;
             packet [0] = 2 | (offset << 2);
             packet [1] = offset >> 6;
             start = 2;
         }

         // Store the end-of-transfer indicator
         packet [start + 8] = 0;
         
         // Copy the data over
         for (c = 0; c < 8; c ++)
            packet [start + c] = data [c];

         // Make the DMA transfer
         REG_DMA3SAD = (u32) &packet [0]; /* Starting address. */
         REG_DMA3DAD = (u32) EEPROMpointer; /* Destination address. */
         REG_DMA3CNT_L = (start + 8 + 2) / 2; /* Number of 16-bit words to transfer, either 5 or 6. */
         REG_DMA3CNT_H = 1 << 15; /* Control bits and fire the DMA. */
         REG_DISPCNT = REG_DISPCNT; /* Waste some clock cycles. */
         while (REG_DMA3CNT_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 (*EEPROMpointer & 1)
                return 1;
               
         return 0;
    }

    // Reads a block of 8 bytes from EEPROM
    s16 EEPROMreadData (u32 size, u32 offset, u8* data)
    {
        // EEPROM pointer
        volatile u8* EEPROMpointer = EEPROM;
        // Transfer packet to and from
        u8 packet [10];
        // Size of the send packet in 16-bit words
        u32 packetSize;
        u32 c;

        if (size != EEPROM_SIZE_4KB && size != EEPROM_SIZE_64KB)
            return -1;

        // Check that the EEPROM is good to go
        if (!(*EEPROMpointer & 1))
            return -1;

        // Write the address into the packet
        if (size == EEPROM_SIZE_4KB)
        {
            if (offset <= 0 || offset > 64)
                 return -1;
            packet [0] = 3 | (offset << 2);
            packet [1] = 0;
            packetSize = 1;
        }
        else
        {
            if (offset <= 0 || offset > 1024)
                 return -1;
            packet [0] = 3 | (offset << 2);
            packet [1] = offset >> 6;
            packet [2] = 0;
            packetSize = 2;
        }

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

        // Get the return packet
        REG_DMA3SAD = (u32) EEPROMpointer; /* Starting address. */
        REG_DMA3DAD = (u32) &packet [0]; /* Destination address. */
        REG_DMA3CNT_L = 5; /* Number of 16-bit words to transfer. */
        REG_DMA3CNT_H = 1 << 15; /* Control bits and fire the DMA. */
        REG_DISPCNT = REG_DISPCNT; /* Waste some clock cycles. */
        while (REG_DMA3CNT_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. */
    }


    I know its a lot, but please try to actually look at the code. Maybe emanuel can help me. I think he had some working routines...
    while (your_engine >= my_engine)
    my_engine++; :P
    User avatar
    dagamer34
    Expert
    Expert
     
    Posts: 143
    Joined: Tue Oct 07, 2003 11:00 pm
    Location: Dallas, Tx

    Postby dagamer34 on Sun May 02, 2004 4:50 am

    I was looking around and I saw this post on gbadev.org. Here's the working code so far, but it only works in VBA, not hardware. Can anyone figure out what is wrong?

    DrawText is simple a function to display data to the screen, but that isn't the problem. Neither are the key polling functions because I flashed a .sav file to my cart but came up with nothing. This code was tested on a EZFA.

    Code: Select all
    #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 );
    }

    int main ()
    {
         SetMode (MODE_0 | BG0_ENABLE);
         u8 buffer[8];
         InitText (0, 0, 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 );
            DrawText (0, 0, "%d\n", buffer[0] );
            do
            {
                WaitVSync ();
                PollKeys ();
            }
            while (!KeyIsDown (KEY_A));
            ++buffer[0];
            DrawText (0, 1, "Read Successfull");
            EEPROM_Write( 0, buffer );
            DrawText (0, 2, "Write Successfull");
       }
       while( 1 );

       return 0;
    }
    while (your_engine >= my_engine)
    my_engine++; :P
    User avatar
    dagamer34
    Expert
    Expert
     
    Posts: 143
    Joined: Tue Oct 07, 2003 11:00 pm
    Location: Dallas, Tx

    Postby caitsith2 on Wed Jun 23, 2004 8:01 am

    Been doing some tests on an actual cart, not a flash cart, but a cart with EEPROM built in, and your code seems to work nicely for reading/writing EEPROM.

    What I found is that there seems to be a slight bug, in the reading code, unless it has to do with the EEPROM itself, where all the bytes read, will show up as being byte += 2 of the actual byte stored.

    In testing of loading of a known SMA1 save, the writing itself worked perfectly.

    I wonder if maybe we should be adding a string that the flash cart hardware would be looking for, like EEPROM_V120, to tell the flash cart that the save type is EEPROM, just as SRAM_V112 tells the flashcart that the save type is SRAM. I know a real cart with this save type does not care if the string is present, but for a flashcart, that may be all that makes a difference.
    User avatar
    caitsith2
    Newbie
    Newbie
     
    Posts: 7
    Joined: Fri Aug 08, 2003 11:00 pm

    Postby dagamer34 on Thu Jun 24, 2004 4:36 am

    caitsith2 wrote:Been doing some tests on an actual cart, not a flash cart, but a cart with EEPROM built in, and your code seems to work nicely for reading/writing EEPROM.

    What I found is that there seems to be a slight bug, in the reading code, unless it has to do with the EEPROM itself, where all the bytes read, will show up as being byte += 2 of the actual byte stored.

    In testing of loading of a known SMA1 save, the writing itself worked perfectly.

    I wonder if maybe we should be adding a string that the flash cart hardware would be looking for, like EEPROM_V120, to tell the flash cart that the save type is EEPROM, just as SRAM_V112 tells the flashcart that the save type is SRAM. I know a real cart with this save type does not care if the string is present, but for a flashcart, that may be all that makes a difference.


    Yeah, and the code has worked on a couple of flash carts too, except for the one I own (EZFA). And it isn't really my code. I simply copied and pasted it from gbadev.org in case someone didn't catch it.

    Most modern flash carts actually look for the save string to determine the size of the save file. I know the EZFA client does it, not sure about the others though...

    By the way, I changed the code up above after you posted your reply. It doesn't work with the EZFA though(which sucks!) but other people say that it works on their flash carts.
    while (your_engine >= my_engine)
    my_engine++; :P
    User avatar
    dagamer34
    Expert
    Expert
     
    Posts: 143
    Joined: Tue Oct 07, 2003 11:00 pm
    Location: Dallas, Tx

    Postby zigg on Sat Jan 29, 2005 6:05 pm

    I've been trying to get this code to work myself; I'm only interested in reading EEPROM.

    On a real EEPROM cart, I get bytes that are the actual byte plus 1 or 2 (no pattern that I can detect...); in VBA I get the actual data.

    Is there any better code out there?
    User avatar
    zigg
    Newbie
    Newbie
     
    Posts: 1
    Joined: Sat Jan 29, 2005 12:00 am


    Return to General GBA development

    Who is online

    Users browsing this forum: No registered users and 2 guests