2022-04-18 10:32 AM
The HAL_FLASH documentation is especially poor.
There in no overview of what you have to do.
You would think (because of lack of anything saying different) you have to
HAL_FLASH_OB_Unlock()
HAL_FLASH_Program(...)
HAL_FLASH_OB_Lock()
The first command HAL_FLASH_OB_Unlock() crashes.
HAL_FLASH_Program(...) says the format is
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
Nowhere in the HAL Documentation's (UM1940) 1441 pages does it say what "TypeProgram" is, what it is used for, or what it should be.
It says TypeProgram indicates the way to program at a specific address. The value can be a value of FLASH Type Program. What is FLASH Type Program?
On page 234 it has
FLASH Type Program
FLASH_TYPEPROGRAM_BYTE
FLASH_TYPEPROGRAM_HALFWORD
FLASH_TYPEPROGRAM_WORD
FLASH_TYPEPROGRAM_DOUBLEWORD
I cannot program that with a byte or a halfword, or a word. it can only be a word.
Looking into the code for
HAL_FLASH_Program() in stm32g0xx_hal_flash.c it says
/**
* @brief Program double word or fast program of a row at a specified address.
* @param TypeProgram Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program
* @param Address Specifies the address to be programmed.
* @param Data Specifies the data to be programmed
* This parameter is the data for the double word program and the address where
* are stored the data for the row fast program depending on the TypeProgram:
* TypeProgram = FLASH_TYPEPROGRAM_DOUBLEWORD (64-bit)
* TypeProgram = FLASH_TYPEPROGRAM_FAST (32-bit).
*
* @retval HAL_StatusTypeDef HAL Status
*/
So one of the options is FLASH_TYPEPROGRAM_FAST. But that is not on the list on page 234! Why?
The macro
#define IS_FLASH_TYPEPROGRAM(__VALUE__) (((__VALUE__) == FLASH_TYPEPROGRAM_DOUBLEWORD) || \
((__VALUE__) == FLASH_TYPEPROGRAM_FAST))
It does not say any of the other values are valid from Page 234.
I still do not know why HAL_FLASH_OB_Unlock() crashes. It is the first step.
Kip
Solved! Go to Solution.
2022-04-21 12:51 AM
> I cannot find DEV_FLASH_KEY1.
These key constants are indeed defined by me. The reason for this is simple - ST has not defined those in register definition files. Such constants are only defined in HAL files, not even LL. The best would be to define those with the same CMSIS style FLASH_KEYR_KEYR_KEY1 (PERIPHERAL_REGISTER_BITFIELD_VALUE) in register definition files, but...
> cannot find FLASH_OPTR_nSWBOOT0, it calls it FLASH_OPTR_nBOOT0
Those two are not the same! But in this case it doesn't matter because that is a code from my project. Just redefine BSP_FLASH_OPTR with your desired values. I defined it as a hexadecimal default value for my MCU "minus" some specific bits, but that's just how I choose to format it.
2022-04-21 07:08 AM
2022-04-21 11:17 AM
Registers and bit fields are there, but not the specific field values. In this case KEY1 and KEY2 are just a two specific values for a KEYR bit field.
2022-04-21 02:21 PM
With thanks to Piranha I have it working. Here is my version of his code.
#define CLEAR_BITS (~(FLASH_OPTR_nBOOT_SEL))
#define SET_BITS (FLASH_OPTR_nBOOT0 | FLASH_OPTR_nBOOT1)
#define BSP_FLASH_OPTR ((FLASH->OPTR & CLEAR_BITS) | SET_BITS)
void BSP_SyncOptionBytes(void)
{
char buf[100];
uint32_t x = *((uint32_t *) 0x1FFF7800);
sprintf(buf,"\r\nStarting BSP_SyncOptionBytes() *0x1FFF7800: 0x%08lX\r\n",x);
print_debug_str(buf);
sprintf(buf,"FLASH_OPTR %08lX, BSP_FLASH_OPTR %08lX\r\n",FLASH->OPTR, BSP_FLASH_OPTR);
print_debug_str(buf);
HAL_Delay(5000); // Give it time to finish printing.
if (FLASH->OPTR == BSP_FLASH_OPTR) {
return;
}
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
if (FLASH->CR & FLASH_CR_OPTLOCK) {
FLASH->OPTKEYR = FLASH_OPTKEY1;
FLASH->OPTKEYR = FLASH_OPTKEY2;
}
FLASH->OPTR = BSP_FLASH_OPTR;
FLASH->CR = FLASH_CR_OPTSTRT;
while (FLASH->SR & FLASH_SR_BSY1);
FLASH->CR = FLASH_CR_OBL_LAUNCH;
}
Thanks all who helped. This was a tough one. Of course I did not help that I did not understand at first that you had to write to registers as opposed to Flash.
We know the HAL code does not work for the STM32G031K6T6.
2022-05-10 01:59 AM
Hey KiptonM,
That looks great! I am hoping you could help me as well...
I am using a Nucleo - L476RG board and would like to enter DFU mode from the software.
I just dont want to copy and paste your code until i understand more about what i am doing.
From the Documentation:
and
it says i need to use Pattern 7:
Boot0(pin) = 1, nBoot1(bit) = 1 and BFB2(bit) = 0
to enter DFU mode.
How could I achieve that using the code snippet you posted above?
Would simply changing the defines above to:
#define CLEAR_BITS (~(FLASH_OPTR_nBOOT_SEL))
#define SET_BITS (FLASH_OPTR_BFB2 | FLASH_OPTR_nBOOT1)
#define BSP_FLASH_OPTR ((FLASH->OPTR & CLEAR_BITS) | SET_BITS)
also, what is the purpse of:
uint32_t x = *((uint32_t *) 0x1FFF7800); ?
Is it in use in the code?
Thanks for your help
Almog
2022-06-06 12:11 PM
Sorry I have been out for all of May and just got to checking this today.
Boot0(pin) = 1, nBoot1(bit) = 1 and BFB2(bit) = 0
to enter DFU mode.
How could I achieve that using the code snippet you posted above?
Would simply changing the defines above to:
#define CLEAR_BITS (~(FLASH_OPTR_nBOOT_SEL))
#define SET_BITS (FLASH_OPTR_BFB2 | FLASH_OPTR_nBOOT1)
#define BSP_FLASH_OPTR ((FLASH->OPTR & CLEAR_BITS) | SET_BITS)
I do not think so. In your case you want to clear BFB2(bit) = 0
#define CLEAR_BITS (~(FLASH_OPTR_BFB2))
And you want to set Boot0(pin) = 1, nBoot1(bit) = 1
#define SET_BITS (FLASH_OPTR_nBOOT_SEL | FLASH_OPTR_nBOOT1)
You combine the same way
BSP_FLASH_OPTR ((FLASH->OPTR & CLEAR_BITS) | SET_BITS)
also, what is the purpose of:
uint32_t x = *((uint32_t *) 0x1FFF7800); ?
Is it in use in the code?
Let's step through that code.
0x1FFF7800 is a number;
(uint32_t *) 0x1FFF7800) says that number is an address for 32-bit unsigned data.
*((uint32_t *) 0x1FFF7800) says get the value stored in that 32-bit unsigned address.
uint32_t x = *((uint32_t *) 0x1FFF7800); says get the value stored in that 32-bit unsigned address and put it in x.
I am then printing the value to see what it is. (For debugging purposes)
Why am I interested in the data in that location? Page 81 of RM0444 says that is the Flash memory address of the "User and read protection option bytes"
That is what gets changed by the code. I wanted to see what it was before I started.
2022-06-19 06:09 AM
Thank you very much for your reply!
Changing my code to what you suggested and adding the following:
HAL_RCC_DeInit();
HAL_DeInit();
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
// /* Initialize user application's Stack Pointer */
__ASM volatile("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n"
:
:
: "r3", "sp");
((void (*)(void)) * ((uint32_t*)(0x00000000 + 4)))();
while (1) {
}
Allows me to enter DFU mode and upgrade my device remotely.
Cheers!
2022-06-27 12:58 PM
#define BSP_FLASH_OPTR ((FLASH->OPTR & CLEAR_BITS) | SET_BITS)
if (FLASH->OPTR == BSP_FLASH_OPTR) {
FLASH->OPTR = BSP_FLASH_OPTR;
Putting a register read in that macro defeats the original purpose of that macro, which was to compare the FLASH_OPTR register against a compile-time constant. Now there are three FLASH_OPTR register reads in total and the same register is read twice even for a single comparison. Also it compares only some bits, not all, and generally looks at least weird. If one needs to ensure a specific state of only some bits, then a simple variables should be used:
uint32_t rOPTR = FLASH->OPTR;
uint32_t rOPTR_ref = (rOPTR & CLEAR_BITS) | SET_BITS;
if (rOPTR == rOPTR_ref) {
FLASH->OPTR = rOPTR_ref;
2024-10-20 03:54 PM
It's not very clear from the driver documentation that you have to unlock the flash separately and as a prerequisite to unlocking the flash option bytes, but that's what fixed it for me.
Here's code that works for me now, to change the BOR level in the option bytes:
HAL_FLASHEx_OBGetConfig(&OB_to_be_programmed);
if((OB_to_be_programmed.UserConfig & FLASH_OPTR_BOR_LEV_Msk) ==0){ //Default is zero for 1.65V
OB_to_be_programmed.OptionType = OPTIONBYTE_USER;
OB_to_be_programmed.UserType = FLASH_OPTR_BOR_LEV;
OB_to_be_programmed.UserConfig |= OB_BOR_LEVEL_3; //BOR_LEVEL_3 is 2.5V
status = HAL_FLASH_Unlock();
status = HAL_FLASH_OB_Unlock();
status = HAL_FLASHEx_OBProgram(&OB_to_be_programmed);
status = HAL_FLASH_OB_Lock();
status = HAL_FLASH_Unlock();
}
I tested out the reset voltage before I added this code, and it was about 1.65V. After I added this code it was 2.5V.