cancel
Showing results for 
Search instead for 
Did you mean: 

WKUP pin wakes MCU twice but it should only wake once ?

freeflyer
Senior

I am using the NUCLEO-L433RC-P with the blue top switch (pin PC13) configured as a wake pin.

When the switch is pressed, the MCU should wake, then turn the LED on, then shutdown.

But for some reason the MCU wakes twice as observed by the following behaviour: 

  1. Switch pressed
  2. MCU wakes (LED turns on)
  3. MCU shuts down (LED turns off)
  4. MCU wakes again (LED turns on)
  5. LED finally shuts down (LED turns off)

This happens even though the switch is only pressed once. 

The switch has RC filters so its not a debounce issue, especially as it happens even if the switch is held down.  

freeflyer_2-1758137138706.png

My function Enable_PC13_Wakeup() clears flags etc before shutdown, so I don't understand why the MCU is waking twice.  

Source code is below...

/* USER CODE BEGIN Header */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */


//#include "common.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hrtc;

TIM_HandleTypeDef htim7;

/* USER CODE BEGIN PV */

RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};

static uint8_t sch_u8_statePower = STATE_PWR_WAKE_CYCLE_START;
static uint8_t sch_u8_pwrCount=0;
static uint8_t sch_u8_pwrSwitchCount=0;
static uint8_t sch_u8_pwrSwitchPress=0;

static volatile uint8_t flgTask100ms=0;
static volatile uint32_t currentSeconds;
static volatile uint32_t startSeconds;
static volatile uint32_t elapsedSeconds;
static volatile uint32_t wake_marker;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM7_Init(void);
static void MX_RTC_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */




