Author Topic: STM32U5: Issue with accessing second bank of the flash space  (Read 566 times)

0 Members and 1 Guest are viewing this topic.

Offline Giannis1990AnastasopoulosTopic starter

  • Newbie
  • Posts: 2
  • Country: gr
STM32U5: Issue with accessing second bank of the flash space
« on: September 03, 2024, 02:42:41 pm »
Dear All,

I am working with an STM32U599NJHxQ mcu. Reading about this module I see that it has 4 Mbytes of Flash divided in 2 banks. So far I have been successful in reading and writing data to the first bank, but accessing the second has been a complete failure.

ased on the sample in STM32Cube_FW_U5_V1.6.0\Projects\STM32U5x9J-DK\Examples\FLASH\FLASH_EraseProgram packet, in order to write to the flash you need to disable the icache, unlock the flash, determine the page you need to write to, the number of pages where to write and finally the bank where these pages are located. Then you erase the pages that you have determined and write the data in the address in the flash where the page starts. Finally you lock the flash and enable back the icache.

In the example there is a limited number of pages where you can actually write to. Furthermore, the bank is also hard-coded. For my use case, I need to be able to write to the last pages of the flash.

If I understand things correctly, since there are 2 banks and since the size of all pages is 8kB there 512 pages in total.
The starting address of each page is 0x08000000 + (n * 0x2000), where n is the number of the page.

So, if I want to write a few bytes on page 254 of the second bank, I would need to populate the FLASH_EraseInitTypeDef like this:
Code: [Select]
FLASH_EraseInitTypeDef erase_init =
        {
          .TypeErase = FLASH_TYPEERASE_PAGES,
          .Banks     = FLASH_BANK_2,
          .Page      = 254,
          .NbPages   = 1};

Then after erasing the page, if I want to write to it, I will need to calculate the address of the page based on the formula from before 0x08000000 + (510 * 0x2000) = 0x83fc000.

But when I call the HAL_FLASH_Program, I am getting a hardfault at the point, shown in the Failure_point.png attachement, because I am trying to write to write to the address calculated above.

If I try the same sequence for page 254, bank 1 then the code works just fine.
Is there any limitation on accessing the second bank? Is there any step that I am missing?
Is there any relevant configuration using the option bytes?

Thanks a lot in advance.
 

Online GromBeestje

  • Frequent Contributor
  • **
  • Posts: 285
  • Country: nl
Re: STM32U5: Issue with accessing second bank of the flash space
« Reply #1 on: September 04, 2024, 10:34:06 am »
When you get a HardFault when attempting to write to flash I wonder whether it has been unlocked properly. Did you call HAL_FLASH_Unlock(); before trying to write to flash?

Can you share the code where you attempt to write to flash?
 

Offline Giannis1990AnastasopoulosTopic starter

  • Newbie
  • Posts: 2
  • Country: gr
Re: STM32U5: Issue with accessing second bank of the flash space
« Reply #2 on: September 06, 2024, 10:56:25 am »
Thanks for your response.

This my "write" function:
Code: [Select]
/**
 * @brief Function used to write data to an address in the flash
 *
 * @param start_address Starting address where to store the data
 * @param p_data Pointer to the data that need to be stored
 * @param data_size The size of the data that needs to be stored
 * @return nvm_status_te eNVM_OK if all went right or any of the other nvm_status_te in case of an error
 */
nvm_status_te nvm_write_data(uint32_t start_address, void* p_data, uint16_t data_size) {
    const uint32_t end_address = start_address + data_size - 1;

    /* Data can only be written in 4-byte chunks at even-numbered addresses.
    Calculate the actual write address range based on that */
    uint32_t real_start_address = start_address - (start_address % 16);
    uint32_t real_end_address   = end_address + (1 - (end_address % 16));

    /* Check if addresses are out of bounds */
    if ((real_start_address < NVM_MIN_START_ADDRESS) || (real_end_address > NVM_MAX_END_ADDRESS) || data_size == 0) {
        return eNVM_BAD_ARGUMENTS;
    }

    /* Disable instruction cache prior to internal cacheable memory update */
    HAL_StatusTypeDef status = HAL_ICACHE_Disable();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    /* Unlock flash */
    status = HAL_FLASH_Unlock();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    uint32_t bytes_flashed = 0;  // Total bytes flashed not including the additional unaligned data
    uint32_t write_address = start_address;
    uint32_t p_data128     = (uint32_t)p_data;

    /* Write 4 words (16 bytes)*/
    while (bytes_flashed + 16 <= data_size) {
        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, write_address, p_data128);
        if (status != HAL_OK) {
            return eNVM_FLASH_ERROR;
        }

        bytes_flashed += 16;
        write_address += 16;
        p_data128     += 16;
    }

    /* Write unaligned end data */
    if (real_end_address != end_address) {
        uint8_t end_data[16];
        memset(end_data, 0xFF, sizeof(end_data));  // Set all the bytes in the buffer to 0xFF which is the value that a byte has in an erased flash
        uint8_t remaining_bytes = data_size - bytes_flashed;
        // Check is needed to avoid overflow
        if ((remaining_bytes <= sizeof(end_data)) && (remaining_bytes > 0)) {
            memcpy(end_data, (uint32_t*)p_data128, remaining_bytes);  // Copy the remaining data to the buffer
            status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, write_address, (uint32_t)end_data);
            if (status != HAL_OK) {
                return eNVM_FLASH_ERROR;
            }
        }
    }

    /* Lock page*/
    status = HAL_FLASH_Lock();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    /* Re-enable instruction cache */
    status = HAL_ICACHE_Enable();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    return eNVM_OK;
}

