2018-05-21 05:34 PM
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 STM32L496uint32_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 STM32L496uint32_t Nvm::GetPage(uint32_t address) { return ((address - FLASH_BASE) / FLASH_PAGE_SIZE) % kPagesPerBank;}Solved! Go to Solution.
2018-05-22 04:35 PM
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
2018-05-22 01:33 AM
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.
2018-05-22 12:07 PM
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
2018-05-22 03:01 PM
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
2018-05-22 04:35 PM
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