Stm32 clock analysis
Most of the analysis materials come from the opendev forum. All I did was add some of my own analysis and collation. Due to my limited personal ability, omissions are inevitable. I welcome your corrections.
1. Hardware connection issues
If you use the internal RC oscillator instead of an external crystal oscillator, please proceed as follows:
1) For products with 100 or 144 pins, OSC_IN should be grounded and OSC_OUT should be left floating.
2) For products with less than 100 pins, there are two ways to connect:
i) OSC_IN and OSC_OUT are grounded through 10K resistors. This method can improve EMC performance.
ii) Remap OSC_IN and OSC_OUT to PD0 and PD1 respectively, and then configure PD0 and PD1 as push-pull outputs and output '0'. This method can reduce power consumption and save 2 external resistors (compared to i above).
The analysis of the above figure is as follows:
Important clocks:
The relationship between PLLCLK, SYSCLK, HCKL, PCLK1, PCLK2 should be clarified;
1. HSI: high-speed internal clock signal The clock (8M frequency) in the STM32 microcontroller has poor accuracy
2. HSE: high-speed external clock signal High-precision source (1) HSE external crystal/ceramic resonator (crystal oscillator) (2) HSE user external clock
3. LSE: low-speed external crystal 32.768kHz mainly provides an accurate clock source Generally used as an RTC clock
in STM32, there are five clock sources, HSI, HSE, LSI, LSE, PLL.
①, HSI is a high-speed internal clock, RC oscillator, with a frequency of 8MHz.
②, HSE is a high-speed external clock, which can be connected to a quartz/ceramic resonator, or an external clock source, with a frequency range of 4MHz~16MHz.
③, LSI is a low-speed internal clock, RC oscillator, with a frequency of 40kHz.
④. LSE is a low-speed external clock connected to a quartz crystal with a frequency of 32.768kHz.
⑤. PLL is a phase-locked loop frequency multiplication output, and its clock input source can be selected as HSI/2, HSE or HSE/2. The frequency multiplication can be selected from 2 to 16 times, but its maximum output frequency must not exceed 72MHz.
The 40kHz LSI is used for the independent watchdog IWDG, and it can also be selected as the clock source of the real-time clock RTC. In addition, the clock source of the real-time clock RTC can also be selected as LSE, or 128-division of HSE. The clock source of RTC is selected by RTCSEL[1:0].
There is a full-speed USB module in STM32, and its serial interface engine requires a clock source with a frequency of 48MHz. This clock source can only be obtained from the PLL output, and can be selected as 1.5 division or 1 division, that is, when the USB module needs to be used, the PLL must be enabled and the clock frequency is configured to 48MHz or 72MHz.
In addition, STM32 can also select a clock signal to output to the MCO pin (PA8), which can be selected as the 2-division of the PLL output, HSI, HSE, or system clock.
The system clock SYSCLK is the clock source for most components in STM32. The system clock can be selected as PLL output, HSI or HSE. The maximum frequency of the system clock is 72MHz. It is divided by the AHB divider and sent to each module for use. The AHB divider can select 1, 2, 4, 8, 16, 64, 128, 256, 512 divisions. The clock output by the AHB divider is sent to 5 major modules:
①, sent to the HCLK clock used by the AHB bus, core, memory and DMA.
②, sent to the system timer clock of Cortex after 8 division.
③, sent directly to the idle running clock FCLK of Cortex.
④, sent to the APB1 divider. The APB1 divider can be divided into 1, 2, 4, 8, or 16 frequency divisions. One of its outputs is used by the APB1 peripheral (PCLK1, maximum frequency 36MHz), and the other is sent to the timer (Timer) 2, 3, or 4 frequency multipliers. The frequency multiplier can be selected as 1 or 2 times, and the clock output is used by timers 2, 3, and 4.
⑤. Sent to the APB2 divider. The APB2 divider can be divided into 1, 2, 4, 8, or 16 frequency divisions. One of its outputs is used by the APB2 peripheral (PCLK2, maximum frequency 72MHz), and the other is sent to the timer (Timer) 1 frequency multiplier. The frequency multiplier can be selected as 1 or 2 times, and the clock output is used by timer 1. In addition, the APB2 divider has one output for the ADC divider, which is sent to the ADC module after division. The ADC divider can be divided into 2, 4, 6, or 8 times.
Among the above clock outputs, many have enable control, such as AHB bus clock, core clock, various APB1 peripherals, APB2 peripherals, etc. When you need to use a module, remember to enable the corresponding clock first.
It should be noted that the timer multiplier, when the APB division is 1, its multiplier value is 1, otherwise its multiplier value is 2.
The devices connected to APB1 (low-speed peripherals) are: power interface, backup interface, CAN, USB, I2C1, I2C2, UART2, UART3, SPI2, window watchdog, Timer2, Timer3, Timer4. Note that although the USB module requires a separate 48MHz clock signal, it should not be the clock for the USB module to work, but only the clock provided to the serial interface engine (SIE). The clock for the USB module to work should be provided by APB1.
The devices connected to APB2 (high-speed peripherals) are: UART1, SPI1, Timer1, ADC1, ADC2, all ordinary IO ports (PA~PE), and second function IO ports.
Registers involved:
RCC register structure, RCC_TypeDeff, is defined in the file "stm32f10x_map.h" as follows:
typedef struct
{
vu32 CR; //HSI, HSE, CSS, PLL, etc. enable
vu32 CFGR; //PLL, etc. clock source selection and division coefficient setting
vu32 CIR; // Clear/enable clock ready interrupt
vu32 APB2RSTR; //APB2 line peripheral reset register
vu32 APB1RSTR; //APB1 line peripheral reset register
vu32 AHBENR; //DMA, SDIO, etc. clock enable
vu32 APB2ENR; //APB2 line peripheral clock enable
vu32 APB1ENR; //APB1 line peripheral clock enable
vu32 BDCR; //Backup domain control register
vu32 CSR;
} RCC_TypeDef;
The specific definition and usage of these registers can be found in the chip manual, because C language development does not need to deal with them directly. Of course, if you can understand and remember them, it will undoubtedly be beneficial.
If the external crystal oscillator is 8Mhz and the maximum operating frequency is 72Mhz, it is obviously necessary to use PLL multiplier 9 times. These settings need to be completed in the initialization stage. For the convenience of explanation, the RCC setting function of the routine is used and explained in the form of Chinese comments:
static void RCC_Config(void)
{
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//This sentence is missing in the above routine, but it is very important
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08)
{}
}
//Enable the peripheral interface bus clock. Pay attention to the affiliation of each peripheral. Different chips have different allocations. You can check the manual when the time comes
. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |
RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG |
RCC_APB2Periph_AFIO, ENABLE);
}
From the above program, it can be seen that the setting of the system clock is relatively complicated. The more peripherals there are, the more factors need to be considered. At the same time, this setting also has rules to follow, and the setting parameters are also in order and specification. This should be noted in the application. For example, the setting of PLL needs to be before enabling. Once the PLL is enabled, the parameters cannot be changed.
After this setting, for the case of an external 8Mhz crystal oscillator, the system clock is 72Mhz, the high-speed bus and low-speed bus 2 are both 72Mhz, the low-speed bus 1 is 36Mhz, the ADC clock is 12Mhz, and the USB clock can achieve 48Mhz data transmission after 1.5 division.
The general clock setting needs to consider the source of the system clock first, whether it is an internal RC, an external crystal or an external oscillator, and whether a PLL is needed. Then consider the internal bus and the external bus, and finally consider the clock signal of the peripherals. Follow the principle of multiplying the frequency first as the CPU clock, and then dividing the frequency from the inside to the outside, and the lower level accommodates the upper level.
Clock Control Register (RCC_CR)
31~26 | 25 | 24 | 23~20 | 19 | 18 | 17 | 16 |
reserve | PLLRDY | PLLON | reserve | CSSON | HSEBYP | HSERDY | HSEON |
eg:RCC->CR|=0x00010000; //External high-speed clock enable HSEON
RCC->CR|=0x01000000; //Enable PLLON
RCC->CR>>25; //Wait for PLL to lock
Clock Configuration Register (RCC_CFGR)
31:27 | 26:24 | 23 | 22 | 21:18 | 17 | 16 | |||||
reserve | MCO[2:0] | reserve | USBPRE | PLLMUL[3:0] | PLLXTPRE | PLLSRC | |||||
15:14 | 13:11 | 10:8 | 7:4 | 3:2 | 1:0 | ||||||
ADCPRE[1:0] | PPRE2[2:0] | PPRE1[2:0] | HPRE[3:0] | SWS[1:0] | SW[1:0] |
Position 26:24 | MCO: Microcontroller clock output Set to '1' or cleared to 0 by software. 0xx: no clock output; 100: system clock (SYSCLK) output; 101: internal RC oscillator clock (HSI) output; 110: external oscillator clock (HSE) output; 111: PLL clock is divided by 2 and output. |
Position 22 | USBPRE: USB prescaler Set to 1 or clear to 0 by software to generate a 48MHz USB clock. This bit must be valid before enabling the USB clock in the RCC_APB1ENR register. If the USB clock is enabled, this bit cannot be cleared. 0: PLL clock is divided by 1.5 times as USB clock 1: PLL clock is directly used as USB clock |
Position 21:18 | PLLMUL: PLL multiplication factor The PLL multiplication factor is determined by software settings. It can only be written when the PLL is turned off. Note: The output frequency of PLL cannot exceed 72MHz 0000: PLL 2x frequency output 1000: PLL 10x frequency output 0001: PLL 3x frequency output 1001: PLL 11x frequency output 0010: PLL 4x frequency output 1010: PLL 12x frequency output 0011: PLL 5x frequency output 1011: PLL 13x frequency output 0100: PLL 6x frequency output 1100: PLL 14x frequency output 0101: PLL 7x frequency output 1101: PLL 15x frequency output 0110: PLL 8x frequency output 1110: PLL 16x frequency output 0111: PLL 9x frequency output 1111: PLL 16x frequency output |
Position 17 | PLLXTPRE: HSE divider for PLL entry Set to '1' or clear to '0' by software to divide HSE as PLL input clock. This bit can only be written when PLL is turned off. 0: HSE does not divide the frequency 1: HSE 2-way |
Bit 16 | PLLSRC: PLL input clock source (PLL entry clock source) Set to '1' or clear to '0' by software to select the PLL input clock source. This bit can only be written when the PLL is turned off. 0: HSI oscillator clock is divided by 2 and used as PLL input clock 1: HSE clock is used as PLL input clock. |
Position 15:14 | ADCPRE[1:0]: ADC prescaler Set to 1 or clear to 0 by software to determine the ADC clock frequency 00: PCLK2 divided by 2 is used as ADC clock 01: PCLK2 divided by 4 is used as ADC clock 10: PCLK2 divided by 6 is used as ADC clock 11: PCLK2 divided by 8 is used as ADC clock |
Position 13:11 | PPRE2[2:0]: APB high-speed prescaler (APB2) Set to '1' or clear to '0' by software to control the prescaler factor of the high-speed APB2 clock (PCLK2). 0xx: HCLK is not divided 100: HCLK divided by 2 101: HCLK divided by 4 110: HCLK divided by 8 111: HCLK 16-division |
Position 10:8 | PPRE1[2:0]: APB low-speed prescaler (APB1) Set to '1' or clear to '0' by software to control the prescaler factor of the low-speed APB1 clock (PCLK1). Warning: The software must ensure that the APB1 clock frequency does not exceed 36MHz. 0xx: HCLK is not divided 100: HCLK divided by 2 101: HCLK divided by 4 110: HCLK divided by 8 111: HCLK 16-division |
Position 7:4 | HPRE[3:0]: AHB prescaler Set to '1' or clear to '0' by software to control the pre-scaling factor of the AHB clock. 0xxx: SYSCLK is not divided 1000: SYSCLK divided by 2 1100: SYSCLK divided by 64 1001: SYSCLK divided by 4 1101: SYSCLK divided by 128 1010: SYSCLK divided by 8 1110: SYSCLK divided by 256 1011: SYSCLK divided by 16 1111: SYSCLK divided by 512 |
Position 3:2 | SWS[1:0]: System clock switch status Set to '1' or cleared to '0' by hardware to indicate which clock source is used as the system clock. 00: HSI is used as the system clock; 01: HSE is used as the system clock; 10: PLL output as system clock; 11: Not available. |
Bit 1:0 | SW[1:0]: System clock switch Set to '1' or clear to '0' by software to select the system clock source. 00: HSI is used as the system clock; 01: HSE is used as the system clock; 10: PLL output as system clock; 11: Unavailable |
eg: RCC->CFGR=0x00000400; //APB1=DIV2;APB2=DIV1 (no frequency division);AHB=DIV1 (no frequency division);
Set the clock process according to the STM32 library function:
RCC_DeInit(); //Set the RCC register to default value
RCC_HSEConfig(RCC_HSE_ON); //Turn on the external high-speed clock crystal
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //Wait for the external high-speed clock crystal to work
if(HSEStartUpStatus == SUCCESS) //External ready
{
//Add here PLL ans system clock config
RCC_HCLKConfig(RCC_SYSCLK_Div1); //Set AHB clock to non-divided
RCC_PCLK2Config(RCC_HCLK_Div1); //Set APB2 clock to non-divided
RCC_PCLK1Config(RCC_HCLK_Div2); //Set APB1 clock frequency to 2
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //Set ADC clock frequency to six
//Set the PLL clock to multiply the 8M clock by 9 times to 72M
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
RCC_PLLCmd(ENABLE); //Enable PLL
FlagStatus Status;
Status = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);
if(Status == RESET)
{
……
}
RCC_SYSCLKConfig(RCC-SYSCLKSource_PLLCLK); //Set PLL output to system clock
while(RCC_GetSYSCLKSource()!=0x08) //Test whether PLL is used as system clock and wait for verification to complete
{}
}
else
{
//Add here some code to deal with this error
}
// Enable the peripheral interface bus clock
RCC_APB2PeriphClockCmd() / RCC_APB1PeriphClockCmd()
Specific configuration process:
first step:
Reset and configure the vector table.
Function MYRCC_DeInit();
The following function is analyzed:
(1) Set the peripheral reset register: RCC->APB1RSTR = 0x00000000
This register contains the reset settings of peripherals such as DAC, power reset, timer, etc. A bit of 1 indicates that the corresponding peripheral is reset. The register data is cleared when the machine is powered on.
(2) Set the peripheral reset register: RCC->APB2RSTR = 0x00000000
Same as the first step of setting the peripheral reset register.
answer:
RCC->APB1RSTR = 0x00000000; //Reset ends
RCC->APB2RSTR = 0x00000000;
What does "reset ends" mean here? ? I commented it out and found that it can still run
1 is reset. 0 is of course not reset. If
not reset, then the reset is over.
(3) Sleep mode Flash and SRAM clocks are enabled, others are turned off. Used to use SRAM. SRAM is equivalent to the memory of a PC.
STm32 has three startup modes:
1. ISP mode. This mode is that after STM32 is reset, it executes the BOOTLOADER program that is fixed inside (it is fixed and we cannot read or write it.), and then waits for serial port data to realize the serial port bootloader function.
This mode will not start from the user storage area (unless it is controlled by the serial port to start from 0X08000000), so after updating the code, it needs to be set to other modes (FLASH mode).
2. FLASH startup mode. This mode starts directly from 0X08000000, which is the startup method of the code we wrote ourselves. This should be used in normal situations.
3. SRAM startup mode. I have not used this mode. It starts from 0X20000000, that is, before the sram mode starts, you must make sure that there is code in the SRAM, otherwise it will freeze.
RCC->AHBENR = 0x00000014
(4) Set the peripheral clock enable register:
RCC->APB1ENR = 0x00000000;
RCC->APB2ENR = 0x00000000; Turn off all peripherals
(5) Enable internal high-speed HSION.
RCC->CR |=0x00000001;
The clock startup process of stm32.
The startup process is:
1. First use the internal clock (this is why you can download the code without connecting the crystal oscillator).
2. Try to turn on the external clock.
3. If it is successfully turned on, use the external clock, otherwise use the internal clock.
4. Do other things.
Of course, you need to write the code to implement the above code yourself. Of course, the internal clock is the default clock, and you don’t have to turn it on.
(6) Reset SW, HPRE, PPRE1, PPRE2, ADCPRE, MCO
RCC->CFGR &= 0xF8FF0000;
What does this step mean? My understanding is that the Cfgr register is mainly used to control the clock division, see the figure below:
Through the configuration of this step:
First, configure MCO to have no output. What is MCO? It means that the internal clock of stm32 can be output through the IO port pin. As shown in the figure above, there are four types of mco outputs for the configuration of cfgr, namely, output after dividing pllclk by two, hsi (on-chip clock) output, etc.
Secondly: configure ADCPRE is the ADC of the AHB divider line surface in the above figure
Next: configure ppre2, which is the high-speed external clock APB2. Set it to non-divided frequency. The high-speed external clock mainly drives some high-speed peripherals. This is introduced in the APB2ENR clock control register.
Again: configure PPRE1, configure the low-speed external clock division, and set APB1 to no division.
Again: configure HPRE. These bits are mainly used to configure the frequency division coefficient of the AHB register. Here it is also set to no frequency division. That is to say, the SYSCLK in the above figure is not divided by AHB.
Finally: configure SW and SWS. This means that HIS is enabled as the system clock.
At this point, after analysis, we know that RCC->CFGR &= 0xF8FF0000; is mainly used to configure the settings of various dividers such as ahb, and to use the on-chip clock as the internal clock of the system.
(6) Close HSEON, CSSON, PLLON
RCC->CR &= 0xFEF6FFFF;
By analyzing the CR register, we can see that this register mainly involves three clocks: PLL, CSS, and HSE.
(7) Reset HSEBYP.
RCC->CR &= 0xFFFBFFFF; What is the purpose of this step? According to page 57 of the data sheet, the external clock source HSE has two modes. When HSEBYP is set to 0, the external crystal is selected as the external clock source. This clock is more accurate and of course it is related to the external circuit. Of course, because HSEON has been set to off in step (6), HSEBYP can be set freely in this step.
(8) 复位PLLSRC,PLLXTPRE,PLLMUL and USBPRE
RCC->CFGR &= 0xFF80FFFF;
Note: In this section you may have questions like:
RCC->CFGR &= 0xFF80FFFF;
PLLSRC=0 The HSI oscillator clock is divided by 2 and used as the PLL input clock
PLLXTPRE=0, the HSE divider is used as the PLL input, and the HSE is not divided
. Is there no conflict?
The answer is: the last configuration shall prevail. That is, the last configuration will change the previous configuration, so the last configuration shall prevail.
That is to say, there are other codes that define it later. So why do we need to repeat the configuration?
Sometimes it is useful. For example, if you want to overclock the stm32 for a while and then resume normal operation, this is useful.
(9) Disable all interrupts
RCC->CIR = 0x00000000;
(10) Configuration vector table
#ifndef VECT_TAB_RAM
MY_NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
MY_NVIC_SetVectorTable(NVIC_VextTab_FLASH,0x0);
#endif
The following is an analysis of the function:
//Function: Set the vector table offset address
//NVIC_VectTab: base address
//Offset: offset
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
//Check parameter validity
assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
assert_param(IS_NVIC_OFFSET(Offset));
SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80); //Set NVIC vector table offset register
//Used to identify whether the vector table is in the CODE area or the RAM area
}
The first two lines are used to check the parameter validity, which will not be analyzed here. Focus on the third line
What is the use of configuring this vector table? See the explanation of the vector table on page 113 of the CortexM3 Definitive Guide
here
#define NVIC_VectTab_RAM ((u32)0x20000000)
#define NVIC_VectTab_FLASH ((u32)0x08000000)
The value of Offset is 0x0, which is the offset address. The address must be divisible by 64 * 4 = 256. For details, please refer to page 113 of the authoritative manual.
SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//Set the NVIC vector table offset register. The questions are as follows:
SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80); //Set the vector table offset register of NVIC.
Since it is to set the vector table offset of NVIC, why do we need to OR it with NVIC_VectTab? Isn't it enough to just set OFFSET? In addition, only BIT [28:7] of VTOR setting is effective. There won't be enough space for so many bits after ORing, right?
This is the base address.
For 7~28, can you define a 28-bit data?
VTOR setting only has BIT [28:7]. Check if (u32) 0x1FFFFF80 is [28:7] in binary format.
Then read the following paragraph:
On page 104 of the <
There is a register in the NVIC called the "vector table offset register" (at address 0xE000_ED08), and the vector table can be located by modifying its value. But it must be noted that there are requirements for the starting address of the vector table: you must first find out how many vectors there are in the system, and then increase this number to an integer power of 2, and the starting address must be aligned to the latter's boundary. For example, if there are 32 interrupts in total, there are 32+16 (system exceptions) = 48 vectors in total, and the value after increasing to an integer power of 2 is 64, so the address
must be divisible by 64*4=256, so the legal starting address can be: 0x0, 0x100, 0x200, etc.
The vector table offset register, that is, SCB->VTOR. Its 29th bit is used to identify whether the vector table is in the CODE area or the RAM area, so 0X1, that is, the highest 3 bits are not moved, which is easy to understand. But the lower bits, according to the understanding of the above paragraph, STM32 has 60 interrupts, plus 16 of CM3, a total of 76 interrupts, expanded to the power of 2, that is 128, and then multiplied by 4, get 512, that is 0X200. According to this calculation, the legal offset address should be 0X0, 0X200, 0X400, 0X600... Therefore, it should be &0X1FFF FE00 here.
The above is my understanding. In fact, it is &0X1FFF FF80; I also have doubts about this.
Answer: The authoritative guide of cortex-m3 says that bit 28-7 is the starting address of the vector table. So the lower 7 bits are not used, so &0X80 is used to clear the lower 7 bits. But here, writing &0X1FFF FE00 can also achieve the purpose of clearing. As for the address must be an integer of 512, just pay attention to the parameter offset.
Let's go back to the Stm32_Clock_Init() function on page 61 of the book STM32:
After the above configuration is completed, start configuring the external clock.
The current implementation of the MinisTM32 development board uses a high-speed external clock as the clock source. After MYRCC_Deinit(), the external clock source is turned off first, and then after cfgr is reconfigured, the high-speed external clock is ready to be turned on.
(11) RCC->CR |= 0x00010000; external high-speed clock enables HSEON. As mentioned earlier, the last setting is used as the reference, so from this step on, HSE is used as the external clock.
(12) Wait for the external clock to be ready
While(!(RCC->CR>>17)); (Actually, the effect of this step is the same as while(RCC->CR&(u32)(1<<17));, because bits 18 to 31 in MYRCC_Deinit() are all 0. Of course, in the forum http://www.openedv.com/posts/list/1943.htm, the 23rd post also admitted that While(!(RCC->CR>>17) is a bit rash to write like this. The 23rd post wrote
In this regard, Atom also said that it is more appropriate to write (RCC-CR>>17)&0X01, but I feel that RCC-CR>>17 is inaccurate. For example, if the 18th bit is 1, then after shifting right by 17 bits, regardless of whether the clock is ready, the result of the expression "RCC-CR>>17" is always true. In this case, while (! (RCC-CR>>17)) is meaningless, right? So writing (RCC-CR>>17)&0X01 is the most accurate.
)
(13) Configure APB1/2 = DIV2 and AHB = DIV1
RCC->CFGR = 0x00000400;
(14) Set PLL frequency division
PLL -=2;
RCC->CFGR = PLL <<18;
Set PLL 9x
There is also a problem involved here, as follows
Actually, here today Lin Meimei asked a more professional question, that is, PLL is a u8 data type, why can it be right shifted 18 bits here? Isn't it already exceeded? Actually, we can understand it by looking at the assembly code, the assembly code is as follows: 219: RCC->CFGR|=PLL<<18; //Set PLL value 2~16 0x08000618 4608 MOV r0,r1 0x0800061A 6840 LDR r0,[r0,#0x04] 0x0800061C EA404084 ORR r0,r0,r4,LSL #18 0x08000620 6048 STR r0,[r1,#0x04] As you can see, this shift operation is performed in R0 and R1. Both r0 and r1 are 32-bit registers, so the shift operation here will not cause an error (the result is assigned to the 32-bit register: RCC->CFGR).
(15) FLASH->ACR |= 0x32 //flash 2 delay cycles. FLASH->ACR|=0x32 is to make the frequency match.
//For details, see "STM32 Flash Programming"
(16) Open PLLON
RCC->CR|=0x01000000;
(17) Waiting for PLL to lock
while(!((RCC->CR>>25)&0x01));
(18) PLL as system clock
RCC->CFGR |= 0x00000002;
(19) Wait for PLL to be successfully set as system clock
Unsigned char Temp = 0;
While(Temp!=0x02)
{
Temp = RCC->CFGR>>2;
Temp &= 0x03;
}
In fact, this code is to judge SWS and wait for the system clock to be successfully converted to PLL clock.
Combined with the above analysis, it is clear that the STM32 clock is always configured. The main flow chart is as follows:
In fact, I personally feel that there are some unnecessary configurations of the routines in mini32, so I changed some of them myself and found that it can also run in the marquee program. Currently, I have only tested it in the marquee program:
first step:
RCC->APB1RSTR = 0x00000000; //Reset ends
RCC->APB2RSTR = 0x00000000;
Step 2:
RCC->AHBENR = 0x00000014; //Sleep mode flash and SRAM clock enable. Others are off.
Step 3: Turn off all peripheral clocks
RCC->APB2ENR = 0x00000000; //Peripheral clock is turned off.
RCC->APB1ENR = 0x00000000;
Why is this step necessary? Because when configuring registers such as cfgr and cr, some peripheral clocks need to be turned off.
the fourth step:
RCC->CR &= 0xFEF2FFFF; //The main function of this patch is to turn on the internal HSION and turn off HSE, CSS, PLLON
Step 5: Set the frequency division register, configure the frequency division, and enable PLLSRC ON
RCC->CFGR=0X00000400; //APB1/2=DIV2;APB2=DIV1;AHB=DIV1; According to the Chinese manual,
The maximum of apb1 is 36MHZ, so it needs to be divided here. Because after this setting, the output of PLLMUL is 72MHZ, so here we need to make APB1/2=DIV2 which is 36MHZ.
PLL-=2; //Offset 2 units
RCC->CFGR|=PLL<<18; //Set PLL value 2~16 Set PLL to 9 times frequency
RCC->CFGR|=1<<16; //PLLSRC ON sets HSE as the input clock. Because the 17th bit of cfgr is also 0, the HSE input to PLLSRC is 8M
At this time, hse is 8MHZ. Obviously, after the 9-times multiplication above, the SYSCLK output to AHB is 72MHZ. Because AHB is set to not divide the frequency, the AHB output is also 72MHZ. Apb1 is divided before, so the output is 36MHZ. Apb2 is 72MHZ
Step 7:
FLASH->ACR|=0x32; //FLASH 2 delay cycles
Step 8:
RCC->CIR = 0x00000000; //Disable all interrupts
Step 9:
//Configure vector table
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //The flash is used here to start
#endif
Step 10:
RCC->CR|=0x00010000; //External high-speed clock enables HSEON. Note that the external clock cannot be the system clock directly or indirectly before enabling hseon. That is to say, the SW bit in cfgr is 0 first. Because it has been set to 0 in the fifth step, there is no need to worry about it here.
while(!(RCC->CR>>17));//Wait for external clock to be ready
Step 11: Turn on the PLL.
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//Wait for PLL to lock
Step 12:
RCC->CFGR|=0x00000002; //PLL as system clock
while(temp!=0x02) //Wait for PLL to be successfully set as system clock
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
/*The above code is a bit messy, let's combine the code to make it easier to read*/
Combined with the clock configuration process of Stm32_Clock_Init(), I summarize the clock configuration as follows:
turn off all peripheral clocks,
(1) enable HSI and turn off HSE, PLL, CSS, configure the frequency division register, and set the system clock to HSI in crgr.
(2) Turn off all interrupts.
(3) Configure the vector table.
(4) Enable HSE and wait for the setting to be completed in CR.
(5) Turn on PLL and wait for PLL to turn on in CR.
(6) Wait for PLL to become the system clock in sws bit in cfgr.
Combined with the above methods, the code I rewrote is as follows:
void Stm32_Clock_Init111(u8 PLL)
{
unsigned char temp=0;
RCC->APB1RSTR = 0x00000000;//Reset endsRCC-
>APB2RSTR = 0x00000000;
RCC->AHBENR = 0x00000014; //Sleep mode flash and SRAM clock enable. Others are turned off.
RCC->APB2ENR = 0x00000000; //Peripheral clock is turned off.
RCC->APB1ENR = 0x00000000;
RCC->CR &= 0xFEF2FFFF; //The main function of this step is to turn on the internal HSION and turn off HSE, CSS, PLLON
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1; HSE is set to non-divided frequency. The main function of CFGR is to configure the frequency division. Before the frequency division, of course, all HSE clocks in cr should be turned off and only the HSI clock should be turned on. Of course, another important function is to set which one is currently used as the system clock, that is, the SW bit.
PLL-=2; //Offset 2 units
RCC->CFGR|=PLL<<18; //Set PLL value 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2 delay cyclesRCC-
>CIR = 0x00000000; //Turn off all interrupts
//Configure vector table
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //Flash startup is used here
#endif
RCC->CR|=0x00010000; //External high-speed clock enable HSEON
while(!(RCC->CR>>17));//Wait for external clock to be readyRCC-
>CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//Wait for PLL to lock
RCC->CFGR|=0x00000002;//PLL as system clock
while(temp!=0x02) //Wait for PLL to be set as system clock successfully
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
Previous article:About BOOT0 and BOOT1 of STM32
Next article:How to start stm32 boot0 boot1
Recommended ReadingLatest update time:2024-11-16 09:28
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Pingtouge RVB2601 board-IIC bus test
- 【GD32E503 Review】 + littlegl ported to GD32E503V-EVAL
- EEWORLD University ---- Deep Learning Course (NYU, Spring 2020) Yann Lecun
- Discover the world's most in-demand medical power supplies
- Great God Tesla ~AC~
- VICOR invites you to participate in the High Performance Power Conversion Seminar (venues: Beijing, Shenzhen, Shanghai, etc.)
- [TI recommended course] #Engineer It series course #Lesson 1 Loop bandwidth in phase-locked loop applications
- EEWORLD University ---- RS-485 Overview
- PicoVGA (1) VGA/TV driver library for Pico
- Step-by-step considerations for designing wide-bandwidth, multichannel systems