This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC2000 IAP, programed data in flash are not consistent with data in RAM buffer.

Hi, Folks,

Hopefully, someone can shed some light to this. Thanks.

I am using the LPC2000 IAP functions to put user data in to flash, but I got a weird problem. My target MCU is a LPC2214 and debugger is the Keil uvision 3.05 + ULink2. I have a MSB2100 evaluation board but it's broken, so I cannot test this on it.

The following is the test program. For each user, I read the 512 bytes block the user should be in to a RAM buffer, update the user data and then program the buffer back in.

The problem is the programed data are often not consistent with the data in the RAM buffer. I programmed 8000 users, usually this will happen more then 1000 times. The following example is one of them. The user number 7 was wrong, and this happened when user 8 was programmed. I had erased this section before I ran this function and checked all data in the section were 0xFF. In the whole process, the IAP functions return 0 (CMD_SUCCESS)

d 0x10000
0x00010000 01 00 00 00 10 FF FF FF
0x00010008 02 00 00 00 10 FF FF FF
0x00010010 03 00 00 00 10 FF FF FF
0x00010018 04 00 00 00 10 FF FF FF
0x00010020 05 00 00 00 10 FF FF FF
0x00010028 06 00 00 00 10 FF FF FF
0x00010030 07 00 02 00 10 FF FF FF
0x00010038 08 00 00 00 10 FF FF FF
0x00010040 FF FF FF FF FF FF FF FF
0x00010048 FF FF FF FF FF FF FF FF
.......ALL oxFF

d flash_buffer
0x4000021C 01 00 00 00 10 FF FF FF
0x40000224 02 00 00 00 10 FF FF FF
0x4000022C 03 00 00 00 10 FF FF FF
0x40000234 04 00 00 00 10 FF FF FF
0x4000023C 05 00 00 00 10 FF FF FF
0x40000244 06 00 00 00 10 FF FF FF
0x4000024C 07 00 00 00 10 FF FF FF
0x40000254 08 00 00 00 10 FF FF FF
0x4000025C FF FF FF FF FF FF FF FF
0x00000264 FF FF FF FF FF FF FF FF
.......ALL oxFF

//////////////my test program//////////////
typedef struct
{
        unsigned long   id;
        BYTE    zone;
} USER_DATA;

unsigned char flash_buffer[512];

//the start address of users in flash (64k block)
USER_DATA *user = (USER_DATA *)0x10000;
unsigned long blockerrors = 0;
unsigned long singleerrors = 0;

void test_user()
{
  unsigned long i;
  unsigned char *program_addr;
  USER_DATA temp_user;

  for(i = 1; i <= 8000, i++)
  {
    //get the 512 bytes block base address the current user is in.
        program_addr =(BYTE*)((unsigned int)(&user[i]) & 0xFFFFFE00);

        //update the user in the buffer.
        memcpy((void*)flash_buffer, (void*)program_addr, 512);
        temp_user = (USER_DATA*)(flash_buffer + (((BYTE*)(user + i)) - program_addr));
        temp_user->id = i;
        temp_user->zone = 16;

    //program the flsh
        FlashProgram((uint)program_addr, flash_buffer, 512);

        if(memcmp(flash_buffer, program_addr, 512)) //check block programming errors
                  ++blockerrors;

          if(i != user[i].id) //
                  ++singleerrors;

                DELAY(100); //delay 100 millisends
  }
}

#define XTAL_HZ    10000000                   // Oscillator Frequency in HZ
#define PLL_MUL 6
#define VPB_DIVIDER 4              // VPB Clock divider
#define CPU_CLK_HZ (XTAL_HZ*PLL_MUL)                    // CPU Clock (cclk) in HZ

#define CPU_CLK_KHZ   (CPU_CLK_HZ / 1000)          // CPU Clock (cclk) in kHz

#define VPB_CLK_HZ   (CPU_CLK_HZ / VPB_DIVIDER)              // VPB Clock (pclk) in Hz


struct iap_in {
  uint cmd;
  uint par[4];
};

typedef void (*IAP)(struct iap_in *in, uint *result);
#define IapEntry ((IAP) 0x7FFFFFF1)       // IAP Entry Point

