AnsweredAssumed Answered

LPC11U35FBD64 flash write slows and fails

Question asked by Jiri Danicek on Apr 5, 2017
Latest reply on Apr 7, 2017 by Jiri Danicek

Hello,
I have weird problem with writing to internal flash. Code is the following:

 

unsigned int flash_op_result = flash_erase(SECTOR_13_ADDR / 0x1000, SECTOR_13_ADDR / 0x1000);
if(flash_op_result != CMD_SUCCESS)
{
    /* Code always goes here */
}
else
{
    /* Code never goes here */
}
if((flash_op_result = flash_write((unsigned int) &memStruct, (unsigned int) SECTOR_13_ADDR, 4096, SECTOR_13_ADDR / 0x1000, SECTOR_13_ADDR / 0x1000) != CMD_SUCCESS );
{
    /* Code always goes here */
}
else
{
    /* Code never goes here */
}
if(memcmp(&memStruct, SECTOR_13_ADDR, sizeof(memStruct)))
{
    /* Error */
}
else
{
    /* Okay */
}

Used routines:

 

int flash_prepare(int start, int end)
{
  command[0] = IAPCommand_Prepare_sector_for_write_operation;
  command[1] = (unsigned int)start;  //  Start Sector Number
  command[2] = (unsigned int)end;    //  End Sector Number (should be greater than or equal to start sector number).
  iap_entry(command, result);
  return ((int)result[0]);
}

int flash_erase(int start_sector_number, int end_sector_number)
{
  __disable_irq();
  if(flash_prepare(start_sector_number,end_sector_number) == CMD_SUCCESS)
  {
    command[0] = IAPCommand_Erase_sector;
    command[1] = (unsigned int)start_sector_number;  //  Start Sector Number
    command[2] = (unsigned int)end_sector_number;    //  End Sector Number (should be greater than or equal to start sector number)
    command[3] = (SystemCoreClock/1000);             //  CPU Clock Frequency (CCLK) in kHz
    iap_entry(command, result);
  }
  __enable_irq();
  return ((int)result[0]);
}

int flash_write(unsigned int source_addr, unsigned int target_addr, int size, int start_sector_number, int end_sector_number)
{
  __disable_irq();
  if(flash_prepare(start_sector_number, end_sector_number) == CMD_SUCCESS)
  {
    command[0]    = IAPCommand_Copy_RAM_to_Flash;
    command[1]    = (unsigned int)target_addr;    //  Destination flash address where data bytes are to be written. This address should be a 256 byte boundary.
    command[2]    = (unsigned int)source_addr;    //  Source RAM address from which data bytes are to be read. This address should be a word boundary.
    command[3]    = size;                         //  Number of bytes to be written. Should be 256 | 512 | 1024 | 4096.
    command[4]    = (SystemCoreClock/1000);                     //  CPU Clock Frequency (CCLK) in kHz.
    iap_entry(command, result);
  }
  __enable_irq();
  return result[0];
}

 

Normally, flash_write takes approx. 17ms and everything works ok. It's possible to reach 2 other states:

1) flash_write takes approx. 400ms and written data differ from data in RAM, mostly in only few of bits. Data other than the changed structure member can be also corrupted in flash.

2) flash_write takes approx. 1400ms and written data are ok.

Functions flash_prepare and flash_erase take always the same time (13,5us and 100,1ms). Result of ROM routines is always CMD_SUCCESS. It's sometimes possible to reach from state 1 to state 2 by several successive retries, not possible to reach the normal state, state 2 seems stable. After reset, everything works normally. Disabling interrupts for the whole erase-write cycle makes no differences.

The weird thing is, how to reach out of the normal state. There are 3 buttons on the device, two for increasing and decreasing value and third for saving the value (and exiting the particular part of menu). If I press increase or decrease for long enough, the device almost always reaches state 1 or 2. These buttons only change the value and consequently, blocking UART write (no interrupt) is called to update LCD. Supply voltage seems ok, nice 3,3V.

Once again: Erase-write is always performed, interrupts are disabled during erase and write and RAM differs from flash right after flash_write.

Outcomes