cancel
Showing results for 
Search instead for 
Did you mean: 

The STM32G0 series microcontroller enters undescribed mode.

red15530
Associate II

I have been sitting with this question for more than a week, I have already run out of strength, I cannot understand how it works and what I am doing wrong ...

And so, I have an STM32G030F6P6 microcontroller. My program needs to do two things with flash memory, namely:

1) Save 8 bit number. I do it like this:

	FLASH->KEYR = 0x45670123;
	FLASH->KEYR = 0xCDEF89AB;
 
	while (FLASH->SR & FLASH_SR_BSY1);
 
	FLASH->SR |= FLASH_SR_OPTVERR;
	FLASH->SR |= FLASH_SR_FASTERR;
	FLASH->SR |= FLASH_SR_MISERR;
	FLASH->SR |= FLASH_SR_PGSERR;
	FLASH->SR |= FLASH_SR_SIZERR;
	FLASH->SR |= FLASH_SR_PGAERR;
	FLASH->SR |= FLASH_SR_WRPERR;
	FLASH->SR |= FLASH_SR_PROGERR;
	FLASH->SR |= FLASH_SR_OPERR;
 
	FLASH->CR |= FLASH_CR_PER; //Page erase enable
	FLASH->CR |= (15<<FLASH_CR_PNB_Pos); //Page number selection
	FLASH->CR |= FLASH_CR_EOPIE; //End-of-operation interrupt enable
	FLASH->CR |= FLASH_CR_STRT; // Start erase operation
 
	while (FLASH->SR & FLASH_SR_BSY1);
 
	if (FLASH->SR & FLASH_SR_EOP)
	{
		FLASH->SR |= FLASH_SR_EOP;
	}
 
	FLASH->CR &= ~FLASH_CR_PER; //Page erase disabled
	//--------------------------------------------------
	while (FLASH->SR & FLASH_SR_BSY1);
 
	FLASH->SR |= FLASH_SR_OPTVERR;
	FLASH->SR |= FLASH_SR_FASTERR;
	FLASH->SR |= FLASH_SR_MISERR;
	FLASH->SR |= FLASH_SR_PGSERR;
	FLASH->SR |= FLASH_SR_SIZERR;
	FLASH->SR |= FLASH_SR_PGAERR;
	FLASH->SR |= FLASH_SR_WRPERR;
	FLASH->SR |= FLASH_SR_PROGERR;
	FLASH->SR |= FLASH_SR_OPERR;
 
	FLASH->CR |= FLASH_CR_PG; //Flash memory programming enable
	FLASH->CR |= (15<<FLASH_CR_PNB_Pos); //Page number selection
	FLASH->CR |= FLASH_CR_EOPIE; //End-of-operation interrupt enable
 
	*(__IO uint32_t*)0x08007800=(uint32_t)mydata;
	*(__IO uint32_t*)0x08007804=0;
 
	while (FLASH->SR & FLASH_SR_BSY1);
 
	if (FLASH->SR & FLASH_SR_EOP)
	{
		FLASH->SR |= FLASH_SR_EOP;
	}
	FLASH->CR &= ~FLASH_CR_PG; //Page programming disabled
	FLASH->CR &= ~FLASH_CR_EOPIE; //End-of-operation interrupt disabled
 
	FLASH->CR |= FLASH_CR_LOCK;

2) Set read protection memory. I do it like this:

    if ((FLASH->OPTR & FLASH_OPTR_RDP) != 0xBB)
    {
  	  FLASH->KEYR = 0x45670123;
  	  FLASH->KEYR = 0xCDEF89AB;
 
  	  FLASH->OPTKEYR = 0x08192A3B;
  	  FLASH->OPTKEYR = 0x4C5D6E7F;
 
  	  while (FLASH->SR & FLASH_SR_BSY1);
 
  	  FLASH->OPTR |= (0xBB << FLASH_OPTR_RDP_Pos);
 
  	  while (FLASH->SR & FLASH_SR_BSY1);
  	  FLASH->CR |= FLASH_CR_OPTSTRT;
  	  while (FLASH->SR & FLASH_SR_BSY1);
  	  FLASH->CR |= FLASH_CR_LOCK;
    }

