STM32F4 Timers - Calculation of Period and Prescale, and Generating 1 ms Delay

TIMupdateFreq(HZ) = Clock/((PSC-1)*(Period-1))

This is obviously wrong. The counters go from 0 to the register value (inclusive), there are always one more cycles than the register value, not one less.

Update Event = TIM clk/((PSC+1) * (ARR+1) * (RCR+1))

This one is better, but general purpose timers don't have RCR registers. You can assume RCR=0, and omit *(RCR+1) from the formula.

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

This attempts to round the result, when no integer solution is possible. More on it later.

Update Event = 84000000/(42000*2000) = 1 (Is this 1ms Delay??)

No, this is one second (1s) delay, or 1 Hz frequency.

how this PSC = 41999 and Period = 1999 are selected?

Take the simple formula,

Updatefrequency = TIM clk/((PSC+1)*(ARR+1))

rearrange it to

(PSC+1)*(ARR+1) = TIMclk/Updatefrequency

then you have a known value on the right hand side, but two unknowns on the left hand side. The trivial solution would be to set one of them, e.g. PSC to 0, and ARR to the right hand side value - 1.

Unfortunately most timers have 16 bit registers only, so this is not going to work when TIMclk/Updatefrequency > 65535. Both PSC and ARR must fall between 0 and 65535. You'd have to find a factorization that satisfies these constraints.

Let's see an example, you'd want a 2.3 seconds delay. Note that 2.3s is the period, not the frequency, so you'd need to put its inverse into the formula.

(PSC+1) * (ARR+1) = 84000000 / (1 / 2.3) = 84000000 * 2.3 = 193200000

Luckily there are lots of zeroes at the end, you can just pick e.g. 10000 as the prescaler (PSC=9999), and ARR becomes 19320-1 = 19319. If the desired ratio is not a nice round number, then you should resort to integer factorization, or write a small program to look for all possible divisors (for(i=0;i<65536;i++) ...).

It can also happen that there are no precise integer solutions at all, then you can still loop through all possible prescaler values, and see which one gives the smallest error.

Update Event = 84000000/(42000*1000) = 2

But my delay is twice in every sec. i.e 500ms

Note the dimensions. You are using frequencies in the formula, you are dividing the 84 MHz input frequency with some values, and get 2 Hz as a result. 2 Hz frequency means two events every second, so the events are indeed 500ms apart.


I thought I'd throw a more comprehensive answer in here. For an 84MHz clock, there are many combinations of prescaler and period that will work. Here are just a few:

  PSC    ARR            F         ERROR EXACT
   1  41999  1000.000000  0.0000000000   YES
   2  27999  1000.000000  0.0000000000   YES
   3  20999  1000.000000  0.0000000000   YES
   4  16799  1000.000000  0.0000000000   YES
   5  13999  1000.000000  0.0000000000   YES
   6  11999  1000.000000  0.0000000000   YES
   7  10499  1000.000000  0.0000000000   YES
   9   8399  1000.000000  0.0000000000   YES
  11   6999  1000.000000  0.0000000000   YES
  13   5999  1000.000000  0.0000000000   YES
  14   5599  1000.000000  0.0000000000   YES
  15   5249  1000.000000  0.0000000000   YES
  19   4199  1000.000000  0.0000000000   YES

How do I come up with these? Even commercial tools like the one from MikroElektronica only come up with one exact (or inexact) combination. How to find them all? I simply wrote a python program to compute them all. It classifies each as exact, or notes the relative error of those that are inexact. By changing the tolerance at the top of the program, you can "tighten" or "loosen" the computations as necessary.

Here is the program in its entirety:

import numpy as np
import pandas as pd

TARGET_F = 1000  # In Hz so 50.0 is 0.020 seconds period and 0.25 is 4 seconds period
CLOCK_MCU = 84000000
TOLERANCE = 0.0001

# -----------------------------------------------------


def abs_error(num1, num2):
    return abs((num1 - num2) / num1)


def hertz(clock, prescaler, period):
    f = clock / (prescaler * period)
    return f


def perfect_divisors():
    exacts = []
    for psc in range(1, 65536):
        arr = CLOCK_MCU / (TARGET_F * psc)
        if CLOCK_MCU % psc == 0:
            if arr <= 65536:
                exacts.append(psc)
    return exacts


def add_exact_period(prescaler):
    entries = []
    arr = CLOCK_MCU / (TARGET_F * prescaler)
    if arr == int(arr):
        entry = [prescaler, arr, TARGET_F, 0.0]
        entries.append(entry)
    return entries


def possible_prescaler_value():
    possibles = []
    for psc in range(1, 65536):
        if psc in exact_prescalers:
            continue
        h1 = hertz(CLOCK_MCU, psc, 1)
        h2 = hertz(CLOCK_MCU, psc, 65536)
        if h1 >= TARGET_F >= h2:
            possibles.append(psc)
    return possibles


def close_divisor(psc, tolerance):
    arr = CLOCK_MCU / (TARGET_F * psc)
    error = abs_error(int(arr), arr)
    if error < tolerance and arr < 65536.0:
        h = hertz(CLOCK_MCU, psc, int(arr))
        return psc, int(arr), h, error
    else:
        return None


#  ------------------------------------------------------------------------

# Make a dataframe to hold results as we compute them
df = pd.DataFrame(columns=['PSC', 'ARR', 'F', 'ERROR'], dtype=np.double)

# Get exact prescalars first.
exact_prescalers = perfect_divisors()
exact_values = []
for index in range(len(exact_prescalers)):
    rows = add_exact_period(exact_prescalers[index])
    for rowindex in range(len(rows)):
        df = df.append(pd.DataFrame(np.array(rows[rowindex]).reshape(1, 4), columns=df.columns))

# Get possible prescalers.
poss_prescalers = possible_prescaler_value()
close_prescalers = []
for index in range(len(poss_prescalers)):
    value = close_divisor(poss_prescalers[index], TOLERANCE)
    if value is not None:
        close_prescalers.append((value[0], value[1], value[2], value[3]))
df = df.append(pd.DataFrame(np.array(close_prescalers).reshape(len(close_prescalers), 4), columns=df.columns))

#  Adjust PSC and ARR values by -1 to reflect the way you'd code them.
df['PSC'] = df['PSC'] - 1
df['ARR'] = df['ARR'] - 1

#  Sort first by errors (zeroes and lowest errors at top of list, and
#  then by prescaler value (ascending).
df = df.sort_values(['ERROR', 'PSC'])

# Make and populate column indicating if combination is exact.
df['EXACT'] = pd.Series("?", index=df.index)
df['EXACT'] = np.where(df['ERROR'] == 0.0, "YES", "NO")

#  Format for output.
df['PSC'] = df['PSC'].map('{:.0f}'.format)
df['ARR'] = df['ARR'].map('{:.0f}'.format)
df['F'] = df['F'].map('{:.6f}'.format)
df['ERROR'] = df['ERROR'].map('{:.10f}'.format)

output = df.to_string()
print(output)
print()
print('these are the ', df.shape[0], ' total combination meeting your tolerance requirement')
exit(0)

Using this program everyone will be able to compute these values with confidence. I hope it proves useful.


There are no "variations". Only one formula exists:

Period = (PSC+1)*(ARR+1) / TmerClockFreq in seconds Period = 1000 * (PSC+1)*(ARR+1) / TmerClockFreq in milliseconds

So you need to find the ARR & PSC which will give you the time as close as possible to the required period