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>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
14   *
15   * Redistribution and use in source and binary forms, with or without modification,
16   * are permitted provided that the following conditions are met:
17   *   1. Redistributions of source code must retain the above copyright notice,
18   *      this list of conditions and the following disclaimer.
19   *   2. Redistributions in binary form must reproduce the above copyright notice,
20   *      this list of conditions and the following disclaimer in the documentation
21   *      and/or other materials provided with the distribution.
22   *   3. Neither the name of STMicroelectronics nor the names of its contributors
23   *      may be used to endorse or promote products derived from this software
24   *      without specific prior written permission.
25   *
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
30   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36   *
37   ******************************************************************************
38   */
39 
40 /* Includes ------------------------------------------------------------------*/
41 #include "stm32l1xx_hal.h"
42 
43 /** @addtogroup STM32L1xx_HAL_Driver
44   * @{
45   */
46 
47 #ifdef HAL_RCC_MODULE_ENABLED
48 
49 /** @defgroup RCCEx RCCEx
50   * @brief RCC Extension HAL module driver
51   * @{
52   */
53 
54 /* Private typedef -----------------------------------------------------------*/
55 /* Private define ------------------------------------------------------------*/
56 /** @defgroup RCCEx_Private_Constants RCCEx Private Constants
57   * @{
58   */
59 /**
60   * @}
61   */
62 
63 /* Private macro -------------------------------------------------------------*/
64 /** @defgroup RCCEx_Private_Macros RCCEx Private Macros
65   * @{
66   */
67 /**
68   * @}
69   */
70 
71 /* Private variables ---------------------------------------------------------*/
72 /* Private function prototypes -----------------------------------------------*/
73 /* Private functions ---------------------------------------------------------*/
74 
75 /** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
76   * @{
77   */
78 
79 /** @defgroup RCCEx_Exported_Functions_Group1 Extended Peripheral Control functions
80  *  @brief  Extended Peripheral Control functions
81  *
82 @verbatim
83  ===============================================================================
84                 ##### Extended Peripheral Control functions  #####
85  ===============================================================================
86     [..]
87     This subsection provides a set of functions allowing to control the RCC Clocks
88     frequencies.
89     [..]
90     (@) Important note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to
91         select the RTC clock source; in this case the Backup domain will be reset in
92         order to modify the RTC Clock source, as consequence RTC registers (including
93         the backup registers) are set to their reset values.
94 
95 @endverbatim
96   * @{
97   */
98 
99 /**
100   * @brief  Initializes the RCC extended peripherals clocks according to the specified
101   *         parameters in the RCC_PeriphCLKInitTypeDef.
102   * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
103   *         contains the configuration information for the Extended Peripherals clocks(RTC/LCD clock).
104   * @retval HAL status
105   * @note   If HAL_ERROR returned, first switch-OFF HSE clock oscillator with @ref HAL_RCC_OscConfig()
106   *         to possibly update HSE divider.
107   */
HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)108 HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
109 {
110   uint32_t tickstart = 0U;
111   uint32_t temp_reg = 0U;
112 
113   /* Check the parameters */
114   assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
115 
116   /*------------------------------- RTC/LCD Configuration ------------------------*/
117   if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
118 #if defined(LCD)
119    || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
120 #endif /* LCD */
121      )
122   {
123     /* check for RTC Parameters used to output RTCCLK */
124     if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
125     {
126       assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
127     }
128 
129 #if defined(LCD)
130     if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
131     {
132       assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->LCDClockSelection));
133     }
134 #endif /* LCD */
135 
136     FlagStatus       pwrclkchanged = RESET;
137 
138     /* As soon as function is called to change RTC clock source, activation of the
139        power domain is done. */
140     /* Requires to enable write access to Backup Domain of necessary */
141     if(__HAL_RCC_PWR_IS_CLK_DISABLED())
142     {
143       __HAL_RCC_PWR_CLK_ENABLE();
144       pwrclkchanged = SET;
145     }
146 
147     if(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
148     {
149       /* Enable write access to Backup domain */
150       SET_BIT(PWR->CR, PWR_CR_DBP);
151 
152       /* Wait for Backup domain Write protection disable */
153       tickstart = HAL_GetTick();
154 
155       while(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
156       {
157         if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
158         {
159           return HAL_TIMEOUT;
160         }
161       }
162     }
163 
164     /* Check if user wants to change HSE RTC prescaler whereas HSE is enabled */
165     temp_reg = (RCC->CR & RCC_CR_RTCPRE);
166     if ((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CR_RTCPRE))
167 #if defined (LCD)
168      || (temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CR_RTCPRE))
169 #endif /* LCD */
170        )
171     { /* Check HSE State */
172       if (((PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL) == RCC_CSR_RTCSEL_HSE) && HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY))
173       {
174         /* To update HSE divider, first switch-OFF HSE clock oscillator*/
175         return HAL_ERROR;
176       }
177     }
178 
179     /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
180     temp_reg = (RCC->CSR & RCC_CSR_RTCSEL);
181 
182     if((temp_reg != 0x00000000U) && (((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL)) \
183       && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC))
184 #if defined(LCD)
185       || ((temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CSR_RTCSEL)) \
186        && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD))
187 #endif /* LCD */
188      ))
189     {
190       /* Store the content of CSR register before the reset of Backup Domain */
191       temp_reg = (RCC->CSR & ~(RCC_CSR_RTCSEL));
192 
193       /* RTC Clock selection can be changed only if the Backup Domain is reset */
194       __HAL_RCC_BACKUPRESET_FORCE();
195       __HAL_RCC_BACKUPRESET_RELEASE();
196 
197       /* Restore the Content of CSR register */
198       RCC->CSR = temp_reg;
199 
200        /* Wait for LSERDY if LSE was enabled */
201       if (HAL_IS_BIT_SET(temp_reg, RCC_CSR_LSEON))
202       {
203         /* Get Start Tick */
204         tickstart = HAL_GetTick();
205 
206         /* Wait till LSE is ready */
207         while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
208         {
209           if((HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE)
210           {
211             return HAL_TIMEOUT;
212           }
213         }
214       }
215     }
216     __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
217 
218     /* Require to disable power clock if necessary */
219     if(pwrclkchanged == SET)
220     {
221       __HAL_RCC_PWR_CLK_DISABLE();
222     }
223   }
224 
225   return HAL_OK;
226 }
227 
228 /**
229   * @brief  Get the PeriphClkInit according to the internal RCC configuration registers.
230   * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
231   *         returns the configuration information for the Extended Peripherals clocks(RTC/LCD clocks).
232   * @retval None
233   */
HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)234 void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
235 {
236   uint32_t srcclk = 0U;
237 
238   /* Set all possible values for the extended clock type parameter------------*/
239   PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_RTC;
240 #if defined(LCD)
241   PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_LCD;
242 #endif /* LCD */
243 
244   /* Get the RTC/LCD configuration -----------------------------------------------*/
245   srcclk = __HAL_RCC_GET_RTC_SOURCE();
246   if (srcclk != RCC_RTCCLKSOURCE_HSE_DIV2)
247   {
248     /* Source clock is LSE or LSI*/
249     PeriphClkInit->RTCClockSelection = srcclk;
250   }
251   else
252   {
253     /* Source clock is HSE. Need to get the prescaler value*/
254     PeriphClkInit->RTCClockSelection = srcclk | (READ_BIT(RCC->CR, RCC_CR_RTCPRE));
255   }
256 #if defined(LCD)
257   PeriphClkInit->LCDClockSelection = PeriphClkInit->RTCClockSelection;
258 #endif /* LCD */
259 }
260 
261 /**
262   * @brief  Return the peripheral clock frequency
263   * @note   Return 0 if peripheral clock is unknown
264   * @param  PeriphClk Peripheral clock identifier
265   *         This parameter can be one of the following values:
266   *            @arg @ref RCC_PERIPHCLK_RTC      RTC peripheral clock
267   *            @arg @ref RCC_PERIPHCLK_LCD      LCD peripheral clock (*)
268   * @note   (*) means that this peripheral is not present on all the devices
269   * @retval Frequency in Hz (0: means that no available frequency for the peripheral)
270   */
HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)271 uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
272 {
273   uint32_t temp_reg = 0U, clkprediv = 0U, frequency = 0U;
274   uint32_t srcclk = 0U;
275 
276   /* Check the parameters */
277   assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
278 
279   switch (PeriphClk)
280   {
281   case RCC_PERIPHCLK_RTC:
282 #if defined(LCD)
283   case RCC_PERIPHCLK_LCD:
284 #endif /* LCD */
285     {
286       /* Get RCC CSR configuration ------------------------------------------------------*/
287       temp_reg = RCC->CSR;
288 
289       /* Get the current RTC source */
290       srcclk = __HAL_RCC_GET_RTC_SOURCE();
291 
292       /* Check if LSE is ready if RTC clock selection is LSE */
293       if ((srcclk == RCC_RTCCLKSOURCE_LSE) && (HAL_IS_BIT_SET(temp_reg, RCC_CSR_LSERDY)))
294       {
295         frequency = LSE_VALUE;
296       }
297       /* Check if LSI is ready if RTC clock selection is LSI */
298       else if ((srcclk == RCC_RTCCLKSOURCE_LSI) && (HAL_IS_BIT_SET(temp_reg, RCC_CSR_LSIRDY)))
299       {
300         frequency = LSI_VALUE;
301       }
302       /* Check if HSE is ready and if RTC clock selection is HSE */
303       else if ((srcclk == RCC_RTCCLKSOURCE_HSE_DIVX) && (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)))
304       {
305         /* Get the current HSE clock divider */
306         clkprediv = __HAL_RCC_GET_RTC_HSE_PRESCALER();
307 
308         switch (clkprediv)
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       /* Clock not enabled for RTC */
333       else
334       {
335         frequency = 0U;
336       }
337       break;
338     }
339   default:
340     {
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