And this is the function that I am using in order to erase a page:

Code: [Select]
/**
 * @brief Function used to erase a page in Flash
 *
 * @param start_address Address from where to start erasing. It needs to match the starting address of a matching page
 * @param page_count Number of pages to erase
 * @return nvm_status_te eNVM_OK if all went right or any of the other nvm_status_te in case of an error
 */
nvm_status_te nvm_erase_flash_page(uint32_t start_address, uint8_t page_count) {
    uint32_t start_page_num                = (start_address - NVM_FLASH_BASE) / FLASH_PAGE_SIZE;   // Calculate the starting page number
    uint32_t calculated_start_page_address = NVM_FLASH_BASE + (start_page_num * FLASH_PAGE_SIZE);  // Calculate the starting page address based on the page num calculated above
    uint32_t end_page_num                  = start_page_num + page_count - 1;                      // Calculate the ending page number

    // Check that the start address matches the calculated start address for that page,
    // And that the pages requested for deletion are within range of the NVM pages allocated to the application
    if ((start_address != calculated_start_page_address) || (start_page_num < NVM_CONFIG_START_PAGE) || (start_page_num > NVM_CONFIG_END_PAGE) || (end_page_num < NVM_CONFIG_START_PAGE) || (end_page_num > NVM_CONFIG_END_PAGE)) {
        return eNVM_BAD_ARGUMENTS;
    }

    // Next calculate the bank in which the requested page belongs to
    uint32_t banks = FLASH_BANK_1;
    if (start_page_num >= NVM_FLASH_PAGES_PER_BANK) {
        start_page_num = start_page_num % NVM_FLASH_PAGES_PER_BANK;
        banks          = FLASH_BANK_2;
    }

    /* Disable instruction cache prior to internal cacheable memory update */
    HAL_StatusTypeDef status = HAL_ICACHE_Disable();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    /* Unlock flash */
    status = HAL_FLASH_Unlock();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    /* Erase page */
    FLASH_EraseInitTypeDef erase_init =
        {
          .TypeErase = FLASH_TYPEERASE_PAGES,
          .Banks     = banks,
          .Page      = start_page_num,
          .NbPages   = page_count};

    uint32_t page_error;
    if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK) {
        /*Error occurred while page erase. FLASH_Error_Codes*/
        return eNVM_FLASH_ERROR;
    }

    /* Lock page*/
    status = HAL_FLASH_Lock();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    /* Re-enable instruction cache */
    status = HAL_ICACHE_Enable();
    if (status != HAL_OK) {
        return eNVM_FLASH_ERROR;
    }

    return eNVM_OK;
}
 

Online GromBeestje

  • Frequent Contributor
  • **
  • Posts: 285
  • Country: nl
Re: STM32U5: Issue with accessing second bank of the flash space
« Reply #3 on: September 08, 2024, 11:26:28 am »
That looks like it should work.
I don't have any Microcontroller board from the STM32U5 series around to test with.
Seeing the U5 series are Cortex M33, the problem might be related to TrustZone.
Looking at a datasheet, it mentions
Code: [Select]
Each flash memory page can be programmed on the fly as privileged or unprivileged.

Other then that, I also see mention of a power down mode for flash bank 2.

Looking at the point of the hardfault, one could assume it is something with the memory. Ensure the addresses are correct.
However, just to make sure this is actually what is happening, analyse the fault, Is it an actual hardfault or some unhandled interrupt?

To tell the difference make your own HardFault_Handler so it doesn;t use the DefaultHandler. 
Something like this
https://web.archive.org/web/20240721104620/https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html
Using the Wayback Machine, as it seems, this content is no longer available on the freertos website.  Note this is not FreeRTOS specific.

A bit more analysis of the fault condition is going on in here. This is looking at the content of CFSR, only a subset of possible faults, but you get the idea.
https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/RTOS2/RTX/Examples/TrustZoneV8M/RTOS_Faults/CM33_s




 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf