Skip to main content
Stanislav Husár
Associate II
July 13, 2019
Question

Cannot switch to PLL1

  • July 13, 2019
  • 8 replies
  • 2027 views

Hello,

I am trying to switch system clock on H743ZI to PPL1. Using following code, it hangs up on checking SWS flag - clock switch begins, but never ends.

I have tried setting domain prescalers before or after clock switch. The same for flash latency.

I can switch to HSE, but not to PLL. I have checked PLL status, PLLRDY is asserted.

What am I doing wrong?

PWR->CR3 |= PWR_CR3_SCUEN;
PWR->CR3 |= PWR_CR3_LDOEN;
PWR->D3CR |= PWR_D3CR_VOS;
while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY) ;
	
FLASH->ACR |= FLASH_ACR_LATENCY_5WS;
	
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) != RCC_CR_HSERDY);
	
RCC->PLLCKSELR |= RCC_PLLCKSELR_PLLSRC_HSE;
RCC->PLLCKSELR |= RCC_PLLCKSELR_DIVM1_2;	// DIVM1 /4
	
RCC->PLLCFGR &= ~RCC_PLLCFGR_DIVQ1EN;
RCC->PLLCFGR &= ~RCC_PLLCFGR_DIVR1EN;
RCC->PLLCFGR |= RCC_PLLCFGR_PLL1RGE_2;
 
RCC->PLL1DIVR |= 1 << RCC_PLL1DIVR_P1_Pos;	//DIVP /2
RCC->PLL1DIVR |= (0x7FUL) << RCC_PLL1DIVR_N1_Pos; // DIVN1 x128
	
RCC->CR |= RCC_CR_PLL1ON;
while ((RCC->CR & RCC_CR_PLL1RDY) != RCC_CR_PLL1RDY) ;
	
RCC->CFGR |= RCC_CFGR_SW_PLL1;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL1) ;
	
RCC->D1CFGR |= RCC_D1CFGR_HPRE_3;
RCC->D1CFGR |= RCC_D1CFGR_D1PPRE_2;
	
RCC->D2CFGR |= RCC_D2CFGR_D2PPRE1_2;
RCC->D2CFGR |= RCC_D2CFGR_D2PPRE2_2;
	
RCC->D3CFGR |= RCC_D3CFGR_D3PPRE_2;

Thanks in advance,

Stanislav

This topic has been closed for replies.

8 replies

waclawek.jan
Super User
July 13, 2019

Do you take into account that not all registers have zero initial value (e.g. PLLCKSELR)?

JW

Stanislav Husár
Associate II
July 13, 2019

I may have missed something, but I did look at reset values in ref manual.

Anyway, I don’t understand, why PLL starts(and locks), but can’t be selected as sysclk.

waclawek.jan
Super User
July 14, 2019

I don't understand it either, but I don't have a 'H7 to try.

> RCC->PLLCKSELR |= RCC_PLLCKSELR_DIVM1_2; // DIVM1 /4

Reset value of PLLCKSELR according to RM0433 rev.5 is 0x02020200, which for the DIVM1 field means 0x100000=32. You OR this field by 0x000100, resulting in 0x100100=36. Is this what you intended? The comment says otherwise.

> RCC->PLL1DIVR |= (0x7FUL) << RCC_PLL1DIVR_N1_Pos; // DIVN1 x128

The default value of DIVN1 field is 0x80, so the result after the OR is 0xFF, making the multiplcicator being x256.

Now both these factors may result in PLL being off its nominal working area. I did not check other registers.

I know that you wait until PLL locks, but the indicator may be a crude counter, and PLL itself may be unstable enough so that some of the protection mechanisms kick in and switch back to HSI automatically.

[style] What I usually do is that I don't RMW most of the registers containing multiple fields, but I directly write the value for the whole register at once, even if alculated from several values

RCC->PLLCKSELR = 0
 | RCC_PLLCKSELR_PLLSRC_HSE
 | (4 << RCC_PLLCKSELR_DIVM1_Pos)
;

Style is of course matter of personal preference, and in this case shouldn't make any difference in functionality - except for the nonzero initial value. [/style]

JW

Stanislav Husár
Associate II
July 14, 2019

Thank you. I have modified code to account for these reset values. Unfortunately, I am still unable to switch.

//PWR->CR3 |= PWR_CR3_SCUEN;
//PWR->CR3 |= PWR_CR3_LDOEN;
PWR->D3CR |= PWR_D3CR_VOS;
while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY) ;
	
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) != RCC_CR_HSERDY);
	
RCC->PLLCKSELR |= RCC_PLLCKSELR_PLLSRC_HSE;
RCC->PLLCKSELR &= ~RCC_PLLCKSELR_DIVM1_Msk;
RCC->PLLCKSELR |= RCC_PLLCKSELR_DIVM1_2;	// DIVM1 /4
	
	
RCC->PLLCFGR &= ~RCC_PLLCFGR_DIVQ1EN;
RCC->PLLCFGR &= ~RCC_PLLCFGR_DIVR1EN;
RCC->PLLCFGR |= RCC_PLLCFGR_PLL1RGE_2;
	
//RCC->PLL1DIVR |= 1 << RCC_PLL1DIVR_P1_Pos;	//DIVP /2
RCC->PLL1DIVR &= ~RCC_PLL1DIVR_N1_Msk;
RCC->PLL1DIVR |= (0x7FUL) << RCC_PLL1DIVR_N1_Pos; // DIVN1 x128
	
RCC->CR |= RCC_CR_PLL1ON;
while ((RCC->CR & RCC_CR_PLL1RDY) != RCC_CR_PLL1RDY) ;
	
RCC->CFGR |= RCC_CFGR_SW_PLL1;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL1) ;
	
RCC->D1CFGR |= RCC_D1CFGR_HPRE_3;
RCC->D1CFGR |= RCC_D1CFGR_D1PPRE_2;
	
RCC->D2CFGR |= RCC_D2CFGR_D2PPRE1_2;
RCC->D2CFGR |= RCC_D2CFGR_D2PPRE2_2;
	
RCC->D3CFGR |= RCC_D3CFGR_D3PPRE_2;
	
FLASH->ACR &= ~FLASH_ACR_LATENCY_Msk;
FLASH->ACR |= FLASH_ACR_LATENCY_2WS;

 Also, I prefer to mask register field before modification. Using the way you mentioned, you're actually trying to zero reserved fields. I think(hope) hw is smart enough to refuse this....but if it's not, few people can tell what will happen.

Stanislav Husár
Associate II
July 14, 2019

UPDATE: I have found in HAL sources that I should change prescalers before clock switch (I am increasing divider).

Stanislav Husár
Associate II
July 14, 2019

Okay, now it gets interesting. I have discovered, that I actually don't have HSE crystal.

Really, no idea what magic is happening on my board.

I have tried to clock PLL from HSI, and then do a clock switch....not working.