Library 59- Change PLL settings while STM32F4xx is running
I’ve been already talking about topic, how to properly set clock speed for your device with PLL settings. This article could be found here and it is definetelly worth of readiny, especially for beginners.
Today, it was very rainy and bad day, so I was thinking about a library that could dynamically change PLL settings. This can be used to change current consumption of your device if there is no need for very high speed clock for some time.
Changing PLL parameters could be very tricky, because you are not able to just set custom value in PLL CONFIG register and hope that it will just work. It won’t.
Here are steps, how you can change PLL settings if PLL is already running:
- Enable HSI/HSE for system core clock
- Select HSI/HSE as system core clock and not PLL
- Disable PLL
- Change PLL parameters
- Enable PLL and wait till it is ready
- Select PLL as system core clock back
This is about 10 lines of code, but knowing that might save your life when you will see that PLL parameters are not changed when you write to register.
Notes: When you change PLL settings and if System core clock is changed, you have to know, that all peripheral buses APB1, APB2, AHB1, AHB2 and AHB3 have also different clock in relation to the system core clock.
When you change clock, you will have to reinit all of your used peripherals again. For example, USART’s baudrate settings depends on APB clock. If it is changed, baudrate is changed and will not be the same as before. This will break your received data. In example below, you will see what I’m talking about.
The same goes for all other peripheral, such as all timers, including systick timer, which might not do interrupts at desired timer period as you defined at startup.
Library
Features
- Set custom PLL settings
- Get custom PLL settings
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- TM
- defines.h
- defines.h
Functions and enumerations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
/** * @defgroup TM_RCC_Typedefs * @brief Library Typedefs * @{ */ /** * @brief PLL structure with settings for read and write operations */ typedef struct { uint16_t PLLM; /*!< PLL M parameter. This value can be between 2 and 63. Use 0 if you don't want to change parameter. */ uint16_t PLLN; /*!< PLL M parameter. This value can be between 192 and 432. Use 0 if you don't want to change parameter. */ uint16_t PLLP; /*!< PLL M parameter. This value can be 2, 4, 6 or 8. Use 0 if you don't want to change parameter. */ uint16_t PLLQ; /*!< PLL M parameter. This value can be between 2 and 15. Use 0 if you don't want to change parameter. */ uint16_t PLLR; /*!< PLL M parameter. This value can be between 2 and 7 and is only available for STM32F446 devices. Use 0 if you don't want to change parameter. */ } TM_RCC_PLL_t; /** * @} */ /** * @defgroup TM_RCC_Functions * @brief Library Functions * @{ */ /** * @brief Sets the main PLL settings for STM32F4xx device * @note PLL can only be configured when PLL is not used as system clock. * For that purpose, this function does the following things: * - Enables HSI as system core clock * - Disables PLL * - Sets PLL parameters passed as parameters in function * - Enables PLL * - Waits will PLL is ready and locked * - Enables PLL as system core clock * - Updates system core clock variable * @param *PLL_Settings: Pointer to @ref TM_RCC_PLL_t structure with PLL settings. * Use 0 for setting you don't want to change * @retval None */ void TM_RCC_SetPLL(TM_RCC_PLL_t* PLL_Settings); /** * @brief Gets current PLL settings from RCC registers * @note You can use this function to read current PLL settings before applying new settings * @param *PLL_Settings: Pointer to @ref TM_RCC_PLL_t structure where PLL settings will be stored * @retval None */ void TM_RCC_GetPLL(TM_RCC_PLL_t* PLL_Settings); /** * @brief Checks if main PLL is ready * @param None * @retval PLL ready status: * - 0: PLL is not ready * - > 0: PLL is ready */ uint8_t TM_RCC_IsPLLReady(void); /** * @} */ |
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
/** * Keil project for changing PLL settings when device is running * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx Keil packs version 2.4.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.5.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_usart.h" #include "tm_stm32f4_rcc.h" #include "stdio.h" int main(void) { /* RCC clocks typedef */ RCC_ClocksTypeDef RCC_Clocks; /* RCC PLL structure */ TM_RCC_PLL_t PLL; /* Initialize system */ SystemInit(); /* Initialize delay, systick has interrupts every 1ms by default */ TM_DELAY_Init(); /* Init USART2, TX: PA2, RX: PA3, 921600 baud */ TM_USART_Init(USART2, TM_USART_PinsPack_1, 921600); /* Get current system clock */ RCC_GetClocksFreq(&RCC_Clocks); /* Print current system clock */ printf("System core clock: %d\n", RCC_Clocks.SYSCLK_Frequency); /* Read PLL settings */ TM_RCC_GetPLL(&PLL); /* Set PLL N to some random value */ PLL.PLLN = 200; /* Change PLL settings */ TM_RCC_SetPLL(&PLL); /* Send something over USART */ printf("This will not be seen correct on USART\n"); /* Reinit everything with new clock */ /* You have to reinit everything what depends on system CLOCK */ /* Like timer prescalers, usarts, i2c, etc */ /* Set new systick preload value */ TM_DELAY_Init(); /* Set new prescalers for USART settings */ TM_USART_Init(USART2, TM_USART_PinsPack_1, 921600); /* Get current system clock */ RCC_GetClocksFreq(&RCC_Clocks); /* Print current system clock */ /* This will be seen on console with new settings */ printf("System core clock after PLL change: %d\n", RCC_Clocks.SYSCLK_Frequency); while (1) { } } /* Handle printf functionality */ int fputc(int ch, FILE* fil) { /* Send character over USART */ TM_USART_Putc(USART2, ch); /* Return character */ return ch; } /* Handle 1ms interrupts from systick timer */ void TM_DELAY_1msHandler(void) { /* Do work, called every 1ms */ } |
Project is available on my Github, download library below.
Recent comments