Showing results for 
Search instead for 
Did you mean: 

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

Senior II

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.

Pavel A.
Evangelist III

Well.... I had several projects recently that detect power-down and save data to external flash.

None of these required to put the MCU to sleep, maybe because the MCU was never the biggest consumer. STM32H7 with FMC+NOR, and iMX6 with eMMC under Linux.

The power source was a super capacitor, providing at least 25 ms for STM32 or ~30 ms for Linux.

This was enough to write ~0.5 KB. Of course, erase of the flash was done beforehand.

Have you tried to measure for how long your STM32 stays alive, and the voltage?

Senior II

You are right; shutting the CPU reduces the power draw only about 2x, but is still worth doing. I posted some scope traces at the link above.

Senior II

I can see that is possible but in this case it was not a planned feature.

This is what it looks like currently:


But the CPU cannot sleep. It should do work. Write to the flash.

Senior II

Sorry, I don't understand. This is a loss of power situation. With the Adesto AT45DB321 you prepare data in one of the two 512-byte RAM buffers and then at some later point, could be days later, issue a write to flash command, and then the device will do the programming fully internally, in about 3ms. So the CPU can shut down right after the command was issued (allowing for SPI to FLASH shifting time, and allowing for the LAN8742 serial config interface shifting time). The SPI part has to be blocking anyway so you can raise CS at the right point.

My wrong, I thought that the flash is internal.

Chief II
Senior II

I am not sure that example is for the 32F417 registers. This is now 6 months after my question, but in case anybody comes across this, this is the entire shutdown code I am using and which works:

		// Stop systick, just in case (also stops RTOS)
		#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
		// Turn off all GPIO-driven LEDs and P3 P4 RS485 drivers
		GPIOD->BSRR = 0x0000fc80;
		GPIOC->BSRR = (uint32_t) 1 << 8;
		// Shut down LAN8742 ETH PHY chip. This saves ~100mA.
		// See "SMI Write Operation" in the RM.
		// This uses a special USART to shift 64 bits at 1.6MHz to the LAN8742 so needs to
		// be started well before CPU shutdown
		uint32_t tmpreg1 = 0U;					// point at phy=0 reg=0
		tmpreg1 = ETH->MACMIIAR;				// get existing MACMIIAR value
		tmpreg1 &= ~ETH_MACMIIAR_CR_MASK;		// mask off 3 clock divider bits
		tmpreg1 |= 3;							// WR=1 BUSY=1 (BUSY=1 prob not necessary)
		ETH->MACMIIDR = 1 << 11;				// data reg = SHUTDOWN bit set
		ETH->MACMIIAR = tmpreg1;				// write it back; WR=1 starts the 64 bit transfer
		// Shut down other stuff - display_cls takes about 100us
		// ** and this delay matters - see comments above **
		// Disable USB interrupts, just in case
		#define USB_CF *(volatile uint32_t*) (USB_OTG_FS_PERIPH_BASE+8)
		USB_CF &= ~1;
		// Blank LEDs on display board
		// Stop any ARINC429 activity
		// 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.
		CLEAR_BIT(PWR->CSR, 0x00000100U);		// disable WKUP pin, just in case
		SET_BIT(PWR->CR, PWR_CR_PDDS);		// select standby mode
		SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));	// Set SLEEPDEEP bit
		__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 (see KDE_watchdog_init()).
		hang_around_us(500); 					// wait for a bit longer than a FLASH read
		for (uint32_t i=0; i<100000; i++)
		// Should never get here, but if we did, we want to start with a freshly
		// initialised product.

Chief II

> I am not sure that example is for the 32F417 registers.

Then port it to your MCU. The issues and general principles are still the same. The code you presented starting from the line 38 manages to ignore and be broken regarding all 4 of the issues I do explain and solve in my article to which I gave the link. The code you needed to port is literally just 3 simple lines:


P.S. @PHolt.1​ , also check the private messages - I sent you a solution to the DMA problem you reported on the EEVblog forum.

Senior II

That DMA solution is not applicable to the problem I had.