After, if you restart the power supply, the microcontroller goes into some kind of incomprehensible state and it can no longer be programmed. It generally ceases to be determined by the programmer through the SWD interface. I also see that my program is not running. (I know this because it should flash the LED)

At the same time, I noticed that after I program the microcontroller, but do not turn off the power, I have the opportunity to connect to it and even erase the memory or write a new program to it. But no matter what I do after a power reset, everything leads to one result - the inability to connect to this microcontroller in any way.

I also noticed that after programming with this program, when I am in debug mode, sometimes (I did not find a pattern) the program can go into the address space> 0x1fff0000 and crashes there.

I don’t know what exactly affects the microcontroller writing to memory or setting read protection. But if I remove these two functions from the program, everything works without problems.

Thus, I have already spoiled more than 10 microcontrollers, and in order to continue to deal with this problem, I do not want to sacrifice new ones.

I use the original ST LINK V2 programmer and original STM32G030F6P6 microcontrollers, as well as the latest versions of STM32CubeIDE 1.11.2, STM32CubeProgrammer v2.12.0 and STM32 ST-LINK Utility.

The programmer is connected according to this scheme

If I forgot to mention something, I am ready to answer any questions. If you need to provide any diagrams, code snippets or any other information, just ask.

I welcome any idea, any opportunity to get to the bottom of the truth! If you need to "kill" more controllers - I'm ready!

If anyone has any ideas how to bring broken microcontrollers back to life (any idea) I'm willing to try.

13 REPLIES 13
S.Ma
Principal

Is it a dual or single bank flash?

If not dual, your code must execute in RAM as the flash is disconnected during erase/write.

MM..1
Chief II

Remove from this scheme all pullups. For example G0F6 have BOOT0 and PA14 SWCLK on same pin usw. 1FFF0000 is on empty flash normal boot step into system mem ...

It is single bank flash

Doing multiple RMW to clear the errors is massively inefficient. Speed perhaps not the goal here, but the code size.

I'd be masking the new pattern on to OTPR, not just or-ing on additional bits to get a non-viable value.

Perhaps try with the library, or take some cues from it.

/**
  * @brief  Set user & RDP configuration
  * @note   !!! Warning : When enabling OB_RDP level 2 it is no more possible
  *         to go back to level 1 or 0 !!!
  * @param  UserType  The FLASH User Option Bytes to be modified.
  *         This parameter can be a combination of @ref FLASH_OB_USER_Type
  * @param  UserConfig  The FLASH User Option Bytes values.
  *         This parameter can be a combination of:
  *           @arg @ref FLASH_OB_USER_BOR_ENABLE(*)
  *           @arg @ref FLASH_OB_USER_BOR_LEVEL(*)
  *           @arg @ref FLASH_OB_USER_RESET_CONFIG(*)
  *           @arg @ref FLASH_OB_USER_nRST_STOP
  *           @arg @ref FLASH_OB_USER_nRST_STANDBY
  *           @arg @ref FLASH_OB_USER_nRST_SHUTDOWN(*)
  *           @arg @ref FLASH_OB_USER_IWDG_SW
  *           @arg @ref FLASH_OB_USER_IWDG_STOP
  *           @arg @ref FLASH_OB_USER_IWDG_STANDBY
  *           @arg @ref FLASH_OB_USER_WWDG_SW
  *           @arg @ref FLASH_OB_USER_SRAM_PARITY
  *           @arg @ref FLASH_OB_USER_BANK_SWAP(*)
  *           @arg @ref FLASH_OB_USER_DUAL_BANK(*)
  *           @arg @ref FLASH_OB_USER_nBOOT_SEL
  *           @arg @ref FLASH_OB_USER_nBOOT1
  *           @arg @ref FLASH_OB_USER_nBOOT0
  *           @arg @ref FLASH_OB_USER_INPUT_RESET_HOLDER(*)
  * @param  RDPLevel  specifies the read protection level.
  *         This parameter can be one of the following values:
  *           @arg @ref OB_RDP_LEVEL_0 No protection
  *           @arg @ref OB_RDP_LEVEL_1 Memory Read protection
  *           @arg @ref OB_RDP_LEVEL_2 Full chip protection
  * @note  (*) availability depends on devices
  * @retval None
  */
