1
2 /**
3 ******************************************************************************
4 * @file system_stm32wb0x.c
5 * @author GPM WBL Application Team
6 * @brief CMSIS Cortex-M0+ Device Peripheral Access Layer System Source File
7 *
8 ******************************************************************************
9 * @attention
10 *
11 * Copyright (c) 2024 STMicroelectronics.
12 * All rights reserved.
13 *
14 * This software is licensed under terms that can be found in the LICENSE file
15 * in the root directory of this software component.
16 * If no LICENSE file comes with this software, it is provided AS-IS.
17 *
18 ******************************************************************************
19 * This file provides two functions and one global variable to be called from
20 * user application:
21 * - SystemInit(): This function is called at startup just after reset and
22 * before branch to main program. This call is made inside
23 * the "startup_stm32wb0x.s" file.
24 *
25 * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
26 * by the user application to setup the SysTick
27 * timer or configure other parameters.
28 *
29 * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
30 * be called whenever the core clock is changed
31 * during program execution.
32 *
33 * After each device reset the HSI (64 MHz) is used as system clock source.
34 * Then SystemInit() function is called, in "startup_stm32wb0x.s" file, to
35 * configure the system clock before to branch to main program.
36 *
37 * This file configures the system clock as follows:
38 *=============================================================================
39 *-----------------------------------------------------------------------------
40 * System Clock source | HSI
41 *-----------------------------------------------------------------------------
42 * SYSCLK(Hz) | 16000000
43 *-----------------------------------------------------------------------------
44 * HCLK(Hz) | 16000000
45 *-----------------------------------------------------------------------------
46 *=============================================================================
47 */
48
49 /** @addtogroup CMSIS
50 * @{
51 */
52
53 /** @addtogroup STM32WB0x_system
54 * @{
55 */
56
57 /** @addtogroup STM32WB0x_System_Private_Includes
58 * @{
59 */
60
61 #include "stm32wb0x.h"
62
63 /**
64 * @}
65 */
66
67 /** @addtogroup STM32WB0x_System_Private_TypesDefinitions
68 * @{
69 */
70
71 /**
72 * @}
73 */
74
75 /** @addtogroup STM32WB0x_System_Private_Defines
76 * @{
77 */
78 #if !defined (HSE_VALUE)
79 #define HSE_VALUE (32000000U) /*!< Value of the External oscillator in Hz */
80 #endif /* HSE_VALUE */
81
82 #if !defined (HSI_VALUE)
83 #define HSI_VALUE (64000000U) /*!< Value of the Internal oscillator in Hz*/
84 #endif /* HSI_VALUE */
85
86 /* Note: Following vector table addresses must be defined in line with linker
87 configuration. */
88 /*!< Uncomment the following line if you need to relocate the vector table
89 anywhere in Flash or Sram, else the vector table is kept at the automatic
90 remap of boot address selected */
91 /* #define USER_VECT_TAB_ADDRESS */
92
93 #if defined(USER_VECT_TAB_ADDRESS)
94 /*!< Uncomment the following line if you need to relocate your vector Table
95 in SRAM else user remap will be done in FLASH. */
96 /* #define VECT_TAB_SRAM */
97 #if defined(VECT_TAB_SRAM)
98 #define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
99 This value must be a multiple of 0x100. */
100 #define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
101 This value must be a multiple of 0x100. */
102 #else
103 #define VECT_TAB_BASE_ADDRESS NVM_BASE /*!< Vector Table base address field.
104 This value must be a multiple of 0x100. */
105 #define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
106 This value must be a multiple of 0x100. */
107 #endif /* VECT_TAB_SRAM */
108 #endif /* USER_VECT_TAB_ADDRESS */
109
110 /******************************************************************************/
111
112 /*!< HW TRIMMING Defines */
113 #define VALIDITY_TAG 0xFCBCECCC /*!< TAG to validate the content of the
114 trimming area content. */
115 #define VALIDITY_LOCATION 0x10001EF8 /*!< ROM address of the the validity trimming values content. */
116
117 /*!< SMPS Configuration Defines */
118 #if !defined(CFG_HW_SMPS)
119 #define CFG_HW_SMPS SMPS_ON
120 #endif
121
122 #if !defined(CFG_HW_SMPS_BOM)
123 #define CFG_HW_SMPS_BOM SMPS_BOM3 /*!< SMPS Inductor 10uH */
124 #endif
125
126 #if !defined(CFG_HW_SMPS_LOW_POWER)
127 #define CFG_HW_SMPS_LOW_POWER SMPS_LOW_POWER_OPEN
128 #endif
129
130 /**
131 * @}
132 */
133
134 /** @addtogroup STM32WB0x_System_Private_Macros
135 * @{
136 */
137
138 /**
139 * @}
140 */
141
142 /** @addtogroup STM32WB0x_System_Private_Variables
143 * @{
144 */
145 /* The SystemCoreClock variable is updated in three ways:
146 1) by calling CMSIS function SystemCoreClockUpdate()
147 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
148 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
149 Note: If you use this function to configure the system clock; then there
150 is no need to call the 2 first functions listed above, since SystemCoreClock
151 variable is updated automatically.
152 */
153 uint32_t SystemCoreClock = 16000000U; /* The HSI (64MHz) is used as system clock source after startup from reset, configured at 16 MHz. */
154
155 /* The RAM_VR variable is a mirroring in RAM of some registers information.
156 It is a sort of virtual register in RAM.
157 */
158 #if defined ( __ICCARM__ )
159 #pragma location=".ram_vr"
160 __root __no_init RAM_VR_TypeDef RAM_VR;
161 #else
162 #if defined ( __ARMCC_VERSION )
163 __attribute__((section(".bss" ".ram_vr")))
164 #elif defined ( __GNUC__ )
165 __attribute__((section(".ram_vr")))
166 #endif
167 RAM_VR_TypeDef RAM_VR __attribute__((used));
168 #endif
169 /**
170 * @}
171 */
172
173 /** @addtogroup STM32WB0x_System_Private_FunctionPrototypes
174 * @{
175 */
176
177 void CPUcontextRestore(void);
178
179 /**
180 * @}
181 */
182
183 /** @addtogroup STM32WB0x_System_Private_Functions
184 * @{
185 */
186
187 /**
188 * @brief Setup the microcontroller system.
189 * @param None
190 * @retval None
191 */
192
SystemInit(void)193 void SystemInit(void)
194 {
195 uint32_t mainRegulator, smpsOutVoltage, hsiCalib;
196 #if defined(STM32WB06) || defined(STM32WB07)
197 uint32_t lsiLpmu;
198 #else
199 uint32_t lsiBw;
200 #endif
201 uint8_t i;
202
203 /* If the reset reason is a wakeup from power save restore the context */
204 if ((RCC->CSR == 0) && ((PWR->SR1 != 0)||(PWR->SR3 != 0))) {
205 RAM_VR.WakeupFromSleepFlag = 1; /* A wakeup from power save occurred */
206 CPUcontextRestore(); /* Restore the context */
207 /* if the context restore worked properly, we should never return here */
208 while(1) {
209 NVIC_SystemReset();
210 }
211 }
212
213 /* Configure the Vector Table location */
214 #if defined(USER_VECT_TAB_ADDRESS)
215 SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation */
216 #else
217 SCB->VTOR = (uint32_t) (__vector_table);
218 #endif /* USER_VECT_TAB_ADDRESS */
219
220 /* Store in RAM the AppBase information */
221 RAM_VR.AppBase = (uint32_t) SCB->VTOR;
222
223 /* Enable all the RAM banks in retention during power save */
224 #if defined(PWR_CR2_RAMRET1)
225 SET_BIT(PWR->CR2, PWR_CR2_RAMRET1);
226 #endif /* PWR_CR2_RAMRET1 */
227
228 #if defined(PWR_CR2_RAMRET2)
229 SET_BIT(PWR->CR2, PWR_CR2_RAMRET2);
230 #endif /* PWR_CR2_RAMRET2 */
231
232 #if defined(PWR_CR2_RAMRET2)
233 SET_BIT(PWR->CR2, PWR_CR2_RAMRET3);
234 #endif /* PWR_CR2_RAMRET3 */
235
236 /* Disable the GPIO retention in power save configuration */
237 #if defined(PWR_CR2_GPIORET)
238 CLEAR_BIT(PWR->CR2, PWR_CR2_GPIORET);
239 #endif /* PWR_CR2_GPIORET */
240
241 /* SMPS setup */
242 if ((CFG_HW_SMPS == SMPS_ON) || (CFG_HW_SMPS == SMPS_BYPAPSS))
243 {
244 while(READ_BIT(PWR->SR2, PWR_SR2_SMPSRDY) != PWR_SR2_SMPSRDY); // Wait until SMPS is ready
245 MODIFY_REG(PWR->CR5, PWR_CR5_SMPSBOMSEL, (CFG_HW_SMPS_BOM<<PWR_CR5_SMPSBOMSEL_Pos)); // Configure the SMPS BOM
246 }
247 if ((CFG_HW_SMPS == SMPS_ON) || (CFG_HW_SMPS == SMPS_OFF))
248 {
249 MODIFY_REG(PWR->CR5, PWR_CR5_NOSMPS, (CFG_HW_SMPS<<PWR_CR5_NOSMPS_Pos)); // SMPS ON/OFF Configuration
250 }
251 else
252 {
253 MODIFY_REG(PWR->CR5, PWR_CR5_SMPSFBYP, (1<<PWR_CR5_SMPSFBYP_Pos)); // SMPS BYPASS Configuration
254 }
255 MODIFY_REG(PWR->CR5, PWR_CR5_SMPSLPOPEN, (CFG_HW_SMPS_LOW_POWER<<PWR_CR5_SMPSLPOPEN_Pos)); // SMPS configuration during power save
256
257 /* If Trimming values from engineering in flash locations are not present load default values */
258 if (*(volatile uint32_t*)VALIDITY_LOCATION != VALIDITY_TAG)
259 {
260 #if defined(STM32WB06) || defined(STM32WB07)
261 hsiCalib = 0x1E;
262 mainRegulator = 0x08;
263 smpsOutVoltage = 0x03;
264 lsiLpmu = 0x08;
265
266 /* Set Low Speed Internal oscillator LPMU trimming value. */
267 MODIFY_REG(PWR->ENGTRIM, PWR_ENGTRIM_TRIM_LSI_LPMU, ((lsiLpmu << PWR_ENGTRIM_TRIM_LSI_LPMU_Pos) & PWR_ENGTRIM_TRIM_LSI_LPMU));
268 SET_BIT(PWR->ENGTRIM, PWR_ENGTRIM_TRIMLSILPMUEN);
269 #else
270 hsiCalib = 0x1F;
271 lsiBw = 8;
272 mainRegulator = 0x0A;
273 smpsOutVoltage = 0x03;
274
275 /* Low speed internal RC trimming value set by software */
276 MODIFY_REG(RCC->CSSWCR, RCC_CSSWCR_LSISWBW, lsiBw << RCC_CSSWCR_LSISWBW_Pos);
277 SET_BIT(RCC->CSSWCR, RCC_CSSWCR_LSISWTRIMEN);
278 #endif
279
280 /* Set HSI Calibration Trimming value */
281 MODIFY_REG(RCC->CSSWCR, RCC_CSSWCR_HSITRIMSW, hsiCalib << RCC_CSSWCR_HSITRIMSW_Pos);
282 SET_BIT(RCC->CSSWCR, RCC_CSSWCR_HSISWTRIMEN);
283
284 /* Set Main Regulator voltage Trimming value */
285 MODIFY_REG(PWR->ENGTRIM, PWR_ENGTRIM_TRIM_MR, ((mainRegulator << PWR_ENGTRIM_TRIM_MR_Pos) & PWR_ENGTRIM_TRIM_MR));
286 SET_BIT(PWR->ENGTRIM, PWR_ENGTRIM_TRIMMREN);
287
288 /* Set SMPS output voltage Trimming value */
289 MODIFY_REG(PWR->ENGTRIM, PWR_ENGTRIM_SMPS_TRIM, ((smpsOutVoltage << PWR_ENGTRIM_SMPS_TRIM_Pos) & PWR_ENGTRIM_SMPS_TRIM));
290 SET_BIT(PWR->ENGTRIM, PWR_ENGTRIM_SMPSTRIMEN);
291 }
292
293 /* Set all the interrupt with low priprity */
294 for (i=0; i<32; i++)
295 {
296 NVIC_SetPriority((IRQn_Type)i, IRQ_LOW_PRIORITY);
297 }
298
299 /* Enable all the irqs */
300 __enable_irq();
301 }
302
303 /**
304 * @brief Update SystemCoreClock variable according to Clock Register Values.
305 * The SystemCoreClock variable contains the core clock (HCLK), it can
306 * be used by the user application to setup the SysTick timer or configure
307 * other parameters.
308 *
309 * @note Each time the core clock (HCLK) changes, this function must be called
310 * to update SystemCoreClock variable value. Otherwise, any configuration
311 * based on this variable will be incorrect.
312 *
313 * @param None
314 * @retval None
315 */
SystemCoreClockUpdate(void)316 void SystemCoreClockUpdate(void)
317 {
318 uint8_t directHSE_enabled;
319 uint8_t divPrescaler;
320
321 /* Get SYSCLK source HSE or HSI+PLL64MHz */
322 directHSE_enabled = (RCC->CFGR & RCC_CFGR_HSESEL) >> RCC_CFGR_HSESEL_Pos;
323
324 #if defined(STM32WB06) || defined(STM32WB07)
325 /* Get the clock divider */
326 divPrescaler = (RCC->CFGR & RCC_CFGR_CLKSYSDIV) >> RCC_CFGR_CLKSYSDIV_Pos;
327 #else
328 /* Get the clock divider */
329 divPrescaler = (RCC->CFGR & RCC_CFGR_CLKSYSDIV_STATUS) >> RCC_CFGR_CLKSYSDIV_STATUS_Pos;
330 #endif
331
332 if (directHSE_enabled)
333 {
334 SystemCoreClock = HSE_VALUE >> (divPrescaler - 1U);
335 }
336 else
337 {
338 SystemCoreClock = HSI_VALUE >> divPrescaler;
339 }
340 }
341
342 /**
343 * @brief Restores the saved CPU state before to enter in power save
344 * by popping it from the stack
345 * @param None
346 * @retval None
347 */
CPUcontextRestore(void)348 __WEAK void CPUcontextRestore(void)
349 {
350 }
351
352 /**
353 * @}
354 */
355
356 /**
357 * @}
358 */
359
360 /**
361 * @}
362 */
363