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
-
2\$\begingroup\$ A couple of points. 1. Numbers usually have a character every 3 digits, to make it easier to parse. For example, 1000000Hz, using the GB/USA-English convention is easier to read written as 1,000,000Hz, or elsewhere 1 000 000Hz (or even 1_000_000). 2. There are SI unit Metric prefixes so 1000000Hz is easier to understand when it is written as 1MHz. 3. A typical crystal, used as the frequency source of an STM32, is accurate to 20 parts in 1 million or worse (2 in 100,000), so quoting numbers like 1281.11273792094, is misleading; 1281.11 is enough. \$\endgroup\$gbulmer– gbulmer2014年10月05日 16:13:43 +00:00Commented Oct 5, 2014 at 16:13
-
\$\begingroup\$ @gblumer - Yes I understand what your points are. However, many Function Generators do have 4 or 6 digit resolutions after the decimal point, expensive ones can have more. A nice example of this: ebay.com.au/itm/… put the numbers in after the decimal points really just to show that I was not messing with the numbers generated. Thank you, helpful post: +1. \$\endgroup\$Rusty Nail– Rusty Nail2014年10月05日 20:32:54 +00:00Commented Oct 5, 2014 at 20:32
-
\$\begingroup\$ That link leads to a ebay.com.au/itm/… device which says "Accuracy:±2ppm". It matters less where the decimal point is, and more how many significant figures are used. So "±2ppm" is only one more digit than a typical crystal, i.e. not 1281.11273792094 but only 1281.113. \$\endgroup\$gbulmer– gbulmer2014年10月05日 20:55:35 +00:00Commented Oct 5, 2014 at 20:55
-
\$\begingroup\$ I don’t understand the question, how can you know the period register value without knowing the prescalar value? The prescaler is to help achieve longer timer periods. Normally you start with a known system/peripheral clock and a desired timer frequency you then need to deduce the prescaler and timer period register values, is this what you are asking? \$\endgroup\$EmbeddedSoftwareEngineer– EmbeddedSoftwareEngineer2020年09月08日 12:55:26 +00:00Commented Sep 8, 2020 at 12:55
3 Answers 3
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
}
Depending on the clock, prescaler and auto reload, repetition counter (if present) parameters, the 16-bit timer can generate an update event from a nanosecond to a few minutes.
For example, to generate an event two times per second, choose Clock frequency(TIM_CLK) = 168 Mhz, Prescalar(PSC) = 16799, Period(ARR) = 4999, repetition counter(RCR) = 0,
then the 16-bit timer will generate an event two times per second.
For more information ;
There is a tool written in python to do all the calculations: https://github.com/v0idv0id/STM32-Scaler