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