cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U575 is memory remapping required - prior to jump to bootloader from application?

RLanz.2
Associate II

In an earlier project based on STM32F7x,

we had to add memory remapping by hand:

SYSCFG->MEMRMP = 0x01;

There is no equivalent in SYSCFG for STMU575,

nor did I find relevant bits under SYSCFG->CFGR1 or CFGR1->CFGR2 or other field as part of SYSCFG.

1 ACCEPTED SOLUTION

Accepted Solutions
Diane POMABIA
ST Employee

Hi @RLanz.2​ 

On the STM32U5, this functionality is not supported by the SYSCFG but by option bytes in the flash ( NBOOT0 and NSWBOOT0) in FLASH option register.

Regards

Diane

View solution in original post

34 REPLIES 34
Diane POMABIA
ST Employee

Hi @RLanz.2​ 

On the STM32U5, this functionality is not supported by the SYSCFG but by option bytes in the flash ( NBOOT0 and NSWBOOT0) in FLASH option register.

Regards

Diane

RLanz.2
Associate II

Indeed, I've discovered that myself a little while ago. Thank you.

I see that FLASH_OB_UserConfig() or FLASH_OB_BootAddrConfig() cannot be applied directly,

but that I should use HAL_FLASHEx_OBProgram().

I need to set OB_USER_NBOOT0, OB_USER_NSWBOOT0 option bytes, maybe also OB_USER_TZEN, and also to set the address of FLASH_NSBOOTADD1R_NSBOOTADD1.

I see partial documentation that it requires specific flow to do that,

including prior to call HAL_FLASH_OB_Unlock() for the option lock bit OPTLOCK to be cleared

and after to call HAL_FLASH_OB_Launch() for the new option bytes configuration to be taken into account, when no power reset, as it is in the case of jumping to bootloader.

Can you give a link to some sample code and/or guidelines to see that I don't miss anything?

Diane POMABIA
ST Employee

@RLanz.2​ Thanks you for your feedback,

You can found this example : https://github.com/STMicroelectronics/STM32CubeU5/tree/main/Projects/NUCLEO-U575ZI-Q/Examples/FLASH/FLASH_ChangeOptionBytes that give you procedure to configure/change options bytes.

Regards

Diane

RLanz.2
Associate II

Great, thank you for the link.

Could this procedure of configure/change options bytes be part of the jump to bootloader function,

not as a final step, then continue with rest steps, or some other order of operations is required?

For example: HAL_FLASH_OB_Launch(); should be done later on?

It seems I lose debugger after calling HAL_FLASH_OB_Launch()

Please see the below code snippet for jumping to bootloader from application, with the step to configure/change options bytes:

void jump_to_bootloader(void) {
	void (*SysMemBootJump)(void);
 
	/**
	 * Step: Boot activation pattern
	 *
	 *       For STM32U575xx, we need to activate the system bootloader at 0x0BF90000
	 *       Pin BOOT0 is pulled low in each of BH4 nodes.
	 *       AN2602 - The STM32U575xx/85xx bootloader is activated by applying pattern 12
	 *       (described in Table 2: Bootloader activation patterns).
	 *       TrustZone is disabled.
	 *       Thus, relevant pattern is:
	 *       TZen = 0, nBoot0(bit) = 0, nSWBoot0(bit) = 0 and NSBOOTADD1 [24:0] = 0x017F200
	 *
	 *       Flow:
	 *       1. To configure any option bytes, the option lock bit OPTLOCK must be
	 *          cleared with the call of HAL_FLASH_OB_Unlock()
	 *       2. Using HAL_FLASHEx_OBProgram() for Program the user Option Bytes & Configure the Boot addresses
	 *       3. New option bytes configuration will be taken into account, when no power reset,
	 *          after an option bytes launch through the call of HAL_FLASH_OB_Launch()
	 *
	 */
	FLASH_OBProgramInitTypeDef OB_Data;
	OB_Data.OptionType = OPTIONBYTE_USER | OPTIONBYTE_BOOTADDR;
	OB_Data.USERType = OB_USER_TZEN | OB_USER_NBOOT0 | OB_USER_NSWBOOT0;
	OB_Data.USERConfig = OB_TZEN_DISABLE | OB_NBOOT0_RESET | OB_BOOT0_FROM_OB;
	OB_Data.BootAddrConfig = OB_BOOTADDR_NS1;
	OB_Data.BootAddr = 0x017F200;
	HAL_FLASH_Unlock();
	HAL_FLASH_OB_Unlock();
	HAL_StatusTypeDef status = HAL_FLASHEx_OBProgram(&OB_Data);
	HAL_FLASH_OB_Launch();
 
	if(HAL_OK != status)
	{
		while(1); // TBD!!!!!!!!
	}
 
	// These are private static functions - not to use directly -
	// this is just a 'logical' sequence to be performed using HAL_FLASHEx_OBProgram()
	//
	//	FLASH_OB_UserConfig(OB_USER_TZEN, OB_TZEN_DISABLE);
	//	FLASH_OB_UserConfig(OB_USER_NBOOT0, OB_NBOOT0_RESET);
	//	FLASH_OB_UserConfig(OB_USER_NSWBOOT0, OB_BOOT0_FROM_OB);
	//	FLASH_OB_BootAddrConfig(OB_BOOTADDR_NS1, 0x017F200);
 
 
	/**
	 * Step: Set system memory address.
	 *
	 *       For STM32U575xx, system memory is at 0x0BF90000
	 *       For other families, check AN2606 document
	 */
	volatile uint32_t addr = 0x0BF90000; // STM32U575xx
 
	/**
	 * Step: Disable RCC, set it to default (after reset) settings
	 *       Internal clock, no PLL, etc.
	 */
	HAL_RCC_DeInit();
 
	/**
	 * Step: Disable systick timer and reset it to default values
	 */
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
 
	/**
	 * Step: Disable all interrupts
	 */
	__disable_irq();
 
	// /**
	//  * Step: Remap system memory to address 0x0000 0000 in address space
	//  *       For each family registers may be different.
	//  *       Check reference manual for each family.
	//  *
	//  *       For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
	//  *       For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
	//  *       For others, check family reference manual
	//  */
	// //Remap by hand... {
	// SYSCFG->MEMRMP = 0x01; //F7
 
	/**
	 * Step: Set jump memory location for system memory
	 *       Use address with 4 bytes offset which specifies jump location where program starts
	 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
	/**
	 * Step: Set main stack pointer.
	 *       This step must be done last otherwise local variables in this function
	 *       don't have proper value since stack pointer is located on different position
	 *
	 *       Set direct address location which specifies stack pointer in SRAM location
	 */
	__set_MSP(*(uint32_t *)addr);
 
	/**
	 * Step: Actually call our function to jump to set location
	 *       This will start system memory execution
	 */
	SysMemBootJump();
 
	/**
	 * Step: Connect USB<->UART converter to dedicated USART pins and test
	 *       and test with bootloader works with STM32 Flash Loader Demonstrator software
	 */
}

RLanz.2
Associate II

Sorry, I have changed the flow during your answer.. It is because I lost debugger during the flow..

I have changed it back now for your review.

Should I keep the procedure of configure/change options bytes flow to be right after disabling all the interrupts?

Would set_MSP after, be still performed before the jump itself?

