Electronic – STM32 Series Microcontroller – Calculations of Timer Variables

microcontroller

This is a subject that seems to have a lot of confusion (I do not fully understand). How to calculate the Variables:

  • Period
  • Prescaler
  • Duration

if only a few other variables are known. At higher frequencies, for example 1000000Hz simple rules work. At lower Frequencies like 1281Hz things get a little more complicated.

As an example: if we aim for an output frequency of 1281Hz, we need to set the ARR Register to: 32785. We need to set the PSC Register to: 3 and if we want a 50% DutyCycle, we need to set the CCRx Register to: 16393. Where the x in CCRx is the specified Channel one is going to use. 1, 2, 3 or 4.

The Registers need to see values of 16 BITs, Integer Values(65535 or less).

Equations exist so calculations can be made, for example:

\$TIM_{Update Frequency(Hz)} = \frac{Clock}{(PSC – 1) * (Period – 1)}\$

\$1281.11273792094 = \frac{84000000}{3 * 32785} \$

now, the problem becomes more complicated, for a desired frequency of 840Hz:

\$425.946209078739 = \frac{84000000}{167 * 1189}\$

Here in lies the problem, how does one find the value of PSC when one knows only the values for "Clock" and "Period"? The value "TIM_Update_Frequency(Hz)" is not always the actual Desired Frequency.

Other equations must exist so as to calculate the "PSC" Value, or to calculate the "TIM_Update_Frequency(Hz)" so as to deduce the other values.

Guess work is just not a logical approach here.

Can anyone help with more equations for solving for the other variables?

Thank you

Chris

Best Answer

I have deleted my last answer because it was not correct all of the time. I have managed to use this equation to get correct results:

Prescaler = ((((ClockSpeed) / ((period) / (1 / frequency))) + 0.5) - 1);

Factoring Numbers was not the answer.

Here is a simple method I am now using to work out the other variables, Period and Duration.

private void CalculateVariables()
    {
        // Set the Bus Speed (APB1 or APB2), all timers are APB1 except TIM1 and TIM8...
        if (PWMPin == CPU.Pin.Pin7_X3 || PWMPin == CPU.Pin.Pin9_X3 || PWMPin == CPU.Pin.Pin7_X4)
        {
            ClockSpeed = CPU.Clock.APB2;
        }
        else
        {
            ClockSpeed = CPU.Clock.APB1;
        }

        #region Fields...

        uint ONE_MHZ = 1000000;

        uint prescaler = 0;
        uint period = m_period;
        uint duration = m_duration;
        uint scale = ((uint)m_scale);

        // Scale in MHz... 
        uint scaleMHz = scale / ONE_MHZ;

        uint clk = ((uint)ClockSpeed / ONE_MHZ);

        if (duration > period) duration = period;

        #endregion

        #region Calculate Variables (This is a C# implimentation of GHI Source ("PWM_ApplyConfiguration"))...

        prescaler = clk / scale;

        if (prescaler == 0)
        {
            if (period > (0xFFFFFFFF / clk))
            {
                // Avoid Overflow... 
                prescaler = clk;
                period /= scaleMHz;
                duration /= scaleMHz;
            }
            else
            {
                prescaler = 1;
                period = period * clk / scaleMHz;
                duration = duration * clk / scaleMHz;
            }
        }
        else
        {
            while (prescaler > 0x10000)
            {
                // Prescaler too Large... 
                if (period >= 0x80000000) break;
                prescaler >>= 1;
                period <<= 1;
                duration <<= 1;
            }
        }

        bool TimerIs16Bit = true;

        // Were not using Timer 2 of Timer 5...
        if (TimerIs16Bit)
        {
            // All Timers are 16 bit Timer's except 2 and 5... 
            while (period >= 0x10000)
            {
                // period too large 
                if (prescaler > 0x8000) break;
                prescaler <<= 1;
                period >>= 1;
                duration >>= 1;
            }
        }

        #endregion

        if (debug)
        {
            Debug.Print("*** Scale *******");
            // Print to Debug window new config...
            Debug.Print("Period = " + period);
            Debug.Print("Prescaler = " + PrescalerFromPeriodFrequencyAndClock(period, this.Frequency));
            Debug.Print("Duration = " + duration);
        }

        ARRValue = (period - 1);
        PSCValue = PrescalerFromPeriodFrequencyAndClock(period, this.Frequency);
        CCRxValue = duration;
    }

a Simple static Class CPU and I have added:

public enum Pin : int
    {
        Pin7_X3 = 1,
        Pin8_X3 = 2,
        Pin9_X3 = 3,
        Pin7_X4 = 4,
        Pin8_X4 = 5,
        Pin9_X4 = 6
    }