1 /* USER CODE BEGIN Header */
2 /**
3 ******************************************************************************
4 * @file scm.c
5 * @author MCD Application Team
6 * @brief Functions for the System Clock Manager.
7 ******************************************************************************
8 * @attention
9 *
10 * Copyright (c) 2024 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 */
19 /* USER CODE END Header */
20
21 /* Includes ------------------------------------------------------------------*/
22 #include "scm.h"
23 #include "RTDebug.h"
24 #include "utilities_common.h"
25
26 #if (CFG_SCM_SUPPORTED == 1)
27
SCM_HSI_CLK_ON(void)28 __weak void SCM_HSI_CLK_ON(void)
29 {
30 LL_RCC_HSI_Enable();
31 while(LL_RCC_HSI_IsReady() == 0);
32 }
33
SCM_HSI_CLK_OFF(void)34 __weak void SCM_HSI_CLK_OFF(void)
35 {
36
37 }
38
39 /* SCM HSE BEGIN */
SCM_HSI_SwithSystemClock_Entry(void)40 __weak void SCM_HSI_SwithSystemClock_Entry(void)
41 {
42
43 }
44
SCM_HSI_SwithSystemClock_Exit(void)45 __weak void SCM_HSI_SwithSystemClock_Exit(void)
46 {
47
48 }
49 /* SCM HSE END */
50 /* Private typedef -----------------------------------------------------------*/
51 #define PLL_INPUTRANGE0_FREQMAX 8000000u /* 8 MHz is maximum frequency for VCO input range 0 */
52
53 /* Private define ------------------------------------------------------------*/
54
55 /* Private macro -------------------------------------------------------------*/
56 /* Private variables ---------------------------------------------------------*/
57 RAMCFG_HandleTypeDef sram1_ns =
58 {
59 RAMCFG_SRAM1, /* Instance */
60 HAL_RAMCFG_STATE_READY, /* RAMCFG State */
61 0U, /* RAMCFG Error Code */
62 };
63
64 RAMCFG_HandleTypeDef sram2_ns =
65 {
66 RAMCFG_SRAM2, /* Instance */
67 HAL_RAMCFG_STATE_READY, /* RAMCFG State */
68 0U, /* RAMCFG Error Code */
69 };
70
71 static scm_system_clock_t scm_system_clock_config;
72 static scm_clockconfig_t scm_system_clock_requests[(scm_user_id_t)TOTAL_CLIENT_NUM] = {NO_CLOCK_CONFIG};
73 static scm_radio_state_t RadioState;
74
75 /* Private function prototypes -----------------------------------------------*/
76 static scm_clockconfig_t scm_getmaxfreq(void);
77 static void scm_systemclockconfig(void);
78 static void ConfigStartPll(void);
79 static void ConfigHwPll(scm_pll_config_t *p_hw_config);
80 static void SwitchHsePre(scm_hse_hsepre_t hse_pre);
81 static void SwitchHse16toHse32(void);
82 static void SwitchHse32toHse16(void);
83 static void SwitchPlltoHse32(void);
84
85 /* Private functions ---------------------------------------------------------*/
scm_getmaxfreq(void)86 OPTIMIZED static scm_clockconfig_t scm_getmaxfreq(void)
87 {
88 uint8_t idx = 0;
89 scm_clockconfig_t max = NO_CLOCK_CONFIG;
90
91 for(idx = 0; idx < sizeof(scm_system_clock_requests) ; idx++)
92 {
93 if(scm_system_clock_requests[idx] > max)
94 {
95 max = scm_system_clock_requests[idx];
96 }
97 }
98
99 return max;
100 }
101
scm_systemclockconfig(void)102 OPTIMIZED static void scm_systemclockconfig(void)
103 {
104 SYSTEM_DEBUG_SIGNAL_SET(SCM_SYSTEM_CLOCK_CONFIG);
105
106 switch (scm_system_clock_config.targeted_clock_freq)
107 {
108 case HSE_16MHZ:
109
110 if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R)
111 {
112 /* currently running on PLL */
113 SwitchPlltoHse32();
114 }
115
116 SwitchHse32toHse16();
117
118 /* Ensure time base clock coherency */
119 SystemCoreClockUpdate();
120
121 break;
122
123 case HSE_32MHZ:
124
125 if (LL_RCC_HSE_IsEnabledPrescaler())
126 {
127 /* currently running on HSE16 */
128 SwitchHse16toHse32();
129
130 /* Ensure time base clock coherency */
131 SystemCoreClockUpdate();
132 }
133 else if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R)
134 {
135 /* currently running on PLL */
136 SwitchPlltoHse32();
137
138 /* Ensure time base clock coherency */
139 SystemCoreClockUpdate();
140 }
141 else
142 {
143 /**
144 * The system is already running on HSE32
145 * The only case is when the PLL has been requested and
146 * aborted before the system switched to PLL
147 */
148
149 /* Disable PLL */
150 LL_RCC_PLL1_Disable();
151
152 /**
153 * Disable PLL1RDY interrupt
154 * No need to worry the case when the PLL interrupt
155 * may already be pending at this time
156 */
157 __HAL_RCC_DISABLE_IT(RCC_IT_PLL1RDY);
158 }
159
160 break;
161
162 case SYS_PLL:
163
164 if (LL_RCC_HSE_IsEnabledPrescaler())
165 {
166 /* currently running on HSE16 */
167 SwitchHse16toHse32();
168
169 /* Ensure time base clock coherency */
170 SystemCoreClockUpdate();
171 }
172
173 ConfigStartPll();
174
175 break;
176
177 default:
178 break;
179 }
180
181 SYSTEM_DEBUG_SIGNAL_RESET(SCM_SYSTEM_CLOCK_CONFIG);
182 }
183
SwitchHsePre(scm_hse_hsepre_t hse_pre)184 OPTIMIZED static void SwitchHsePre(scm_hse_hsepre_t hse_pre)
185 {
186 /* Start HSI */
187 SCM_HSI_CLK_ON();
188
189 /* SCM HSE BEGIN */
190 /* Entry hook for HSI switch */
191 SCM_HSI_SwithSystemClock_Entry();
192 /* SCM HSE END */
193
194 /* Set HSI as SYSCLK */
195 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
196 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI);
197
198 /* Enable HSEON */
199 /* SCM HSE BEGIN */
200 LL_RCC_HSE_Enable();
201 while(LL_RCC_HSE_IsReady() == 0);
202
203 /* Exit hook for HSI switch */
204 SCM_HSI_SwithSystemClock_Exit();
205 /* SCM HSE END */
206
207 /* Set/Clear HSEPRE */
208 if(hse_pre == HSEPRE_DISABLE)
209 {
210 LL_RCC_HSE_DisablePrescaler();
211 }
212 else
213 {
214 LL_RCC_HSE_EnablePrescaler();
215 }
216
217 /* Set HSE as SYSCLK */
218 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
219 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
220
221 /* Disable HSI */
222 SCM_HSI_CLK_OFF();
223
224 #if defined(STM32WBAXX_SI_CUT1_0)
225 /* STM32WBA5 Cut1.0 only: if the radio is not active is set to OFF by the hardware. */
226 if(isRadioActive() == SCM_RADIO_NOT_ACTIVE)
227 {
228 /* SCM HSE BEGIN */
229 SCM_HSE_Clear_SW_HSERDY();
230 /* SCM HSE END */
231 }
232 #endif /* STM32WBAXX_SI_CUT1_0 */
233 }
234
SwitchHse16toHse32(void)235 OPTIMIZED static void SwitchHse16toHse32(void)
236 {
237 /**
238 * Switch from HSE_16MHz to HSE_32MHz
239 * 1. Voltage Range1
240 * 2. Disable prescaler ==> HSE16 to HSE32
241 * 3. Change RAM/FLASH waitstates (no limitation in Rang1)
242 * 4. AHB5 Div 1
243 */
244
245 /* first switch to VOS1 */
246 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
247 while (LL_PWR_IsActiveFlag_VOS() == 0);
248
249 /* Switch to 32Mhz */
250 SwitchHsePre(HSEPRE_DISABLE);
251
252 /* Configure flash and SRAMs */
253 scm_setwaitstates(HSE32);
254
255 /* Need to set HDIV5 */
256 LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1); /* divided by 1 */
257 }
258
SwitchHse32toHse16(void)259 OPTIMIZED static void SwitchHse32toHse16(void)
260 {
261 /**
262 * Switch from HSE_16MHz to HSE_32MHz
263 * 1. AHB5 Div 2
264 * 2. Change RAM/FLASH waitstates
265 * 3. Disable prescaler ==> HSE16 to HSE32
266 * 4. Voltage Range2
267 */
268
269 /* Divide HDIV5 by 2 */
270 LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_2);
271
272 /* Configure flash and SRAMs before switching to VOS2 */
273 scm_setwaitstates(HSE16);
274
275 /* Switch to HSE 16 */
276 SwitchHsePre(HSEPRE_ENABLE);
277
278 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
279 }
280
SwitchPlltoHse32(void)281 OPTIMIZED static void SwitchPlltoHse32(void)
282 {
283 /**
284 * Switch from PLL to HSE_32MHz
285 * 1. Switch system clock source to HSE
286 * 2. Turn OFF PLL
287 * 3. Change RAM/FLASH waitstates (no limitation in Rang1)
288 */
289
290 /* Switch to HSE */
291 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
292 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
293
294 /* Disable PLL */
295 LL_RCC_PLL1_Disable();
296
297 /* Configure flash and SRAMs */
298 scm_setwaitstates(HSE32);
299 }
300
ConfigStartPll(void)301 OPTIMIZED static void ConfigStartPll(void)
302 {
303 /* Enable PLL1 output for SYSCLK (PLL1R) */
304 LL_RCC_PLL1_EnableDomain_PLL1R();
305
306 /* Configure and start the PLL */
307 LL_RCC_PLL1_SetMainSource(LL_RCC_PLL1SOURCE_HSE);
308
309 /* Enable PLL1 */
310 __HAL_RCC_PLL1_ENABLE();
311
312 /* PLL1RDY interrupt raised when PLL is enabled */
313 __HAL_RCC_ENABLE_IT(RCC_IT_PLL1RDY);
314 }
315
ConfigHwPll(scm_pll_config_t * p_hw_config)316 static void ConfigHwPll(scm_pll_config_t *p_hw_config)
317 {
318 uint32_t freq_vco_in = 0;
319
320 /* Apply user PLL mode */
321 if(p_hw_config->pll_mode == PLL_FRACTIONAL_MODE)
322 {
323 scm_pll_fractional_update(p_hw_config->PLLFractional);
324 }
325 else
326 {
327 /* Integer configuration will be used for PLL mode */
328 LL_RCC_PLL1FRACN_Disable();
329 }
330
331 /* Apply correct frequency range for VCO_IN */
332 /* Note as PLL clock source is always HSE 32MHz, only PLL1M value impact VCO_IN */
333
334 freq_vco_in = 32000000UL/p_hw_config->PLLM;
335 if (freq_vco_in > PLL_INPUTRANGE0_FREQMAX)
336 {
337 freq_vco_in = RCC_PLL_VCOINPUT_RANGE1;
338 }
339 else
340 {
341 freq_vco_in = RCC_PLL_VCOINPUT_RANGE0;
342 }
343 __HAL_RCC_PLL1_VCOINPUTRANGE_CONFIG(freq_vco_in);
344
345 __HAL_RCC_PLL1_CONFIG(RCC_PLLSOURCE_HSE, /* PLL clock source is always HSE 32MHz */
346 p_hw_config->PLLM,
347 p_hw_config->PLLN,
348 p_hw_config->PLLP,
349 p_hw_config->PLLQ,
350 p_hw_config->PLLR
351 );
352
353 LL_RCC_SetAHB5Prescaler(p_hw_config->AHB5_PLL1_CLKDivider);
354
355 /* PLL is now initialized */
356 scm_system_clock_config.pll.are_pll_params_initialized = 1;
357 }
358
359 /* Public functions ----------------------------------------------------------*/
360
361 /**
362 * @brief System Clock Manager init code
363 * @param None
364 * @retval None
365 */
scm_init()366 OPTIMIZED void scm_init()
367 {
368 /* init scm_system_clock_config with LP config
369 * scm_system_clock_config SHALL BE UPDATED BY READING HW CONFIG FROM HAL APIs
370 * SHALL BE CALLED AFTER SystemClock_Config()
371 **/
372
373 /* Default PLL configuration => no configuration */
374 memset(&(scm_system_clock_config.pll), 0, sizeof(scm_pll_config_t));
375
376 /* Reading FLASH and SRAMs waitstates from registers */
377 scm_system_clock_config.flash_ws_cfg = __HAL_FLASH_GET_LATENCY();
378 scm_system_clock_config.sram_ws_cfg = HAL_RAMCFG_GetWaitState(&sram1_ns);
379
380 /* Link Layer is not active at this stage */
381 RadioState = SCM_RADIO_NOT_ACTIVE;
382
383 /* Enable RAMCFG clock */
384 __HAL_RCC_RAMCFG_CLK_ENABLE();
385
386 /* Reading system core clock configuration from registers */
387 switch(LL_RCC_GetSysClkSource())
388 {
389 case LL_RCC_SYS_CLKSOURCE_STATUS_HSI:
390 /* HSI system clock configuration is not supported on SCM module as radio activity is not possible.
391 * Switch to HSE_16MHz required.
392 */
393
394 /* Target system clock frequency is now HSE_16MHZ */
395 scm_system_clock_config.targeted_clock_freq = HSE_16MHZ;
396
397 /* Enable prescaler */
398 LL_RCC_HSE_EnablePrescaler();
399
400 /* Set HDIV 5 */
401 LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_2); /* divided by 2 */
402
403 scm_setup();
404
405 /* Set VOS to range 2 */
406 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
407
408 break;
409
410 case LL_RCC_SYS_CLKSOURCE_STATUS_HSE:
411
412 /* Get AHB5 divider for HSE frequency */
413 if (LL_RCC_HSE_IsEnabledPrescaler())
414 {
415 /* System core clock is HSE_16MHz */
416 scm_system_clock_config.targeted_clock_freq = HSE_16MHZ;
417 }
418 else
419 {
420 /* System core clock is HSE_32MHz */
421 scm_system_clock_config.targeted_clock_freq = HSE_32MHZ;
422 }
423
424 break;
425
426 case LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R:
427 scm_system_clock_config.targeted_clock_freq = SYS_PLL;
428
429 /* Initial PLL configuration */
430 scm_system_clock_config.pll.PLLM = LL_RCC_PLL1_GetDivider();
431 scm_system_clock_config.pll.PLLN = LL_RCC_PLL1_GetN();
432 scm_system_clock_config.pll.PLLP = LL_RCC_PLL1_GetP();
433 scm_system_clock_config.pll.PLLQ = LL_RCC_PLL1_GetQ();
434 scm_system_clock_config.pll.PLLR = LL_RCC_PLL1_GetR();
435 scm_system_clock_config.pll.PLLFractional = LL_RCC_PLL1_GetFRACN();
436 scm_system_clock_config.pll.AHB5_PLL1_CLKDivider = LL_RCC_GetAHB5Prescaler();
437 if(scm_system_clock_config.pll.PLLFractional == PLL_FRACTIONAL_MODE)
438 {
439 scm_system_clock_config.pll.pll_mode = PLL_FRACTIONAL_MODE;
440 }
441 else
442 {
443 scm_system_clock_config.pll.pll_mode = PLL_INTEGER_MODE;
444 }
445
446 break;
447 }
448
449 scm_system_clock_requests[SCM_USER_APP]= scm_system_clock_config.targeted_clock_freq;
450 }
451
452 /**
453 * @brief Setup the system clock source in usable configuration for Connectivity use cases.
454 * Called at startup or out of low power modes.
455 * @param None
456 * @retval None
457 */
scm_setup(void)458 OPTIMIZED void scm_setup(void)
459 {
460 SYSTEM_DEBUG_SIGNAL_SET(SCM_SETUP);
461
462 /* System clock is now on HSI 16Mhz, as it exits from stop mode */
463
464 /* Start HSE */
465 LL_RCC_HSE_Enable();
466
467 if ((LL_RCC_HSE_IsReady() != 0) && (RadioState == SCM_RADIO_ACTIVE))
468 {
469 /**
470 * The current system configuration is:
471 * Range1, HDIV5 cleared, HSEPRE cleared
472 */
473
474 /* Switch System Clock on HSE32 */
475 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
476
477 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
478
479 scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
480
481 /* As system switched to HSE, disable HSI */
482 SCM_HSI_CLK_OFF();
483
484 /* Check if the clock system used PLL before low power mode entry */
485 if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
486 {
487 /* Configure system clock to use PLL */
488 ConfigStartPll();
489 }
490
491 /* Ensure time base clock coherency */
492 SystemCoreClockUpdate();
493 }
494 else
495 {
496 scm_setwaitstates(HSE16);
497
498 /* Check if the system need to increase VOS range (clock frequency higher than HSE 16Mhz)*/
499 if(scm_system_clock_config.targeted_clock_freq != HSE_16MHZ)
500 {
501 /* Set VOS to range 1 */
502 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
503 }
504
505 if (LL_RCC_HSE_IsReady() != 0)
506 {
507 scm_hserdy_isr();
508 }
509 else
510 {
511 /* Enable HSERDY interrupt */
512 __HAL_RCC_ENABLE_IT(RCC_IT_HSERDY);
513 }
514 }
515 SYSTEM_DEBUG_SIGNAL_RESET(SCM_SETUP);
516 }
517
518 /**
519 * @brief Configure the PLL mode and parameters before PLL selection as system clock.
520 * @param p_pll_config PLL coniguration to apply
521 * @retval None
522 * @note scm_pll_setconfig to be called before PLL activation (PLL set as system core clock)
523 */
scm_pll_setconfig(const scm_pll_config_t * p_pll_config)524 OPTIMIZED void scm_pll_setconfig(const scm_pll_config_t *p_pll_config)
525 {
526 /* Initial PLL configuration */
527 scm_system_clock_config.pll.PLLM = p_pll_config->PLLM;
528 scm_system_clock_config.pll.PLLN = p_pll_config->PLLN;
529 scm_system_clock_config.pll.PLLP = p_pll_config->PLLP;
530 scm_system_clock_config.pll.PLLQ = p_pll_config->PLLQ;
531 scm_system_clock_config.pll.PLLR = p_pll_config->PLLR;
532 scm_system_clock_config.pll.PLLFractional = p_pll_config->PLLFractional;
533 scm_system_clock_config.pll.pll_mode = p_pll_config->pll_mode;
534 scm_system_clock_config.pll.AHB5_PLL1_CLKDivider = p_pll_config->AHB5_PLL1_CLKDivider;
535
536 ConfigHwPll(&scm_system_clock_config.pll);
537 }
538
539 /**
540 * @brief Configure the PLL for switching fractional parameters on the fly.
541 * @param pll_frac Up to date fractional configuration.
542 * @retval None
543 * @note A PLL update is requested only when the system clock is
544 * running on the PLL with a different configuration that the
545 * one required
546 */
scm_pll_fractional_update(uint32_t pll_frac)547 OPTIMIZED void scm_pll_fractional_update(uint32_t pll_frac)
548 {
549 /* PLL1FRACEN set to 0 */
550 LL_RCC_PLL1FRACN_Disable();
551
552 /* Update PLL1FRACR register */
553 LL_RCC_PLL1_SetFRACN(pll_frac);
554
555 /* PLL1FRACEN set to 1 */
556 LL_RCC_PLL1FRACN_Enable();
557
558 /* Ensure time base clock coherency */
559 SystemCoreClockUpdate();
560 }
561
562 /**
563 * @brief Set the system clock to the requested frequency.
564 * @param user_id This parameter can be one of the following:
565 * @arg SCM_USER_APP
566 * @arg SCM_USER_LL_FW
567 * @param sysclockconfig This parameter can be one of the following:
568 * @arg HSE_16MHZ
569 * @arg HSE_32MHZ
570 * @arg SYS_PLL
571 * @retval None
572 */
scm_setsystemclock(scm_user_id_t user_id,scm_clockconfig_t sysclockconfig)573 OPTIMIZED void scm_setsystemclock(scm_user_id_t user_id, scm_clockconfig_t sysclockconfig)
574 {
575 scm_clockconfig_t max_freq_requested;
576
577 UTILS_ENTER_LIMITED_CRITICAL_SECTION(RCC_INTR_PRIO<<4);
578
579 /* Register the request by updating the requested frequency for this user */
580 scm_system_clock_requests[user_id] = sysclockconfig;
581
582 /* Get the higher frequency required by the clients */
583 max_freq_requested = scm_getmaxfreq();
584
585 /* Check if we need to apply another clock frequency */
586 if(scm_system_clock_config.targeted_clock_freq != max_freq_requested)
587 {
588 scm_system_clock_config.targeted_clock_freq = max_freq_requested;
589
590 /* Check the current system clock source (HSI or HSE) */
591 if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
592 {
593 /* HSI is still the system clock */
594
595 if(scm_system_clock_config.targeted_clock_freq == HSE_16MHZ)
596 {
597 /* The system clock target is HSE 16Mhz */
598
599 /* Clear VOS (Range 2) */
600 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
601 }
602 else
603 {
604 /* The system clock target is higher than HSE 16Mhz */
605
606 /* Set VOS (Range 1) */
607 LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
608
609 if(RadioState != SCM_RADIO_NOT_ACTIVE)
610 {
611 /* Disable HSERDY interrupt */
612 __HAL_RCC_DISABLE_IT(RCC_IT_HSERDY);
613
614 /* Wait until VOS has changed */
615 while (LL_PWR_IsActiveFlag_VOS() == 0);
616
617 /* Wait until HSE is ready */
618 while (LL_RCC_HSE_IsReady() == 0);
619
620 LL_RCC_HSE_DisablePrescaler();
621
622 /* Switch to HSE */
623 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
624 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
625
626 scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
627
628 LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1);
629
630 SCM_HSI_CLK_OFF();
631
632 /* Check if PLL is requested */
633 if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
634 {
635 /* Configure system clock to use PLL */
636 ConfigStartPll();
637 }
638
639 /* Ensure time base clock coherency */
640 SystemCoreClockUpdate();
641 }
642 }
643
644 /* System clock is going to be configured in RCC HSERDY interrupt */
645 }
646 else
647 {
648 /* HSE is already the system clock source */
649 /* Configure the system clock */
650 scm_systemclockconfig();
651 }
652 }
653 else if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
654 {
655 /* PLL has requested but system clock is already on PLL */
656 scm_pllready();
657 }
658
659 UTILS_EXIT_LIMITED_CRITICAL_SECTION();
660 }
661
662 /**
663 * @brief Called each time the PLL is ready
664 * @param None
665 * @retval None
666 * @note This function is defined as weak in SCM module.
667 * Can be overridden by user.
668 */
scm_pllready(void)669 __WEAK void scm_pllready(void)
670 {
671 /* To be override by user */
672 }
673
674 /**
675 * @brief Configure the Flash and SRAMs wait cycle (when required for system clock source change)
676 * @param ws_lp_config: This parameter can be one of the following:
677 * @arg LP
678 * @arg RUN
679 * @arg HSE16
680 * @arg HSE32
681 * @arg PLL
682 * @retval None
683 */
scm_setwaitstates(const scm_ws_lp_t ws_lp_config)684 OPTIMIZED void scm_setwaitstates(const scm_ws_lp_t ws_lp_config)
685 {
686 /* Configure flash and SRAMs */
687 switch (ws_lp_config) {
688 case LP:
689 __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_3);
690 while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_3);
691 HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_1);
692 HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_1);
693 break;
694
695 case RUN:
696 __HAL_FLASH_SET_LATENCY(scm_system_clock_config.flash_ws_cfg);
697 while(__HAL_FLASH_GET_LATENCY() != scm_system_clock_config.flash_ws_cfg);
698 HAL_RAMCFG_ConfigWaitState(&sram1_ns, scm_system_clock_config.sram_ws_cfg);
699 HAL_RAMCFG_ConfigWaitState(&sram2_ns, scm_system_clock_config.sram_ws_cfg);
700 break;
701
702 case HSE16:
703 __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
704 while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_1);
705 HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_1);
706 HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_1);
707
708 scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_1;
709 scm_system_clock_config.sram_ws_cfg = RAMCFG_WAITSTATE_1;
710
711 break;
712
713 case HSE32:
714 __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_0);
715 while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_0);
716 HAL_RAMCFG_ConfigWaitState(&sram1_ns, RAMCFG_WAITSTATE_0);
717 HAL_RAMCFG_ConfigWaitState(&sram2_ns, RAMCFG_WAITSTATE_0);
718
719 scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_0;
720 scm_system_clock_config.sram_ws_cfg = RAMCFG_WAITSTATE_0;
721
722 break;
723
724 case PLL:
725 /* RAM latencies are alreadey set to 0WS */
726 /* Set Flash LATENCY according to PLL configuration */
727 /* BELOW CONFIGURATION IS WORST CASE, SHALL BE OPTIMIZED */
728 __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_3);
729 while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_3);
730 scm_system_clock_config.flash_ws_cfg = FLASH_LATENCY_3;
731 break;
732
733 default:
734 break;
735 }
736 }
737
738 /**
739 * @brief SCM HSERDY interrupt handler.
740 * Switch system clock on HSE.
741 * @param None
742 * @retval None
743 */
scm_hserdy_isr(void)744 OPTIMIZED void scm_hserdy_isr(void)
745 {
746 SYSTEM_DEBUG_SIGNAL_SET(SCM_HSERDY_ISR);
747
748 if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
749 {
750 /* Wait until VOS has changed */
751 while (LL_PWR_IsActiveFlag_VOS() == 0);
752
753 if(scm_system_clock_config.targeted_clock_freq == HSE_16MHZ)
754 {
755 /**
756 * The current system configuration is:
757 * Range2, HDIV5 set, Wait States compliant to HSE16
758 */
759 LL_RCC_HSE_EnablePrescaler();
760 /* Switch to HSE */
761 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
762 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
763 }
764 else
765 {
766 /**
767 * The current system configuration is:
768 * Range1
769 */
770
771 LL_RCC_HSE_DisablePrescaler();
772
773 /* Switch to HSE */
774 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
775 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
776
777 scm_setwaitstates(HSE32); /* There is no limitation when in Range1 */
778
779 if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
780 {
781 /* The system clock target is based on PLL */
782
783 /* Configure and start PLL */
784 ConfigStartPll();
785 }
786
787 /* Set HDIV 5 */
788 LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1); /* divided by 1 */
789 }
790
791 /* As system switched to HSE, disable HSI */
792 SCM_HSI_CLK_OFF();
793
794 /* Disable HSERDY interrupt */
795 __HAL_RCC_DISABLE_IT(RCC_IT_HSERDY);
796
797 /* Ensure time base clock coherency */
798 SystemCoreClockUpdate();
799 }
800
801 SYSTEM_DEBUG_SIGNAL_RESET(SCM_HSERDY_ISR);
802 }
803
804 /**
805 * @brief SCM PLLRDY interrupt handler.
806 * Switch system clock on PLL.
807 * @param None
808 * @retval None
809 */
scm_pllrdy_isr(void)810 OPTIMIZED void scm_pllrdy_isr(void)
811 {
812 if(scm_system_clock_config.targeted_clock_freq == SYS_PLL)
813 {
814 /* Set PLL compatible waitstates */
815 scm_setwaitstates(PLL);
816
817 /* Switch to PLL */
818 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1R);
819 while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R);
820
821 /* Ensure time base clock coherency */
822 SystemCoreClockUpdate();
823
824 scm_pllready();
825 }
826 else
827 {
828 /**
829 * The PLL was enabled but is not used anymore as system clock
830 * The only case is when a request has been made and cancelled before
831 * the system had time to switch the system clock on PLL
832 */
833 /* Disable PLL */
834 LL_RCC_PLL1_Disable();
835
836 /* Disable PLL1RDY interrupt */
837 __HAL_RCC_DISABLE_IT(RCC_IT_PLL1RDY);
838 }
839 }
840
841 /**
842 * @brief Notify the state of the Radio
843 * @param radio_state: This parameter can be one of the following:
844 * @arg SCM_RADIO_ACTIVE
845 * @arg SCM_RADIO_NOT_ACTIVE
846 * @retval None
847 */
scm_notifyradiostate(const scm_radio_state_t radio_state)848 OPTIMIZED void scm_notifyradiostate(const scm_radio_state_t radio_state)
849 {
850 if(radio_state != SCM_RADIO_NOT_ACTIVE)
851 {
852 RadioState = SCM_RADIO_ACTIVE; /* shall be set before calling scm_setsystemclock() */
853 scm_setsystemclock(SCM_USER_LL_FW, HSE_32MHZ); /* shall be set before calling scm_setsystemclock() */
854 }
855 else
856 {
857 RadioState = SCM_RADIO_NOT_ACTIVE;
858 scm_setsystemclock(SCM_USER_LL_FW, HSE_16MHZ);
859 }
860 }
861
862 /**
863 * @brief Restore system clock configuration when moving out of standby.
864 * @param None
865 * @retval None
866 */
scm_standbyexit(void)867 OPTIMIZED void scm_standbyexit(void)
868 {
869 if(scm_system_clock_config.pll.are_pll_params_initialized == 1)
870 {
871 /* Restore PLL even if not yet used in case it has been setup upfron at initialization */
872 ConfigHwPll(&scm_system_clock_config.pll);
873 }
874
875 scm_setup();
876 }
877
878 #else /* CFG_SCM_SUPPORTED */
scm_pllrdy_isr(void)879 __weak void scm_pllrdy_isr(void){/* Intentionally enpty */}
scm_hserdy_isr(void)880 __weak void scm_hserdy_isr(void){/* Intentionally enpty */}
881 #endif /* CFG_SCM_SUPPORTED */
882