1 /**
2   ******************************************************************************
3   * @file    stm32f2xx_hal_timebase_rtc_wakeup_template.c
4   * @author  MCD Application Team
5   * @brief   HAL time base based on the hardware RTC_WAKEUP Template.
6   *
7   *          This file overrides the native HAL time base functions (defined as weak)
8   *          to use the RTC WAKEUP for the time base generation:
9   *           + Intializes the RTC peripheral with required prescalers value for each
10   *             RTC clock source (HSE, LSE or LSI)
11   *           + The wakeup feature is configured to assert an interrupt each 1ms
12   *           + HAL_IncTick is called inside the HAL_RTCEx_WakeUpTimerEventCallback
13   *           + HSE (default), LSE or LSI can be selected as RTC clock source
14   *
15   ******************************************************************************
16   * @attention
17   *
18   * Copyright (c) 2016 STMicroelectronics.
19   * All rights reserved.
20   *
21   * This software is licensed under terms that can be found in the LICENSE file
22   * in the root directory of this software component.
23   * If no LICENSE file comes with this software, it is provided AS-IS.
24   *
25   ******************************************************************************
26   @verbatim
27   ==============================================================================
28                         ##### How to use this driver #####
29   ==============================================================================
30     [..]
31     This file must be copied to the application folder and modified as follows:
32     (#) Rename it to 'stm32f2xx_hal_timebase_rtc_wakeup.c'
33     (#) Add this file and the RTC HAL drivers to your project and uncomment
34         HAL_RTC_MODULE_ENABLED define in stm32f2xx_hal_conf.h
35 
36     [..]
37     (@) HAL RTC alarm and HAL RTC wakeup drivers can�t be used with low power modes:
38         The wake up capability of the RTC may be intrusive in case of prior low power mode
39         configuration requiring different wake up sources.
40         Application/Example behavior is no more guaranteed
41     (@) The stm32f2xx_hal_timebase_tim use is recommended for the Applications/Examples
42         requiring low power modes
43 
44   @endverbatim
45   ******************************************************************************
46   */
47 
48 /* Includes ------------------------------------------------------------------*/
49 #include "stm32f2xx_hal.h"
50 
51 /** @addtogroup STM32F2xx_HAL_Driver
52   * @{
53   */
54 
55 /** @defgroup HAL_TimeBase_RTC_WakeUp_Template  HAL TimeBase RTC WakeUp Template
56   * @{
57   */
58 
59 /* Private typedef -----------------------------------------------------------*/
60 /* Private define ------------------------------------------------------------*/
61 
62 /* Uncomment the line below to select the appropriate RTC Clock source for your application:
63   + RTC_CLOCK_SOURCE_HSE: can be selected for applications requiring timing precision.
64   + RTC_CLOCK_SOURCE_LSE: can be selected for applications with low constraint on timing
65                           precision.
66   + RTC_CLOCK_SOURCE_LSI: can be selected for applications with low constraint on timing
67                           precision.
68   */
69 #define RTC_CLOCK_SOURCE_HSE
70 /* #define RTC_CLOCK_SOURCE_LSE */
71 /* #define RTC_CLOCK_SOURCE_LSI */
72 
73 #ifdef RTC_CLOCK_SOURCE_HSE
74   #define RTC_ASYNCH_PREDIV       99U
75   #define RTC_SYNCH_PREDIV        9U
76   #define RCC_RTCCLKSOURCE_1MHZ   ((uint32_t)((uint32_t)RCC_BDCR_RTCSEL | (uint32_t)((HSE_VALUE/1000000U) << 16U)))
77 #elif defined (RTC_CLOCK_SOURCE_LSE)
78   #define RTC_ASYNCH_PREDIV       2U
79   #define RTC_SYNCH_PREDIV        0U
80 #else /* RTC_CLOCK_SOURCE_LSI */
81   #define RTC_ASYNCH_PREDIV       1U
82   #define RTC_SYNCH_PREDIV        0U
83 #endif /* RTC_CLOCK_SOURCE_HSE */
84 
85 /* Private macro -------------------------------------------------------------*/
86 /* Private variables ---------------------------------------------------------*/
87 RTC_HandleTypeDef        hRTC_Handle;
88 
89 /* Private function prototypes -----------------------------------------------*/
90 void RTC_WKUP_IRQHandler(void);
91 
92 /* Private functions ---------------------------------------------------------*/
93 
94 /**
95   * @brief  This function configures the RTC_WKUP as a time base source.
96   *         The time source is configured  to have 1ms time base with a dedicated
97   *         Tick interrupt priority.
98   * @note   This function is called  automatically at the beginning of program after
99   *         reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
100   * @param  TickPriority Tick interrupt priority.
101   * @retval HAL status
102   */
HAL_InitTick(uint32_t TickPriority)103 HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
104 {
105   __IO uint32_t counter = 0U;
106 
107   RCC_OscInitTypeDef        RCC_OscInitStruct;
108   RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
109   HAL_StatusTypeDef     status;
110 
111 #ifdef RTC_CLOCK_SOURCE_LSE
112   /* Configue LSE as RTC clock soucre */
113   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
114   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
115   RCC_OscInitStruct.LSEState = RCC_LSE_ON;
116   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
117 #elif defined (RTC_CLOCK_SOURCE_LSI)
118   /* Configue LSI as RTC clock soucre */
119   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
120   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
121   RCC_OscInitStruct.LSIState = RCC_LSI_ON;
122   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
123 #elif defined (RTC_CLOCK_SOURCE_HSE)
124   /* Configue HSE as RTC clock soucre */
125   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
126   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
127   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
128   /* Ensure that RTC is clocked by 1MHz */
129   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_1MHZ;
130 #else
131 #error Please select the RTC Clock source
132 #endif /* RTC_CLOCK_SOURCE_LSE */
133 
134   status = HAL_RCC_OscConfig(&RCC_OscInitStruct);
135   if (status == HAL_OK)
136   {
137     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
138     status = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
139   }
140   if (status == HAL_OK)
141   {
142     /* Enable RTC Clock */
143     __HAL_RCC_RTC_ENABLE();
144 
145     /* The time base should be 1ms
146        Time base = ((RTC_ASYNCH_PREDIV + 1) * (RTC_SYNCH_PREDIV + 1) * (WakeUpCounter + 1)) / RTC_CLOCK
147        HSE as RTC clock
148          Time base = ((99 + 1) * (9 + 1) * (0 + 1)) / 1Mhz
149                    = 1ms
150        LSE as RTC clock
151          Time base = ((2 + 1) * (0 + 1) * (10 + 1)) / 32.768Khz
152                    = ~1ms
153        LSI as RTC clock
154          Time base = ((1 + 1) * (0 + 1) * (15 + 1)) / 32Khz
155                    = 1ms
156     */
157     hRTC_Handle.Instance = RTC;
158     hRTC_Handle.Init.HourFormat = RTC_HOURFORMAT_24;
159     hRTC_Handle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
160     hRTC_Handle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
161     hRTC_Handle.Init.OutPut = RTC_OUTPUT_DISABLE;
162     hRTC_Handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
163     hRTC_Handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
164     status = HAL_RTC_Init(&hRTC_Handle);
165   }
166   if (status == HAL_OK)
167   {
168     /* Disable the write protection for RTC registers */
169     __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
170 
171     /* Disable the Wake-up Timer */
172     __HAL_RTC_WAKEUPTIMER_DISABLE(&hRTC_Handle);
173 
174     /* In case of interrupt mode is used, the interrupt source must disabled */
175     __HAL_RTC_WAKEUPTIMER_DISABLE_IT(&hRTC_Handle, RTC_IT_WUT);
176 
177     /* Wait till RTC WUTWF flag is set  */
178     while (__HAL_RTC_WAKEUPTIMER_GET_FLAG(&hRTC_Handle, RTC_FLAG_WUTWF) == RESET)
179     {
180       if (counter++ == SystemCoreClock / 48U)
181       {
182         status = HAL_ERROR;
183       }
184     }
185   }
186   if (status == HAL_OK)
187   {
188 
189     /* Clear PWR wake up Flag */
190     __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
191 
192     /* Clear RTC Wake Up timer Flag */
193     __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hRTC_Handle, RTC_FLAG_WUTF);
194 
195     /* Configure the Wake-up Timer counter */
196 #ifdef RTC_CLOCK_SOURCE_HSE
197     hRTC_Handle.Instance->WUTR = 0U;
198 #elif defined (RTC_CLOCK_SOURCE_LSE)
199     hRTC_Handle.Instance->WUTR = 10U;
200 #else
201     hRTC_Handle.Instance->WUTR = 15U;
202 #endif
203 
204     /* Clear the Wake-up Timer clock source bits in CR register */
205     hRTC_Handle.Instance->CR &= (uint32_t)~RTC_CR_WUCKSEL;
206 
207     /* Configure the clock source */
208     hRTC_Handle.Instance->CR |= (uint32_t)RTC_WAKEUPCLOCK_CK_SPRE_16BITS;
209 
210     /* RTC WakeUpTimer Interrupt Configuration: EXTI configuration */
211     __HAL_RTC_WAKEUPTIMER_EXTI_ENABLE_IT();
212 
213     __HAL_RTC_WAKEUPTIMER_EXTI_ENABLE_RISING_EDGE();
214 
215     /* Configure the Interrupt in the RTC_CR register */
216     __HAL_RTC_WAKEUPTIMER_ENABLE_IT(&hRTC_Handle, RTC_IT_WUT);
217 
218     /* Enable the Wake-up Timer */
219     __HAL_RTC_WAKEUPTIMER_ENABLE(&hRTC_Handle);
220 
221     /* Enable the write protection for RTC registers */
222     __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
223 
224     /* Enable the RTC global Interrupt */
225     HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
226 
227     /* Configure the SysTick IRQ priority */
228     if (TickPriority < (1UL << __NVIC_PRIO_BITS))
229     {
230       HAL_NVIC_SetPriority(RTC_WKUP_IRQn, TickPriority, 0U);
231       uwTickPrio = TickPriority;
232     }
233     else
234     {
235       status = HAL_ERROR;
236     }
237   }
238 
239   return status;
240 }
241 
242 /**
243   * @brief  Suspend Tick increment.
244   * @note   Disable the tick increment by disabling RTC_WKUP interrupt.
245   * @param  None
246   * @retval None
247   */
HAL_SuspendTick(void)248 void HAL_SuspendTick(void)
249 {
250   /* Disable the write protection for RTC registers */
251   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
252   /* Disable WAKE UP TIMER Interrupt */
253   __HAL_RTC_WAKEUPTIMER_DISABLE_IT(&hRTC_Handle, RTC_IT_WUT);
254   /* Enable the write protection for RTC registers */
255   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
256 }
257 
258 /**
259   * @brief  Resume Tick increment.
260   * @note   Enable the tick increment by Enabling RTC_WKUP interrupt.
261   * @param  None
262   * @retval None
263   */
HAL_ResumeTick(void)264 void HAL_ResumeTick(void)
265 {
266   /* Disable the write protection for RTC registers */
267   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
268   /* Enable  WAKE UP TIMER  interrupt */
269   __HAL_RTC_WAKEUPTIMER_ENABLE_IT(&hRTC_Handle, RTC_IT_WUT);
270   /* Enable the write protection for RTC registers */
271   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
272 }
273 
274 /**
275   * @brief  Wake Up Timer Event Callback in non blocking mode
276   * @note   This function is called  when RTC_WKUP interrupt took place, inside
277   * RTC_WKUP_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
278   * a global variable "uwTick" used as application time base.
279   * @param  hrtc RTC handle
280   * @retval None
281   */
HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef * hrtc)282 void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
283 {
284   HAL_IncTick();
285 }
286 
287 /**
288   * @brief  This function handles  WAKE UP TIMER  interrupt request.
289   * @param  None
290   * @retval None
291   */
RTC_WKUP_IRQHandler(void)292 void RTC_WKUP_IRQHandler(void)
293 {
294   HAL_RTCEx_WakeUpTimerIRQHandler(&hRTC_Handle);
295 }
296 
297 /**
298   * @}
299   */
300 
301 /**
302   * @}
303   */
304 
305