/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM7_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

	MAN_checkWake();
	Enable_PC13_EXTI();	// enable external interrupt for power switch wake
	HAL_TIM_Base_Start_IT(&htim7);  // timer for task scheduler

	while (1) {
		if(flgTask100ms)
		{
			SCH_powerSwitch();
			flgTask100ms = 0;
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief RTC Initialization Function
  *  None
  * @retval None
  */
static void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  /* USER CODE BEGIN RTC_Init 1 */

  /* USER CODE END RTC_Init 1 */

  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */

  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 0x0;
  sTime.Minutes = 0x0;
  sTime.Seconds = 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_JANUARY;
  sDate.Date = 0x1;
  sDate.Year = 0x0;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

/**
  * @brief TIM7 Initialization Function
  *  None
  * @retval None
  */
static void MX_TIM7_Init(void)
{

  /* USER CODE BEGIN TIM7_Init 0 */

	// timer 7 used for 1ms task
	// timer period = (Init.Period + 1) * (Init.Prescaler / Clock)
	// timer period = (799 + 1) * (9999 / 80,000,000)
	// timer period = 100 ms
	// timer frequency = 10 Hz

  /* USER CODE END TIM7_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM7_Init 1 */

  /* USER CODE END TIM7_Init 1 */
  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 9999;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 799;
  htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM7_Init 2 */

  /* USER CODE END TIM7_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  *  None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */

  /* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC0 PC1 PC2 PC3
                           PC4 PC6 PC7 PC8
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PA0 PA1 PA2 PA3
                           PA4 PA5 PA6 PA7
                           PA8 PA9 PA10 PA11
                           PA12 PA15 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
                          |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 PB10
                           PB11 PB12 PB14 PB15
                           PB4 PB5 PB6 PB7
                           PB8 PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_14|GPIO_PIN_15
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
                          |GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : STATUS_LED_Pin */
  GPIO_InitStruct.Pin = STATUS_LED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(STATUS_LED_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PH3 */
  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

  /* USER CODE BEGIN MX_GPIO_Init_2 */

  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

void SCH_powerSwitch (void)
{
	switch (sch_u8_statePower)
	{
	case STATE_PWR_WAKE_CYCLE_START:	//**** delay before turning LED on ****//

			sch_u8_pwrCount++;												// increment sequence counter
			if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT)
			{
				HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_SET); 		// turn LED on
				sch_u8_pwrCount=0;											// reset sequence counter
				sch_u8_pwrSwitchPress=0;									// reset power switch state
				sch_u8_statePower = STATE_PWR_WAKE_CYCLE_CHECK;				// proceed to check click cycle state
			}
		break;
	case STATE_PWR_WAKE_CYCLE_CHECK: //**** switch cycle check ****//
		sch_u8_pwrCount++;												// increment sequence counter
		if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT)
		{
			// LED has NOT been extinguished by power switch
			sch_u8_pwrSwitchCount=0;									// reset switch press counter
			sch_u8_pwrCount=0;											// reset sequence counter
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_RESET);	// turn LED off
			sch_u8_statePower = STATE_PWR_SHUTDOWN;						// power up cycle is invalid, return to power down
			break;
		}
		if(sch_u8_pwrSwitchPress)
		{
			// LED HAS been extinguished by the power switch
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_RESET);	// turn LED off
			sch_u8_pwrCount=0;											// reset sequence counter
			sch_u8_pwrSwitchPress=0;									// reset power switch state
			sch_u8_pwrSwitchCount++;									// increment switch counter
			if(sch_u8_pwrSwitchCount>=STATE_PWR_SWITCH_COUNT)
			{
				// LED HAS been extinguished by the power switch enough times
				sch_u8_pwrSwitchCount=0;								// reset switch counter
				sch_u8_statePower=STATE_PWR_WAKE_INPROGRESS;			// power up cycle is valid, proceed to waking state
			}

			else
			{
				sch_u8_statePower = STATE_PWR_WAKE_CYCLE_START;			// start next cycle
			}
		}
		break;
	case STATE_PWR_WAKE_INPROGRESS: // **** wakeup delay ****//
		sch_u8_pwrCount++;												// increment sequence counter
		if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT>>1)
		{
			sch_u8_pwrCount=0;											// reset sequence counter
			sch_u8_statePower = STATE_PWR_WAKE_INDICATE;				// proceed to indicate state (flash LED)
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_SET); 		// turn LED on
		}
		break;
	case STATE_PWR_WAKE_INDICATE: //**** flashes LED to indicate power up was successful ****//
		sch_u8_pwrCount++;
		HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);						// flash LED

		if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT)
		{
			// counter threshold reached
			sch_u8_pwrCount=0;											// reset sequence counter
			sch_u8_pwrSwitchPress=0;									// reset power switch state
			sch_u8_statePower = STATE_PWR_RUNNING;						// proceed to run state
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_RESET);	// turn LED off
		}
		break;

	case STATE_PWR_RUNNING: //**** running mode - monitor power switch ****//

		if(sch_u8_pwrSwitchPress)
		{
				sch_u8_statePower = STATE_PWR_STANDBY_CYCLE_START;		// power switch pressed, proceed to start cycle
				HAL_GPIO_WritePin(GPIOA, STATUS_LED_Pin,GPIO_PIN_RESET);// LED off
		}
		break;

	case STATE_PWR_STANDBY_CYCLE_START:	//**** delay before turning LED on ****//
		sch_u8_pwrCount++;												// increment sequence counter
		if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT)
		{
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_SET);	// turn LED on
			sch_u8_pwrCount=0;											// reset sequence counter
			sch_u8_pwrSwitchPress=0;									// reset power switch state
			sch_u8_statePower = STATE_PWR_STANDBY_CYCLE_CHECK;			// proceed to cycle check for power down request
		}
		break;
	case STATE_PWR_STANDBY_CYCLE_CHECK: //**** switch cycle check ****//
		sch_u8_pwrCount++;												// increment sequence counter
		if(sch_u8_pwrCount>=STATE_PWR_LED_COUNT)
		{
			// LED has NOT been extinguished by power switch
			sch_u8_pwrSwitchCount=0;									// reset switch press counter
			sch_u8_pwrCount=0;											// reset sequence counter
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_RESET);	// turn LED off
			sch_u8_statePower = STATE_PWR_RUNNING;						// switch cycle is invalid, return to run state
			break;
		}
		if(sch_u8_pwrSwitchPress)
		{
			// LED HAS been extinguished by the power switch
			HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin,GPIO_PIN_RESET);	// turn LED off
			sch_u8_pwrCount=0;											// reset sequence counter
			sch_u8_pwrSwitchPress=0;									// reset power switch state
			sch_u8_pwrSwitchCount++;									// increment switch counter
			if(sch_u8_pwrSwitchCount>=STATE_PWR_SWITCH_COUNT)
			{
				// LED HAS been extinguished by the power switch enough times
				sch_u8_pwrSwitchCount=0;								// reset switch counter
				sch_u8_statePower=STATE_PWR_SHUTDOWN;					// switch cycle is valid, proceed to power down
			}
			else
			{
				sch_u8_statePower = STATE_PWR_STANDBY_CYCLE_START;		// start next cycle
			}
		}
		break;

	case STATE_PWR_SHUTDOWN:
			SCH_mcuShutdown();											// shutdown
		break;
	case STATE_PWR_BOOTLOADER:
		HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);						// flash LED
		break;

	default:
		break;
	}
}

