1 /**
2   ******************************************************************************
3   * @file    stm32c0xx_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 extended peripheral:
8   *           + Extended Peripheral Control functions
9   *           + Extended Clock management functions
10   *
11   ******************************************************************************
12   * @attention
13   *
14   * Copyright (c) 2022 STMicroelectronics.
15   * All rights reserved.
16   *
17   * This software is licensed under terms that can be found in the LICENSE file
18   * in the root directory of this software component.
19   * If no LICENSE file comes with this software, it is provided AS-IS.
20   *
21   ******************************************************************************
22   */
23 
24 /* Includes ------------------------------------------------------------------*/
25 #include "stm32c0xx_hal.h"
26 
27 /** @addtogroup STM32C0xx_HAL_Driver
28   * @{
29   */
30 
31 /** @defgroup RCCEx RCCEx
32   * @brief RCC Extended HAL module driver
33   * @{
34   */
35 
36 #ifdef HAL_RCC_MODULE_ENABLED
37 
38 /* Private typedef -----------------------------------------------------------*/
39 /* Private defines -----------------------------------------------------------*/
40 /** @defgroup RCCEx_Private_Constants RCCEx Private Constants
41   * @{
42   */
43 #define LSCO_CLK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()
44 #define LSCO_GPIO_PORT        GPIOA
45 #define LSCO_PIN              GPIO_PIN_2
46 /**
47   * @}
48   */
49 
50 /* Private macros ------------------------------------------------------------*/
51 /* Private variables ---------------------------------------------------------*/
52 /* Private function prototypes -----------------------------------------------*/
53 /* Exported functions --------------------------------------------------------*/
54 
55 /** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
56   * @{
57   */
58 
59 /** @defgroup RCCEx_Exported_Functions_Group1 Extended Peripheral Control functions
60   *  @brief  Extended Peripheral Control functions
61   *
62 @verbatim
63  ===============================================================================
64                 ##### Extended Peripheral Control functions  #####
65  ===============================================================================
66     [..]
67     This subsection provides a set of functions allowing to control the RCC Clocks
68     frequencies.
69     [..]
70     (@) Important note: Care must be taken when @ref HAL_RCCEx_PeriphCLKConfig() is used to
71         select the RTC clock source; as consequence RTC registers and RCC_CSR1 register are
72         set to their reset values.
73 
74 @endverbatim
75   * @{
76   */
77 /**
78   * @brief  Initialize the RCC extended peripherals clocks according to the specified
79   *         parameters in the @ref RCC_PeriphCLKInitTypeDef.
80   * @param  PeriphClkInit  pointer to a @ref RCC_PeriphCLKInitTypeDef structure that
81   *         contains a field PeriphClockSelection which can be a combination of the following values:
82   *            @arg @ref RCC_PERIPHCLK_RTC  RTC peripheral clock
83   *            @arg @ref RCC_PERIPHCLK_ADC    ADC peripheral clock
84   *            @arg @ref RCC_PERIPHCLK_I2C1   I2C1 peripheral clock
85   *            @arg @ref RCC_PERIPHCLK_I2S1   I2S1 peripheral clock
86   *            @arg @ref RCC_PERIPHCLK_USART1 USART1 peripheral clock
87   *            @arg @ref RCC_PERIPHCLK_USB     USB peripheral clock (*)
88   * @note   Care must be taken when @ref HAL_RCCEx_PeriphCLKConfig() is used to select
89   *         the RTC clock source: in this case the access to RTC domain is enabled.
90   * @note (*) not available on all devices
91   *
92   * @retval HAL status
93   */
HAL_RCCEx_PeriphCLKConfig(const RCC_PeriphCLKInitTypeDef * PeriphClkInit)94 HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(const RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
95 {
96   uint32_t tmpregister;
97   uint32_t tickstart;
98   HAL_StatusTypeDef ret    = HAL_OK;   /* Intermediate status */
99   HAL_StatusTypeDef status = HAL_OK;   /* Final status */
100 
101   /* Check the parameters */
102   assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
103 
104   /*-------------------------- RTC clock source configuration ----------------------*/
105   if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
106   {
107     FlagStatus       pwrclkchanged = RESET;
108 
109     /* Check for RTC Parameters used to output RTCCLK */
110     assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
111 
112     /* Enable Power Clock */
113     if (__HAL_RCC_PWR_IS_CLK_DISABLED())
114     {
115       __HAL_RCC_PWR_CLK_ENABLE();
116       pwrclkchanged = SET;
117     }
118 
119 
120     /* Reset the RTC domain only if the RTC Clock source selection is modified from default */
121     tmpregister = READ_BIT(RCC->CSR1, RCC_CSR1_RTCSEL);
122 
123     /* Reset the RTC domain only if the RTC Clock source selection is modified */
124     if ((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection))
125     {
126       /* Store the content of CSR1 register before the reset of RTC Domain */
127       tmpregister = READ_BIT(RCC->CSR1, ~(RCC_CSR1_RTCSEL));
128       /* RTC Clock selection can be changed only if the RTC Domain is reset */
129       __HAL_RCC_BACKUPRESET_FORCE();
130       __HAL_RCC_BACKUPRESET_RELEASE();
131       /* Restore the Content of CSR1 register */
132       RCC->CSR1 = tmpregister;
133     }
134 
135     /* Wait for LSE reactivation if LSE was enable prior to RTC Domain reset */
136     if (HAL_IS_BIT_SET(tmpregister, RCC_CSR1_LSEON))
137     {
138       /* Get Start Tick*/
139       tickstart = HAL_GetTick();
140 
141       /* Wait till LSE is ready */
142       while (READ_BIT(RCC->CSR1, RCC_CSR1_LSERDY) == 0U)
143       {
144         if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
145         {
146           ret = HAL_TIMEOUT;
147           break;
148         }
149       }
150     }
151 
152     if (ret == HAL_OK)
153     {
154       /* Apply new RTC clock source selection */
155       __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
156     }
157     else
158     {
159       /* set overall return value */
160       status = ret;
161     }
162 
163     /* Restore clock configuration if changed */
164     if (pwrclkchanged == SET)
165     {
166       __HAL_RCC_PWR_CLK_DISABLE();
167     }
168   }
169 
170   /*-------------------------- USART1 clock source configuration -------------------*/
171   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART1) == RCC_PERIPHCLK_USART1)
172   {
173     /* Check the parameters */
174     assert_param(IS_RCC_USART1CLKSOURCE(PeriphClkInit->Usart1ClockSelection));
175 
176     /* Configure the USART1 clock source */
177     __HAL_RCC_USART1_CONFIG(PeriphClkInit->Usart1ClockSelection);
178   }
179 
180   /*-------------------------- I2C1 clock source configuration ---------------------*/
181   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C1) == RCC_PERIPHCLK_I2C1)
182   {
183     /* Check the parameters */
184     assert_param(IS_RCC_I2C1CLKSOURCE(PeriphClkInit->I2c1ClockSelection));
185 
186     /* Configure the I2C1 clock source */
187     __HAL_RCC_I2C1_CONFIG(PeriphClkInit->I2c1ClockSelection);
188   }
189 
190   /*-------------------------- ADC clock source configuration ----------------------*/
191   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_ADC) == RCC_PERIPHCLK_ADC)
192   {
193     /* Check the parameters */
194     assert_param(IS_RCC_ADCCLKSOURCE(PeriphClkInit->AdcClockSelection));
195 
196     /* Configure the ADC interface clock source */
197     __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection);
198 
199   }
200 #if defined (USB_DRD_FS)
201   /*-------------------------- USB clock source configuration ----------------*/
202   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USB) == RCC_PERIPHCLK_USB)
203   {
204     /* Check the parameters */
205     assert_param(IS_RCC_USBCLKSOURCE(PeriphClkInit->UsbClockSelection));
206 
207     /* Configure the USB clock source */
208     __HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection);
209 
210   }
211 #endif /* USB_DRD_FS */
212   /*-------------------------- I2S1 clock source configuration ---------------------*/
213   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S1) == RCC_PERIPHCLK_I2S1)
214   {
215     /* Check the parameters */
216     assert_param(IS_RCC_I2S1CLKSOURCE(PeriphClkInit->I2s1ClockSelection));
217 
218     /* Configure the I2S1 clock source */
219     __HAL_RCC_I2S1_CONFIG(PeriphClkInit->I2s1ClockSelection);
220   }
221   /*------------------------------------ HSI Kernel clock source configuration --------------------------------------*/
222   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_HSIKER) == RCC_PERIPHCLK_HSIKER)
223   {
224     /* Check the parameters */
225     assert_param(IS_RCC_HSIKERDIV(PeriphClkInit->HSIKerClockDivider));
226 
227     /* Configure the HSI Kernel clock source Divider */
228     __HAL_RCC_HSIKER_CONFIG(PeriphClkInit->HSIKerClockDivider);
229   }
230   return status;
231 }
232 
233 /**
234   * @brief  Get the RCC_ClkInitStruct according to the internal RCC configuration registers.
235   * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
236   *         returns the configuration information for the Extended Peripherals
237   *         clocks: I2C1, I2S1, USART1, RTC, ADC,
238   * @retval None
239   */
HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)240 void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
241 {
242   /* Set all possible values for the extended clock type parameter------------*/
243   PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_I2C1 | RCC_PERIPHCLK_I2S1 | \
244                                         RCC_PERIPHCLK_ADC    | RCC_PERIPHCLK_RTC  | RCC_PERIPHCLK_HSIKER ;
245 
246 #if defined(USB_DRD_FS)
247   PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_USB;
248 #endif /* USB_DRD_FS */
249   /* Get the USART1 clock source ---------------------------------------------*/
250   PeriphClkInit->Usart1ClockSelection  = __HAL_RCC_GET_USART1_SOURCE();
251 
252   /* Get the I2C1 clock source -----------------------------------------------*/
253   PeriphClkInit->I2c1ClockSelection    = __HAL_RCC_GET_I2C1_SOURCE();
254 
255   /* Get the RTC clock source ------------------------------------------------*/
256   PeriphClkInit->RTCClockSelection     = __HAL_RCC_GET_RTC_SOURCE();
257 
258   /* Get the ADC clock source -----------------------------------------------*/
259   PeriphClkInit->AdcClockSelection     = __HAL_RCC_GET_ADC_SOURCE();
260 
261 #if defined (USB_DRD_FS)
262   /* Get the USB clock source -------------------------------------------------*/
263   PeriphClkInit->UsbClockSelection     = __HAL_RCC_GET_USB_SOURCE();
264 #endif /* USB_DRD_FS */
265 
266   /* Get the I2S1 clock source -----------------------------------------------*/
267   PeriphClkInit->I2s1ClockSelection    = __HAL_RCC_GET_I2S1_SOURCE();
268 
269   /* Get the HSI Kernel clock divider -----------------------------------------------*/
270   PeriphClkInit->HSIKerClockDivider    = __HAL_RCC_GET_HSIKER_DIVIDER();
271 }
272 
273 /**
274   * @brief  Return the peripheral clock frequency for peripherals
275   * @note   Return 0 if peripheral clock identifier not managed by this API
276   * @param  PeriphClk  Peripheral clock identifier
277   *         This parameter can be one of the following values:
278   *            @arg @ref RCC_PERIPHCLK_RTC     RTC peripheral clock
279   *            @arg @ref RCC_PERIPHCLK_ADC     ADC peripheral clock
280   *            @arg @ref RCC_PERIPHCLK_I2C1    I2C1 peripheral clock
281   *            @arg @ref RCC_PERIPHCLK_I2S1    I2S1 peripheral clock
282   *            @arg @ref RCC_PERIPHCLK_USART1  USART1 peripheral clock
283   *            @arg @ref RCC_PERIPHCLK_USB     USB peripheral clock (*)
284   * @note (*) not available on all devices
285   * @retval Frequency in Hz
286   */
HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)287 uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
288 {
289   uint32_t frequency = 0U;
290   uint32_t srcclk;
291 
292   /* Check the parameters */
293   assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
294 
295   if (PeriphClk == RCC_PERIPHCLK_RTC)
296   {
297     /* Get the current RTC source */
298     srcclk = __HAL_RCC_GET_RTC_SOURCE();
299 
300     /* Check if LSE is ready and if RTC clock selection is LSE */
301     if ((HAL_IS_BIT_SET(RCC->CSR1, RCC_CSR1_LSERDY)) && (srcclk == RCC_RTCCLKSOURCE_LSE))
302     {
303       frequency = LSE_VALUE;
304     }
305     /* Check if LSI is ready and if RTC clock selection is LSI */
306     else if ((HAL_IS_BIT_SET(RCC->CSR2, RCC_CSR2_LSIRDY)) && (srcclk == RCC_RTCCLKSOURCE_LSI))
307     {
308       frequency = LSI_VALUE;
309     }
310     /* Check if HSE is ready  and if RTC clock selection is HSI_DIV32*/
311     else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) && (srcclk == RCC_RTCCLKSOURCE_HSE_DIV32))
312     {
313       frequency = HSE_VALUE / 32U;
314     }
315     /* Clock not enabled for RTC*/
316     else
317     {
318       /* Nothing to do as frequency already initialized to 0U */
319     }
320   }
321   else
322   {
323     /* Other external peripheral clock source than RTC */
324 
325     switch (PeriphClk)
326     {
327 
328       case RCC_PERIPHCLK_USART1:
329         /* Get the current USART1 source */
330         srcclk = __HAL_RCC_GET_USART1_SOURCE();
331 
332         if (srcclk == RCC_USART1CLKSOURCE_PCLK1)            /* PCLK1 */
333         {
334           frequency = HAL_RCC_GetPCLK1Freq();
335         }
336         else if (srcclk == RCC_USART1CLKSOURCE_SYSCLK)     /* SYSCLK  */
337         {
338           frequency = HAL_RCC_GetSysClockFreq();
339         }
340         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_USART1CLKSOURCE_HSIKER))
341         {
342           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
343         }
344         else if ((HAL_IS_BIT_SET(RCC->CSR1, RCC_CSR1_LSERDY)) && (srcclk == RCC_USART1CLKSOURCE_LSE))
345         {
346           frequency = LSE_VALUE;
347         }
348         /* Clock not enabled for USART1 */
349         else
350         {
351           /* Nothing to do as frequency already initialized to 0U */
352         }
353         break;
354 
355       case RCC_PERIPHCLK_ADC:
356 
357         srcclk = __HAL_RCC_GET_ADC_SOURCE();
358 
359         if (srcclk == RCC_ADCCLKSOURCE_SYSCLK)
360         {
361           frequency = HAL_RCC_GetSysClockFreq();
362         }
363         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_ADCCLKSOURCE_HSIKER))
364         {
365           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
366         }
367         /* Clock not enabled for ADC */
368         else
369         {
370           /* Nothing to do as frequency already initialized to 0U */
371         }
372         break;
373 
374       case RCC_PERIPHCLK_I2C1:
375         /* Get the current I2C1 source */
376         srcclk = __HAL_RCC_GET_I2C1_SOURCE();
377 
378         if (srcclk == RCC_I2C1CLKSOURCE_PCLK1)
379         {
380           frequency = HAL_RCC_GetPCLK1Freq();
381         }
382         else if (srcclk == RCC_I2C1CLKSOURCE_SYSCLK)
383         {
384           frequency = HAL_RCC_GetSysClockFreq();
385         }
386         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_I2C1CLKSOURCE_HSIKER))
387         {
388           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
389         }
390         /* Clock not enabled for I2C1 */
391         else
392         {
393           /* Nothing to do as frequency already initialized to 0U */
394         }
395         break;
396 
397       case RCC_PERIPHCLK_I2S1:
398         /* Get the current I2S1 source */
399         srcclk = __HAL_RCC_GET_I2S1_SOURCE();
400 
401         if (srcclk == RCC_I2S1CLKSOURCE_SYSCLK)
402         {
403           frequency = HAL_RCC_GetSysClockFreq();
404         }
405         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_I2S1CLKSOURCE_HSIKER))
406         {
407           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
408         }
409         else if (srcclk == RCC_I2S1CLKSOURCE_EXT)
410         {
411           /* External clock used.*/
412           frequency = EXTERNAL_I2S1_CLOCK_VALUE;
413         }
414         /* Clock not enabled for I2S1 */
415         else
416         {
417           /* Nothing to do as frequency already initialized to 0U */
418         }
419         break;
420 #if defined (USB_DRD_FS)
421       case RCC_PERIPHCLK_USB:
422         /* Get the current USB source */
423         srcclk = __HAL_RCC_GET_USB_SOURCE();
424         if (srcclk == RCC_USBCLKSOURCE_HSI48)
425         {
426           frequency = HSI48_VALUE;
427         }
428         else if (srcclk == RCC_USBCLKSOURCE_HSE)
429         {
430           frequency = HSE_VALUE;
431         }
432         /* Clock not enabled for USB */
433         else
434         {
435           /* Nothing to do as frequency already initialized to 0U */
436         }
437 #endif /* USB_DRD_FS */
438       default:
439         break;
440     }
441   }
442 
443   return (frequency);
444 }
445 
446 /**
447   * @}
448   */
449 
450 /** @defgroup RCCEx_Exported_Functions_Group2 Extended Clock management functions
451   *  @brief  Extended Clock management functions
452   *
453 @verbatim
454  ===============================================================================
455                 ##### Extended clock management functions  #####
456  ===============================================================================
457     [..]
458     This subsection provides a set of functions allowing to control the
459     activation or deactivation of LSE CSS, Low speed clock output and
460     clock after wake-up from STOP mode.
461 @endverbatim
462   * @{
463   */
464 
465 /**
466   * @brief  Select the Low Speed clock source to output on LSCO pin (PA2).
467   * @param  LSCOSource  specifies the Low Speed clock source to output.
468   *          This parameter can be one of the following values:
469   *            @arg @ref RCC_LSCOSOURCE_LSI  LSI clock selected as LSCO source
470   *            @arg @ref RCC_LSCOSOURCE_LSE  LSE clock selected as LSCO source
471   * @retval None
472   */
HAL_RCCEx_EnableLSCO(uint32_t LSCOSource)473 void HAL_RCCEx_EnableLSCO(uint32_t LSCOSource)
474 {
475   GPIO_InitTypeDef GPIO_InitStruct;
476 
477   /* Check the parameters */
478   assert_param(IS_RCC_LSCOSOURCE(LSCOSource));
479 
480   /* LSCO Pin Clock Enable */
481   LSCO_CLK_ENABLE();
482 
483   /* configure the LSCO pin in analog mode */
484   GPIO_InitStruct.Pin = LSCO_PIN;
485   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
486   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
487   GPIO_InitStruct.Pull = GPIO_NOPULL;
488   HAL_GPIO_Init(LSCO_GPIO_PORT, &GPIO_InitStruct);
489 
490   MODIFY_REG(RCC->CSR1, RCC_CSR1_LSCOSEL | RCC_CSR1_LSCOEN, LSCOSource | RCC_CSR1_LSCOEN);
491 
492 }
493 
494 /**
495   * @brief  Disable the Low Speed clock output.
496   * @retval None
497   */
HAL_RCCEx_DisableLSCO(void)498 void HAL_RCCEx_DisableLSCO(void)
499 {
500 
501   CLEAR_BIT(RCC->CSR1, RCC_CSR1_LSCOEN);
502 
503 }
504 
505 /**
506   * @}
507   */
508 
509 #if defined(CRS)
510 
511 /** @defgroup RCCEx_Exported_Functions_Group3 Extended Clock Recovery System Control functions
512   * @brief  Extended Clock Recovery System Control functions
513   *
514 @verbatim
515  ===============================================================================
516                 ##### Extended Clock Recovery System Control functions  #####
517  ===============================================================================
518     [..]
519       For devices with Clock Recovery System feature (CRS), RCC Extension HAL driver can be used as follows:
520 
521       (#) In System clock config, HSI48 needs to be enabled
522 
523       (#) Enable CRS clock in IP MSP init which will use CRS functions
524 
525       (#) Call CRS functions as follows:
526           (##) Prepare synchronization configuration necessary for HSI48 calibration
527               (+++) Default values can be set for frequency Error Measurement (reload and error limit)
528                         and also HSI48 oscillator smooth trimming.
529               (+++) Macro __HAL_RCC_CRS_RELOADVALUE_CALCULATE can be also used to calculate
530                         directly reload value with target and synchronization frequencies values
531           (##) Call function HAL_RCCEx_CRSConfig which
532               (+++) Resets CRS registers to their default values.
533               (+++) Configures CRS registers with synchronization configuration
534               (+++) Enables automatic calibration and frequency error counter feature
535            Note: When using USB LPM (Link Power Management) and the device is in Sleep mode, the
536            periodic USB SOF will not be generated by the host. No SYNC signal will therefore be
537            provided to the CRS to calibrate the HSI48 on the run. To guarantee the required clock
538            precision after waking up from Sleep mode, the LSE or reference clock on the GPIOs
539            should be used as SYNC signal.
540 
541           (##) A polling function is provided to wait for complete synchronization
542               (+++) Call function HAL_RCCEx_CRSWaitSynchronization()
543               (+++) According to CRS status, user can decide to adjust again the calibration or continue
544                         application if synchronization is OK
545 
546       (#) User can retrieve information related to synchronization in calling function
547             HAL_RCCEx_CRSGetSynchronizationInfo()
548 
549       (#) Regarding synchronization status and synchronization information, user can try a new calibration
550            in changing synchronization configuration and call again HAL_RCCEx_CRSConfig.
551            Note: When the SYNC event is detected during the downcounting phase (before reaching the zero value),
552            it means that the actual frequency is lower than the target (and so, that the TRIM value should be
553            incremented), while when it is detected during the upcounting phase it means that the actual frequency
554            is higher (and that the TRIM value should be decremented).
555 
556       (#) In interrupt mode, user can resort to the available macros (__HAL_RCC_CRS_XXX_IT). Interrupts will go
557           through CRS Handler (CRS_IRQn/CRS_IRQHandler)
558               (++) Call function HAL_RCCEx_CRSConfig()
559               (++) Enable CRS_IRQn (thanks to NVIC functions)
560               (++) Enable CRS interrupt (__HAL_RCC_CRS_ENABLE_IT)
561               (++) Implement CRS status management in the following user callbacks called from
562                    HAL_RCCEx_CRS_IRQHandler():
563                    (+++) HAL_RCCEx_CRS_SyncOkCallback()
564                    (+++) HAL_RCCEx_CRS_SyncWarnCallback()
565                    (+++) HAL_RCCEx_CRS_ExpectedSyncCallback()
566                    (+++) HAL_RCCEx_CRS_ErrorCallback()
567 
568       (#) To force a SYNC EVENT, user can use the function HAL_RCCEx_CRSSoftwareSynchronizationGenerate().
569           This function can be called before calling HAL_RCCEx_CRSConfig (for instance in Systick handler)
570 
571 @endverbatim
572   * @{
573   */
574 
575 /**
576   * @brief  Start automatic synchronization for polling mode
577   * @param  pInit Pointer on RCC_CRSInitTypeDef structure
578   * @retval None
579   */
HAL_RCCEx_CRSConfig(RCC_CRSInitTypeDef * pInit)580 void HAL_RCCEx_CRSConfig(RCC_CRSInitTypeDef *pInit)
581 {
582   uint32_t value;  /* no init needed */
583 
584   /* Check the parameters */
585   assert_param(IS_RCC_CRS_SYNC_DIV(pInit->Prescaler));
586   assert_param(IS_RCC_CRS_SYNC_SOURCE(pInit->Source));
587   assert_param(IS_RCC_CRS_SYNC_POLARITY(pInit->Polarity));
588   assert_param(IS_RCC_CRS_RELOADVALUE(pInit->ReloadValue));
589   assert_param(IS_RCC_CRS_ERRORLIMIT(pInit->ErrorLimitValue));
590   assert_param(IS_RCC_CRS_HSI48CALIBRATION(pInit->HSI48CalibrationValue));
591 
592   /* CONFIGURATION */
593 
594   /* Before configuration, reset CRS registers to their default values*/
595   __HAL_RCC_CRS_FORCE_RESET();
596   __HAL_RCC_CRS_RELEASE_RESET();
597 
598   /* Set the SYNCDIV[2:0] bits according to Prescaler value */
599   /* Set the SYNCSRC[1:0] bits according to Source value */
600   /* Set the SYNCSPOL bit according to Polarity value */
601   value = (pInit->Prescaler | pInit->Source | pInit->Polarity);
602   /* Set the RELOAD[15:0] bits according to ReloadValue value */
603   value |= pInit->ReloadValue;
604   /* Set the FELIM[7:0] bits according to ErrorLimitValue value */
605   value |= (pInit->ErrorLimitValue << CRS_CFGR_FELIM_Pos);
606   WRITE_REG(CRS->CFGR, value);
607 
608   /* Adjust HSI48 oscillator smooth trimming */
609   /* Set the TRIM[6:0] bits according to RCC_CRS_HSI48CalibrationValue value */
610   MODIFY_REG(CRS->CR, CRS_CR_TRIM, (pInit->HSI48CalibrationValue << CRS_CR_TRIM_Pos));
611 
612   /* START AUTOMATIC SYNCHRONIZATION*/
613 
614   /* Enable Automatic trimming & Frequency error counter */
615   SET_BIT(CRS->CR, CRS_CR_AUTOTRIMEN | CRS_CR_CEN);
616 }
617 
618 /**
619   * @brief  Generate the software synchronization event
620   * @retval None
621   */
HAL_RCCEx_CRSSoftwareSynchronizationGenerate(void)622 void HAL_RCCEx_CRSSoftwareSynchronizationGenerate(void)
623 {
624   SET_BIT(CRS->CR, CRS_CR_SWSYNC);
625 }
626 
627 /**
628   * @brief  Return synchronization info
629   * @param  pSynchroInfo Pointer on RCC_CRSSynchroInfoTypeDef structure
630   * @retval None
631   */
HAL_RCCEx_CRSGetSynchronizationInfo(RCC_CRSSynchroInfoTypeDef * pSynchroInfo)632 void HAL_RCCEx_CRSGetSynchronizationInfo(RCC_CRSSynchroInfoTypeDef *pSynchroInfo)
633 {
634   /* Check the parameter */
635   assert_param(pSynchroInfo != (void *)NULL);
636 
637   /* Get the reload value */
638   pSynchroInfo->ReloadValue = (READ_BIT(CRS->CFGR, CRS_CFGR_RELOAD));
639 
640   /* Get HSI48 oscillator smooth trimming */
641   pSynchroInfo->HSI48CalibrationValue = (READ_BIT(CRS->CR, CRS_CR_TRIM) >> CRS_CR_TRIM_Pos);
642 
643   /* Get Frequency error capture */
644   pSynchroInfo->FreqErrorCapture = (READ_BIT(CRS->ISR, CRS_ISR_FECAP) >> CRS_ISR_FECAP_Pos);
645 
646   /* Get Frequency error direction */
647   pSynchroInfo->FreqErrorDirection = (READ_BIT(CRS->ISR, CRS_ISR_FEDIR));
648 }
649 
650 /**
651   * @brief Wait for CRS Synchronization status.
652   * @param Timeout  Duration of the timeout
653   * @note  Timeout is based on the maximum time to receive a SYNC event based on synchronization
654   *        frequency.
655   * @note    If Timeout set to HAL_MAX_DELAY, HAL_TIMEOUT will be never returned.
656   * @retval Combination of Synchronization status
657   *          This parameter can be a combination of the following values:
658   *            @arg @ref RCC_CRS_TIMEOUT
659   *            @arg @ref RCC_CRS_SYNCOK
660   *            @arg @ref RCC_CRS_SYNCWARN
661   *            @arg @ref RCC_CRS_SYNCERR
662   *            @arg @ref RCC_CRS_SYNCMISS
663   *            @arg @ref RCC_CRS_TRIMOVF
664   */
HAL_RCCEx_CRSWaitSynchronization(uint32_t Timeout)665 uint32_t HAL_RCCEx_CRSWaitSynchronization(uint32_t Timeout)
666 {
667   uint32_t crsstatus = RCC_CRS_NONE;
668   uint32_t tickstart;
669 
670   /* Get timeout */
671   tickstart = HAL_GetTick();
672 
673   /* Wait for CRS flag or timeout detection */
674   do
675   {
676     if (Timeout != HAL_MAX_DELAY)
677     {
678       if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
679       {
680         crsstatus = RCC_CRS_TIMEOUT;
681       }
682     }
683     /* Check CRS SYNCOK flag  */
684     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCOK))
685     {
686       /* CRS SYNC event OK */
687       crsstatus |= RCC_CRS_SYNCOK;
688 
689       /* Clear CRS SYNC event OK bit */
690       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCOK);
691     }
692 
693     /* Check CRS SYNCWARN flag  */
694     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCWARN))
695     {
696       /* CRS SYNC warning */
697       crsstatus |= RCC_CRS_SYNCWARN;
698 
699       /* Clear CRS SYNCWARN bit */
700       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCWARN);
701     }
702 
703     /* Check CRS TRIM overflow flag  */
704     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_TRIMOVF))
705     {
706       /* CRS SYNC Error */
707       crsstatus |= RCC_CRS_TRIMOVF;
708 
709       /* Clear CRS Error bit */
710       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_TRIMOVF);
711     }
712 
713     /* Check CRS Error flag  */
714     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCERR))
715     {
716       /* CRS SYNC Error */
717       crsstatus |= RCC_CRS_SYNCERR;
718 
719       /* Clear CRS Error bit */
720       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCERR);
721     }
722 
723     /* Check CRS SYNC Missed flag  */
724     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCMISS))
725     {
726       /* CRS SYNC Missed */
727       crsstatus |= RCC_CRS_SYNCMISS;
728 
729       /* Clear CRS SYNC Missed bit */
730       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCMISS);
731     }
732 
733     /* Check CRS Expected SYNC flag  */
734     if (__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_ESYNC))
735     {
736       /* frequency error counter reached a zero value */
737       __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_ESYNC);
738     }
739   } while (RCC_CRS_NONE == crsstatus);
740 
741   return crsstatus;
742 }
743 
744 /**
745   * @brief Handle the Clock Recovery System interrupt request.
746   * @retval None
747   */
HAL_RCCEx_CRS_IRQHandler(void)748 void HAL_RCCEx_CRS_IRQHandler(void)
749 {
750   uint32_t crserror = RCC_CRS_NONE;
751   /* Get current IT flags and IT sources values */
752   uint32_t itflags = READ_REG(CRS->ISR);
753   uint32_t itsources = READ_REG(CRS->CR);
754 
755   /* Check CRS SYNCOK flag  */
756   if (((itflags & RCC_CRS_FLAG_SYNCOK) != 0U) && ((itsources & RCC_CRS_IT_SYNCOK) != 0U))
757   {
758     /* Clear CRS SYNC event OK flag */
759     WRITE_REG(CRS->ICR, CRS_ICR_SYNCOKC);
760 
761     /* user callback */
762     HAL_RCCEx_CRS_SyncOkCallback();
763   }
764   /* Check CRS SYNCWARN flag  */
765   else if (((itflags & RCC_CRS_FLAG_SYNCWARN) != 0U) && ((itsources & RCC_CRS_IT_SYNCWARN) != 0U))
766   {
767     /* Clear CRS SYNCWARN flag */
768     WRITE_REG(CRS->ICR, CRS_ICR_SYNCWARNC);
769 
770     /* user callback */
771     HAL_RCCEx_CRS_SyncWarnCallback();
772   }
773   /* Check CRS Expected SYNC flag  */
774   else if (((itflags & RCC_CRS_FLAG_ESYNC) != 0U) && ((itsources & RCC_CRS_IT_ESYNC) != 0U))
775   {
776     /* frequency error counter reached a zero value */
777     WRITE_REG(CRS->ICR, CRS_ICR_ESYNCC);
778 
779     /* user callback */
780     HAL_RCCEx_CRS_ExpectedSyncCallback();
781   }
782   /* Check CRS Error flags  */
783   else
784   {
785     if (((itflags & RCC_CRS_FLAG_ERR) != 0U) && ((itsources & RCC_CRS_IT_ERR) != 0U))
786     {
787       if ((itflags & RCC_CRS_FLAG_SYNCERR) != 0U)
788       {
789         crserror |= RCC_CRS_SYNCERR;
790       }
791       if ((itflags & RCC_CRS_FLAG_SYNCMISS) != 0U)
792       {
793         crserror |= RCC_CRS_SYNCMISS;
794       }
795       if ((itflags & RCC_CRS_FLAG_TRIMOVF) != 0U)
796       {
797         crserror |= RCC_CRS_TRIMOVF;
798       }
799 
800       /* Clear CRS Error flags */
801       WRITE_REG(CRS->ICR, CRS_ICR_ERRC);
802 
803       /* user error callback */
804       HAL_RCCEx_CRS_ErrorCallback(crserror);
805     }
806   }
807 }
808 
809 /**
810   * @brief  RCCEx Clock Recovery System SYNCOK interrupt callback.
811   * @retval none
812   */
HAL_RCCEx_CRS_SyncOkCallback(void)813 __weak void HAL_RCCEx_CRS_SyncOkCallback(void)
814 {
815   /* NOTE : This function should not be modified, when the callback is needed,
816             the @ref HAL_RCCEx_CRS_SyncOkCallback should be implemented in the user file
817    */
818 }
819 
820 /**
821   * @brief  RCCEx Clock Recovery System SYNCWARN interrupt callback.
822   * @retval none
823   */
HAL_RCCEx_CRS_SyncWarnCallback(void)824 __weak void HAL_RCCEx_CRS_SyncWarnCallback(void)
825 {
826   /* NOTE : This function should not be modified, when the callback is needed,
827             the @ref HAL_RCCEx_CRS_SyncWarnCallback should be implemented in the user file
828    */
829 }
830 
831 /**
832   * @brief  RCCEx Clock Recovery System Expected SYNC interrupt callback.
833   * @retval none
834   */
HAL_RCCEx_CRS_ExpectedSyncCallback(void)835 __weak void HAL_RCCEx_CRS_ExpectedSyncCallback(void)
836 {
837   /* NOTE : This function should not be modified, when the callback is needed,
838             the @ref HAL_RCCEx_CRS_ExpectedSyncCallback should be implemented in the user file
839    */
840 }
841 
842 /**
843   * @brief  RCCEx Clock Recovery System Error interrupt callback.
844   * @param  Error Combination of Error status.
845   *         This parameter can be a combination of the following values:
846   *           @arg @ref RCC_CRS_SYNCERR
847   *           @arg @ref RCC_CRS_SYNCMISS
848   *           @arg @ref RCC_CRS_TRIMOVF
849   * @retval none
850   */
HAL_RCCEx_CRS_ErrorCallback(uint32_t Error)851 __weak void HAL_RCCEx_CRS_ErrorCallback(uint32_t Error)
852 {
853   /* Prevent unused argument(s) compilation warning */
854   UNUSED(Error);
855 
856   /* NOTE : This function should not be modified, when the callback is needed,
857             the @ref HAL_RCCEx_CRS_ErrorCallback should be implemented in the user file
858    */
859 }
860 
861 /**
862   * @}
863   */
864 
865 #endif /* CRS */
866 /**
867   * @}
868   */
869 
870 /**
871   * @}
872   */
873 
874 #endif /* HAL_RCC_MODULE_ENABLED */
875 /**
876   * @}
877   */
878 
879 /**
880   * @}
881   */
882