2021-11-07 07:54 AM
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