1 /**
2   ******************************************************************************
3   * @file    stm32wbxx_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   *           + Initializes the RTC peripheral to increment the seconds registers each 1s
10   *           + The alarm is configured to assert an interrupt when the RTC
11   *             subsecond register reaches 1ms when uwTickFreq is set to default
12   *             value, else 10 ms or 100 ms, depending of above global variable value.
13   *           + HAL_IncTick is called at each Alarm event
14   *           + HSE (default), LSE or LSI can be selected as RTC clock source
15   ******************************************************************************
16   * @attention
17   *
18   * Copyright (c) 2019 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 'stm32wbxx_hal_timebase_rtc_alarm.c'
33     (#) Add this file and the RTC HAL drivers to your project and uncomment
34        HAL_RTC_MODULE_ENABLED define in stm32wbxx_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 stm32wbxx_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 "stm32wbxx_hal.h"
50 
51 /** @addtogroup STM32WBxx_HAL_Driver
52   * @{
53   */
54 
55 /** @defgroup HAL_TimeBase_RTC_Alarm_Template  HAL TimeBase RTC Alarm 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 /* Minimize Asynchronous prescaler for power consumption :
74   ck_apre = RTCCLK / (ASYNC prediv + 1)
75   ck_spre = ck_apre /(SYNC prediv + 1) = 1 Hz */
76 #if defined (RTC_CLOCK_SOURCE_LSE)
77 /* LSE Freq = 32.768 kHz RC */
78 #define RTC_ASYNCH_PREDIV                   1U
79 #define RTC_SYNCH_PREDIV                    0x3FFFu /* (16384 - 1) */
80 #elif defined (RTC_CLOCK_SOURCE_LSI)
81 /* LSI Freq = 32 kHz RC  */
82 #define RTC_ASYNCH_PREDIV                   1U
83 #define RTC_SYNCH_PREDIV                    0x3E7Fu /* (16000 - 1) */
84 #elif defined (RTC_CLOCK_SOURCE_HSE)
85 /* HSE Freq as RTCCLK = 32 MHz / 32 = 1 MHz */
86 #define RTC_ASYNCH_PREDIV                   0x27u
87 #define RTC_SYNCH_PREDIV                    0x5161
88 #endif /* RTC_CLOCK_SOURCE_LSE */
89 
90 /* Private macro -------------------------------------------------------------*/
91 /* Private variables ---------------------------------------------------------*/
92 extern RTC_HandleTypeDef hRTC_Handle;
93 RTC_HandleTypeDef        hRTC_Handle;
94 
95 /* Private function prototypes -----------------------------------------------*/
96 void RTC_Alarm_IRQHandler(void);
97 
98 /* Private functions ---------------------------------------------------------*/
99 
100 /**
101   * @brief  This function configures the RTC ALARM A as a time base source.
102   *         The time source is configured to have 1ms time base with a dedicated
103   *         Tick interrupt priority.
104   *         Calendar time base is = ((RTC_ASYNCH_PREDIV + 1) * (RTC_SYNCH_PREDIV + 1)) / RTC_CLOCK
105   *                               = 1s
106   *         Alarm interrupt timebase is = (RTC_SYNCH_PREDIV / (1000 / uwTickFreq))
107   *                                     = 1 ms when uwTickFreq is set to 1 kHz
108   * @note   This function is called automatically at the beginning of program after
109   *         reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
110   * @param  TickPriority  Tick interrupt priority.
111   * @retval HAL status
112   */
HAL_InitTick(uint32_t TickPriority)113 HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
114 {
115   HAL_StatusTypeDef status = HAL_OK;
116 
117   RCC_OscInitTypeDef        RCC_OscInitStruct;
118   RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
119   RTC_TimeTypeDef           time;
120   RTC_DateTypeDef           date;
121   RTC_AlarmTypeDef          alarm;
122 
123   /* Check uwTickFreq for MisraC 2012 (even if uwTickFreq is a enum type that don't take the value zero) */
124   if ((uint32_t)uwTickFreq != 0U)
125   {
126     /* Disable backup domeain protection */
127     HAL_PWR_EnableBkUpAccess();
128 
129     /* Enable RTC APB clock gating */
130     __HAL_RCC_RTCAPB_CLK_ENABLE();
131 
132     /* Disable the Alarm A */
133     __HAL_RTC_ALARMA_DISABLE(&hRTC_Handle);
134 
135     /* In case of interrupt mode is used, the interrupt source must disabled */
136     __HAL_RTC_ALARM_DISABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
137     __HAL_RTC_ALARM_CLEAR_FLAG(&hRTC_Handle, RTC_FLAG_ALRAF);
138 
139     /* Get RTC clock configuration */
140     HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInitStruct);
141 
142     /*In case of RTC clock already enable, make sure it's the good one */
143 #if defined (RTC_CLOCK_SOURCE_LSE)
144     if ((PeriphClkInitStruct.RTCClockSelection == RCC_RTCCLKSOURCE_LSE)
145         && (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != 0x00u))
146 #elif defined (RTC_CLOCK_SOURCE_LSI)
147     if ((PeriphClkInitStruct.RTCClockSelection == RCC_RTCCLKSOURCE_LSI)
148         && (__HAL_RCC_GET_FLAG(RCC_FLAG_LSI1RDY) != 0x00u))
149 #elif defined (RTC_CLOCK_SOURCE_HSE)
150     if ((PeriphClkInitStruct.RTCClockSelection == RCC_RTCCLKSOURCE_HSE_DIV32)
151         && (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != 0x00u))
152 #else
153 #error Please select the RTC Clock source
154 #endif /* RTC_CLOCK_SOURCE_LSE */
155     {
156       /* Do nothing */
157     }
158     else
159     {
160 #ifdef RTC_CLOCK_SOURCE_LSE
161       /* Configure LSE as RTC clock source */
162       RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
163       RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
164       RCC_OscInitStruct.LSEState = RCC_LSE_ON;
165       PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
166 #elif defined (RTC_CLOCK_SOURCE_LSI)
167       /* Configure LSI as RTC clock source */
168       RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI1;
169       RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
170       RCC_OscInitStruct.LSIState = RCC_LSI_ON;
171       PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
172 #elif defined (RTC_CLOCK_SOURCE_HSE)
173       /* Configure HSE as RTC clock source */
174       RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
175       RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
176       RCC_OscInitStruct.HSEState = RCC_HSE_ON;
177       /* Ensure that RTC is clocked by 1MHz */
178       PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32;
179 #endif /* RTC_CLOCK_SOURCE_LSE */
180 
181       /* Configure oscillator */
182       status = HAL_RCC_OscConfig(&RCC_OscInitStruct);
183       if(status == HAL_OK)
184       {
185         /* Configure RTC clock source */
186         PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
187         status = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
188 
189         /* Enable RTC Clock */
190         if(status == HAL_OK)
191         {
192           __HAL_RCC_RTC_ENABLE();
193         }
194       }
195     }
196 
197     /* If RTC Clock configuration is ok */
198     if (status == HAL_OK)
199     {
200       /* The time base is defined to have highest synchronous prescaler but keeping
201          a 1Hz RTC frequency. */
202       hRTC_Handle.Instance = RTC;
203       hRTC_Handle.Init.HourFormat = RTC_HOURFORMAT_24;
204       hRTC_Handle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;
205       hRTC_Handle.Init.SynchPrediv = RTC_SYNCH_PREDIV;
206       hRTC_Handle.Init.OutPut = RTC_OUTPUT_DISABLE;
207       hRTC_Handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
208       hRTC_Handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
209       status = HAL_RTC_Init(&hRTC_Handle);
210     }
211 
212     /* HAL RTC Init is ok & calendar has never been initialized */
213     if (status == HAL_OK)
214     {
215       time.Hours = 0x00u;
216       time.Minutes = 0x00u;
217       time.Seconds = 0x00u;
218       time.TimeFormat = RTC_HOURFORMAT12_PM;
219       time.SubSeconds = 0x00u;
220       time.SecondFraction = 0x00u;
221       time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
222       time.StoreOperation = RTC_STOREOPERATION_RESET;
223       status = HAL_RTC_SetTime(&hRTC_Handle, &time, RTC_FORMAT_BCD);
224       if ((status == HAL_OK)&& (__HAL_RTC_IS_CALENDAR_INITIALIZED(&hRTC_Handle) == 0u))
225       {
226         date.WeekDay = RTC_WEEKDAY_MONDAY;
227         date.Date = 0x01u;
228         date.Month = RTC_MONTH_JANUARY;
229         date.Year = 0x01u;
230         status = HAL_RTC_SetDate(&hRTC_Handle, &date, RTC_FORMAT_BCD);
231       }
232     }
233 
234     /* If RTC calendar is initialized */
235     if (status == HAL_OK)
236     {
237       alarm.AlarmTime.Hours = 0x00u;
238       alarm.AlarmTime.Minutes = 0x00u;
239       alarm.AlarmTime.Seconds = 0x00u;
240       alarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_PM;
241       alarm.AlarmTime.SubSeconds = ((RTC_SYNCH_PREDIV + 1) / (1000 / (uint32_t)uwTickFreq));
242       alarm.AlarmTime.SecondFraction = 0x00u;
243       alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
244       alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
245       alarm.AlarmMask = RTC_ALARMMASK_ALL;
246 
247       /* Depending on input frequency select Subsecond mask */
248       if (uwTickFreq == HAL_TICK_FREQ_1KHZ)
249       {
250 #if defined (RTC_CLOCK_SOURCE_HSE)
251         alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_5;
252 #else
253         alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_4;
254 #endif
255       }
256       else if (uwTickFreq == HAL_TICK_FREQ_100HZ)
257       {
258 #if defined (RTC_CLOCK_SOURCE_HSE)
259         alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_8;
260 #else
261         alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_7;
262 #endif
263       }
264       else
265       {
266        alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14_11;
267       }
268 
269       alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
270       alarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY;
271       alarm.Alarm = RTC_ALARM_A;
272       status = HAL_RTC_SetAlarm_IT(&hRTC_Handle, &alarm, RTC_FORMAT_BCD);
273       if(status == HAL_OK)
274       {
275         /* Enable the RTC global Interrupt */
276         HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
277 
278         /* Configure the SysTick IRQ priority */
279         if (TickPriority < (1UL << __NVIC_PRIO_BITS))
280         {
281           HAL_NVIC_SetPriority(RTC_Alarm_IRQn, TickPriority, 0U);
282           uwTickPrio = TickPriority;
283         }
284         else
285         {
286           status = HAL_ERROR;
287         }
288       }
289     }
290   }
291   else
292   {
293     status = HAL_ERROR;
294   }
295   return status;
296 }
297 
298 /**
299   * @brief  Suspend Tick increment.
300   * @note   Disable the tick increment by disabling ALARM A interrupt.
301   * @retval None
302   */
HAL_SuspendTick(void)303 void HAL_SuspendTick(void)
304 {
305   /* Disable the write protection for RTC registers */
306   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
307   /* Disable ALARM A Interrupt */
308   __HAL_RTC_ALARM_DISABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
309   /* Enable the write protection for RTC registers */
310   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
311 }
312 
313 /**
314   * @brief  Resume Tick increment.
315   * @note   Enable the tick increment by Enabling ALARM A interrupt.
316   * @retval None
317   */
HAL_ResumeTick(void)318 void HAL_ResumeTick(void)
319 {
320   /* Disable the write protection for RTC registers */
321   __HAL_RTC_WRITEPROTECTION_DISABLE(&hRTC_Handle);
322   /* Enable ALARM A interrupt */
323   __HAL_RTC_ALARM_ENABLE_IT(&hRTC_Handle, RTC_IT_ALRA);
324   /* Enable the write protection for RTC registers */
325   __HAL_RTC_WRITEPROTECTION_ENABLE(&hRTC_Handle);
326 }
327 
328 /**
329   * @brief  Alarm Timer Event Callback in non blocking mode
330   * @note   This function is called when RTC Alarm takes place, inside
331   *         HAL_RTC_AlarmIRQHandler(). It makes a direct call to HAL_IncTick() to increment
332   *         a global variable "uwTick" used as application time base.
333   * @param  hrtc  RTC handle
334   * @retval None
335   */
HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef * hrtc)336 void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
337 {
338   HAL_IncTick();
339 }
340 
341 /**
342   * @brief  This function handles Alarm interrupt request.
343   * @retval None
344   */
RTC_Alarm_IRQHandler(void)345 void RTC_Alarm_IRQHandler(void)
346 {
347   HAL_RTC_AlarmIRQHandler(&hRTC_Handle);
348 }
349 
350 /**
351   * @}
352   */
353 
354 /**
355   * @}
356   */
357