cancel
Showing results for 
Search instead for 
Did you mean: 

Is this the right way to "shut down" a 32F417?

PHolt.1
Senior III

I am implementing a data save procedure when power fail is detected and want to shut down as much stuff as possible to give myself the most time to copy some data into FLASH.

Shutting down the CPU has many modes which are quite complicated. I have been reading the RM and various appnotes. Googling around shows a lot of people are having problems.

Is this a right way to do it? It never needs to come out of it, and it must not come out of it for any interrupt

CLEAR_BIT(PWR->CSR, 0x00000100U);		// disable WKUP pin, just in case
		#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
		portNVIC_SYSTICK_CTRL_REG = 0UL;		// stop systick, just in case (also stops RTOS)
		SET_BIT(PWR->CR, PWR_CR_PDDS);			// select standby mode
		SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));	// Set SLEEPDEEP bit
		__WFI();								// request "wait for interrupt"

Some of the above is out of HAL_PWR_EnterSTANDBYMode().

I don't get what __WFI is supposed to do.

Thank you for any help or suggestions.

26 REPLIES 26
PHolt.1
Senior III

This is my current "shut down everything" code

If it is still wrong, perhaps somebody can tell me.

// We are now ~100us after issuing the ETH PHY shutdown. So the LAN8742 Serial Management
		// Interface (SMI) 64-bit USART has finished (takes ~40us)
		// Enter CPU standby mode. Some is out of HAL_PWR_EnterSTANDBYMode(). There is some
		// weird stuff around the shutdown code e.g.
		// https://www.eevblog.com/forum/microcontrollers/how-fast-does-st-32f417-enter-standby-mode/msg4062652/#msg4062652
		// Also https://community.st.com/s/question/0D73W000001nnJOSAY/detail
		
		PWR->CSR &= ~PWR_CSR_EWUP;				// disable WKUP pin, just in case
		PWR->CR |= PWR_CR_CWUF | PWR_CR_PDDS;	// select standby mode (deep sleep)
		(void)PWR->CR;							// readback to ensure the bit is set before next
		__WFI();								// This actually does the "shutdown"
 
		// CPU clock stops, DAC outputs float, etc
		// ** Code after this point is not executed (checked by waggling GPIO) **
		// But sometimes __WFI can fail - if e.g. there is an interrupt pending
		// e.g. USB serial FLASH read interrupt can be blocked for 200-300us.
 
		// Note that if the supply didn't actually die but we ended up here, the watchdog
		// will eventually trip
 
		hang_around_us(500); 		// wait for a bit longer than a FLASH read
 
		for (uint32_t i=0; i<100000; i++)
		{
			__WFI();
		}
 
		// Should never get here, but if we did, we want to start with a freshly
		// initialised unit.
 
		reboot();

Piranha
Chief II

You've forgot setting the SCB_SCR_SLEEPDEEP bit, resetting the DBGMCU_CR register and using the DSB instruction macro. Instead the code has a useless (the first one) WFI instruction, a useless magic delay, a finite (and therefore broken) loop with a magic number of iterations and a useless reset.

I cannot understand why you don't just take the much simpler and correct code from my article. Starting from the line 14 it doesn't even have to be modified for your MCU.

PHolt.1
Senior III

Dear Piranha

Why don't you just tell me what code to use for the 32F417?

You refer to various other posts but always leave out the key piece of info somebody needs.

Kind regards,

Peter

Is this right?

		PWR->CSR &= ~PWR_CSR_EWUP;				// disable WKUP pin, just in case
		PWR->CR |= PWR_CR_CWUF | PWR_CR_PDDS;	// select standby mode
		(void)PWR->CR;							// readback to ensure the bit is set before next
		SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;		// deep sleep
		
		// CPU clock stops, DAC outputs float, etc
		// ** Code after this point is not executed (checked by waggling GPIO) **
		// But sometimes __WFI can fail - if e.g. there is an interrupt pending
		// e.g. USB serial FLASH read interrupt can be blocked for 200-300us. Hence the loop.
		
		for (;;) 
		{
			__DSB();
			__WFI();
		}
 
		// Should never get here, but if we did, we want to start with a freshly
		// initialised unit.
 
		reboot();

