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   * @note   Care must be taken when @ref HAL_RCCEx_PeriphCLKConfig() is used to select
88   *         the RTC clock source: in this case the access to RTC domain is enabled.
89   *
90   * @retval HAL status
91   */
HAL_RCCEx_PeriphCLKConfig(const RCC_PeriphCLKInitTypeDef * PeriphClkInit)92 HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(const RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
93 {
94   uint32_t tmpregister;
95   uint32_t tickstart;
96   HAL_StatusTypeDef ret    = HAL_OK;   /* Intermediate status */
97   HAL_StatusTypeDef status = HAL_OK;   /* Final status */
98 
99   /* Check the parameters */
100   assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
101 
102   /*-------------------------- RTC clock source configuration ----------------------*/
103   if ((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
104   {
105     FlagStatus       pwrclkchanged = RESET;
106 
107     /* Check for RTC Parameters used to output RTCCLK */
108     assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
109 
110     /* Enable Power Clock */
111     if (__HAL_RCC_PWR_IS_CLK_DISABLED())
112     {
113       __HAL_RCC_PWR_CLK_ENABLE();
114       pwrclkchanged = SET;
115     }
116 
117 
118     /* Reset the RTC domain only if the RTC Clock source selection is modified from default */
119     tmpregister = READ_BIT(RCC->CSR1, RCC_CSR1_RTCSEL);
120 
121     /* Reset the RTC domain only if the RTC Clock source selection is modified */
122     if ((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection))
123     {
124       /* Store the content of CSR1 register before the reset of RTC Domain */
125       tmpregister = READ_BIT(RCC->CSR1, ~(RCC_CSR1_RTCSEL));
126       /* RTC Clock selection can be changed only if the RTC Domain is reset */
127       __HAL_RCC_BACKUPRESET_FORCE();
128       __HAL_RCC_BACKUPRESET_RELEASE();
129       /* Restore the Content of CSR1 register */
130       RCC->CSR1 = tmpregister;
131     }
132 
133     /* Wait for LSE reactivation if LSE was enable prior to RTC Domain reset */
134     if (HAL_IS_BIT_SET(tmpregister, RCC_CSR1_LSEON))
135     {
136       /* Get Start Tick*/
137       tickstart = HAL_GetTick();
138 
139       /* Wait till LSE is ready */
140       while (READ_BIT(RCC->CSR1, RCC_CSR1_LSERDY) == 0U)
141       {
142         if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
143         {
144           ret = HAL_TIMEOUT;
145           break;
146         }
147       }
148     }
149 
150     if (ret == HAL_OK)
151     {
152       /* Apply new RTC clock source selection */
153       __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
154     }
155     else
156     {
157       /* set overall return value */
158       status = ret;
159     }
160 
161     /* Restore clock configuration if changed */
162     if (pwrclkchanged == SET)
163     {
164       __HAL_RCC_PWR_CLK_DISABLE();
165     }
166   }
167 
168   /*-------------------------- USART1 clock source configuration -------------------*/
169   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART1) == RCC_PERIPHCLK_USART1)
170   {
171     /* Check the parameters */
172     assert_param(IS_RCC_USART1CLKSOURCE(PeriphClkInit->Usart1ClockSelection));
173 
174     /* Configure the USART1 clock source */
175     __HAL_RCC_USART1_CONFIG(PeriphClkInit->Usart1ClockSelection);
176   }
177 
178   /*-------------------------- I2C1 clock source configuration ---------------------*/
179   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C1) == RCC_PERIPHCLK_I2C1)
180   {
181     /* Check the parameters */
182     assert_param(IS_RCC_I2C1CLKSOURCE(PeriphClkInit->I2c1ClockSelection));
183 
184     /* Configure the I2C1 clock source */
185     __HAL_RCC_I2C1_CONFIG(PeriphClkInit->I2c1ClockSelection);
186   }
187 
188   /*-------------------------- ADC clock source configuration ----------------------*/
189   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_ADC) == RCC_PERIPHCLK_ADC)
190   {
191     /* Check the parameters */
192     assert_param(IS_RCC_ADCCLKSOURCE(PeriphClkInit->AdcClockSelection));
193 
194     /* Configure the ADC interface clock source */
195     __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection);
196 
197   }
198 
199   /*-------------------------- I2S1 clock source configuration ---------------------*/
200   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S1) == RCC_PERIPHCLK_I2S1)
201   {
202     /* Check the parameters */
203     assert_param(IS_RCC_I2S1CLKSOURCE(PeriphClkInit->I2s1ClockSelection));
204 
205     /* Configure the I2S1 clock source */
206     __HAL_RCC_I2S1_CONFIG(PeriphClkInit->I2s1ClockSelection);
207   }
208   /*------------------------------------ HSI Kernel clock source configuration --------------------------------------*/
209   if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_HSIKER) == RCC_PERIPHCLK_HSIKER)
210   {
211     /* Check the parameters */
212     assert_param(IS_RCC_HSIKERDIV(PeriphClkInit->HSIKerClockDivider));
213 
214     /* Configure the HSI Kernel clock source Divider */
215     __HAL_RCC_HSIKER_CONFIG(PeriphClkInit->HSIKerClockDivider);
216   }
217   return status;
218 }
219 
220 /**
221   * @brief  Get the RCC_ClkInitStruct according to the internal RCC configuration registers.
222   * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
223   *         returns the configuration information for the Extended Peripherals
224   *         clocks: I2C1, I2S1, USART1, RTC, ADC,
225   * @retval None
226   */
HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef * PeriphClkInit)227 void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
228 {
229   /* Set all possible values for the extended clock type parameter------------*/
230   PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_I2C1 | RCC_PERIPHCLK_I2S1 | \
231                                         RCC_PERIPHCLK_ADC    | RCC_PERIPHCLK_RTC  | RCC_PERIPHCLK_HSIKER ;
232 
233 
234   /* Get the USART1 clock source ---------------------------------------------*/
235   PeriphClkInit->Usart1ClockSelection  = __HAL_RCC_GET_USART1_SOURCE();
236 
237   /* Get the I2C1 clock source -----------------------------------------------*/
238   PeriphClkInit->I2c1ClockSelection    = __HAL_RCC_GET_I2C1_SOURCE();
239 
240   /* Get the RTC clock source ------------------------------------------------*/
241   PeriphClkInit->RTCClockSelection     = __HAL_RCC_GET_RTC_SOURCE();
242 
243   /* Get the ADC clock source -----------------------------------------------*/
244   PeriphClkInit->AdcClockSelection     = __HAL_RCC_GET_ADC_SOURCE();
245 
246   /* Get the I2S1 clock source -----------------------------------------------*/
247   PeriphClkInit->I2s1ClockSelection    = __HAL_RCC_GET_I2S1_SOURCE();
248 
249   /* Get the HSI Kernel clock divider -----------------------------------------------*/
250   PeriphClkInit->HSIKerClockDivider    = __HAL_RCC_GET_HSIKER_DIVIDER();
251 }
252 
253 /**
254   * @brief  Return the peripheral clock frequency for peripherals
255   * @note   Return 0 if peripheral clock identifier not managed by this API
256   * @param  PeriphClk  Peripheral clock identifier
257   *         This parameter can be one of the following values:
258   *            @arg @ref RCC_PERIPHCLK_RTC     RTC peripheral clock
259   *            @arg @ref RCC_PERIPHCLK_ADC     ADC peripheral clock
260   *            @arg @ref RCC_PERIPHCLK_I2C1    I2C1 peripheral clock
261   *            @arg @ref RCC_PERIPHCLK_I2S1    I2S1 peripheral clock
262   *            @arg @ref RCC_PERIPHCLK_USART1  USART1 peripheral clock
263   * @retval Frequency in Hz
264   */
HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)265 uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
266 {
267   uint32_t frequency = 0U;
268   uint32_t srcclk;
269 
270   /* Check the parameters */
271   assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
272 
273   if (PeriphClk == RCC_PERIPHCLK_RTC)
274   {
275     /* Get the current RTC source */
276     srcclk = __HAL_RCC_GET_RTC_SOURCE();
277 
278     /* Check if LSE is ready and if RTC clock selection is LSE */
279     if ((HAL_IS_BIT_SET(RCC->CSR1, RCC_CSR1_LSERDY)) && (srcclk == RCC_RTCCLKSOURCE_LSE))
280     {
281       frequency = LSE_VALUE;
282     }
283     /* Check if LSI is ready and if RTC clock selection is LSI */
284     else if ((HAL_IS_BIT_SET(RCC->CSR2, RCC_CSR2_LSIRDY)) && (srcclk == RCC_RTCCLKSOURCE_LSI))
285     {
286       frequency = LSI_VALUE;
287     }
288     /* Check if HSE is ready  and if RTC clock selection is HSI_DIV32*/
289     else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) && (srcclk == RCC_RTCCLKSOURCE_HSE_DIV32))
290     {
291       frequency = HSE_VALUE / 32U;
292     }
293     /* Clock not enabled for RTC*/
294     else
295     {
296       /* Nothing to do as frequency already initialized to 0U */
297     }
298   }
299   else
300   {
301     /* Other external peripheral clock source than RTC */
302 
303     switch (PeriphClk)
304     {
305 
306       case RCC_PERIPHCLK_USART1:
307         /* Get the current USART1 source */
308         srcclk = __HAL_RCC_GET_USART1_SOURCE();
309 
310         if (srcclk == RCC_USART1CLKSOURCE_PCLK1)            /* PCLK1 */
311         {
312           frequency = HAL_RCC_GetPCLK1Freq();
313         }
314         else if (srcclk == RCC_USART1CLKSOURCE_SYSCLK)     /* SYSCLK  */
315         {
316           frequency = HAL_RCC_GetSysClockFreq();
317         }
318         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_USART1CLKSOURCE_HSIKER))
319         {
320           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
321         }
322         else if ((HAL_IS_BIT_SET(RCC->CSR1, RCC_CSR1_LSERDY)) && (srcclk == RCC_USART1CLKSOURCE_LSE))
323         {
324           frequency = LSE_VALUE;
325         }
326         /* Clock not enabled for USART1 */
327         else
328         {
329           /* Nothing to do as frequency already initialized to 0U */
330         }
331         break;
332 
333       case RCC_PERIPHCLK_ADC:
334 
335         srcclk = __HAL_RCC_GET_ADC_SOURCE();
336 
337         if (srcclk == RCC_ADCCLKSOURCE_SYSCLK)
338         {
339           frequency = HAL_RCC_GetSysClockFreq();
340         }
341         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_ADCCLKSOURCE_HSIKER))
342         {
343           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
344         }
345         /* Clock not enabled for ADC */
346         else
347         {
348           /* Nothing to do as frequency already initialized to 0U */
349         }
350         break;
351 
352       case RCC_PERIPHCLK_I2C1:
353         /* Get the current I2C1 source */
354         srcclk = __HAL_RCC_GET_I2C1_SOURCE();
355 
356         if (srcclk == RCC_I2C1CLKSOURCE_PCLK1)
357         {
358           frequency = HAL_RCC_GetPCLK1Freq();
359         }
360         else if (srcclk == RCC_I2C1CLKSOURCE_SYSCLK)
361         {
362           frequency = HAL_RCC_GetSysClockFreq();
363         }
364         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_I2C1CLKSOURCE_HSIKER))
365         {
366           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
367         }
368         /* Clock not enabled for I2C1 */
369         else
370         {
371           /* Nothing to do as frequency already initialized to 0U */
372         }
373         break;
374 
375       case RCC_PERIPHCLK_I2S1:
376         /* Get the current I2S1 source */
377         srcclk = __HAL_RCC_GET_I2S1_SOURCE();
378 
379         if (srcclk == RCC_I2S1CLKSOURCE_SYSCLK)
380         {
381           frequency = HAL_RCC_GetSysClockFreq();
382         }
383         else if ((HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) && (srcclk == RCC_I2S1CLKSOURCE_HSIKER))
384         {
385           frequency = (HSI_VALUE / ((__HAL_RCC_GET_HSIKER_DIVIDER() >> RCC_CR_HSIKERDIV_Pos) + 1U));
386         }
387         else if (srcclk == RCC_I2S1CLKSOURCE_EXT)
388         {
389           /* External clock used.*/
390           frequency = EXTERNAL_I2S1_CLOCK_VALUE;
391         }
392         /* Clock not enabled for I2S1 */
393         else
394         {
395           /* Nothing to do as frequency already initialized to 0U */
396         }
397         break;
398 
399       default:
400         break;
401     }
402   }
403 
404   return (frequency);
405 }
406 
407 /**
408   * @}
409   */
410 
411 /** @defgroup RCCEx_Exported_Functions_Group2 Extended Clock management functions
412   *  @brief  Extended Clock management functions
413   *
414 @verbatim
415  ===============================================================================
416                 ##### Extended clock management functions  #####
417  ===============================================================================
418     [..]
419     This subsection provides a set of functions allowing to control the
420     activation or deactivation of LSE CSS, Low speed clock output and
421     clock after wake-up from STOP mode.
422 @endverbatim
423   * @{
424   */
425 
426 /**
427   * @brief  Select the Low Speed clock source to output on LSCO pin (PA2).
428   * @param  LSCOSource  specifies the Low Speed clock source to output.
429   *          This parameter can be one of the following values:
430   *            @arg @ref RCC_LSCOSOURCE_LSI  LSI clock selected as LSCO source
431   *            @arg @ref RCC_LSCOSOURCE_LSE  LSE clock selected as LSCO source
432   * @retval None
433   */
HAL_RCCEx_EnableLSCO(uint32_t LSCOSource)434 void HAL_RCCEx_EnableLSCO(uint32_t LSCOSource)
435 {
436   GPIO_InitTypeDef GPIO_InitStruct;
437 
438   /* Check the parameters */
439   assert_param(IS_RCC_LSCOSOURCE(LSCOSource));
440 
441   /* LSCO Pin Clock Enable */
442   LSCO_CLK_ENABLE();
443 
444   /* configure the LSCO pin in analog mode */
445   GPIO_InitStruct.Pin = LSCO_PIN;
446   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
447   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
448   GPIO_InitStruct.Pull = GPIO_NOPULL;
449   HAL_GPIO_Init(LSCO_GPIO_PORT, &GPIO_InitStruct);
450 
451   MODIFY_REG(RCC->CSR1, RCC_CSR1_LSCOSEL | RCC_CSR1_LSCOEN, LSCOSource | RCC_CSR1_LSCOEN);
452 
453 }
454 
455 /**
456   * @brief  Disable the Low Speed clock output.
457   * @retval None
458   */
HAL_RCCEx_DisableLSCO(void)459 void HAL_RCCEx_DisableLSCO(void)
460 {
461 
462   CLEAR_BIT(RCC->CSR1, RCC_CSR1_LSCOEN);
463 
464 }
465 
466 /**
467   * @}
468   */
469 
470 
471 /**
472   * @}
473   */
474 
475 /**
476   * @}
477   */
478 
479 #endif /* HAL_RCC_MODULE_ENABLED */
480 /**
481   * @}
482   */
483 
484 /**
485   * @}
486   */
487