Understanding the the setup of a Timer on an STM32F10x

I'm trying to understand how to correctly setup the timer on an STM32F10x.

The board is running with an external crystal of 16 MHz, and I'm using the PLL:

/* PLLCLK = 16MHz / 2 * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);

so the board is running at 72Mhz. I'm configuring the timer as follows:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseInitTypeDef timerInitstructure;
timerInitstructure.TIM_Prescaler =72000-1;
timerInitstructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitstructure.TIM_Period=1;
timerInitstructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitstructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&timerInitstructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3,ENABLE);

To make sure that I set the correct frequency I am toggling a pin using the interrupt, but when I measure with the scope I get 2.784 kHz. Can anyone tell me why I get this frequency?

I wrote up a longer answer, before I realized the simple solution. I'm including the full answer in case it's helpful.

The quick answer: The values passed into the TIM_TimeBaseInit() function are only 16-bit, so 69999 is an invalid value. You'll need to choose the period and prescaler such that they are both below 65536.

There is a second problem, however, so please continue reading :)

It looks like you're targeting a 1kHz (1ms) clock?

Here is the basic equation, where PSC is the prescaler and ARR is the period ("Auto Reload Register"):

(PSC+1)(ARR+1) = (EventTime)(ClkFreq)

For 1ms:

(PSC+1)(ARR+1) = (1ms)(72MHz) = 72000

Now, you can choose any set of values to make this true, as long as they don't exceed 16 bits each. I chose:

(PSC+1) = 2 and (ARR+1) = 36000,

which gives PSC = 1 and ARR = 35999.

Then finish setting up the clock as you have.

In your case, you choose ARR=1 and PSC=71999. Turning the equations around:

EventTime = (PSC+1)(ARR+1)/ClkFreq

EventTime = (1+1)(71999+1)/72MHz = 2ms, which isn't what you're looking for.

Of course, this isn't actually what you're getting either, because of the earlier-mentioned problem with the size of the prescaler.

Incidentally, as @ScottSeidman points out, often the timer is set up correctly but the clock itself isn't. The clock trees are surprisingly complicated! One way to verify the clocks is to use the RCC_MCOConfig() function (or see the RCC_CFGR register). They can be used to output the internal clocks directly onto the MCO pin.

Good luck!

• 2ms would produce a 500Hz timer, and the OP is getting closer to 5kHz (a 2.7kHz square wave). Is this because of the invalid number passed to the structure? – Scott Seidman Jun 29 '15 at 16:30
• @ScottSeidman Yeah, I wrote that part before realizing the 16-bit size problem. I've just edited my answer a bit for clarity. Thanks :) – bitsmack Jun 29 '15 at 16:35
• For completeness to the rest of the STM32-ARM Cortex family, I'll add that often the problem is the exact opposite -- the timer is set up correctly, and the system clock is wrong! This is less probable for the F1's, where the clock is pretty straightforward, but a real issue for the F4's and such, where pretty arcane Excel-based clock setup routines are used to provide startup files. In fact, I often check my clock setup by toggling a bit with a timer! – Scott Seidman Jun 29 '15 at 16:42
• well I don't know if I could be thankful enough for this great answer . thanks a lot – Engine Jun 29 '15 at 20:41

@Bitsmack has given a great answer, however there is another parameter that is in play that has not been mentioned: TIM_ClockDivision. It is simply the hardware clock divisor sitting between busclock and the counter, and has discrete values of 1,2 or 4 if memory serves. In the OP's example it is 1 (TIM_CKD_DIV1). So if for some reason you need to bring ClkFreq into a range where you can use 16-bit values for PSC and/or ARR then this parameter will be useful. Not so much in this case but if you are dealing with cores at higher clock frequencies then maybe so. Also if you need longer timer duration (period). So @bitsmack's formula could be written as:

(PSC+1)(ARR+1) = (EventTime)[(ClkFreq)/ClkDiv]

An intuitive way to think of basic timers is that the timer event frequency (note: not event time) is simply the input clock divided by each of these parameters:

EventFreq = ClkFreq/ClkDiv/(PSC+1)/(ARR+1), and
EventTime = 1/EventFreq

which gets us to bitsmack's formula. You can frame your requirement either as an event time interval requirement (I want a timer with 1ms period), or as an event frequency requirement (I want a 1kHz interrupt rate), both of which are served by the formulas above.