void jump_to_bootloader(void) {
	void (*SysMemBootJump)(void);
 
 
	/**
	 * Step: Set system memory address.
	 *
	 *       For STM32U575xx, system memory is at 0x0BF90000
	 *       For other families, check AN2606 document
	 */
	volatile uint32_t addr = 0x0BF90000; // STM32U575xx
 
	/**
	 * Step: Disable RCC, set it to default (after reset) settings
	 *       Internal clock, no PLL, etc.
	 */
	HAL_RCC_DeInit();
 
	/**
	 * Step: Disable systick timer and reset it to default values
	 */
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
 
	/**
	 * Step: Disable all interrupts
	 */
	__disable_irq();
 
	// /**
	//  * Step: Remap system memory to address 0x0000 0000 in address space
	//  *       For each family registers may be different.
	//  *       Check reference manual for each family.
	//  *
	//  *       For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
	//  *       For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
	//  *       For others, check family reference manual
	//  */
	// //Remap by hand... {
	// SYSCFG->MEMRMP = 0x01; //F7
	/**
	 * Step: Boot activation pattern
	 *
	 *       For STM32U575xx, we need to activate the system bootloader at 0x0BF90000
	 *       Pin BOOT0 is pulled low in each of BH4 nodes.
	 *       AN2602 - The STM32U575xx/85xx bootloader is activated by applying pattern 12
	 *       (described in Table 2: Bootloader activation patterns).
	 *       TrustZone is disabled.
	 *       Thus, relevant pattern is:
	 *       TZen = 0, nBoot0(bit) = 0, nSWBoot0(bit) = 0 and NSBOOTADD1 [24:0] = 0x017F200
	 *
	 *       Flow:
	 *       1. To configure any option bytes, the option lock bit OPTLOCK must be
	 *          cleared with the call of HAL_FLASH_OB_Unlock()
	 *       2. Using HAL_FLASHEx_OBProgram() for Program the user Option Bytes & Configure the Boot addresses
	 *       3. New option bytes configuration will be taken into account, when no power reset,
	 *          after an option bytes launch through the call of HAL_FLASH_OB_Launch()
	 *
	 */
	FLASH_OBProgramInitTypeDef OB_Data;
	OB_Data.OptionType = OPTIONBYTE_USER | OPTIONBYTE_BOOTADDR;
	OB_Data.USERType = OB_USER_TZEN | OB_USER_NBOOT0 | OB_USER_NSWBOOT0;
	OB_Data.USERConfig = OB_TZEN_DISABLE | OB_NBOOT0_RESET | OB_BOOT0_FROM_OB;
	OB_Data.BootAddrConfig = OB_BOOTADDR_NS1;
	OB_Data.BootAddr = 0x017F200;
	HAL_FLASH_Unlock();
	HAL_FLASH_OB_Unlock();
	HAL_StatusTypeDef status = HAL_FLASHEx_OBProgram(&OB_Data);
	HAL_FLASH_OB_Launch();
 
//	if(HAL_OK != status)
//	{
//		while(1); // TBD!!!!!!!!
//	}
 
	// These are private static functions - not to use directly -
	// this is just a 'logical' sequence to be performed using HAL_FLASHEx_OBProgram()
	//
	//	FLASH_OB_UserConfig(OB_USER_TZEN, OB_TZEN_DISABLE);
	//	FLASH_OB_UserConfig(OB_USER_NBOOT0, OB_NBOOT0_RESET);
	//	FLASH_OB_UserConfig(OB_USER_NSWBOOT0, OB_BOOT0_FROM_OB);
	//	FLASH_OB_BootAddrConfig(OB_BOOTADDR_NS1, 0x017F200);
 
 
	/**
	 * Step: Set jump memory location for system memory
	 *       Use address with 4 bytes offset which specifies jump location where program starts
	 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
 
	/**
	 * Step: Set main stack pointer.
	 *       This step must be done last otherwise local variables in this function
	 *       don't have proper value since stack pointer is located on different position
	 *
	 *       Set direct address location which specifies stack pointer in SRAM location
	 */
	__set_MSP(*(uint32_t *)addr);
 
	/**
	 * Step: Actually call our function to jump to set location
	 *       This will start system memory execution
	 */
	SysMemBootJump();
 
	/**
	 * Step: Connect USB<->UART converter to dedicated USART pins and test
	 *       and test with bootloader works with STM32 Flash Loader Demonstrator software
	 */
}

It's an normal behaviour because HAL_FLASH_OB_Launch will reset your MCU and you will lost your debug.

on the other hand, what is likely to happen is that you will pass the max number of read and write cycles per page of your flash that assures the data retention with this function. Because after the HAL_FLASH_OB_Launch , MCU is reset and go back to the beginning. So won't jump in memory location for system memory.

You have to add one condition to assures that the options bytes config happening just at the first time.

I have test on my side this little code , You can integrate it in your function :

