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