You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello,
I'm using the STM32H743VIT6 board and arm-none-eabi-gcc compiler version 14.2.0 with -O0 option. I'm not using CubeMX setup or bigger HAL driver in this project, only LL routines mixed with some CMSIS-style register access.
It seems that LL driver routine LL_RCC_GetSystemClocksFreq() incorrectly determines HCLK frequency when non-unit D1 core prescaler (D1CPRE) is set.
The following behavior looks like a potential bug:
Setup PLL1 sourced from HSE so that pll1_p_ck = 96 MHz in integer mode (lines 18-44 in my MRE below)
Set D1 core prescaler = 2, i.e. D1CPRE = 0b1000 in the D1CFGR register of RCC block (line 47 in MRE)
Set dividers for AHB, APB1...APB4 = 1 (lines 48-52 in MRE)
Select system clock sys_ck to be sourced from pll1_p_ck, i.e. 96 MHz (line 53 in MRE)
Call LL_RCC_GetSystemClocksFreq(&clk) (line 67 in MRE)
Now clk.SYSCLK_Frequency = 96 MHz (correct), but clk.HCLK_Frequency = 96 MHz which is incorrect since it should be HCLK = sys_ck / D1CPRE = sys_ck / 2 = 48 MHz. Consequently, all other PCLKx_Frequency are incorrect as well (96 MHz instead of 48 MHz). Also LL_RCC_GetSystemClocksFreq(&clk) does not calculate clk.CPUCLK_Frequency what looks inconsistent too.
Some debugging suggests that this routine Src/stm32h7xx_ll_rcc.c simply ignores D1CPRE as if it were always = 1. It divides SYSCLK by HPRE from D1CFGR register, but does not divide it further by D1CPRE from the same register.
The frequencies are set up indeed as expected, since LED on GPIO PA1 with two LL_mDelay(500) intervals blinks 1 time per second when LL_Init1msTick() is fed with 48 MHz value (see lines 80-92 in MRE).
The ignored prescaler is framed in red at this screenshot from reference manual (RM0433 Rev 8, page 350).
Here is my MRE (the only custom source file 'main.c' in project):
#include"stm32h743xx.h"#include"stm32h7xx_ll_rcc.h"#include"stm32h7xx_ll_bus.h"#include"stm32h7xx_ll_gpio.h"#include"stm32h7xx_ll_utils.h"intmain(void) {
// Increase system voltage scale to the VOS1PWR->CR3 |= PWR_CR3_LDOEN; // Ensure that LDO voltage regulator is enableduint32_td3cr=PWR->D3CR;
d3cr &= ~PWR_D3CR_VOS;
d3cr |= (3 << PWR_D3CR_VOS_Pos); // Set VOS1 voltage scalePWR->D3CR=d3cr;
while (0== (PWR->D3CR&PWR_D3CR_VOSRDY));
// Start HSE clockLL_RCC_HSE_Enable();
while (!LL_RCC_HSE_IsReady()); // Wait until HSE becomes ready// Configure PLL1// 0. HSE @ 25 MHz = REF_CK// 1. REF_CK / PLLM = VCO_IN = 1 MHz (thus PLLM = 25) Must be: 1 MHz <= VCO_IN <= 2 MHz// 2. VCO_IN * PLLN = VCO_OUT = 384 MHz (thus PLLN = 384) Must be: 192 MHz <= VCO_OUT <= 836 MHz// 3. VCO_OUT / PLLP = SYS_CK = 96 MHz (thus PLLP = 4) Must be: PLL_OUT <= 180 MHzuint32_tpllM=25 << RCC_PLLCKSELR_DIVM1_Pos; // This factor is specific for PLL1uint32_tpllN= (384-1) << RCC_PLL1DIVR_N1_Pos; // Multiplier for VCOuint32_tpllP= (4-1) << RCC_PLL1DIVR_P1_Pos; // Divider for SYS_CKLL_RCC_PLL1_Disable();
while (LL_RCC_PLL1_IsReady());
RCC->PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_Msk;
RCC->PLLCKSELR |= RCC_PLLCKSELR_PLLSRC_HSE | pllM; // Use HSE as input for PLLRCC->PLLCFGR &= ~RCC_PLLCFGR_PLL1RGE; // Select PLL1 input (VCO_IN) between 1 and 2 MHzRCC->PLLCFGR |= RCC_PLLCFGR_PLL1VCOSEL; // Select low-frequency VCO (VCO_IN is 1 to 2 MHz)RCC->PLLCFGR &= ~RCC_PLLCFGR_PLL1FRACEN;// Disable sigma-delta modulator (fractional mode)RCC->PLLCFGR |= RCC_PLLCFGR_DIVP1EN; // Enable P dividerRCC->PLLCFGR &= ~RCC_PLLCFGR_DIVQ1EN; // Disable Q dividerRCC->PLLCFGR &= ~RCC_PLLCFGR_DIVR1EN; // Disable R dividerRCC->PLL1DIVR=pllN | pllP; // Configure PLL dividers and multipliers// Start the PLL1LL_RCC_PLL1_Enable();
while (!LL_RCC_PLL1_IsReady()); // Wait until PLL1 becomes ready// Configure bus prescalers: CPU 48 MHz, AHBx 48 MHz, APBx 48 MHzLL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_2); // Divide SYS_CLK by 2 to obtain 48 MHz CPU frequencyLL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_RCC_SetAPB3Prescaler(LL_RCC_APB3_DIV_1);
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1);
// Decrease the count of FLASH wait states (to accomodate its latency)// 1 WS for 70 < HCLK < 140 MHz, 2 WS for 140 < HCLK < 210 MHz (VOS1 voltage range)// 1 WS for 45 < HCLK < 90 MHz, 2 WS for 90 < HCLK < 135 MHz (default VOS3 voltage range)constuint32_tFLATENCY=FLASH_ACR_LATENCY_0WS;
uint32_tflACR=FLASH->ACR;
flACR &= ~FLASH_ACR_LATENCY_Msk;
flACR |= FLATENCY;
FLASH->ACR=flACR;
if ((FLASH->ACR&FLASH_ACR_LATENCY_Msk) !=FLATENCY) while (1);
// Check clock frequenciesLL_RCC_ClocksTypeDefclk= {};
LL_RCC_GetSystemClocksFreq(&clk); // Get all frequencies (probably, there is a bug with HCLK and subsequent freqs)constuint32_tSYS_FREQ=96*1000*1000;
constuint32_tCPU_FREQ=48*1000*1000;
constuint32_tBUS_FREQ=48*1000*1000;
while (SYS_FREQ!=clk.SYSCLK_Frequency) {} // OK (96 MHz)// while (BUS_FREQ != clk.HCLK_Frequency) {} // Incorrect 96 MHz (should be 48 MHz)// while (BUS_FREQ != clk.PCLK1_Frequency) {} // Incorrect// while (BUS_FREQ != clk.PCLK2_Frequency) {} // Incorrect// while (BUS_FREQ != clk.PCLK3_Frequency) {} // Incorrect// while (BUS_FREQ != clk.PCLK4_Frequency) {} // Incorrect// while (CPU_FREQ != clk.CPUCLK_Frequency) {} // Incorrect 0 MHz (should be 48 MHz)LL_Init1msTick(CPU_FREQ); // Configure generic millisecond clock// Setup GPIO PA1 for LEDLL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_1, LL_GPIO_MODE_OUTPUT);
// Switch LED approx. 2 times per second (each blink ~ +1 sec)while (1) {
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_1);
LL_mDelay(500);
LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_1);
LL_mDelay(500);
}
}
The text was updated successfully, but these errors were encountered:
Hello,
I'm using the STM32H743VIT6 board and arm-none-eabi-gcc compiler version 14.2.0 with -O0 option. I'm not using CubeMX setup or bigger HAL driver in this project, only LL routines mixed with some CMSIS-style register access.
It seems that LL driver routine
LL_RCC_GetSystemClocksFreq()
incorrectly determines HCLK frequency when non-unit D1 core prescaler (D1CPRE) is set.The following behavior looks like a potential bug:
LL_RCC_GetSystemClocksFreq(&clk)
(line 67 in MRE)clk.SYSCLK_Frequency
= 96 MHz (correct), butclk.HCLK_Frequency
= 96 MHz which is incorrect since it should be HCLK = sys_ck / D1CPRE = sys_ck / 2 = 48 MHz. Consequently, all other PCLKx_Frequency are incorrect as well (96 MHz instead of 48 MHz). AlsoLL_RCC_GetSystemClocksFreq(&clk)
does not calculateclk.CPUCLK_Frequency
what looks inconsistent too.Some debugging suggests that this routine Src/stm32h7xx_ll_rcc.c simply ignores D1CPRE as if it were always = 1. It divides SYSCLK by HPRE from D1CFGR register, but does not divide it further by D1CPRE from the same register.
The frequencies are set up indeed as expected, since LED on GPIO PA1 with two
LL_mDelay(500)
intervals blinks 1 time per second whenLL_Init1msTick()
is fed with 48 MHz value (see lines 80-92 in MRE).The ignored prescaler is framed in red at this screenshot from reference manual (RM0433 Rev 8, page 350).
Here is my MRE (the only custom source file 'main.c' in project):
The text was updated successfully, but these errors were encountered: