2021-06-28 02:36 PM
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();
}
}
Solved! Go to Solution.
2021-06-28 03:03 PM
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
2021-06-28 03:03 PM
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