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
  • Anyway, I think it is better to always write full FLASH pages. If you get a problem with a full page, then you have the contents of that page available and can decide if you want to try again, or possibly use a different page as "spare".

    If your code constantly adds a couple of bytes at a time and there is a timing glitch somewhere in the bootloader code, then the probability of you getting hit by the glitch will increase.

    When storing log information or similar to the FLASH, i.e. the data gets available in small blocks, then it may be a good idea to define all zero and all one bytes as NULL-information. This may be used to inform the program that a couple of bytes does not work as expected, and that the software should ignore these bytes - or possibly skip to the next sector. It isn't totally foolproof, but may increase the usability of the chip.

    Hi Per,

    We add users from time to time and not in batches, so it's impossible to get a page of users and write them in to flash. If I use one page for one user I will get fired. lol. So I have to choose to update the flash in small blocks.

    I did what exactly you said to use 8 bytes blocks. And I wanted to correct any programming errors by deleting the wrong user and add it again at the blank area. But you may have already found in my example, when I was writting user 8, the user 8 was ok but the user 7 was changed. It just so hard for me to trace all the old users which one is wrong. So I want to figure out what is the root cause of the inconsistency problem. I guess something wrong with the small blocks writing, but I don't know exactly what's wrong.

    I don't think I have damaged my flash section, because I have only erased it less than 100 times, and everything is ok if I update it in a whole section manner.

    Leo

Reply
  • Anyway, I think it is better to always write full FLASH pages. If you get a problem with a full page, then you have the contents of that page available and can decide if you want to try again, or possibly use a different page as "spare".

    If your code constantly adds a couple of bytes at a time and there is a timing glitch somewhere in the bootloader code, then the probability of you getting hit by the glitch will increase.

    When storing log information or similar to the FLASH, i.e. the data gets available in small blocks, then it may be a good idea to define all zero and all one bytes as NULL-information. This may be used to inform the program that a couple of bytes does not work as expected, and that the software should ignore these bytes - or possibly skip to the next sector. It isn't totally foolproof, but may increase the usability of the chip.

    Hi Per,

    We add users from time to time and not in batches, so it's impossible to get a page of users and write them in to flash. If I use one page for one user I will get fired. lol. So I have to choose to update the flash in small blocks.

    I did what exactly you said to use 8 bytes blocks. And I wanted to correct any programming errors by deleting the wrong user and add it again at the blank area. But you may have already found in my example, when I was writting user 8, the user 8 was ok but the user 7 was changed. It just so hard for me to trace all the old users which one is wrong. So I want to figure out what is the root cause of the inconsistency problem. I guess something wrong with the small blocks writing, but I don't know exactly what's wrong.

    I don't think I have damaged my flash section, because I have only erased it less than 100 times, and everything is ok if I update it in a whole section manner.

    Leo

Children
No data