Skip to main content
lizerd
Associate III
November 7, 2021
Question

STM32WB Switch mode ( BLE ) / (No BLE standby) + RTC calender + SRAM2A retention. working Example Included. Question.. Is this the best way???

  • November 7, 2021
  • 0 replies
  • 718 views

working example Included/provided..

So I have been working to get to the point where I can switch between between two modes.

Mode 1 = BLE working with RTC calender and Low Power + my application, with <= 50uA current consumption.

And

Mode 2 = MCU is in standby 99% of the time + my application, RTC wake-up every one second. with few uA current consumption.

So I have been trying to get the timeServer to get below 5uA with just an wakeup every second to set an IO pin for indication and nothing else. That failed.

So I change to make an NVIC_SystemReset(); to change mode.

Is this really the best way ??

The how to and changes for this project that is provided.

The project is target is the Nucleo WB55 board.

I used the https://www.youtube.com/watch?v=i10X4Blr8ns as base of the project

Main.c

int main(void)
{
 
 HAL_Init();
 MX_APPE_Config();
 
 
 SystemClock_Config();
 MX_RTC_Init();
 
 
 MX_IPCC_Init();
 MX_GPIO_Init();
 MX_DMA_Init();
 MX_USART1_UART_Init();
 MX_USB_PCD_Init();
 MX_RF_Init();
 
 
 if(Startup_Mode == 8)
 {
	 // Mode = BLE ON
	 /* Init code with WPAN */
	 MX_APPE_Init();
 
	 /*Configure GPIO pin Output Level */
	 HAL_GPIO_WritePin(GPIOB, LD2_Pin, GPIO_PIN_SET);
 }
 else
 {
	 // Mode = BLE OFF
	 /* Init code without WPAN */
	 MX_APPE_Init_No_BLE();
 
	 /*Configure GPIO pin Output Level */
	 HAL_GPIO_WritePin(GPIOB, LD1_Pin, GPIO_PIN_SET);
	 HAL_Delay_2(5);
 }
 
 // check button
 ModeChanegButton_Check();
 
 
 while (1)
 {
		if(Startup_Mode == 8)
		{
			/* USER CODE END WHILE */
			MX_APPE_Process();
		}
		else
		{
			LowPowerMode();
		}
 }
}
 
//////////////////////////////////////////////////////////////////////////////
void LowPowerMode()
{
#if (CFG_DEBUGGER_SUPPORTED == 1)
	 HAL_DBGMCU_EnableDBGSleepMode();
	 HAL_DBGMCU_EnableDBGStopMode();
	 HAL_DBGMCU_EnableDBGStandbyMode();
#else
	 HAL_DBGMCU_DisableDBGSleepMode();
	 HAL_DBGMCU_DisableDBGStopMode();
	 HAL_DBGMCU_DisableDBGStandbyMode();
#endif /* (CFG_DEBUGGER_SUPPORTED == 1) */
 
	 /* Make sure the Core 2 is in shutdown mode */
	 LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
 
	 /* Check if the system was resumed from StandBy mode */
	 /* Note: On STM32WB, both CPU1 and CPU2 must be in standby mode to set the entire system in standby mode */
	 if((__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) && (__HAL_PWR_GET_FLAG(PWR_FLAG_C2SB) != RESET))
	 {
	 /* Clear Standby flag */
	 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
	 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_C2SB);
	 }
 
	 /* Clear all related wakeup flags */
	 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
	__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUFI);
 
 
	 if((LL_PWR_IsActiveFlag_C1SB() == 0) || (LL_PWR_IsActiveFlag_C2SB() == 0))
	 {
	 /* Set the lowest low-power mode for CPU2: shutdown mode */
	 LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
	 }
 
	 HAL_PWREx_EnableSRAMRetention();
 
	 GPIO_Set_HW_Before_Standby_Mode();
 
	 /* Enter the Standby mode */
	 HAL_PWR_EnterSTANDBYMode();
 
	// if the MCU gets here. then there is an error!!
	while (1)
	{
 
	}
}
 
 
//////////////////////////////////////////////////////////////////////////////
void ModeChanegButton_Check()
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOA_CLK_ENABLE();
 
 
	/*Configure GPIO pin : BUTTON_Pin */
	 GPIO_InitStruct.Pin = B1_Pin;
	 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	 GPIO_InitStruct.Pull = GPIO_PULLUP;
	 HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
 
	// Check if button already is pressed
	if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == GPIO_PIN_RESET)
	{
		HAL_GPIO_EXTI_Callback(B1_Pin);
	}
}
 
 
//////////////////////////////////////////////////////////////////////////////
void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin )
{
	if(GPIO_Pin == B1_Pin)
	{
		 if(Startup_Mode == 8)
		 {
			 // Reset back to None BLE startup
			 Startup_Mode = 0;
			 //Make sure there is no contact bounce (Not needed here, just to be safe)
			 HAL_Delay_2(500);
			 // Reset to get back
			 NVIC_SystemReset();
		 }
		 else
		 {
			 // Make sure BLE starts at reset/standby resume
			 Startup_Mode = 8;
			 //Make sure there is no contact bounce
			 HAL_Delay_2(500);
		 }
	}
}

Also in main.c, the RTC init is updated to handle standby restarts (STM32wbxx_hal_msp.c is also updated)

