Preface
Look at the knowledge point routine of the STM32H743I-EVAL2 board.After counting, it looks like there are more than 100 demo s.
Now look at the RCC_ClockConfig routine.The knowledge point of the last external interrupt demo is used.
RCC_ClockConfig routine that dynamically switches the clock source to HSE, HSI, CSI through an external interrupt (button) response.
The point of knowledge is clear, but you don't know the demo scenario.There is no rebuilding project with CubeMx, just look at it and know it.
What is the need to switch the clock source dynamically? Usually the clock source is matched with CubeMX to generate the initialization code, so it will not change.
In the routine, SystemClock_Config() is generated by CubeMx and called once in the main function.
The functions for dynamically switching the clock source are SystemClockCSI_Config(), SystemClockHSI_Config(), SystemClockHSE_Config().
Take a note of these four functions.
test
After the external interrupt is pressed, the order of modifying the clock source is HSE (initializing the clock source is HSE). After the button is pressed, the order of dynamically modifying the clock source by the external interrupt response function is HSE => HSI => CSI => HSE
/** * @brief switch in system clock out of ISR context. * @retval None */ static void SwitchSystemClock(void) { if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI) { // 2. HSI => CSI /* PLL source is HSI oscillator */ /* Set SYSCLK frequency to 400000000 Hz, coming from the PLL which is clocked by CSI */ SystemClockCSI_Config(); } else if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) { // CubeMx is configured with an HSE clock source, so when you press a key, the first thing you do is here 1. HSE => HSI /* PLL source is HSE oscillator */ /* Set SYSCLK frequency to 400000000 Hz, coming from the PLL which is clocked by HSI */ SystemClockHSI_Config(); } else if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_CSI) { /* PLL source is CSI oscillator */ /* Set SYSCLK frequency to 400000000 Hz, coming from the PLL which is clocked by HSE */ // 3. CSI => HSE returns to the system default clock source SystemClockHSE_Config(); } /* reset global variable */ SwitchClock = RESET; }
Initialize clock source
/** * @brief System Clock Configuration * The system Clock is configured as follow : * System Clock source = PLL (HSE) * SYSCLK(Hz) = 400000000 (CPU Clock) * HCLK(Hz) = 200000000 (AXI and AHBs Clock) * AHB Prescaler = 2 * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz) * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz) * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz) * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz) * HSE Frequency(Hz) = 25000000 * PLL_M = 5 * PLL_N = 160 * PLL_P = 2 * PLL_Q = 4 * PLL_R = 2 * VDD(V) = 3.3 * Flash Latency(WS) = 4 * @param None * @retval None */ static void SystemClock_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; /*!< Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /* The voltage scaling allows optimizing the power consumption when the device is clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {} /* Enable HSE Oscillator and activate PLL with HSE as source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // The default is to use HSE crystal oscillation // Turn on HSE only, turn off (HSI, CSI) RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_OFF; RCC_OscInitStruct.CSIState = RCC_CSI_OFF; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // Using a phase-locked loop RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // The source of PLL is HSE // Lock-in-loop parameter can turn on CubeMx to have a look RCC_OscInitStruct.PLL.PLLM = 5; RCC_OscInitStruct.PLL.PLLN = 160; RCC_OscInitStruct.PLL.PLLFRACN = 0; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLQ = 4; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { while(1) {} } // Set the peripheral channel clock (specify the crossover factor after PLL) /* Select PLL as system clock source and configure bus clocks dividers */ RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; // Setting is the peripheral clock channel // FLASH_LATENCY_4 requires 4 clock cycles for flash memory delay if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { while(1) {} } }
Switch clock source from CSI => HSE
/** * @brief Switch the PLL source from CSI to HSE , and select the PLL as SYSCLK * The system Clock is configured as follow : * System Clock source = PLL (HSE) * SYSCLK(Hz) = 400000000 (CPU Clock) * HCLK(Hz) = 200000000 (AXI and AHBs Clock) * AHB Prescaler = 2 * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz) * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz) * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz) * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz) * HSE Frequency(Hz) = 25000000 * PLL_M = 5 * PLL_N = 160 * PLL_P = 2 * PLL_Q = 4 * PLL_R = 2 * VDD(V) = 3.3 * Flash Latency(WS) = 4 * @param None * @retval None */ static void SystemClockHSE_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // Now cut the clock source to the CSI to modify the clock source (this is different from the first initialization clock) /* -1- Select CSI as system clock source to allow modification of the PLL configuration */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_CSI; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* -2- Enable HSE Oscillator, select it as PLL source and finally activate the PLL */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // Clock source for operation is HSE RCC_OscInitStruct.HSEState = RCC_HSE_ON; // HSE on RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // PLL Open RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL source is HSE // Reference to CubeMX graphical configuration RCC_OscInitStruct.PLL.PLLM = 5; RCC_OscInitStruct.PLL.PLLN = 160; RCC_OscInitStruct.PLL.PLLFRACN = 0; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLQ = 4; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } // Set device channel clock /* Select PLL as system clock source and configure bus clocks clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { /* Initialization Error */ Error_Handler(); } // Turn on HSE only (turn off CSI because last clock source was CSI) /* -4- Optional: Disable CSI Oscillator (if the HSI is no more needed by the application)*/ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_CSI; // Clock source for operation is CSI RCC_OscInitStruct.CSIState = RCC_CSI_OFF; // Turn off CSI RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Disconnect CSI and PLL if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } }
/** * @brief Switch the PLL source from HSE to HSI, and select the PLL as SYSCLK * source. * System Clock source = PLL (HSI) * SYSCLK(Hz) = 400000000 (CPU Clock) * HCLK(Hz) = 200000000 (AXI and AHBs Clock) * AHB Prescaler = 2 * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz) * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz) * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz) * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz) * HSI Frequency(Hz) = 64000000 * PLL_M = 16 * PLL_N = 200 * PLL_P = 2 * PLL_Q = 4 * PLL_R = 2 * VDD(V) = 3.3 * Flash Latency(WS) = 4 * @param None * @retval None */ static void SystemClockHSI_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // You can modify the target clock source only if you specify a different clock source than the one you want to modify // E.g. To modify the HSI as the final clock source, first set the clock source as an idle clock source (e.g. The clock source is now HSE and the clock source is HSI) /* -1- Select HSE as system clock source to allow modification of the PLL configuration */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* -2- Enable HSI Oscillator, select it as PLL source and finally activate the PLL */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; // Reference to CubeMx graphical settings RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 16; RCC_OscInitStruct.PLL.PLLN = 200; RCC_OscInitStruct.PLL.PLLFRACN = 0; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLQ = 4; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* Select PLL as system clock source and configure bus clocks clocks dividers */ // Set up device clock channel RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* -4- Optional: Disable HSE Oscillator (if the HSE is no more needed by the application) */ // Turn off the previous clock source (HSE). RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_OFF; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } }
/** * @brief Switch the PLL source from HSI to CSI, and select the PLL as SYSCLK * source. * System Clock source = PLL (CSI) * SYSCLK(Hz) = 400000000 (CPU Clock) * HCLK(Hz) = 200000000 (AXI and AHBs Clock) * AHB Prescaler = 2 * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz) * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz) * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz) * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz) * CSI Frequency(Hz) = 4000000 * PLL_M = 1 * PLL_N = 200 * PLL_P = 2 * PLL_Q = 4 * PLL_R = 2 * VDD(V) = 3.3 * Flash Latency(WS) = 4 * @param None * @retval None */ static void SystemClockCSI_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // Since the last clock source was HSI (the order of clock source switching pressed by the button is HSE => HSI => CSI => HSE), cut to HSI first /* -1- Select HSI as system clock source to allow modification of the PLL configuration */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* -2- Enable CSI Oscillator, select it as PLL source and finally activate the PLL */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_CSI; RCC_OscInitStruct.CSIState = RCC_CSI_ON; RCC_OscInitStruct.CSICalibrationValue = RCC_CSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_CSI; RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 200; RCC_OscInitStruct.PLL.PLLFRACN = 0; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLQ = 4; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* Select PLL as system clock source and configure bus clocks clocks dividers */ RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { /* Initialization Error */ Error_Handler(); } /* -4- Optional: Disable HSI Oscillator (if the HSI is no more needed by the application) */ // Turn off the last clock source HSI RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSEState = RCC_HSI_OFF; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ Error_Handler(); } }
summary
This demo doesn't make much sense.
How to write clock initialization without using CubeMx? Those crossover, frequency doubling coefficients (so complex coefficients...) How to fill in?
On practical engineering boards, the clock source used is the external crystal oscillation on HSE (for clock accuracy), so what should be sliced onto the intra-chip crystal oscillation?
If the external crystal breaks down, it seems that the document says that the STMCU will automatically cut to the HSI (to keep the system from hanging up, but the system will run at a much slower speed).So why do you want to slice the crystal in the slice by hand?