1 /**
2   ******************************************************************************
3   * @file    stm32f2xx_hal_timebase_rtc_alarm_template.c
4   * @author  MCD Application Team
5   * @brief   HAL time base based on the hardware RTC_ALARM Template.
6   *
7   *          This file override the native HAL time base functions (defined as weak)
8   *          to use the RTC ALARM for time base generation:
9   *           + Intializes the RTC peripheral with required prescalers value for each
10   *             RTC clock source (HSE, LSE or LSI)
11   *           + The alarm is configured to assert an interrupt when the RTC reaches 1ms
12   *           + HAL_IncTick is called at each Alarm event and the time is reset to 00:00:00
13   *           + HSE (default), LSE or LSI can be selected as RTC clock source
14  @verbatim
15   ==============================================================================
16                         ##### How to use this driver #####
17   ==============================================================================
18     [..]
19     This file must be copied to the application folder and modified as follows:
20     (#) Rename it to 'stm32f2xx_hal_timebase_rtc_alarm.c'
21     (#) Add this file and the RTC HAL drivers to your project and uncomment
22         HAL_RTC_MODULE_ENABLED define in stm32f2xx_hal_conf.h
23 
24     [..]
25     (@) HAL RTC alarm and HAL RTC wakeup drivers can�t be used with low power modes:
26         The wake up capability of the RTC may be intrusive in case of prior low power mode
27         configuration requiring different wake up sources.
28         Application/Example behavior is no more guaranteed
29     (@) The stm32f2xx_hal_timebase_tim use is recommended for the Applications/Examples
30         requiring low power modes
31 
32   @endverbatim
33   ******************************************************************************
34   * @attention
35   *
36   * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
37   * All rights reserved.</center></h2>
38   *
39   * This software component is licensed by ST under BSD 3-Clause license,
40   * the "License"; You may not use this file except in compliance with the
41   * License. You may obtain a copy of the License at:
42   *                        opensource.org/licenses/BSD-3-Clause
43   *
44   ******************************************************************************
45   */
46 
47 /* Includes ------------------------------------------------------------------*/
48 #include "stm32f2xx_hal.h"
49 
50 /** @addtogroup STM32F2xx_HAL_Driver
51   * @{
52   */
53 
54 /** @defgroup HAL_TimeBase_RTC_Alarm_Template  HAL TimeBase RTC Alarm Template
55   * @{
56   */
57 
58 /* Private typedef -----------------------------------------------------------*/
59 /* Private define ------------------------------------------------------------*/
60 
61 /* Uncomment the line below to select the appropriate RTC Clock source for your application:
62   + RTC_CLOCK_SOURCE_HSE: can be selected for applications requiring timing precision.
63   + RTC_CLOCK_SOURCE_LSE: can be selected for applications with low constraint on timing
64                           precision.
65   + RTC_CLOCK_SOURCE_LSI: can be selected for applications with low constraint on timing
66                           precision.
67   */
68 #define RTC_CLOCK_SOURCE_HSE
69 /* #define RTC_CLOCK_SOURCE_LSE */
70 /* #define RTC_CLOCK_SOURCE_LSI */
71 
72 #ifdef RTC_CLOCK_SOURCE_HSE
73   #define RTC_ASYNCH_PREDIV       9U
74   #define RTC_SYNCH_PREDIV        9U
75   #define RCC_RTCCLKSOURCE_1MHZ   ((uint32_t)((uint32_t)RCC_BDCR_RTCSEL | (uint32_t)((HSE_VALUE/1000000U) << 16U)))
76 #elif defined (RTC_CLOCK_SOURCE_LSE)
77   #define RTC_ASYNCH_PREDIV       2U
78   #define RTC_SYNCH_PREDIV        0U
79 #else /* RTC_CLOCK_SOURCE_LSI */
80   #define RTC_ASYNCH_PREDIV       1U
81   #define RTC_SYNCH_PREDIV        0U
82 #endif /* RTC_CLOCK_SOURCE_HSE */
83 
84 /* Private macro -------------------------------------------------------------*/
85 /* Private variables ---------------------------------------------------------*/
86 RTC_HandleTypeDef        hRTC_Handle;
87 /* Private function prototypes -----------------------------------------------*/
88 void RTC_Alarm_IRQHandler(void);
89 /* Private functions ---------------------------------------------------------*/
90 
91 /**
92   * @brief  This function configures the RTC_ALARMA as a time base source.
93   *         The time source is configured  to have 1ms time base with a dedicated
94   *         Tick interrupt priority.
95   * @note   This function is called  automatically at the beginning of program after
96   *         reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
97   * @param  TickPriority Tick interrupt priority.
98   * @retval HAL status
99   */
HAL_InitTick(uint32_t TickPriority)100 HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
101 {
102   __IO uint32_t counter = 0U;
103 
104   RCC_OscInitTypeDef        RCC_OscInitStruct;
105   RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
106   HAL_StatusTypeDef     status;
107 
108 #ifdef RTC_CLOCK_SOURCE_LSE
109   /* Configue LSE as RTC clock soucre */
110   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
111   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
112   RCC_OscInitStruct.LSEState = RCC_LSE_ON;
113   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
114 #elif defined (RTC_CLOCK_SOURCE_LSI)
115   /* Configue LSI as RTC clock soucre */
116   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
117   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
118   RCC_OscInitStruct.LSIState = RCC_LSI_ON;
119   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
120 #elif defined (RTC_CLOCK_SOURCE_HSE)
121   /* Configue HSE as RTC clock soucre */
122   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
123   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
124   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
125   /* Ensure that RTC is clocked by 1MHz */
126   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_1MHZ;
127 #else
128 #error Please select the RTC Clock source
129 #endif /* RTC_CLOCK_SOURCE_LSE */
130 
131   status = HAL_RCC_OscConfig(&RCC_OscInitStruct);
132   if (status == HAL_OK)
133   {
134     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
135     status = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
136   }
137   if (status == HAL_OK)
138   {
139     /* Enable RTC Clock */
140     __HAL_RCC_RTC_ENABLE();
141 
142     /* The time base should be 1ms
143        Time base = ((RTC_ASYNCH_PREDIV + 1) * (RTC_SYNCH_PREDIV + 1) * ALARM_VALUE) / RTC_CLOCK
144        HSE as RTC clock
145          Time base = ((9 + 1) * (9 + 1) * 10) / 1MHz
146                    = 1ms
147        LSE as RTC clock
148          Time base = ((2 + 1) * (0 + 1) * 11) / 32.768KHz
149                    = ~1ms
150        LSI as RTC clock
151          Time base = ((1 + 1) * (0 + 1) * 16) / 32KHz
152                    = 1ms
153     */
154     hRTC_Handle.Instance = RTC;
155     hRTC_Handle.Init.HourFormat = RTC_HOURFORMAT_24;
156     hRTC_Handle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
157     hRTC_Handle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
158     hRTC_Handle.Init.OutPut = RTC_OUTPUT_DISABLE;
159     hRTC_Handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
160     hRTC_Handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
161     status = HAL_RTC_Init(&hRTC_Handle);
162   }
163   if (status == HAL_OK)
164   {
165     /* Disable the write protection for RTC registers */
166     __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
167 
168     /* Disable the Alarm A interrupt */
169     __HAL_RTC_ALARMA_DISABLE(&hRTC_Handle);
170 
171     /* Clear flag alarm A */
172     __HAL_RTC_ALARM_CLEAR_FLAG(&hRTC_Handle, RTC_FLAG_ALRAF);
173 
174     counter = 0U;
175     /* Wait till RTC ALRAWF flag is set and if Time out is reached exit */
176     while (__HAL_RTC_ALARM_GET_FLAG(&hRTC_Handle, RTC_FLAG_ALRAWF) == RESET)
177     {
178       if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
179       {
180         status = HAL_ERROR;
181       }
182     }
183   }
184   if (status == HAL_OK)
185   {
186     /* Set alarm value for each RTC clock source */
187 #ifdef RTC_CLOCK_SOURCE_HSE
188     hRTC_Handle.Instance->ALRMAR = 0x10U;
189 #elif defined (RTC_CLOCK_SOURCE_LSE)
190     hRTC_Handle.Instance->ALRMAR = 0x11U;
191 #else
192     hRTC_Handle.Instance->ALRMAR = 0x16U;
193 #endif
194 
195     /* Configure the Alarm state: Enable Alarm */
196     __HAL_RTC_ALARMA_ENABLE(&hRTC_Handle);
197 
198     /* Configure the Alarm interrupt */
199     __HAL_RTC_ALARM_ENABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
200 
201     /* RTC Alarm Interrupt Configuration: EXTI configuration */
202     __HAL_RTC_ALARM_EXTI_ENABLE_IT();
203     __HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();
204 
205     /* Check if the Initialization mode is set */
206     if ((hRTC_Handle.Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
207     {
208       /* Set the Initialization mode */
209       hRTC_Handle.Instance->ISR = (uint32_t)RTC_INIT_MASK;
210       counter = 0U;
211       while ((hRTC_Handle.Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
212       {
213         if (counter++ == SystemCoreClock / 48U) /* Timeout = ~ 1s */
214         {
215           status = HAL_ERROR;
216         }
217       }
218     }
219   }
220   if (status == HAL_OK)
221   {
222     hRTC_Handle.Instance->DR = 0U;
223     hRTC_Handle.Instance->TR = 0U;
224 
225     hRTC_Handle.Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
226 
227     /* Enable the write protection for RTC registers */
228     __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
229 
230     /* Enable the RTC Alarm Interrupt */
231     HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
232 
233     /* Configure the SysTick IRQ priority */
234     if (TickPriority < (1UL << __NVIC_PRIO_BITS))
235     {
236       HAL_NVIC_SetPriority(RTC_Alarm_IRQn, TickPriority, 0U);
237       uwTickPrio = TickPriority;
238     }
239     else
240     {
241       status = HAL_ERROR;
242     }
243 
244   }
245   return status;
246 }
247 
248 /**
249   * @brief  Suspend Tick increment.
250   * @note   Disable the tick increment by disabling RTC ALARM interrupt.
251   * @param  None
252   * @retval None
253   */
HAL_SuspendTick(void)254 void HAL_SuspendTick(void)
255 {
256   /* Disable the write protection for RTC registers */
257   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
258   /* Disable RTC ALARM update Interrupt */
259   __HAL_RTC_ALARM_DISABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
260   /* Enable the write protection for RTC registers */
261   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
262 }
263 
264 /**
265   * @brief  Resume Tick increment.
266   * @note   Enable the tick increment by Enabling RTC ALARM interrupt.
267   * @param  None
268   * @retval None
269   */
HAL_ResumeTick(void)270 void HAL_ResumeTick(void)
271 {
272   /* Disable the write protection for RTC registers */
273   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
274   /* Enable RTC ALARM Update interrupt */
275   __HAL_RTC_ALARM_ENABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
276   /* Enable the write protection for RTC registers */
277   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
278 }
279 
280 /**
281   * @brief  ALARM A Event Callback in non blocking mode
282   * @note   This function is called  when RTC_ALARM interrupt took place, inside
283   * RTC_ALARM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
284   * a global variable "uwTick" used as application time base.
285   * @param  hrtc RTC handle
286   * @retval None
287   */
HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef * hrtc)288 void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
289 {
290   __IO uint32_t counter = 0U;
291 
292   HAL_IncTick();
293 
294   __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
295 
296   /* Set the Initialization mode */
297   hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;
298 
299   while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
300   {
301     if(counter++ == SystemCoreClock /48U) /* Timeout = ~ 1s */
302     {
303       break;
304     }
305   }
306 
307   hrtc->Instance->DR = 0U;
308   hrtc->Instance->TR = 0U;
309 
310   hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
311 
312   /* Enable the write protection for RTC registers */
313   __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
314 }
315 
316 /**
317   * @brief  This function handles RTC ALARM interrupt request.
318   * @param  None
319   * @retval None
320   */
RTC_Alarm_IRQHandler(void)321 void RTC_Alarm_IRQHandler(void)
322 {
323   HAL_RTC_AlarmIRQHandler(&hRTC_Handle);
324 }
325 
326 /**
327   * @}
328   */
329 
330 /**
331   * @}
332   */
333 
334 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
335