static void MX_RTC_Init(void)
{
	RTC_TimeTypeDef sTime = {0};
	RTC_DateTypeDef sDate = {0};
 
 
	/** Initialize RTC Only
	*/
	hrtc.Instance = RTC;
	hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
	hrtc.Init.AsynchPrediv = CFG_RTC_ASYNCH_PRESCALER;
	hrtc.Init.SynchPrediv = CFG_RTC_SYNCH_PRESCALER;
	hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
	hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
	hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
	hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
	if (HAL_RTC_Init(&hrtc) != HAL_OK)
	{
		Error_Handler();
	}
 
	/* Set Date and Time (if not already done before)*/
	/* Read the Back Up Register 0 Data */
	if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)
	{
		/* Configure RTC Calendar */
		/** Initialize RTC and set the Time and Date
		*/
		sTime.Hours = 0x0;
		sTime.Minutes = 0x0;
		sTime.Seconds = 0x0;
		sTime.SubSeconds = 0x0;
		sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
		sTime.StoreOperation = RTC_STOREOPERATION_RESET;
		if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
		{
			Error_Handler();
		}
		sDate.WeekDay = RTC_WEEKDAY_MONDAY;
		sDate.Month = RTC_MONTH_APRIL;
		sDate.Date = 0x16;
		sDate.Year = 0x18;
 
		if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
		{
			Error_Handler();
		}
 
		/* Writes a data in a RTC Backup data Register0 */
		HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x32F2);
	}
	else
	{
		/* Check if the Power On Reset flag is set */
		if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET)
		{
		}
 
		/* Check if Pin Reset flag is set */
		if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET)
		{
		}
	}
	/* Clear source Reset Flag */
	__HAL_RCC_CLEAR_RESET_FLAGS();
 
	/* Disable all used wakeup sources*/
	HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
 
	/** Enable the WakeUp
	*/
	if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != HAL_OK)
	{
		Error_Handler();
	}
 
	HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 3, 0);
	HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
 
 
	// Need to enable shadow registers for RTC to solve the sub second bug
	HAL_RTCEx_EnableBypassShadow(&hrtc);
}

In app_entry.c I have Added an APPE_init_No_BLE() and a period wakeup

#define PERIOD_WAKEUP_TIME			(1.0*1000*1000/CFG_TS_TICK_VAL)		//1.0sec, 1Hz
uint8_t								Periodic_Wakeup_timer_Id;
void Periodic_Wakeup_Callback(void);
 
 
/////////////////////////////////////////////////////////////////////////////////////
void MX_APPE_Init( void )
{
 System_Init( ); /**< System initialization */
 
 SystemPower_Config(); /**< Configure the system Power Mode */
 
 HW_TS_Init(hw_ts_InitMode_Full, &hrtc); /**< Initialize the TimerServer */
 
 appe_Tl_Init();	/* Initialize all transport layers */
 
 // APPD_Init();
 UTIL_LPM_SetOffMode(1 << CFG_LPM_APP, UTIL_LPM_DISABLE);
 
 HW_TS_Create(CFG_TIM_PROC_ID_ISR, &Periodic_Wakeup_timer_Id, hw_ts_Repeated, Periodic_Wakeup_Callback);
 HW_TS_Start(Periodic_Wakeup_timer_Id, PERIOD_WAKEUP_TIME); // <--start with this
 
 return;
}
 
/////////////////////////////////////////////////////////////////////////////////////
void MX_APPE_Init_No_BLE( void )
{
	Init_Smps( );
	Init_Exti( );
 
	SystemPower_Config(); /**< Configure the system Power Mode */
	return;
}
 
/////////////////////////////////////////////////////////////////////////////////////
void Periodic_Wakeup_Callback(void)
{
	 GPIO_InitTypeDef GPIO_InitStruct = {0};
 
	 /* GPIO Ports Clock Enable */
	 __HAL_RCC_GPIOB_CLK_ENABLE();
 
	 /*Configure GPIO pins : LD2_Pin LD3_Pin LD1_Pin */
	 GPIO_InitStruct.Pin = LD2_Pin;
	 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	 GPIO_InitStruct.Pull = GPIO_NOPULL;
	 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
	 /*Configure GPIO pin Output Level */
	 HAL_GPIO_WritePin(GPIOB, LD2_Pin, GPIO_PIN_SET);
	 HAL_Delay(5);
 
	 // check button
	 ModeChanegButton_Check();
}

changes for SRAM2A retention

Do not forget to check SRAM RESET flag in option bytes !! for the SRAM2A retention to work (FLASH_OPTR_SRAM2RST)

In STM32WB55RGVX_FLASH.ld

/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 4K
RAM2 (xrw) 			 : ORIGIN = 0x20031000, LENGTH = 6K
}
 
 
 /* Define RAM2 area. Or something. Works at least! */
 .ram2 (NOLOAD):
 {
 _sram2 = .;
 *(.ram2*)
 . = ALIGN(4);
 _eram2 = .;
 } >RAM2

So, I have been working to get this far for to many weeks so I thought that I show this example to others that is striving for the same goal.

And for the others that have done this before, how did you guys do it ? and did you find a better solution ??

Really happy for comments :)

// The example works like,

SW1 longpress switch between modes.

LED 1 (BLUE) blink = Mode 2

LED 2 (GREEN) blink = Mode 1

This topic has been closed for replies.