This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

preface

The clock system is an essential part of the MCU. This paper will discuss the following issues:

  • What is a clock?
  • How to understand the STM32 clock structure?
  • Why does an MCU have multiple clock sources?
  • Stm32 How do I configure the clock?

Of course, due to my lack of knowledge, and the clock is slightly complex, so here can only be said to have a perceptual preliminary understanding of the clock, if there is a mistake, I hope not hesitate to correct.

directory

  • A brief introduction to the clock
  • Stm32 clock tree
  • Three, some thoughts about the clock
  • 4. Analysis of clock configuration
  • Five, the summary

A brief introduction to the clock

First we need to be clear about a few concepts:

  • Clock: the heart of the single chip microcomputer, all peripherals need clock to supply energy.
  • Clock period: also known as oscillation period, can be simply understood as the time required to transmit a 0 or 1.
  • Instruction cycle: The time required to execute an instruction (e.g. MOV A, #34H). The instruction cycle length may vary for different types of instructions.
  • Machine cycle: The period of time during which an action is performed. For example, executing an instruction requires two actions: “fetch and post code” and “execute operand”.

The diagram of the above three cycles is as follows:

(The blue part includes four machine cycles)

And because the clock signal is also a kind of electrical signal, so it also has the function of providing energy, and because the time interval of the level change is certain, we can even use the clock to time.

(PS: Corrected by the teacher, the clock “energy supply” is wrong, clock does not play the role of energy supply. But personally, from a beginner’s point of view, such perceptual understanding is not a big problem, as long as you remember that this statement is wrong.

Stm32 clock tree

With that in mind, let’s take a look at the stM32F10X clock tree:

2.1 STM32F10X clock source

The blue part of the figure above shows the 5 clock sources of STM32, which are:

  • HSI: High speed internal clock, generated by internal RC oscillator, frequency is 8MHz.
  • HSE: High speed external clock, which can be connected to 4-16mhz crystal excitation as clock source.
  • LSE: low-speed external clock, connected to an external 32.768khz clock source.
  • LSI: low speed internal clock generated by an internal RC oscillator at a frequency of 32kHz.
  • PLL: Phase-locked loop frequency doubling output. Can do input clock 2-16 times of frequency output.

PLL is also listed as a clock source here in reference to the argument such as wildfire data. I think the actual clock source can only be counted as 4, because PLL itself only plays the role of frequency doubling and cannot generate the clock frequency itself. Of course, these are artificially defined things, do not affect the use and understanding of this knowledge point.

(The PS: RC oscillator produces clocks with relatively low accuracy.)

2.2. System clock

Knowing which clock sources there are, we can find that the clock tree is AHB, APB1, APB2 bus that we are familiar with.

The clock source and these peripherals are connected by the red part of the system clock SYSCLK, which is very important!!

Since it’s so important, let’s analyze it first!

As you can see, the system clock has three input sources:

  • HSI: 8 MHZ
  • PLLCLK: 8-128mhz (because the external crystal oscillator is generally 8MHz)
  • HSE: 4-16 MHZ

The maximum frequency SYSCLK can accept is 72MHz, which is the frequency at which all the later peripherals work.

As you can see, this number can only be achieved by PLL frequency doubling (you can even use it for overclocking).

By the way, SYSCLK is also connected to something called CSS. Check the data sheet and get the following description:

As you can see, this thing is basically an alarm… Help you check whether there is a problem with HSE, if there is, first cut to the internal clock source, and then give relevant prompt information.

Analysis here, we can have a relatively clear understanding of the CLOCK tree of STM32.

Here I would like to add some points that I did not mention ~~ (mainly because I did not think of other relatively scattered knowledge points how to use logic string) ~~ :

  • Low speed internal and external clock applications
  • MCO clock output: used for oscilloscope clock signal observation, debugging.

Three, some thoughts about the clock

3.1 clock frequency

From the discussion of 2.1 and 2.2, we can see that the system clock works properly at 72MHz. But the actual input system clock frequency can be as high as 128MHz and as low as 8MHz, which means we can do something “out of the book”.

What about “irregularities”? Because the current only lights, and LED this guy has no requirements for the clock… Basically change the frequency is light off the speed of different things, can not see what, so I went to check the next information:

What is the concept of clock frequency? – Answer from Yu Ji – Zhihu

From the answer, we can probably draw a conclusion:

  • If the frequency is low and cannot meet the frequency requirements of the device, the device may fail to start.
  • At higher frequencies, system stability is compromised. Specifically, the peripheral may not be able to receive accurate signals when communicating.

3.2 Multiple clock sources

When I first learned about clock trees, my first thought was — why are there so many clock sources?

Since peripherals are managed by the system clock, isn’t one clock enough?

Based on the above questions, I read and studied relevant materials and came to two most obvious conclusions:

  • Multiple clocks can be used to save time when a single clock source is faulty.
  • An external clock source is configured with multiple clock sources. You can select the clock source with the corresponding frequency as required.

4. Analysis of clock configuration

After the stM32 clock tree is understood, it is the clock configuration problem.

In fact, when we created the project import startup file, the startup file already called SystemInit to initialize the system clock before the main function was called.

So why do you need configuration analysis? Why don’t you just use it?

The stM32 firmware library provides library functions (below is a screenshot of system_STm32f10x.c) :

The family ST official only provides 24MHz, 36MHz, 48MHz, 56MHz, 72MHz five frequency system clock Settings.

If the project has a need for clocks beyond these 5 frequencies, you still have to do it yourself. For these reasons, an analysis of the clock configuration is essential.

So, let’s comb through the context of the system clock again on the clock tree diagram.

Input sources:

  • HSI direct output, frequency is only 8MHz.
  • HSE direct output, range of 4-16mhz, generally 8MHz.
  • PLL: phase-locked loop frequency doubling output, frequency doubling range is 2-16 times. And PLL itself has two input sources:
    • HSI binary output to PLL, this mode of system clock up to 64MHz.
    • HSE directly outputs to PLL.

Output the source:

  • Direct output.
  • Output to AHB bus, through the predivider can do 1~512 frequency.
  • After the AHB bus is pre-divided, it passes through low speed peripheral bus APB1 and high speed bus APB2.

SYSCLK only needs to initialize the bus clock because the clock is turned on only when the peripherals are needed for power consumption.

For this reason, the process for configuring the system clock can be summarized as follows:

  1. Select and enable the clock source. (To use PLL as the system clock source, select frequency doubling.)
  2. Select APB1 and APB2 predivision.
  3. Select AHB predivision.

Why not follow the diagram from left to right?

A: If AHB is enabled first and APB1 and APB2 are not set, disorder will occur. (after reading the source code speculated)

The following library function **SetSysClockTo72()** as an example, with the data manual to learn the configuration process, first paste the source code:

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter ! = HSE_STARTUP_TIMEOUT));if((RCC->CR & RCC_CR_HSERDY) ! = RESET) { HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t) ((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0) {}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t) ((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0) {}/* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t) ((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) ! = (uint32_t)0x08) {}}else
  { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */}}Copy the code