void (*SysMemBootJump)(void);
       volatile uint32_t addr = 0x0BF90000; // STM32U575xx
        HAL_RCC_DeInit();
        SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
        __disable_irq();
        
        
        FLASH_OBProgramInitTypeDef OB_Data;
	OB_Data.OptionType = OPTIONBYTE_USER | OPTIONBYTE_BOOTADDR;
	OB_Data.USERType = OB_USER_TZEN | OB_USER_NBOOT0 | OB_USER_NSWBOOT0;
	OB_Data.USERConfig = OB_TZEN_DISABLE | OB_NBOOT0_RESET | OB_BOOT0_FROM_OB;
	OB_Data.BootAddrConfig = OB_BOOTADDR_NS1;
	OB_Data.BootAddr = 0x017F200;
	
        
        
        uint32_t Nboot0_OB=READ_BIT(FLASH->OPTR, FLASH_OPTR_nBOOT0);
        uint32_t NSWBoot0_OB= READ_BIT(FLASH->OPTR, FLASH_OPTR_nSWBOOT0);
        uint32_t TZEN_OB=READ_BIT(FLASH->OPTR, FLASH_OPTR_TZEN);
        
        
        if (Nboot0_OB!=OB_NBOOT0_RESET || TZEN_OB !=OB_TZEN_DISABLE ||NSWBoot0_OB !=OB_BOOT0_FROM_OB){
                HAL_FLASH_Unlock();
	        HAL_FLASH_OB_Unlock();
        	HAL_StatusTypeDef status = HAL_FLASHEx_OBProgram(&OB_Data);
                HAL_FLASH_OB_Launch();
        }
       SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
        __set_MSP(*(uint32_t *)addr);
        SysMemBootJump();

Regards,

Diane

RLanz.2
Associate II

If I understand correctly, the change you have made to my code,

is to check if it is required to write the option bytes: first reading the option bytes,

and compare with required values and then decide if to update them.

I need to ask few questions to better understand your solution:

  1. Do you compare the values of option bytes in order to avoid reaching the number of write cycles of flash?
  2. Does HAL_FLASH_OB_Launch() cause an immediate reset, thus the code after will not be executed at all, and the jump in memory location to system memory of the system bootloader will not be performed?
  3. You say you have tested on your side this little code - what do you mean:

Did you test it on the STM32U575 CPU and saw that the option bytes is indeed written?

Do you see that next execution the jump to bootloader memory was successful?

How can I be sure my code jumped to the bootloader (how can I verify it)?

  1. AN2606 says that the STM32U575xx/85xx bootloader is activated by applying pattern 12

(described in Table 2: Bootloader activation patterns). TrustZone is disabled. Thus, relevant

pattern is:

TZen = 0, nBoot0(bit) = 0, nSWBoot0(bit) = 0 and NSBOOTADD1 [24:0] = 0x017F200

So, if I write OB_Data.BootAddr = 0x0BF90000; using the above code,

then when I connect with the tool of STM32 CUBE Programmer to verify it,

then I see NSBOOTADD1 value: 0x17f200, address: 0x0bf90000

, and if I write OB_Data.BootAddr = 0x017F200, the behavior is strange and execution halts(!?), so I needed to change the values back using the tool of STM32 CUBE Programmer.

So, my question is: should I write the value 0x0BF90000 or 0x017F200 to OB_Data.BootAddr ?

Thank you for your help!

Diane POMABIA
ST Employee

Hi @RLanz.2​ 

Q1: Yes because your code left as it is becomes a while loop that will never get into the bootloader. it is necessary to limit the writing of the flash options bytes.

Q2: Exactly to avoid this a condition is needed that this configuration is only done if it has not already been done before.

Q3: In my test I could see after loading that my bytes options had changed and in debug we can confirm that the change of the value of the bytes options has place only once.

I also check if the jump in bootloader is ok by connecting to USART2 with STM32CubeProgrammer(UART, with baudrate 115200).

For STM32U575 , if you have choose configuration : TZen = 0, nBoot0(bit) = 0, nSWBoot0(bit) = 0,You have to write 0x017F200 to OB_Data.BootAdrr .

Regards

DianeP

RLanz.2
Associate II

Hi

Thank you for detailed answers!

Just to make sure one more thing:

Writing to  OB_Data.BootAdrr should also be conditioned only to be done once, if it is different than 0x017F200 ?