cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5 FRACN not working

I am trying to use the PLL1 fractional PLL on a Nucleo-U545RE-Q board to fine-tune a frequency measurement.  RM0456 rev 5 has the following procedure to adjust the fractional PLL:

"If the application intends to tune the PLLx frequency on-the-fly, then:

a) PLLxFRACEN must be set to 0 to update the PLLxFRACN value while keeping the PLL running.

b) A new value can be uploaded into PLLxFRACN (FracValue(n).

c) PLLxFRACEN must be set to 1 to activate the new programed value in PLLxFRACN that is taken into account by the PLL."

When using the above algorithm, I found that often the actual fractional-adjusted frequency was wrong.  Looking through the STM32CubeU5 code :

/* FRACN1 on-the-fly value update */
      if ((READ_BIT(RCC->PLL1FRACR, RCC_PLL1FRACR_PLL1FRACN) >> \
           RCC_PLL1FRACR_PLL1FRACN_Pos) != (pRCC_OscInitStruct->PLL.PLLFRACN))
      {
        assert_param(IS_RCC_PLL_FRACN_VALUE(pRCC_OscInitStruct->PLL.PLLFRACN));

        /* Disable PLL1FRACN. */
        __HAL_RCC_PLL_FRACN_DISABLE();

        /* Get Start Tick*/
        tickstart = HAL_GetTick();

        /* Wait at least 2 CK_REF (PLL1 input source divided by M) period to make sure next latched value
           will be taken into account. */
        while ((HAL_GetTick() - tickstart) < PLL_FRAC_WAIT_VALUE)
        {
        }

        /* Configure PLL PLL1FRACN */
        __HAL_RCC_PLL_FRACN_CONFIG(pRCC_OscInitStruct->PLL.PLLFRACN);

        /* Enable PLL1FRACN to latch the new value. */
        __HAL_RCC_PLL_FRACN_ENABLE();
      }

 Well that's nice.  An undocumented delay is required for the fractional part to be noticed by the sigma-delta modulator.  I've added a 2us delay in my code (which I think should be 8 refx_ck clocks at the worst-case of 4 MHz, assuming refx_ck is the same as CK_REF in the comment) along with some DMB instructions for good measure and it seems to be working properly now.

It is very frustrating that apparently the HAL dev team is working from completely different manuals than the rest of the world.  Please update the RM with the proper algorithm, and maybe spell check that section while you are at it.

Thanks,

TG

2 REPLIES 2
KDJEM.1
ST Employee

Hello @Terry Greeniaus ,

 

Thank you for bringing this issue to our attention.

I confirm the issue in reference manual and I reported it internally.

Internal ticket number: 190376 (This is an internal tracking number and is not accessible or usable by customers).

 

Thank you.

Kaouthar

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

ebrombaugh1
Associate III

I've bumped into this one too on the STM32H503. It seems the delay value can be a lot smaller - I found that 20 SYSCLK cycles at 250MHz (plus function call overhead) was sufficient, while less would sometimes fail to update the PLL. I also found that it doesn't really matter if the delay is before or after the write to the FRAC R register, as long as the FRACEN bit is low for the minimum delay time. My code looks like this:

 

		/* bump PLL2 Frac N register to increase freq slightly */
		__HAL_RCC_PLL2_FRACN_DISABLE();
		__HAL_RCC_PLL2_FRACN_CONFIG(2);
		cyclesleep(20);	// needed to ensure PLL sees the change
		__HAL_RCC_PLL2_FRACN_ENABLE();
		
		/* wait a bit to allow phase to advance */
		delay_us(2000);
		
		__HAL_RCC_PLL2_FRACN_DISABLE();
		__HAL_RCC_PLL2_FRACN_CONFIG(0);
		cyclesleep(20);	// needed to ensure PLL sees the change
		__HAL_RCC_PLL2_FRACN_ENABLE();

 

 FYI the cyclesleep() function uses the DWT cycle counter to delay for a fixed number of CPU clocks. My application here is an experiment to slip the phases of PLL1 and PLL2 to see if I can get around the DAC kernel clock synchronization erratum.