At first glance it looks long and has a lot of registers, but meters matter. First write down the registers that appear:

  • RCC->CR
  • RCC->CFGR
  • RCC->CFGR2
  • FLASH->ACR

And then what? Check the manual for these registers, of course! Because it is still a small sprout new stage, only need to understand the role of each register combined with the source code learning can be, the manual does not have to go into depth for the time being.

Combined with the above understanding, let’s analyze the source code one by one:

1. Start the HSE clock

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);//HSEON -> HSE_ON
Copy the code

2. Wait for HSE to be ready

Exit for exception handling if you cannot wait for a certain amount of time.

  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;//HSERDY -> HSE_Ready
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter ! = HSE_STARTUP_TIMEOUT));/** HSEStatus = 1 **/

/** If HSE_Ready = RESET, that is, HSE is not ready **/
  if((RCC->CR & RCC_CR_HSERDY) ! = RESET) { HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  
Copy the code

3, HSE status normal continue, abnormal immediately handle

If the status is abnormal, the conditional statement will jump to the module below to deal with the exception.

3.1 Analysis of normal HSE status

3.1.1. Wait for the machine to fetch instructions
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t) ((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
Copy the code
3.1.2. Set the predivision factors of AHB, AP1 and AP2
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
Copy the code
3.1.3. Select the PLL clock source

In fact, there are 20 or 30 lines of code in the source code, but that is the interconnection chip configuration code, here F103 is the basic type, so temporarily skip to see.

    /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t) ((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));

	/* The HSE works with the PLLMULL9 to achieve 72MHz system clock output */
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
Copy the code
3.1.4 Start PLL clock and wait ready
/* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0) {}Copy the code
3.1.5. Select PLL as the system clock source
 /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t) ((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) ! = (uint32_t)0x08) {}Copy the code

The above.

Five, the summary

5.1 Process for configuring the clock

  • Turn on the clock and wait ready
  • If the clock starts abnormally, exit (relevant exception processing can be done)
  • If the bus is normal, configure the predivision factor of the bus
  • Finally choose the system clock, so that peripherals get power supply

5.2. Learn the clock flow of an MCU

  • Look at the clock tree – Analyze the context of the clock source
  • Consult the data sheet to find answers to the following questions:
    • How do I enable the clock source?
    • How to control the clock of related peripherals?
    • How do I select the system clock source?

The resources

  • What is the concept of clock frequency? – Answer from Yu Ji – Zhihu
  • Instruction cycle, machine cycle and clock cycle
  • First introduction to STM32 on the clock enablement problem – understanding
  • An article, thoroughly understand MCU clock architecture!
  • STM32 clock tree analysis