void SCH_mcuStandby (void){
	/* The Following Wakeup sequence is highly recommended prior to each Standby mode entry
	    mainly  when using more than one wakeup source this is to not miss any wakeup event.
	    - Disable all used wakeup sources,
	    - Clear all related wakeup flags,
	    - Re-enable all used wakeup sources,
	    - Enter the shutdown mode.
	 */

	// write value to RTC backup register to indicate mcu was in sleep
	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_STANDBY);

	// write power switch state to RTC backup register
	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, *(uint32_t*)&sch_u8_statePower);

	// Disable all used wakeup sources
	HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
	HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, RTC_WAKE_SEC, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);

	// Clear all related wakeup flags
	__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

	// enable pin wakeup
	Enable_PC13_Wakeup();

	// enable pull up resistor during shutdown for charger CE pin
	HAL_PWREx_EnableGPIOPullUp(PWR_GPIO_A, PWR_GPIO_BIT_8);
	HAL_PWREx_EnablePullUpPullDownConfig();

	// Call standby
	HAL_PWR_EnterSTANDBYMode();
}

void SCH_mcuShutdown (void){
	// write value to RTC backup register to indicate mcu was in shutdown
	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_SHUTDOWN_WKUP);

	// disable RTC wakeup
	HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);

	// enable pin wakeup
	Enable_PC13_Wakeup();

	// enable pull up resistor during shutdown for charger CE pin
	HAL_PWREx_EnableGPIOPullUp(PWR_GPIO_A, PWR_GPIO_BIT_8);
	HAL_PWREx_EnablePullUpPullDownConfig();

	// Call shut down
	HAL_PWREx_EnterSHUTDOWNMode();
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == GPIO_PIN_13)
	{
		sch_u8_pwrSwitchPress=1;
	}
}

void SCH_retrieveStatePower(uint8_t val)
{
	sch_u8_statePower = val;
}

// Switch PC13 to EXTI interrupt mode (for in-application use)
void Enable_PC13_EXTI(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	__HAL_RCC_GPIOC_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_13;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);
	HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

// Switch PC13 back to wakeup pin (for shutdown mode)
void Enable_PC13_Wakeup(void)
{
	HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);
	HAL_GPIO_DeInit(GPIOC, GPIO_PIN_13);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
	__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

	HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2); // or PWR_WAKEUP_PIN2_LOW for falling edge
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM7)
	{
		flgTask100ms = 1;
	}
}