uint FlashProgram (uint addr, uchar *data, uint size)
{
        struct iap_in iap;                       // IAP Input Parameters
        uint  result[16];                // IAP Results

        assert(FlashGetSecNum (addr) >= 8);

        di();                                    // disable all interrupts


        iap.cmd = 50;                            // IAP Command: Prepare Sectors for Write
        iap.par[0] = FlashGetSecNum (addr);         // Start Sector
        iap.par[1] = iap.par[0];                 // End Sector
        IapEntry (&iap, result);                // Call IAP Function
        if (result[0])
                goto exit;                // Error occured?

        iap.cmd = 51;                            // IAP Command: Copy RAM to Flash
        iap.par[0] = addr;                       // Destination Address
        iap.par[1] = (uint) data;        // Source Address
        iap.par[2] = size;                       // Number of Bytes
        iap.par[3] = CPU_CLK_KHZ;                       // CPU Clock
        IapEntry (&iap, result);                // Call IAP Function

exit:
        ei();                                    // enable all interrupts
        return (result[0]);
}

Parents
  • "To my understanding, one flash erase-rewrite cycle means you can erase the section once and rewrite it multiple times"

    Not exactly.

    Erasing an EPROM cell (whether Flash or not) sets it to a '1'.

    Thus, erasing a section of EPROM sets all cells (ie, bits) in that section to '1'

    To program it, you write '0' to those cells (bits) that you don't want to be '1'

    The only way to set a cell back to '1' is to erase it again.

    Thus, after an erase cycle, you can only ever change bits from '1' to '0' - you cannot "write" a '1' to a bit that has been '0'

    Maybe this is the source of your problem?

Reply
  • "To my understanding, one flash erase-rewrite cycle means you can erase the section once and rewrite it multiple times"

    Not exactly.

    Erasing an EPROM cell (whether Flash or not) sets it to a '1'.

    Thus, erasing a section of EPROM sets all cells (ie, bits) in that section to '1'

    To program it, you write '0' to those cells (bits) that you don't want to be '1'

    The only way to set a cell back to '1' is to erase it again.

    Thus, after an erase cycle, you can only ever change bits from '1' to '0' - you cannot "write" a '1' to a bit that has been '0'

    Maybe this is the source of your problem?

Children
  • Thus, after an erase cycle, you can only ever change bits from '1' to '0' - you cannot "write" a '1' to a bit that has been '0'

    And each sector of flash ROM can only take high, but limited number of erase cycles (usually, the manufacturers guarantee a number between 10^4 and 10^6). Once you get past that number, there is no guarantee that any following erase or write operations will be successful.

  • "Once you get past that number, there is no guarantee that any following erase or write operations will be successful."

    Also, even if the write appears successful initially, there is no guarantee of how long the data will remain valid...

  • "usually, the manufacturers guarantee a number between 10^4 and ..."

    Remember that these are statistical measures - it doesn't mean that everything will be fine up to cycle number 9,999 and fail completely on cylce 10,000...

  • To program it, you write '0' to those cells (bits) that you don't want to be '1'

    The only way to set a cell back to '1' is to erase it again.

    Thanks, Andy.

    I was aware of this, so only add users at blank area, that is, the Oxff area. Once write the user in I will never change it until erase the whole section unless I want to delete it. when deleting an user, I will set the user id to 0, which is defined as an invalid user. When I want to change the user zone information, I just delete this user, change the zone and add the user to the blank area.

    I said "write multiple times", I mean the section can be written by small blocks, not just write it in a whole section manner.

    Leo

  • Your data source and destination address to IAP should be Long alligned. Add an Long allignment clause to your data buffer.

    This can be one of the reason for your problem.

    Regards

    Suvidh

  • The flash has an error correction mechanism which works in blocks of 16 bytes. So if you write 8 bytes first and another 8 bytes later, the error correction data is programmed wrong resulting in wrong data.


  • The flash has an error correction mechanism which works in blocks of 16 bytes. So if you write 8 bytes first and another 8 bytes later, the error correction data is programmed wrong resulting in wrong data.

    Thanks,

    I believe this is the problem. I found an explaination about this in a lpc discussion group.
    tech.groups.yahoo.com/.../2681

    Leo