1 /**
2 ******************************************************************************
3 * @file stm32l1xx_hal_rcc_ex.c
4 * @author MCD Application Team
5 * @brief Extended RCC HAL module driver.
6 * This file provides firmware functions to manage the following
7 * functionalities RCC extension peripheral:
8 * + Extended Peripheral Control functions
9 *
10 ******************************************************************************
11 * @attention
12 *
13 * <h2><center>© Copyright(c) 2017 STMicroelectronics.
14 * All rights reserved.</center></h2>
15 *
16 * This software component is licensed by ST under BSD 3-Clause license,
17 * the "License"; You may not use this file except in compliance with the
18 * License. You may obtain a copy of the License at:
19 * opensource.org/licenses/BSD-3-Clause
20 *
21 ******************************************************************************
22 */
23
24 /* Includes ------------------------------------------------------------------*/
25 #include "stm32l1xx_hal.h"
26
27 /** @addtogroup STM32L1xx_HAL_Driver
28 * @{
29 */
30
31 #ifdef HAL_RCC_MODULE_ENABLED
32
33 /** @defgroup RCCEx RCCEx
34 * @brief RCC Extension HAL module driver
35 * @{
36 */
37
38 /* Private typedef -----------------------------------------------------------*/
39 /* Private define ------------------------------------------------------------*/
40 /** @defgroup RCCEx_Private_Constants RCCEx Private Constants
41 * @{
42 */
43 /**
44 * @}
45 */
46
47 /* Private macro -------------------------------------------------------------*/
48 /** @defgroup RCCEx_Private_Macros RCCEx Private Macros
49 * @{
50 */
51 /**
52 * @}
53 */
54
55 /* Private variables ---------------------------------------------------------*/
56 /* Private function prototypes -----------------------------------------------*/
57 /* Private functions ---------------------------------------------------------*/
58
59 /** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
60 * @{
61 */
62
63 /** @defgroup RCCEx_Exported_Functions_Group1 Extended Peripheral Control functions
64 * @brief Extended Peripheral Control functions
65 *
66 @verbatim
67 ===============================================================================
68 ##### Extended Peripheral Control functions #####
69 ===============================================================================
70 [..]
71 This subsection provides a set of functions allowing to control the RCC Clocks
72 frequencies.
73 [..]
74 (@) Important note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to
75 select the RTC clock source; in this case the Backup domain will be reset in
76 order to modify the RTC Clock source, as consequence RTC registers (including
77 the backup registers) are set to their reset values.
78
79 @endverbatim
80 * @{
81 */
82
83 /**
84 * @brief Initializes the RCC extended peripherals clocks according to the specified
85 * parameters in the RCC_PeriphCLKInitTypeDef.
86 * @param PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
87 * contains the configuration information for the Extended Peripherals clocks(RTC/LCD clock).
88 * @retval HAL status
89 * @note If HAL_ERROR returned, first switch-OFF HSE clock oscillator with @ref HAL_RCC_OscConfig()
90 * to possibly update HSE divider.
91 */
HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)92 HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
93 {
94 uint32_t tickstart;
95 uint32_t temp_reg;
96
97 /* Check the parameters */
98 assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
99
100 /*------------------------------- RTC/LCD Configuration ------------------------*/
101 if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
102 #if defined(LCD)
103 || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
104 #endif /* LCD */
105 )
106 {
107 /* check for RTC Parameters used to output RTCCLK */
108 if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
109 {
110 assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
111 }
112
113 #if defined(LCD)
114 if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
115 {
116 assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->LCDClockSelection));
117 }
118 #endif /* LCD */
119
120 FlagStatus pwrclkchanged = RESET;
121
122 /* As soon as function is called to change RTC clock source, activation of the
123 power domain is done. */
124 /* Requires to enable write access to Backup Domain of necessary */
125 if(__HAL_RCC_PWR_IS_CLK_DISABLED())
126 {
127 __HAL_RCC_PWR_CLK_ENABLE();
128 pwrclkchanged = SET;
129 }
130
131 if(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
132 {
133 /* Enable write access to Backup domain */
134 SET_BIT(PWR->CR, PWR_CR_DBP);
135
136 /* Wait for Backup domain Write protection disable */
137 tickstart = HAL_GetTick();
138
139 while(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
140 {
141 if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
142 {
143 return HAL_TIMEOUT;
144 }
145 }
146 }
147
148 /* Check if user wants to change HSE RTC prescaler whereas HSE is enabled */
149 temp_reg = (RCC->CR & RCC_CR_RTCPRE);
150 if ((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CR_RTCPRE))
151 #if defined (LCD)
152 || (temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CR_RTCPRE))
153 #endif /* LCD */
154 )
155 { /* Check HSE State */
156 if ((PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL) == RCC_CSR_RTCSEL_HSE)
157 {
158 if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY))
159 {
160 /* To update HSE divider, first switch-OFF HSE clock oscillator*/
161 return HAL_ERROR;
162 }
163 }
164 }
165
166 /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
167 temp_reg = (RCC->CSR & RCC_CSR_RTCSEL);
168
169 if((temp_reg != 0x00000000U) && (((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL)) \
170 && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC))
171 #if defined(LCD)
172 || ((temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CSR_RTCSEL)) \
173 && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD))
174 #endif /* LCD */
175 ))
176 {
177 /* Store the content of CSR register before the reset of Backup Domain */
178 temp_reg = (RCC->CSR & ~(RCC_CSR_RTCSEL));
179
180 /* RTC Clock selection can be changed only if the Backup Domain is reset */
181 __HAL_RCC_BACKUPRESET_FORCE();
182 __HAL_RCC_BACKUPRESET_RELEASE();
183
184 /* Restore the Content of CSR register */
185 RCC->CSR = temp_reg;
186
187 /* Wait for LSERDY if LSE was enabled */
188 if (HAL_IS_BIT_SET(temp_reg, RCC_CSR_LSEON))
189 {
190 /* Get Start Tick */
191 tickstart = HAL_GetTick();
192
193 /* Wait till LSE is ready */
194 while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == 0U)
195 {
196 if((HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE)
197 {
198 return HAL_TIMEOUT;
199 }
200 }
201 }
202 }
203 #if defined(LCD)
204 if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
205 {
206 __HAL_RCC_LCD_CONFIG(PeriphClkInit->LCDClockSelection);
207 }
208 #endif /* LCD */
209
210 if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
211 {
212 __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
213 }
214
215 /* Require to disable power clock if necessary */
216 if(pwrclkchanged == SET)
217 {
218 __HAL_RCC_PWR_CLK_DISABLE();
219 }
220 }
221
222 return HAL_OK;
223 }
224
225 /**
226 * @brief Get the PeriphClkInit according to the internal RCC configuration registers.
227 * @param PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
228 * returns the configuration information for the Extended Peripherals clocks(RTC/LCD clocks).
229 * @retval None
230 */
HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)231 void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
232 {
233 uint32_t srcclk;
234
235 /* Set all possible values for the extended clock type parameter------------*/
236 PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_RTC;
237 #if defined(LCD)
238 PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_LCD;
239 #endif /* LCD */
240
241 /* Get the RTC/LCD configuration -----------------------------------------------*/
242 srcclk = __HAL_RCC_GET_RTC_SOURCE();
243 if (srcclk != RCC_RTCCLKSOURCE_HSE_DIV2)
244 {
245 /* Source clock is LSE or LSI*/
246 PeriphClkInit->RTCClockSelection = srcclk;
247 }
248 else
249 {
250 /* Source clock is HSE. Need to get the prescaler value*/
251 PeriphClkInit->RTCClockSelection = srcclk | (READ_BIT(RCC->CR, RCC_CR_RTCPRE));
252 }
253 #if defined(LCD)
254 PeriphClkInit->LCDClockSelection = PeriphClkInit->RTCClockSelection;
255 #endif /* LCD */
256 }
257
258 /**
259 * @brief Return the peripheral clock frequency
260 * @note Return 0 if peripheral clock is unknown
261 * @param PeriphClk Peripheral clock identifier
262 * This parameter can be one of the following values:
263 * @arg @ref RCC_PERIPHCLK_RTC RTC peripheral clock
264 * @arg @ref RCC_PERIPHCLK_LCD LCD peripheral clock (*)
265 * @note (*) means that this peripheral is not present on all the devices
266 * @retval Frequency in Hz (0: means that no available frequency for the peripheral)
267 */
HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)268 uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
269 {
270 uint32_t frequency = 0;
271 uint32_t srcclk;
272
273 /* Check the parameters */
274 assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
275
276 switch (PeriphClk)
277 {
278 case RCC_PERIPHCLK_RTC:
279 #if defined(LCD)
280 case RCC_PERIPHCLK_LCD:
281 #endif /* LCD */
282 {
283 /* Get the current RTC source */
284 srcclk = __HAL_RCC_GET_RTC_SOURCE();
285
286 /* Check if LSE is ready if RTC clock selection is LSE */
287 if (srcclk == RCC_RTCCLKSOURCE_LSE)
288 {
289 if (HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSERDY))
290 {
291 frequency = LSE_VALUE;
292 }
293 }
294 /* Check if LSI is ready if RTC clock selection is LSI */
295 else if (srcclk == RCC_RTCCLKSOURCE_LSI)
296 {
297 if (HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSIRDY))
298 {
299 frequency = LSI_VALUE;
300 }
301 }
302 /* Check if HSE is ready and if RTC clock selection is HSE */
303 else if (srcclk == RCC_RTCCLKSOURCE_HSE_DIVX)
304 {
305 if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY))
306 {
307 /* Get the current HSE clock divider */
308 switch (__HAL_RCC_GET_RTC_HSE_PRESCALER())
309 {
310 case RCC_RTC_HSE_DIV_16: /* HSE DIV16 has been selected */
311 {
312 frequency = HSE_VALUE / 16U;
313 break;
314 }
315 case RCC_RTC_HSE_DIV_8: /* HSE DIV8 has been selected */
316 {
317 frequency = HSE_VALUE / 8U;
318 break;
319 }
320 case RCC_RTC_HSE_DIV_4: /* HSE DIV4 has been selected */
321 {
322 frequency = HSE_VALUE / 4U;
323 break;
324 }
325 default: /* HSE DIV2 has been selected */
326 {
327 frequency = HSE_VALUE / 2U;
328 break;
329 }
330 }
331 }
332 }
333 else
334 {
335 /* No clock source, frequency default init at 0 */
336 }
337 break;
338 }
339
340 default:
341 break;
342 }
343
344 return(frequency);
345 }
346
347 #if defined(RCC_LSECSS_SUPPORT)
348 /**
349 * @brief Enables the LSE Clock Security System.
350 * @note If a failure is detected on the external 32 kHz oscillator, the LSE clock is no longer supplied
351 * to the RTC but no hardware action is made to the registers.
352 * In Standby mode a wakeup is generated. In other modes an interrupt can be sent to wakeup
353 * the software (see Section 5.3.4: Clock interrupt register (RCC_CIR) on page 104).
354 * The software MUST then disable the LSECSSON bit, stop the defective 32 kHz oscillator
355 * (disabling LSEON), and can change the RTC clock source (no clock or LSI or HSE, with
356 * RTCSEL), or take any required action to secure the application.
357 * @note LSE CSS available only for high density and medium+ devices
358 * @retval None
359 */
HAL_RCCEx_EnableLSECSS(void)360 void HAL_RCCEx_EnableLSECSS(void)
361 {
362 *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)ENABLE;
363 }
364
365 /**
366 * @brief Disables the LSE Clock Security System.
367 * @note Once enabled this bit cannot be disabled, except after an LSE failure detection
368 * (LSECSSD=1). In that case the software MUST disable the LSECSSON bit.
369 * Reset by power on reset and RTC software reset (RTCRST bit).
370 * @note LSE CSS available only for high density and medium+ devices
371 * @retval None
372 */
HAL_RCCEx_DisableLSECSS(void)373 void HAL_RCCEx_DisableLSECSS(void)
374 {
375 /* Disable LSE CSS */
376 *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)DISABLE;
377
378 /* Disable LSE CSS IT */
379 __HAL_RCC_DISABLE_IT(RCC_IT_LSECSS);
380 }
381
382 /**
383 * @brief Enable the LSE Clock Security System IT & corresponding EXTI line.
384 * @note LSE Clock Security System IT is mapped on RTC EXTI line 19
385 * @retval None
386 */
HAL_RCCEx_EnableLSECSS_IT(void)387 void HAL_RCCEx_EnableLSECSS_IT(void)
388 {
389 /* Enable LSE CSS */
390 *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)ENABLE;
391
392 /* Enable LSE CSS IT */
393 __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS);
394
395 /* Enable IT on EXTI Line 19 */
396 __HAL_RCC_LSECSS_EXTI_ENABLE_IT();
397 __HAL_RCC_LSECSS_EXTI_ENABLE_RISING_EDGE();
398 }
399
400 /**
401 * @brief Handle the RCC LSE Clock Security System interrupt request.
402 * @retval None
403 */
HAL_RCCEx_LSECSS_IRQHandler(void)404 void HAL_RCCEx_LSECSS_IRQHandler(void)
405 {
406 /* Check RCC LSE CSSF flag */
407 if(__HAL_RCC_GET_IT(RCC_IT_LSECSS))
408 {
409 /* RCC LSE Clock Security System interrupt user callback */
410 HAL_RCCEx_LSECSS_Callback();
411
412 /* Clear RCC LSE CSS pending bit */
413 __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS);
414 }
415 }
416
417 /**
418 * @brief RCCEx LSE Clock Security System interrupt callback.
419 * @retval none
420 */
HAL_RCCEx_LSECSS_Callback(void)421 __weak void HAL_RCCEx_LSECSS_Callback(void)
422 {
423 /* NOTE : This function should not be modified, when the callback is needed,
424 the @ref HAL_RCCEx_LSECSS_Callback should be implemented in the user file
425 */
426 }
427 #endif /* RCC_LSECSS_SUPPORT */
428
429 /**
430 * @}
431 */
432
433 /**
434 * @}
435 */
436
437 /**
438 * @}
439 */
440
441 /**
442 * @}
443 */
444
445 #endif /* HAL_RCC_MODULE_ENABLED */
446 /**
447 * @}
448 */
449
450 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
451