# STM32 PWM output frequency is off

Using an STM32F429I-DISCO board. SYSCLK is set to 180 MHz. I verified the value from MCO2 output pin, and it is spot on. Setting up GPIO_AF3_TIM9 channel 1, and need an output of 12.288 MHz and 50% duty cycle. Calculated config values as:

  const uint32_t TIMF =  180000000;
const uint32_t TFOUT =  12288000;
uint16_t ARR = (TIMF / TFOUT) - 1;
uint16_t uhPrescalerValue =  ((SystemCoreClock) / TIMF) - 1;
uint16_t pulse = ARR/2 + 1;


Results are prescalar = 0, ARR = 13, pulse = 7.

Here is the setup code:

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed =  GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM9;
GPIO_InitStruct.Pin = GPIO_PIN_CHANNEL1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct)

TimHandle.Instance = TIMx;
TimHandle.Init.Prescaler =  uhPrescalerValue;
TimHandle.Init.Period = ARR;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
{
Error_Handler();
}

sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
sConfig.Pulse = pulse;
if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}


Output on scope counter shows PWM frequency as 12.8582 MHz. Duty cycle is correct. Where have I gone wrong in deriving the parameters?

• Your timer can't do fractions of a count 180M/14 = 12.857M. That's as close as you'll get with that clock. Mar 19, 2017 at 2:12

You cannot produce 12.288 MHz by integer division of a 180 MHz source.

The closest you would come would be dividing by 14, which would yield the 12.857 and some following decimals, which is likely within measurement error of what you think you got.

Perhaps you can adjust your goal to use that. Or perhaps you can change the source crystal frequency to something which when multiplied up by the STM32 PLL and divided down will produce your goal more exactly. There are yet more complicated ways of doing this - fractional N synthesizer, etc.

In the end solutions for turning one frequency into another have various power, cost, accuracy and phase noise consequences. To pick one, you'll need to consider your specific requirements in detail.

• OK. That makes sense. I'm using the clock output to generate a input for a codec that is 256*Fs. I was going for 48kHz sampling rate, but this should be close enough. Mar 19, 2017 at 3:00
• For a recorded source, especially if you can pre-compensate the frequency error, yes. Note however that if you have a streaming source, even creating a 12.288 MHz clock to nominally match the source will still require that you either keep the sessions short enough to absorb clock differences in a buffer, or implement variable sample rate conversion, since you'll never exactly match the source rate, and the difference will accumulate with time. Mar 19, 2017 at 3:04
• Not a recorded source. line input to codec adc, out to i2s on mcu, then back in to dac on the codec. Mar 19, 2017 at 5:24
• That suggests a slightly different frequency should work fine - keeping it close will mean not only that data timing is in spec, but that digital filters in the codec work about as designed. Anything you do in the mcu that needs a precise relationship to frequency can hopefully be recalculated around knowledge of the actual sample rate achieved. Mar 19, 2017 at 19:08

as 12.8582 MHz

180Mhz / (13+1) = ?

You got precisely what your code should have produced.

To get a 12.288Mhz, you may be able to dither. Or use a reference clock generator if the chip has one.

If it is acceptable you can modify the system clock frequeny by adjusting the PLL to achieve closer result and find out what you can do with that.

You best choices are, starting from the best:

• System clock: 86 MHz, Prescaler: 7, $\frac{86\,MHz}{6+1} = 12.2857\,MHz$
• System clock: 172 MHz, Prescaler: 14, $\frac{172\,MHz}{13+1} = 12.2857\,MHz$

Actually these are almost the same.

• System clock: 123 MHz, Prescaler: 10, $\frac{123\,MHz}{9+1} = 12.3\,MHz$