static void FLASH_OB_OptrConfig(uint32_t UserType, uint32_t UserConfig, uint32_t RDPLevel)
{
  uint32_t optr;
 
  /* Check the parameters */
  assert_param(IS_OB_USER_TYPE(UserType));
  assert_param(IS_OB_USER_CONFIG(UserType, UserConfig));
  assert_param(IS_OB_RDP_LEVEL(RDPLevel));
 
  /* Configure the RDP level in the option bytes register */
  optr = FLASH->OPTR;
  optr &= ~(UserType | FLASH_OPTR_RDP);
  FLASH->OPTR = (optr | UserConfig | RDPLevel);
}

Yes, these protection methods are a bit of a minefield, plenty of opportunity to brick devices. Have code on-board that you can debug and interact with, like a old-school monitor type application, so you can dump, and peek/poke registers and memory, without needing a debug pod.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

All programming pins in my scheme are no pull-up, pull-down

red15530
Associate II

Thanks to everyone who is trying to help. Sorry for not answering right away, I needed time and this is what I came up with:

1) Now I have one microcontroller connected to debugging with which I can test, so if you have any ideas, write!

2) If you run any program (without any interruptions - this is important), then everything works fine, the program is executed, debugging works, it stops at breakpoints. When debugging is disabled, everything continues to work.

3) If you configure at least one any interrupt (I tried it from ADC, DMA, TIM), then something unknown happens. As soon as an interrupt should occur, the program jumps to >0x1fff0000 and stays there forever. Next, I spent a lot of time reading about how interrupts work. As I understood from the documentation:

There is a table of interrupt vectors. RM0454 Rev 5 page 250/989

0693W00000aH7HWQA0.pngWhen and how it is written, I did not quite understand, but as I understand it, it is written to the address that lies in the VTOR register

0693W00000aH7HbQAK.pngIn the end, I put a breakpoint before starting the interrupt and looked at this register

0693W00000aH7HvQAK.pngI saw 0 there, which seemed strange to me ... It turns out that the addresses of the interrupt vectors are from address 0?

Next, I unpaused the program so that an interrupt occurred and also hung on the address space> 0x1fff0000, but if you pause in the VTOR register, it will already be just 0x1fff0000. Coincidence? Don't think. I also noticed that in FLASH the Latency register was set to 2. I don’t know what this is connected with, but it’s a fact.

0693W00000aH7IUQA0.png4) I realized that all this goes away not when I set the read protection, but when I write to the last page of the flash memory. What can happen that the controller goes into such a state?

5) I deliberately do not turn off the power of this MK now, because I believe that after that it will also cease to be detected by the SWD interface.

6) Maybe I forgot to mention something, so ask.

7) Also, if you remove the FLASH entry from the program, then it works absolutely fine on another same microcontroller. That is, it's all about writing to memory. To be honest, it doesn’t fit in my head what can be done when writing to memory in order to spoil the microcontroller in such a way ... I thought you could get only two states, either everything works or it doesn’t work. And here it turns out that everything seems to be working, until the interrupt is triggered. And again, even the complete erasure of flash memory does not bring the microcontroller out of this state. I don't understand. After all, I could not change other parts of the memory, except for flash, or could I?

Try use HAL

c:\Users\YOU\STM32Cube\Repository\STM32Cube_FW_G0_V1.5.0\Projects\NUCLEO-G031K8\Examples\FLASH\FLASH_EraseProgram\

Normally people set SCB->VTOR to the base of the vector table in SystemInit()

ST has this #define thing going on, I just tend to use the linker symbol directly, so the build tracks the linker script or scatter file, without secondary unrelated code changes.

The SCB->VTOR typically clears to zero at reset, but the mapping of memory at the zero address is controlled by the BOOT pins, so shadows the RAM, FLASH, or ROM at zero, via the bus decoding scheme. This allows it to boot from different memories, and immediate transfer control to the appropriate Reset_Handler.

The role of SystemInit() in ARM's CMSIS model is to bring up external memories, MCU, FPU, etc before C run-time code attempts to initialize the statics, ie copy/clear RAM, with initial data staged in FLASH

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..