uint32_t RTC_to_unix(RTC_TimeTypeDef *time, RTC_DateTypeDef *date) {
	struct tm timeinfo;

	timeinfo.tm_year = 2000 + date->Year - 1900;  // RTC year is offset from 2000
	timeinfo.tm_mon  = date->Month - 1;           // struct tm months 0-11
	timeinfo.tm_mday = date->Date;
	timeinfo.tm_hour = time->Hours;
	timeinfo.tm_min  = time->Minutes;
	timeinfo.tm_sec  = time->Seconds;

	timeinfo.tm_isdst = 0;

	return (uint32_t)mktime(&timeinfo);  // Convert to UNIX timestamp
}

void wakeConfigReset (void) {
	/** Initialize RTC and set the Time and Date
	 */
	sTime.Hours = 0x0;
	sTime.Minutes = 0x0;
	sTime.Seconds = 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_JANUARY;
	sDate.Date = 0x1;
	sDate.Year = 0x0;

	if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
	{
		Error_Handler();
	}
	// get time and date
	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

	// convert start time and date to unix time
	startSeconds = RTC_to_unix(&sTime, &sDate);

	// store start time in RTC backup register
	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, startSeconds);
}

void wakeConfigUpdate (void) {

	// get time and date
	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

	// convert time and date to unix time
	currentSeconds = RTC_to_unix(&sTime, &sDate);

	// read unix start time from RTC backup register
	startSeconds = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);

	// calculate elapsed time
	elapsedSeconds = currentSeconds - startSeconds;
}

void MAN_checkWake (void)
{
	// read wake marker from RTC backup register to determine if woken from standby or shutdown
	wake_marker = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
	if (wake_marker == WAKE_FROM_STANDBY)	// woken from standby
	{
		uint8_t man_flg_pwrSwitchState = HAL_GPIO_ReadPin(PWR_SWITCH_GPIO_Port, PWR_SWITCH_Pin);	// read power switch input
		if (man_flg_pwrSwitchState)		// woken from standby by power switch
		{
			SCH_retrieveStatePower(STATE_PWR_STANDBY_CYCLE_START);	// set power state to check 4 cycle switch for shutdown request

		}
		else // woken from standby by RTC
		{
			wakeConfigUpdate(); // get time and date and restore reference pressure from RTC backup register

			uint32_t tmp = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3); // restore power switch state from RTC backup register
			SCH_retrieveStatePower((uint8_t)tmp);

			// check if elapsed time is greater then shutdown time
			if (elapsedSeconds >= RTC_SHUTDOWN_S)
			{
				SCH_mcuShutdown(); // go into shutdown
			}
		}
	}
	else if (wake_marker == WAKE_FROM_SHUTDOWN_WKUP) // woken from shutdown
	{
		// woken from shutdown (power switch pressed during shutdown)
		wakeConfigReset(); // reset time and date and set default reference pressure
	}
	else	// woken from cold reset
	{
//		wakeConfigReset();	// reset time and date and set default reference pressure
		// store value in RTC backup register to indicate mcu was reset
//		HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_RESET);

	}

}




/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1)
	{
	}
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  *   file: pointer to the source file name
  *   line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

Header is below...

 

/* USER CODE BEGIN Header */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <time.h>

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */


extern RTC_HandleTypeDef hrtc;


/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

void SCH_task100ms(void);
void SCH_powerSwitch(void);
void SCH_mcuStandby(void);
void SCH_mcuShutdown(void);
void SCH_initSoftTimer(void);
void SCH_retrieveStatePower(uint8_t);
void MAN_checkWake (void);

void Enable_PC13_Wakeup(void);
void Enable_PC13_EXTI(void);

uint32_t RTC_to_unix(RTC_TimeTypeDef *time, RTC_DateTypeDef *date);
void wakeConfigReset (void);
void wakeConfigUpdate (void);

extern TIM_HandleTypeDef htim6;

