cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with writing flash memory on STM32L4

Ricardo Hassan
Associate III
Posted on May 22, 2018 at 02:34

Hi,

    I am trying to write a flash memory location on an STM32L496 and I can't get it to work.  From reading the manual, I understand that each location can only be written once, and it must be erased before it can be rewritten.  Also, the smallest piece of memory that can be erased is a page, which is 2K on this MCU.  So, I have written some code that reads a copy page I want to write to into RAM, modifies the copy to the desired state, erases the page, then writes the new version to the page using the standard programming API.  This is not working.  The first write works, but the second is returning a HAL_ERROR.  What am I doing wrong?  Any advice is appreciated. I will include a code snippet:

bool Nvm::Write(uint32_t destination, uint8_t* source, uint16_t length) {

uint32_t start_page_index = GetPage(destination);

uint32_t end_page_index = GetPage(destination + length);

uint32_t page_start = FLASH_BASE + FLASH_PAGE_SIZE * start_page_index;

page_start += (GetBank(destination) == FLASH_BANK_2) ? FLASH_BANK_SIZE : 0;

bool result = true;

if (start_page_index != end_page_index) {

result = false;

}

if (result == true) {

memcpy(ram_buffer_, (void*)page_start, FLASH_PAGE_SIZE); // make a ram copy of the entire flash page

uint32_t start_offset = destination - page_start;

memcpy(ram_buffer_ + start_offset, source, length); // make the desired chage

HAL_StatusTypeDef status = HAL_FLASH_Unlock();

if (status != HAL_OK) {

result = false;

}

}

if (result == true) {

result = Erase(GetBank(destination), start_page_index); // erase the page so it will accept a new write

}

if (result == true) {

  uint32_t write_location = page_start;

  uint64_t* write_source = (uint64_t*)ram_buffer_;

  uint32_t page_end = page_start + FLASH_PAGE_SIZE;

  for(; write_location < page_end; write_location += sizeof(uint64_t), write_source++) {

    HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,

                                                                                         page_start,

                                                                                         *write_source); // write the page with the new value

    if (status != HAL_OK) {

      //uint32_t error = HAL_FLASH_GetError();

      result = false;

      break;

    }

    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

  }

}

HAL_FLASH_Lock();

return result;

}

////////////////////////////////////////////////////////////////////////////////////////////////////

/// Erase a page of flash memory.

bool Nvm::Erase(uint32_t bank, uint32_t page) {

FLASH_EraseInitTypeDef erase_init_struct = {0};

uint32_t page_error = 0;

bool result = true;

erase_init_struct.TypeErase = FLASH_TYPEERASE_PAGES;

erase_init_struct.Banks = bank;

erase_init_struct.Page = page;

erase_init_struct.NbPages = 1;

if (HAL_FLASHEx_Erase(&erase_init_struct, &page_error) != HAL_OK) {

result = false;

}

return result;

}

////////////////////////////////////////////////////////////////////////////////////////////////////

/// Gets the flash bank of the specified flash address - this is for our STM32L496

uint32_t Nvm::GetBank(uint32_t address) {

return (address < FLASH_BASE + FLASH_BANK_SIZE) ? FLASH_BANK_1 : FLASH_BANK_2;

}

////////////////////////////////////////////////////////////////////////////////////////////////////

/// Gets the flash page of the specified flash address - this is for our STM32L496

uint32_t Nvm::GetPage(uint32_t address) {

return ((address - FLASH_BASE) / FLASH_PAGE_SIZE) % kPagesPerBank;

}
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on May 22, 2018 at 23:35

HAL_FLASH_Program(

FLASH_TYPEPROGRAM_DOUBLEWORD,..

) does not write a whole page.

It writes 4 bytes (aka doubleword) at the specified address. You don't increment the address, hence the error.

uint32_t start_page_index = GetPage(destination);

uint32_t end_page_index = GetPage(destination + length);

Maybe this should be : 

end_page_index = GetPage(destination + length - 1);

-- pa

View solution in original post

4 REPLIES 4
ingwmeier
Senior
Posted on May 22, 2018 at 10:33

ran into the same problem with a STM32L431. Found that calling HAL_FLASHEx_Erase 2x always works the second time. I did not bother to search the reason within HAL_FLASHEx_Erase. Hope ST will look into it, if it solves your problem too.

Posted on May 22, 2018 at 19:07

Hi Werner,

Thanks for your reply. I tried calling HAL_FLASHEx_Erase twice before writing, but I saw no change in behavior. Did you mean something else?

Ricardo

Ricardo Hassan
Associate III
Posted on May 23, 2018 at 00:01

Hi Pavel,

    You are spotted the problem, that was just a garden variety bug that I should have caught.  The actual programming line should have used the variable write_location, which is being incremented, not page_start, which is not:

  HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,

                                                                                        write_location,

                                                                                         *write_source); // write the page with the new value

When I don't try to write the same address twice, everything works.

Thank you very much for your observation.  Sorry to use the forum to find silly stuff.

Ricardo

 
Posted on May 22, 2018 at 23:35

HAL_FLASH_Program(

FLASH_TYPEPROGRAM_DOUBLEWORD,..

) does not write a whole page.

It writes 4 bytes (aka doubleword) at the specified address. You don't increment the address, hence the error.

uint32_t start_page_index = GetPage(destination);

uint32_t end_page_index = GetPage(destination + length);

Maybe this should be : 

end_page_index = GetPage(destination + length - 1);

-- pa