2017-01-20 03:31 AM
I have a very typical application here - long periods of minimal current consumption (15 minutes to 24 hours sleep duration) with short periods of activity in between. In my particular case, this is mostly ADC and GPIO manipulation (which explains some of the extra initialisation in my code which is unused) but for this example, I am just trying to achieve the following:
So far this works well for the first loop through - I see the LED turn on, turn off after 1000ms, stay off for 5 seconds (current draw drops to approx. 2uA) and then turn on again. However, the LED never turns off again. I can't use SWD to debug this as the board seems to never enter Stop mode with SWD debugging active.
My code (partially generated by STM32CubeMX and partially from reading docs) is as below:
#include 'main.h'#include 'stm32l0xx_hal.h' // specific target MCU is STM32L011D3P6 ADC_HandleTypeDef hadc; RTC_HandleTypeDef hrtc; void SystemClock_Config(void); void Error_Handler(void); static void MX_GPIO_Init(void); static void MX_ADC_Init(void); static void MX_RTC_Init(void); void SystemPower_Config(void); int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC_Init(); MX_RTC_Init(); SystemPower_Config(); #ifdef DEBUG HAL_DBGMCU_EnableDBGStopMode(); #else HAL_DBGMCU_DisableDBGStopMode(); #endif while (1) { HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, GPIO_PIN_SET); HAL_Delay(1000); HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, GPIO_PIN_RESET); HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 5, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != HAL_OK) { Error_Handler(); } __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); } } void SystemClock_Config(void){ RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInit; __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.HSIState = RCC_HSI_DIV4; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_4; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; 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_0) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } static void MX_ADC_Init(void){ ADC_ChannelConfTypeDef sConfig; hadc.Instance = ADC1; hadc.Init.OversamplingMode = DISABLE; hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV16; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerFrequencyMode = ENABLE; hadc.Init.LowPowerAutoPowerOff = ENABLE; if (HAL_ADC_Init(&hadc) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_1; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_4; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); } } static void MX_RTC_Init(void){ RTC_TimeTypeDef sTime; RTC_DateTypeDef sDate; 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(); } 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(); } } static void MX_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); HAL_GPIO_WritePin(SENSOR_EN_GPIO_Port, SENSOR_EN_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, LED_2_Pin|LED_1_Pin|LED_0_Pin, GPIO_PIN_RESET); GPIO_InitStruct.Pin = SELF_TEST_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(SELF_TEST_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = SENSOR_EN_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SENSOR_EN_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = LED_2_Pin|LED_1_Pin|LED_0_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc){ __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); } void SystemPower_Config(void){ __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWREx_EnableUltraLowPower(); } void Error_Handler(void){ while(1) { } �?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
}
Main.h simply maps GPIO pins to the names used in the code - happy to post that if it's useful. Can anyone point out where I am going wrong here? Or suggest a helpful debug approach? (given that I sadly can't do much register poking with SWD ruining my ability to go into sleep mode)
Using a current shunt amplifier and an oscilloscope, I checked the current draw over time. It's very easy to see when the device enters stop mode this way (and trigger from this). I can see from the scope trace that the device only enters stop mode once, that is it doesn't enter a second time and then immediately return.
#low-power #rtc-wakeup #stop-mode #stm32l011 #stm32-cube-mx Note: this post was migrated and contained many threaded conversations, some content may be missing.Solved! Go to Solution.
2017-01-20 07:19 AM
Hi - Just adding the function is not enough, you have to enable the RTC interrupt in your code (look at the example Nesrine provided on how to do that).
But if I'm correct, then how come it works once ? It should stay in sleep forever...
2017-01-20 04:24 AM
Hi
stefandz
,Could you please have a look this example :
STM32Cube_FW_L0_V1.8.0\Projects\STM32L011K4-Nucleo\Examples\PWR\PWR_STOP_RTC
it shows how to enter Stop mode and wake up from this mode by using the RTC wakeup timer event connected to an interrupt.
-Nesrine-
2017-01-20 06:11 AM
Hi
ELMHIRI.Syrine
- thanks for replying. I can get this example working without problems - however I still can't work out why my program doesn't function as expected. From what I can see, my code should work fine, and it does the first time around. I am trying to work out what causes the second entry to stop mode to fail.If you could shed any light on that I would be most appreciative.
2017-01-20 06:24 AM
Hi
stefandz
,could you please checkyourstm32l0xx_it.c file?
-Nesrine-
2017-01-20 06:31 AM
Hi again
- my stm32l0xx_it.c file was entirely generated by STM32cubeMX - the listing is below, with comments stripped out.#include 'stm32l0xx_hal.h'#include 'stm32l0xx.h'#include 'stm32l0xx_it.h'void NMI_Handler(void){}void HardFault_Handler(void){ while (1) { }}void SVC_Handler(void){}void PendSV_Handler(void){}void SysTick_Handler(void){ HAL_IncTick(); HAL_SYSTICK_IRQHandler();}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2017-01-20 06:46 AM
Hi
,it seems that you have missed theRTC wake-up interrupt request in the
stm32l0xx_it.c:
extern RTC_HandleTypeDef hrtc;/** * @brief This function handles RTC Auto wake-up interrupt request. * @param None * @retval None */void RTC_IRQHandler(void){ HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);}�?�?�?�?�?�?�?�?�?�?
-Nesrine-
2017-01-20 06:56 AM
Hi
ELMHIRI.Syrine
- adding that function and external variable prototype didn't change the behaviour I am seeing, sadly. Thank you very much for your continued efforts with this.2017-01-20 07:19 AM
Hi - Just adding the function is not enough, you have to enable the RTC interrupt in your code (look at the example Nesrine provided on how to do that).
But if I'm correct, then how come it works once ? It should stay in sleep forever...
2017-01-20 07:57 AM
Hi
Kjeldsen.Carl_Nicola
- thank you so much for taking a look at this. You've cracked it! I think I can also see why the wake works first time. At boot and after initial config, the RTC is all set up and ready to generate wakeup interrupts. So the first time, this works fine. However, because the interrupt routine wasn't correctly implemented (and mapped to the HAL IRQ handler), the relevant flags never got reset. Thanks too toELMHIRI.Syrine
for helping out with this too - I am much obliged!2017-02-12 05:36 PM
Hello folks,
I'm having a very similar problem, however with a custom board for the STM32L071KZU, I have implemented the fixes as specified, however the device does not trigger a lower power sleep even once, never mind repeatebily.
Is there an errata I am missing? (I checked here:
Full Code is here (compiled code included in case my compiler is somehow misbehaving...) :
https://mrrobot.ca/owncloud/s/rIHnlSKQ3NEgiaN
Thanks all