1 /**
2   ******************************************************************************
3   * @file    system_stm32u0xx.c
4   * @author  MCD Application Team
5   * @brief   CMSIS Cortex-M0+ Device Peripheral Access Layer System Source File
6   *
7   ******************************************************************************
8   * @attention
9   *
10   * Copyright (c) 2023 STMicroelectronics.
11   * All rights reserved.
12   *
13   * This software is licensed under terms that can be found in the LICENSE file
14   * in the root directory of this software component.
15   * If no LICENSE file comes with this software, it is provided AS-IS.
16   *
17   ******************************************************************************
18   *   This file provides two functions and one global variable to be called from
19   *   user application:
20   *      - SystemInit(): This function is called at startup just after reset and
21   *                      before branch to main program. This call is made inside
22   *                      the "startup_stm32u0xx.s" file.
23   *
24   *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
25   *                                  by the user application to setup the SysTick
26   *                                  timer or configure other parameters.
27   *
28   *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
29   *                                 be called whenever the core clock is changed
30   *                                 during program execution.
31   *
32   *   After each device reset the MSI (4 MHz) is used as system clock source.
33   *   Then SystemInit() function is called, in "startup_stm32u0xx.s" file, to
34   *   configure the system clock before to branch to main program.
35   *
36   *   This file configures the system clock as follows:
37   *=============================================================================
38   *-----------------------------------------------------------------------------
39   *        System Clock source                    | MSI
40   *-----------------------------------------------------------------------------
41   *        SYSCLK(Hz)                             | 4000000
42   *-----------------------------------------------------------------------------
43   *        HCLK(Hz)                               | 4000000
44   *-----------------------------------------------------------------------------
45   *        AHB Prescaler                          | 1
46   *-----------------------------------------------------------------------------
47   *        APB Prescaler                          | 1
48   *-----------------------------------------------------------------------------
49   *        HSI Division factor                    | 1
50   *-----------------------------------------------------------------------------
51   *        PLL_M                                  | 1
52   *-----------------------------------------------------------------------------
53   *        PLL_N                                  | 8
54   *-----------------------------------------------------------------------------
55   *        PLL_P                                  | 7
56   *-----------------------------------------------------------------------------
57   *        PLL_Q                                  | 2
58   *-----------------------------------------------------------------------------
59   *        PLL_R                                  | 2
60   *-----------------------------------------------------------------------------
61   *        Require 48MHz for RNG                  | Disabled
62   *-----------------------------------------------------------------------------
63   *=============================================================================
64   */
65 
66 /** @addtogroup CMSIS
67   * @{
68   */
69 
70 /** @addtogroup stm32u0xx_system
71   * @{
72   */
73 
74 /** @addtogroup STM32U0xx_System_Private_Includes
75   * @{
76   */
77 
78 #include "stm32u0xx.h"
79 
80 #if !defined  (HSE_VALUE)
81 #define HSE_VALUE    (32000000U)     /*!< Value of the External oscillator in Hz */
82 #endif /* HSE_VALUE */
83 
84 #if !defined  (HSI_VALUE)
85 #define HSI_VALUE    (16000000UL)    /*!< Value of the Internal oscillator in Hz*/
86 #endif /* HSI_VALUE */
87 
88 #if !defined  (MSI_VALUE)
89 #define MSI_VALUE    (4000000UL)     /*!< Value of the Internal oscillator in Hz*/
90 #endif /* MSI_VALUE */
91 
92 #if !defined  (LSI_VALUE)
93 #define LSI_VALUE    (32000UL)       /*!< Value of the Internal oscillator in Hz */
94 #endif /* LSI_VALUE */
95 
96 #if !defined  (LSE_VALUE)
97 #define LSE_VALUE    (32768UL)       /*!< Value of the External oscillator in Hz */
98 #endif /* LSE_VALUE */
99 
100 /**
101   * @}
102   */
103 
104 /** @addtogroup STM32U0xx_System_Private_TypesDefinitions
105   * @{
106   */
107 
108 /**
109   * @}
110   */
111 
112 /** @addtogroup STM32U0xx_System_Private_Defines
113   * @{
114   */
115 
116 /************************* Miscellaneous Configuration ************************/
117 /*!< Uncomment the following line if you need to relocate your vector Table in
118      Internal SRAM. */
119 //#define VECT_TAB_SRAM
120 #define VECT_TAB_OFFSET  0x0U /*!< Vector Table base offset field.
121                                    This value must be a multiple of 0x200. */
122 
123 /*!< Comment the following line if you would like to disable the software
124      workaround related to debug access in case RDP=1 and Boot_Lock=1      */
125 #define ENABLE_DBG_SWEN /*!< Enable the debugger read access. */
126 /******************************************************************************/
127 /**
128   * @}
129   */
130 
131 /** @addtogroup STM32U0xx_System_Private_Macros
132   * @{
133   */
134 
135 /**
136   * @}
137   */
138 
139 /** @addtogroup STM32U0xx_System_Private_Variables
140   * @{
141   */
142 /* The SystemCoreClock variable is updated in three ways:
143     1) by calling CMSIS function SystemCoreClockUpdate()
144     2) by calling HAL API function HAL_RCC_GetHCLKFreq()
145     3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
146        Note: If you use this function to configure the system clock; then there
147              is no need to call the 2 first functions listed above, since SystemCoreClock
148              variable is updated automatically.
149 */
150 uint32_t SystemCoreClock = 4000000U;
151 
152 const uint8_t  AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
153 const uint8_t  APBPrescTable[8] =  {0, 0, 0, 0, 1, 2, 3, 4};
154 const uint32_t MSIRangeTable[12] = {100000U,   200000U,   400000U,   800000U,  1000000U,  2000000U, \
155                                     4000000U, 8000000U, 16000000U, 24000000U, 32000000U, 48000000U
156                                    };
157 
158 /**
159   * @}
160   */
161 
162 /** @addtogroup STM32U0xx_System_Private_FunctionPrototypes
163   * @{
164   */
165 
166 /**
167   * @}
168   */
169 
170 /** @addtogroup STM32U0xx_System_Private_Functions
171   * @{
172   */
173 
174 /**
175   * @brief  Setup the microcontroller system.
176   * @param  None
177   * @retval None
178   */
179 
SystemInit(void)180 void SystemInit(void)
181 {
182 #ifdef ENABLE_DBG_SWEN
183 uint32_t tmp_seccr;
184 uint32_t tmp_optr;
185 #endif /* ENABLE_DBG_SWEN */
186   /* Configure the Vector Table location add offset address ------------------*/
187 #ifdef VECT_TAB_SRAM
188   SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
189 #else
190   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
191 #endif /* VECT_TAB_SRAM */
192 
193 /* Software workaround added to keep Debug enabled after Boot_Lock activation and RDP=1  */
194 #ifdef ENABLE_DBG_SWEN
195   tmp_seccr = FLASH->SECR;
196   tmp_optr = FLASH->OPTR;
197   if (((tmp_seccr & FLASH_SECR_BOOT_LOCK) == FLASH_SECR_BOOT_LOCK)         \
198       && (((tmp_optr & FLASH_OPTR_RDP) != 0xCCU)                           \
199       && ((tmp_optr & FLASH_OPTR_RDP) != 0xAAU)))
200   {
201     FLASH->ACR |= FLASH_ACR_DBG_SWEN;  /* Debug access software enabled to avoid the chip
202                                           to be locked when RDP=1 and Boot_Lock=1        */
203   }
204 #endif /* ENABLE_DBG_SWEN */
205 }
206 
207 /**
208   * @brief  Update SystemCoreClock variable according to Clock Register Values.
209   *         The SystemCoreClock variable contains the core clock (HCLK), it can
210   *         be used by the user application to setup the SysTick timer or configure
211   *         other parameters.
212   *
213   * @note   Each time the core clock (HCLK) changes, this function must be called
214   *         to update SystemCoreClock variable value. Otherwise, any configuration
215   *         based on this variable will be incorrect.
216   *
217   * @note   - The system frequency computed by this function is not the real
218   *           frequency in the chip. It is calculated based on the predefined
219   *           constant and the selected clock source:
220   *
221   *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*)
222   *
223   *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
224   *
225   *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
226   *
227   *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***)
228   *             or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors.
229   *
230   *         (*) MSI_VALUE is a constant defined in stm32u0xx_hal.h file (default value
231   *             4 MHz) but the real value may vary depending on the variations
232   *             in voltage and temperature.
233   *
234   *         (**) HSI_VALUE is a constant defined in stm32u0xx_hal.h file (default value
235   *              16 MHz) but the real value may vary depending on the variations
236   *              in voltage and temperature.
237   *
238   *         (***) HSE_VALUE is a constant defined in stm32u0xx_hal.h file (default value
239   *              8 MHz), user has to ensure that HSE_VALUE is same as the real
240   *              frequency of the crystal used. Otherwise, this function may
241   *              have wrong result.
242   *
243   *         - The result of this function could be not correct when using fractional
244   *           value for HSE crystal.
245   *
246   * @param  None
247   * @retval None
248   */
SystemCoreClockUpdate(void)249 void SystemCoreClockUpdate(void)
250 {
251   uint32_t tmp, msirange, pllvco, pllsource, pllm, pllr;
252 
253   /* Get MSI Range frequency--------------------------------------------------*/
254   if ((RCC->CR & RCC_CR_MSIRGSEL) == 0U)
255   {
256     /* MSISRANGE from RCC_CSR applies */
257     msirange = (RCC->CSR & RCC_CSR_MSISTBYRG) >> 8U;
258   }
259   else
260   {
261     /* MSIRANGE from RCC_CR applies */
262     msirange = (RCC->CR & RCC_CR_MSIRANGE) >> 4U;
263   }
264   /* MSI frequency range in HZ*/
265   if (msirange > 11U)
266   {
267     msirange = 0U;
268   }
269   msirange = MSIRangeTable[msirange];
270 
271   /* Get SYSCLK source -------------------------------------------------------*/
272   switch (RCC->CFGR & RCC_CFGR_SWS)
273   {
274     case 0x00:  /* MSI used as system clock source */
275       SystemCoreClock = msirange;
276       break;
277 
278     case RCC_CFGR_SWS_0:  /* HSI used as system clock source */
279       SystemCoreClock = HSI_VALUE;
280       break;
281 
282     case RCC_CFGR_SWS_1:  /* HSE used as system clock source */
283       SystemCoreClock = HSE_VALUE;
284       break;
285 
286     case RCC_CFGR_SWS_2:  /* LSI used as system clock */
287       SystemCoreClock = LSI_VALUE;
288       break;
289 
290     case (RCC_CFGR_SWS_2 | RCC_CFGR_SWS_0):  /* LSE used as system clock */
291       SystemCoreClock = LSE_VALUE;
292       break;
293 
294     case (RCC_CFGR_SWS_1 | RCC_CFGR_SWS_0):  /* PLL used as system clock  source */
295       /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN
296          SYSCLK = PLL_VCO / PLLR
297          */
298       pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
299       pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ;
300 
301       switch (pllsource)
302       {
303         case RCC_PLLCFGR_PLLSRC_0:  /* MSI used as PLL clock source */
304           pllvco = (msirange / pllm);
305           break;
306 
307         case RCC_PLLCFGR_PLLSRC_1:  /* HSI used as PLL clock source */
308           pllvco = (HSI_VALUE / pllm);
309           break;
310 
311         case (RCC_PLLCFGR_PLLSRC_1 | RCC_PLLCFGR_PLLSRC_0):  /* HSE used as PLL clock source */
312           pllvco = (HSE_VALUE / pllm);
313           break;
314 
315         default:  /* no clock used as PLL clock source */
316           pllvco = 0x0U;
317           break;
318       }
319       pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
320       pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
321       SystemCoreClock = pllvco / pllr;
322       break;
323 
324     default:
325       SystemCoreClock = msirange;
326       break;
327   }
328   /* Compute HCLK clock frequency --------------------------------------------*/
329   /* Get HCLK prescaler */
330   tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos) & 0xFU];
331   /* HCLK clock frequency */
332   SystemCoreClock >>= tmp;
333 }
334 
335 /**
336   * @}
337   */
338 
339 /**
340   * @}
341   */
342 
343 /**
344   * @}
345   */
346 
347