📜 ⬆️ ⬇️

STM32H7 - setting clocking without HAL

Not so long ago, STM launched a very powerful, by the standards of microcontrollers, line of STM32H7 crystals. What attracted me to her:


I thought very well, I soldered the STM32H743IIT6 crystal instead of STM32F746IGT6 and started a new project in SW4STM32.

To calculate the coefficients of the dividers and multipliers of the microcontroller clocking system, it is convenient to use the STM32CubeMX program's Clock Configuration tab.

Clocking settings:
')

Accordingly, the core frequency (SYSCLK) is 400 MHz.



In addition to the STM32CubeMX, there is also a set of the “STM32CubeH7 firmware package”, which contains a large number of examples for working with peripherals for the STM32H7. It was from him was taken the sequence of initialization of the clocking system of the microcontroller.

Information and comments are taken from the following sources:


So, let's begin.

1. Turning on external quartz and waiting for readiness.

// Enable HSE RCC->CR |= RCC_CR_HSEON; // Wait till HSE is ready while((RCC->CR & RCC_CR_HSERDY) == 0); 

2. Specify the frequency source for PLL1 - external quartz.

 //RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC -> PLLCKSELR |= RCC_PLLCKSELR_PLLSRC_HSE; 

3. The value of the divider is set to 4.

 //PLLM = 4 RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_5; //0 RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_4; //0 RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_3; //0 RCC -> PLLCKSELR |= RCC_PLLCKSELR_DIVM1_2; //1 RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_1; //0 RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_0; //0 

4. The multiplier N and dividers P, Q, R

  //PLL1DIVR bits //DIVN1[8:0] 0 - 8 PLLN = 400 //DIVP1[6:0] 9 - 15 PLLP = 2 //DIVQ1[6:0] 16 - 22 PLLQ = 2 //DIVR1[6:0] 24 - 30 PLLR = 2 RCC -> PLL1DIVR |= 0x0101038F; 

5. Fractional PLL frequency divider (if needed)

 // /* Configure PLL PLL1FRACN */ //__HAL_RCC_PLLFRACN_CONFIG(RCC_OscInitStruct->PLL.PLLFRACN); RCC -> PLL1FRACR = 0; 

6. Specify the PLL1 input frequency range

  /* Select PLL1 input reference frequency range: VCI */ //__HAL_RCC_PLL_VCIRANGE(RCC_OscInitStruct->PLL.PLLRGE) ; RCC->PLLCFGR |= RCC_PLLCFGR_PLL1RGE_3; 

7. Specify the output frequency range of PLL1

  /* Select PLL1 output frequency range : VCO */ //__HAL_RCC_PLL_VCORANGE(RCC_OscInitStruct->PLL.PLLVCOSEL) ; RCC->PLLCFGR &= ~RCC_PLLCFGR_PLL1VCOSEL; 

8. Switching on output dividers PLL1: P, Q, R

  /* Enable PLL System Clock output. */ // __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVP); //Bit 16 DIVP1EN: PLL1 DIVP divider output enable RCC->PLLCFGR |= RCC_PLLCFGR_DIVP1EN; /* Enable PLL1Q Clock output. */ //__HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); RCC->PLLCFGR |= RCC_PLLCFGR_DIVQ1EN; /* Enable PLL1R Clock output. */ // __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVR); RCC->PLLCFGR |= RCC_PLLCFGR_DIVR1EN; 

9. The inclusion of a fractional divider.

  /* Enable PLL1FRACN . */ //__HAL_RCC_PLLFRACN_ENABLE(); RCC->PLLCFGR |= RCC_PLLCFGR_PLL1FRACEN; 

10. Start PLL1 and wait for readiness

  /* Enable the main PLL. */ //__HAL_RCC_PLL_ENABLE(); RCC->CR |= RCC_CR_PLLON; while((RCC->CR & RCC_CR_PLL1RDY) == 0); 

PLL1 is configured and running. Now select the source of the SYSCLK frequency and set up the bus dividers.

11. Divider by 2 HPRE

  //RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; // MODIFY_REG(RCC->D1CFGR, RCC_D1CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider); //HPRE[3:0]: D1 domain AHB prescaler //1000: rcc_hclk3 = sys_d1cpre_ck / 2 RCC -> D1CFGR |= RCC_D1CFGR_HPRE_3; //1 RCC -> D1CFGR &= ~RCC_D1CFGR_HPRE_2; //0 RCC -> D1CFGR &= ~RCC_D1CFGR_HPRE_1; //0 RCC -> D1CFGR &= ~RCC_D1CFGR_HPRE_0; //0 

