cancel
Showing results for 
Search instead for 
Did you mean: 

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

lizerd
Associate III

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

0 REPLIES 0