typedef enum {
	STATE_PWR_WAKE_CYCLE_START,
	STATE_PWR_WAKE_CYCLE_CHECK,
	STATE_PWR_WAKE_INPROGRESS,
	STATE_PWR_WAKE_INDICATE,
	STATE_PWR_RUNNING,
	STATE_PWR_STANDBY_CYCLE_START,
	STATE_PWR_STANDBY_CYCLE_CHECK,
	STATE_PWR_SHUTDOWN,
	STATE_PWR_BOOTLOADER
} sch_statePower_t;


/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
#define PWR_SWITCH_Pin GPIO_PIN_13
#define PWR_SWITCH_GPIO_Port GPIOC
#define MCO_Pin GPIO_PIN_0
#define MCO_GPIO_Port GPIOH
#define STATUS_LED_Pin GPIO_PIN_13
#define STATUS_LED_GPIO_Port GPIOB
#define TMS_Pin GPIO_PIN_13
#define TMS_GPIO_Port GPIOA
#define TCK_Pin GPIO_PIN_14
#define TCK_GPIO_Port GPIOA
#define SWO_Pin GPIO_PIN_3
#define SWO_GPIO_Port GPIOB

/* USER CODE BEGIN Private defines */

#define WAKE_FROM_STANDBY 0xA5A5
#define WAKE_FROM_SHUTDOWN_WKUP 0xBEEF
#define WAKE_FROM_RESET 0x00FF

#define ALLOW_LOWPOWER

#define STATE_PWR_LED_COUNT 10
#define STATE_PWR_LED_WAKE_COUNT 50
#define STATE_PWR_LED_OFF_COUNT 40
#define STATE_PWR_SWITCH_COUNT 4
#define STATE_PWR_BOOTLOADER_CNT 50

#define RTC_WAKE_SEC	30

#define RTC_SHUTDOWN_H	14
#define RTC_SHUTDOWN_S	RTC_SHUTDOWN_H * 60 * 60
/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

Detailed description:

I am using the following technique to wake the MCU from shutdown...

Start the switch-on cycle by clicking the button once. After approx. one second, an LED will flash. You must
acknowledge the LED light immediately by clicking the button again. This sequence - a click as soon as the LED appears - will be repeated three more times. After a total of four clicks, the MCU will wake up.

If you do not act promptly after seeing the LED light, or if you push the button too soon, it will ignore the switch-on attempt.  This four-click switch-on cycle has been designed to prevent the MCU from being switched on accidentally.

An example is shown in this video...

https://www.youtube.com/watch?v=TpTqGVCbXGE

 

Below are diagrams of the state machine (running in a 100ms task) after the switch has intially been pressed and woken the MCU from shutdown.  This is how the functionality should work.

The following diagram shows an invalid power up request.  When the LED is on, the switch is not pressed to 'extinguish' the LED and when the counter (sch_u8_pwrCount) reaches 10 the state machine goes into the shutdown state where it calls the shutdown function.

freeflyer_0-1758141293843.png

The following diagram shows a valid power up request.  Each time the LED is on, the switch is pressed to 'extinguish' the LED before the counter (sch_u8_pwrCount) reaches 10.  When the counter (sch_u8_pwrSwitchCount) reaches 4, the state machine goes into the running state.

freeflyer_1-1758141415581.png

 

 

 

 

 

2 REPLIES 2
TDK
Super User

Maybe try it on a simpler example.

You say it's waking up twice but i don't see that shown in your figures. First figure has LED on only once. Second figure has LED on 4 times and buttons pressed 4 times.

If you feel a post has answered your question, please click "Accept as Solution".

The figures show how it’s supposed to work. 

But the fact is that the MCU wakes twice from shutdown when the button is pressed (this is not shown in the figures).  

I confirmed that the MCU is waking from shutdown twice by setting a breakpoint at the beginning of the program (HAL_Init) which is hit twice and also by setting a GPIO pin and monitoring it on a scope. 

The figure below shows what is actually happening...

 

freeflyer_0-1758141726329.png