12. Without division D1CPRE

  //RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; //MODIFY_REG(RCC->D1CFGR, RCC_D1CFGR_D1CPRE, RCC_ClkInitStruct->SYSCLKDivider); //D1CPRE[3:0]: D1 domain Core prescaler //0xxx: sys_ck not divided (default after reset) RCC -> D1CFGR &= ~RCC_D1CFGR_D1CPRE_3; //0 RCC -> D1CFGR &= ~RCC_D1CFGR_D1CPRE_2; //0 RCC -> D1CFGR &= ~RCC_D1CFGR_D1CPRE_1; //0 RCC -> D1CFGR &= ~RCC_D1CFGR_D1CPRE_0; //0 

13. Set PLL1 as source of SYSCLK and expect readiness.

  //RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_ClkInitStruct->SYSCLKSource); //SW[2:0]: System clock switch //011: PLL1 selected as system clock (pll1_p_ck) RCC->CFGR &= ~RCC_CFGR_SW_2; //0 RCC->CFGR |= RCC_CFGR_SW_1; //1 RCC->CFGR |= RCC_CFGR_SW_0; //1 while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL1); 

14. Divider by 2 D1PPRE

  //D1PCLK1 Configuration //RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; //MODIFY_REG(RCC->D1CFGR, RCC_D1CFGR_D1PPRE, RCC_ClkInitStruct->APB3CLKDivider); //Bits 6:4 D1PPRE[2:0]: D1 domain APB3 prescaler //100: rcc_pclk3 = rcc_hclk3 / 2 RCC -> D1CFGR |= RCC_D1CFGR_D1PPRE_2; RCC -> D1CFGR &= ~RCC_D1CFGR_D1PPRE_1; RCC -> D1CFGR &= ~RCC_D1CFGR_D1PPRE_0; 

15. Divider by 2 D2PPRE1

  //PCLK1 Configuration //RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; //MODIFY_REG(RCC->D2CFGR, RCC_D2CFGR_D2PPRE1, (RCC_ClkInitStruct->APB1CLKDivider)); //Bits 6:4 D2PPRE1[2:0]: D2 domain APB1 prescaler //100: rcc_pclk1 = rcc_hclk1 / 2 RCC -> D2CFGR |= RCC_D2CFGR_D2PPRE1_2; RCC -> D2CFGR &= ~RCC_D2CFGR_D2PPRE1_1; RCC -> D2CFGR &= ~RCC_D2CFGR_D2PPRE1_0; 

16. Divider by 2 D2PPRE2

  //PCLK2 Configuration //RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; //MODIFY_REG(RCC->D2CFGR, RCC_D2CFGR_D2PPRE2, (RCC_ClkInitStruct->APB2CLKDivider)); //Bits 10:8 D2PPRE2[2:0]: D2 domain APB2 prescaler //100: rcc_pclk2 = rcc_hclk1 / 2 RCC -> D2CFGR |= RCC_D2CFGR_D2PPRE2_2; RCC -> D2CFGR &= ~RCC_D2CFGR_D2PPRE2_1; RCC -> D2CFGR &= ~RCC_D2CFGR_D2PPRE2_0; 

17. Divider by 2 D3PPRE

  //D3PCLK1 Configuration //RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; //MODIFY_REG(RCC->D3CFGR, RCC_D3CFGR_D3PPRE, (RCC_ClkInitStruct->APB4CLKDivider) ); //Bits 6:4 D3PPRE[2:0]: D3 domain APB4 prescaler //100: rcc_pclk4 = rcc_hclk4 / 2 RCC -> D3CFGR |= RCC_D3CFGR_D3PPRE_2; RCC -> D3CFGR &= ~RCC_D3CFGR_D3PPRE_1; RCC -> D3CFGR &= ~RCC_D3CFGR_D3PPRE_0; 

In order to make sure that the configuration and the launch were successful, we use the output of the MCO2 microcontroller. This output should have a frequency of 26.666 MHz with output divider 15.



Fine. The frequency is present, then everything is done correctly.

Source: https://habr.com/ru/post/427435/


All Articles