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