cancel
Showing results for 
Search instead for 
Did you mean: 

wake from RTC only works 32 times and system Battery Drain

Ryan Coleman
Associate II

Hi All, 

My company has a board which uses the STM32G473 MCU. It serves a battery powered industrial application. 

 

Architecture:

The board is connected to a 4-cell 18650 LiIon pack. A TI BQ76942 handles pack monitoring, cell balancing, safety cut offs, and main system power switching. When the system is turned off by the operator or MCU (from timeouts or low pack voltage) we put the BQ76942 in to SHUTDOWN mode which powers down most of it's internals, turns off the FETs between the pack and rest of the board, and enters a low power state with a draw of ~2uA. 

The MCU remains powered by a linear regulator which is always connected to the pack. The user can power the system on by plugging in wall power or pressing a button. Both of these cause a rising edge on one of the sys wkup pins. When this happens, the MCU exits deepsleep and reinitializes all the peripherals including the BQ76942. 

The total system current draw when powered down is 4uA. We've stored these systems without issue for over a month and done multi day data logging and see no anomalies. 

 

The problem:

We've had this product on the market for about 8 months now and just had two units that came back with packs drained to 2.75V. One of these was in use only a few weeks before the pack was discovered to be drained.

We saw this once in beta testing and thought it was due to a debugger setting when flashing the MCU before sending the unit out. Many months later of no issues and here we are again. 

The BQ76942 is set to enter SHUTDOWN automatically below a voltage threshold, so we think it's unlikely that it is the culprit. The only current path left when the BQ76942 is shutdown is the MCU and it's LDO. This is supported by the fact that our LDO will work down to 2.7V which is very close to the voltage of each pack when they arrived. 

We have tested extensively by looking at the ground current drain while powered down using the customer boards and see no anomalies. We also used the RTC to wake the MCU and then enter the system shutdown state in a loop (using our normal turnOff() function) while looking at the current and it entered the shutdown state successfully thousands of times. 

So, at this point we're humbly confident the MCU is causing the power draw by either waking from deepsleep but failing to run correctly or failing to truly enter deepsleep. If the MCU exited deepsleep and ran it would power itself down after the system was inactive for 10 minutes. 

Because we can't replicate the issue we're looking for code solutions to guard against whatever edge case is causing the issue. I know, not the best situation but we have to get these back to the customers while we continue searching for the ground truth of the issue.

Our approach is to use the RTC to wake the system periodically (once every 24hrs or so), initialize just enough peripherals on the MCU to check a pin state on the BQ76942 for it's SHUTDOWN mode, and then place the MCU back in to deepsleep. Perhaps someone will have a better proposal or can suggest a test to find the fault condition. 

Final point, the code we're using to periodically wake the system only sets RTC_FLAG_WUTF 32 times and then stops. We use this flag to check for a wakeup from the RTC so we can run our checks and immediately shutdown. What could be causing this? The most obvious culprit is some RTC register incrementing and not being reset but a glance at the registers after a few cycles doesn't show anything interesting. 

image (12).png

Here is the code which executes the system shutdown:

 

 

 

 

void turnOff() {
	ChangeIWDGSettings(4000);
	HAL_IWDG_Refresh(&hiwdg);
	CANSendCommand(&hfdcan1, CAN_TURNOFF);


	md.odr = ILPS28QSW_ONE_SHOT;
	ilps28qsw_mode_set(&dev_ctx, &md);
	uint32_t press_sensor_off_state = ilps28qsw_read_reg(ctx, ILPS28QSW_CTRL_REG1, reg, 3);
	if(press_sensor_off_state != 0x00)
	delayUS(1000);


	if (__HAL_RTC_WAKEUPTIMER_GET_FLAG(&hrtc, RTC_FLAG_WUTF) != RESET)
	{
		md.odr = ILPS28QSW_ONE_SHOT;
		ilps28qsw_mode_set(&dev_ctx, &md);
		delayUS(1000);

		storeFillSettings();
		delayUS(60);
		storeFactoryStorage();
		delayUS(60);
		storePackState();
		delayUS(60);
		CommandSubcommands(ALL_FETS_OFF);
		delayUS(60);
		CommandSubcommands(DEEPSLEEP);
		delayUS(60);
		CommandSubcommands(DEEPSLEEP);
		delayUS(60);
	}


	standby();
}

void standby() {
	HAL_Delay(1000);
	HAL_IWDG_Refresh(&hiwdg);

	// Disable interrupts
	HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);
	HAL_NVIC_DisableIRQ(ADC4_IRQn);
	HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
	HAL_NVIC_DisableIRQ(TIM1_TRG_COM_TIM17_IRQn);
	HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);

	//Configure GPIOs and interrupt pins for sleep mode
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };

	//Configure all GPIO pins as analog input to reduce power consumption
	GPIO_InitStruct.Pin = GPIO_PIN_All;
	GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

	__HAL_RCC_PWR_CLK_ENABLE();

	//Added for testing//////////////////////
    // Ensure that the wake-up timer flag is cleared
    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);

    // Enable RTC Wake-up Interrupt
    HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);

    HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);  // Deactivate previous settings
    uint32_t wakeup_time = 10; // Wake up after 1 hour
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_time, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
    ////////////////////////////////////////

	HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN4_HIGH);
	HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1_HIGH);

	/* Clear the WU FLAG */
	__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

	/* Set Stand-by mode */
	MODIFY_REG(PWR->CR1, PWR_CR1_LPMS, PWR_CR1_LPMS_STANDBY);
	(void)PWR->CR1; //Ensure register ops are complete

	/* Set SLEEPDEEP bit of Cortex System Control Register */
	SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));

	//DBGMCU->CR = 0; // Disable debug, trace and IWDG in low-power modes

	/* Request Wait For Interrupt */
	for (;;) {
		__DSB();
		__WFI();
	}

	HAL_PWR_EnterSTANDBYMode();

}

 

 

 

 

 

The code that checks for an RTC wakeup. This is in main() after all the Cube MX generated peripheral initialization calls:

 

 

 

 

  hrtc.Instance = RTC;
	if (__HAL_RTC_WAKEUPTIMER_GET_FLAG(&hrtc, RTC_FLAG_WUTF) != RESET)
	{
		// The MCU woke up from the RTC wakeup timer
		MX_RTC_Init();
		standby();
	}

 

 

 

 

 

Thanks in advance for any help!

1 REPLY 1
PGump.1
Senior III

Hi,

You should start by reading the Reference Manual for your device. There are so many things about your code that are "???"...

I hope that helps.

Kind regards
Pedro

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.