2025-08-28 12:19 AM
Hey all,
I’m trying to squeeze the lowest possible STOP1 current out of an STM32U031F8P6 (TSSOP-20), no external crystals. The board itself looks fine: in the deepest mode (Shutdown/Standby) I see < 0.5 µA, so I don’t think it’s a hardware leak.
Goal (later): run ADC at 1 kHz triggered by LPTIM1 from LSI, push to DMA (circular), and only wake after 1000 samples (DMA TC). While that runs, the core should sit in STOP1 (low-power regulator).
Problem (now, with everything stripped):
Even with a minimal firmware that goes straight to STOP1 and (supposedly) nothing enabled, I measure ~5–6 µA average at room temp. The current trace shows a baseline of ~4.2–5 µA with short spikes to ~10–12 µA every ~100 ms. That really looks like something waking up periodically.
What I see on the analyzer (≈3 V supply):
Baseline settles around 4.2–5 µA
Spikes to ~10–12 µA every ~100 ms
Average ≈ 5.2 µA
If I switch to the deepest mode, I get < 0.5 µA, which makes me think the PCB is fine and I’m just missing a setting in STOP1.
What I’ve tried/checked:
RTC/LSI/LSE: disabled
SysTick: suspended before STOP
Debug in stop/standby: disabled
Watchdogs: not started
ADC/VREFBUF: off
All common peripheral clocks (DMA/DMAMUX/LPTIM/UART/I2C/SPI/TIM): disabled
GPIOs: Analog + NOPULL, then GPIO clocks off
PVD off, Flash PD in STOP on, lowest VOS
HSI16 turned off before STOP
Questions:
On STM32U031, is there anything “hidden” that could explain a ~100 ms periodic blip in STOP1 (some default monitor/oscillator/retention I’m not switching off)?
Any extra register bits specific to U0 that I should clear for a truly quiet STOP1 beyond the usual suspects above?
Could EXTI/WKUP pins be doing this even if I didn’t configure them? Any default WKUP behavior on U031F8P6 I should double-check?
What’s a realistic STOP1 current (everything off: no RTC/LSI, no ADC, Flash PD, no debug, etc.) that I should expect on this device so I can sanity-check my ~4–5 µA baseline (between spikes)?
/* Minimal STOP1 baseline for STM32U031F8P6 — no wake sources
*
* Purpose:
* Provide a known-good ultra-low-power baseline to measure STOP1 current.
* The MCU enters STOP1 (low-power regulator) immediately with no wake sources.
*
* Expected result:
* ~1–2 µA typical at 3 V, 25 °C on a bare MCU (no external loads).
*
* Notes:
* - Do NOT enable RTC/LSE/LSI, timers, DMA, USART/I2C/SPI, or watchdogs in CubeMX.
* - SysTick is suspended to avoid periodic wake-ups.
* - All GPIOs are set to Analog + NOPULL, then GPIO port clocks are disabled.
* - ADC/VREFBUF are ensured OFF.
* - LSI/LSE/RTC are OFF to avoid periodic wake-ups and extra µA.
* - HSI16 is turned OFF before entering STOP1.
*/
#include "main.h"
/* Prototypes */
static void Minimal_Clocks_On_For_Init(void);
static void All_Gpio_Analog_NoPull_Then_Off(void);
static void Turn_Peripherals_Off(void);
int main(void)
{
HAL_Init();
/* Keep HSI16 just for early init; it will be turned off before STOP */
Minimal_Clocks_On_For_Init();
/* Prevent periodic wake-ups from SysTick; also disable debug in stop/standby */
HAL_SuspendTick();
#if defined(HAL_DBGMCU_MODULE_ENABLED)
HAL_DBGMCU_DisableDBGStopMode();
HAL_DBGMCU_DisableDBGStandbyMode();
#endif
/* Put every available pin to Analog + NOPULL and gate GPIO clocks */
All_Gpio_Analog_NoPull_Then_Off();
/* Make sure all potential leaky IPs and clocks are OFF */
Turn_Peripherals_Off();
/* Lowest voltage scaling allowed saves some nA/µA (if supported) */
#if defined(PWR_REGULATOR_VOLTAGE_SCALE4)
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE4);
#elif defined(PWR_REGULATOR_VOLTAGE_SCALE3)
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE3);
#endif
/* Put Flash into power-down during STOP (if supported on this device) */
#if defined(PWR_FLASHPD_STOP)
HAL_PWREx_EnableFlashPowerDown(PWR_FLASHPD_STOP);
#endif
/* HSI16 OFF before entering STOP — not needed while sleeping */
__HAL_RCC_HSI_DISABLE();
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) {}
/* --- Measure here: device remains in STOP1 with no wake sources --- */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* Should not wake; if it does (e.g., external noise), re-enter STOP1 */
for (;;)
{
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
}
/* ---------- Helpers ---------- */
static void Minimal_Clocks_On_For_Init(void)
{
/* Ensure HSI16 is ON for register access; do not set PLL/LSE/LSI */
__HAL_RCC_HSI_ENABLE();
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET) {}
}
static void All_Gpio_Analog_NoPull_Then_Off(void)
{
/* STM32U031F8P6 (TSSOP20) exposes GPIOA and GPIOB */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef g = {0};
g.Mode = GPIO_MODE_ANALOG;
g.Pull = GPIO_NOPULL;
g.Speed = GPIO_SPEED_FREQ_LOW;
g.Pin = GPIO_PIN_ALL;
HAL_GPIO_Init(GPIOA, &g);
HAL_GPIO_Init(GPIOB, &g);
/* Disable GPIO port clocks to minimize leakage in STOP */
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
}
static void Turn_Peripherals_Off(void)
{
/* Ensure ADC is fully disabled; also disable VREFBUF if present */
#if defined(ADC1)
__HAL_RCC_ADC_CLK_ENABLE();
if (READ_BIT(ADC1->CR, ADC_CR_ADEN))
{
SET_BIT(ADC1->CR, ADC_CR_ADDIS);
while (READ_BIT(ADC1->CR, ADC_CR_ADEN)) {}
}
__HAL_RCC_ADC_CLK_DISABLE();
#endif
#if defined(VREFBUF)
__HAL_RCC_VREF_CLK_ENABLE();
CLEAR_BIT(VREFBUF->CSR, VREFBUF_CSR_ENVR); /* VREFBUF off */
__HAL_RCC_VREF_CLK_DISABLE();
#endif
/* RTC/LSI/LSE OFF: avoids periodic wake-ups and extra microamps */
#if defined(__HAL_RCC_RTC_DISABLE)
__HAL_RCC_RTC_DISABLE();
#endif
#if defined(__HAL_RCC_LSI_ENABLE)
__HAL_RCC_LSI_DISABLE();
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET) {}
#endif
#if defined(RCC_BDCR_LSEON)
__HAL_RCC_LSE_CONFIG(RCC_LSE_OFF);
#endif
/* Do NOT start watchdogs for this baseline measurement */
/* Common IP clocks OFF (DMA/DMAMUX/LPTIM/UART/I2C/SPI/TIM) */
#ifdef __HAL_RCC_DMA1_CLK_DISABLE
__HAL_RCC_DMA1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_DMAMUX1_CLK_DISABLE
__HAL_RCC_DMAMUX1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_LPTIM1_CLK_DISABLE
__HAL_RCC_LPTIM1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_USART1_CLK_DISABLE
__HAL_RCC_USART1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_I2C1_CLK_DISABLE
__HAL_RCC_I2C1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_SPI1_CLK_DISABLE
__HAL_RCC_SPI1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_TIM1_CLK_DISABLE
__HAL_RCC_TIM1_CLK_DISABLE();
#endif
#ifdef __HAL_RCC_TIM3_CLK_DISABLE
__HAL_RCC_TIM3_CLK_DISABLE();
#endif
/* Disable PVD if enabled to shave a bit more current */
#if defined(PWR_CR2_PVDE)
CLEAR_BIT(PWR->CR2, PWR_CR2_PVDE);
#endif
}
current graph showing spikes