Skip to main content
FSkro.1
Associate II
June 28, 2021
Solved

STM32H7 Hard Fault when RCC at 165 MHz

  • June 28, 2021
  • 1 reply
  • 899 views

I have the STM32H7B3I-DK (MCU: STM32H7B3LIH6Q), and I am trying to get the sys_ck close to its maximum frequency of 280 MHz, by running HSI or HSE through PLL. The trouble is that I can only get up to 164 MHz. Any higher and I get a hard fault. Is there something I am forgetting or messing up? Code:

File : main.c
Purpose : Generic application start
 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <stm32h7xx.h>
 
void setup_user_leds(void);
void user_led_red_high(void);
void user_led_red_low(void);
void user_led_blue_low(void);
void user_led_blue_high(void);
 
 
//User LEDs are on PG2 and PG11
void setup_user_leds(void)
{
 uint32_t reg_copy;
 
 //enable the clock to GPIOG peripheral
 RCC->AHB4ENR |= RCC_AHB4ENR_GPIOGEN;
 
 //(MODER states are 2 bits, hence Read/Modify/Write)
 //make a copy of the current state of the register
 reg_copy = GPIOG->MODER;
 //use the masks to clear the bits 
 reg_copy &= ~(GPIO_MODER_MODE2_Msk|GPIO_MODER_MODE11_Msk);
 //set any of the cleared bits
 reg_copy |= (GPIO_MODER_MODE2_0|GPIO_MODER_MODE11_0);
 //save it back to memory
 GPIOG->MODER = reg_copy;
 
}
 
void user_led_red_high(void)
{
 GPIOG->BSRR = GPIO_BSRR_BS2;
}
 
void user_led_red_low(void)
{
 GPIOG->BSRR = GPIO_BSRR_BR2;
}
 
void user_led_blue_low(void)
{
 GPIOG->BSRR = GPIO_BSRR_BR11;
}
 
void user_led_blue_high(void)
{
 GPIOG->BSRR = GPIO_BSRR_BS11;
}
 
void delay()
{
 uint64_t t,i;
 t = 1000000;
 for(i=0;i<t;i++)
 {
 __NOP();
 }
}
 
void set_system_clk_hse(int pre_speed, int divisor) {
 if (280 < pre_speed || pre_speed < 64) return; // VCO output range F_ref*[64, 280] (F_ref = 2) must be respected
 if (64 < divisor || divisor < 1) return;
 RCC -> CFGR |= RCC_CFGR_SW_PLL1; // System clock and trace clock switch: Select PLL1 as system clock
 //while ((RCC -> CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL1); // System clock switch status: Wait until PLL1 is system clock
 RCC -> CR |= RCC_CR_HSEON; // HSE clock enable
 while (!(RCC -> CR & RCC_CR_HSERDY)); // Wait until HSE clock is ready
 RCC -> PLLCKSELR = 0x020200C2; // Divide HSE by 12 = 24 / 12 = 2 MHz = F_ref
 int divp = 2*divisor - 1;
 int divn = pre_speed - 1;
 RCC -> PLL1DIVR = 0x01010000 + (divp << RCC_PLL1DIVR_P1_Pos) + divn; // Set register (reset = 0x01010280)
 RCC -> CR |= RCC_CR_PLL1ON; // PLL1 enable
 //while((RCC -> CR & RCC_CR_PLL1RDY) == 0); // Wait until PLL1 clock is ready
}
 
void set_system_clk_hsi(int pre_speed, int divisor) {
 if (280 < pre_speed || pre_speed < 64) return; // VCO output range F_ref*[64, 280] (F_ref = 2) must be respected
 if (64 < divisor || divisor < 1) return;
 RCC -> CFGR |= RCC_CFGR_SW_PLL1; // System clock and trace clock switch: Select PLL1 as system clock
 //while ((RCC -> CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL1); // System clock switch status: Wait until PLL1 is system clock
 int divp = 2*divisor - 1;
 int divn = pre_speed - 1;
 RCC -> PLL1DIVR = 0x01010000 + (divp << RCC_PLL1DIVR_P1_Pos) + divn; // Set register (reset = 0x01010280)
 RCC -> CR |= RCC_CR_PLL1ON; // PLL1 enable
 //while((RCC -> CR & RCC_CR_PLL1RDY) == 0); // Wait until PLL1 clock is ready
}
 
/*********************************************************************
*
* main()
*
* Function description
* Application entry point.
*/
int main(void) {
 int pre_speed = 165; // Theoretically, pre_speeds from 64 to 280 should work
 int divisor = 1; // [1, 64]
 set_system_clk_hsi(pre_speed, divisor); // Speed = pre_speed / divisor; trial max ~ 164 MHz, theoretical max = 280 MHz (high range) or 210 MHz (low range)
 /* frequency:
 before divn1 = 2
 after divn1 = 2 * speed
 after div[p/q/r]1 = speed
 */
 setup_user_leds();
 while(1)
 {
 user_led_red_high();
 delay();
 user_led_blue_high();
 delay();
 user_led_red_low();
 delay();
 user_led_blue_low();
 delay();
 }
}

This topic has been closed for replies.
Best answer by waclawek.jan

You are not supposed to set PLL as system clock source *before* you actually set up PLL.

Also, make sure the proper VOS and FLASH latency are set for given system clock frequency.

JW

1 reply

waclawek.jan
waclawek.janBest answer
Super User
June 28, 2021

You are not supposed to set PLL as system clock source *before* you actually set up PLL.

Also, make sure the proper VOS and FLASH latency are set for given system clock frequency.

JW