Piranha
Chief II

You are still ignoring the resetting of DBGMCU_CR. Did you read my article and clearly understood that you 100% don't need it? And even then what does skipping it really gain - saves 4 bytes and 2 clock cycles? Also what's the point of a code after an infinite loop?

> You refer to various other posts but always leave out the key piece of info somebody needs.

Of course I point to a worthy information because it's inefficient and dumb to duplicate the same things over and over again. What key piece of information my article is missing? It does present a complete code example and it also splits it into 4 key issues and explains every single one in details. Honestly, it's the best example and explanation for this topic on the whole internet, and probably the only one, which is completely correct. So what information is it missing? Ask and I will explain or probably even add it to the article if it's relevant!

> Why don't you just tell me what code to use for the 32F417?

A developer must be capable of porting 3 simple lines of code and copying the rest of the example.

PHolt.1
Senior III

A number of people have concluded that you like playing with people who are less clever than you.

I have no idea where your "article" is.

But it sounds like I am missing just one line. For somebody far more stupid than you are, I am doing ok then.

A google on DBGMCU_CR suggests this is for detecting if a debugger is connected. In my case, and this is purely to achieve the lowest possible CPU current once a fall in VCC has been detected (for which I use ADC1) a debugger will never be connected.

Maybe you are talking about this?

https://community.st.com/s/question/0D53W00001bnh8dSAA/how-to-enter-standby-or-shutdown-mode-on-stm32

I now have

		PWR->CSR &= ~PWR_CSR_EWUP;				// disable WKUP pin, just in case
		PWR->CR |= PWR_CR_CWUF | PWR_CR_PDDS;	// select standby mode
		(void)PWR->CR;							// readback to ensure the bit is set before next
		SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;		// deep sleep
		DBGMCU->CR = 0; 						// Disable debug, trace and IWDG in low-power modes
 
		// CPU clock stops, DAC outputs float, etc
		// ** Code after this point is not executed (checked by waggling GPIO) **
		// But sometimes __WFI can fail - if e.g. there is an interrupt pending
		// e.g. USB serial FLASH read interrupt can be blocked for 200-300us. Hence the loop.
 
		for (;;)
		{
			__DSB();
			__WFI();
		}

Piranha
Chief II

Now the code is OK. Congratulations with successfully managing opening the link and copying a few lines of code!

> A google on DBGMCU_CR suggests this is for detecting if a debugger is connected.

The reference manual, my article and the comment on that exact line of my code explains that it's not "for detecting".

> you like playing with people

I'm not the one, who is playing the games here... Some citations from this topic:

Piranha: This topic shows the right way and has all the answers: <link to the article>

PHolt.1: I am not sure that example is for the 32F417 registers.

Piranha: I cannot understand why you don't just take the much simpler and correct code from my article.

PHolt.1: [took some of the necessary code lines from the article]

Piranha: You are still...

PHolt.1: [took the rest of the necessary code lines from the article] I have no idea where your "article" is. ... Maybe you are talking about this? <link to the article>

> A number of people have concluded

Actually a number of people on both forums have concluded (and pointed it out) that you are systematically ignoring the information other users provide and do not read the documentation or read it superficially. I'm not "attacking" like you like to interpret it, but I'm pointing out that such approach makes your RnD process very slow and error prone. Also you tell those tales about the mighty 2000 page reference manuals, but everyone, who actually reads the documentation, knows that a technical documentation is not a novel and there is no point in reading the reference manual from A to Z. Read the necessary chapters/sections and you are good to go and develop a driver code. The moral of the story - reading the reference manual, learning the C language features etc. does not make the RnD process longer, but actually makes it shorter and the code more reliable and efficient.

PHolt.1
Senior III

WOW.

This post is 3 weeks after the Q was posted.

You seem to be running a windup scheme where you have a diary system which reminds you to reply to a post after some weeks (or months) by which time the reply is of no use to anybody.

Still, I congratulate you on knowing everything.