# STM32F4 TIM2 timer, getting to 1 second

I'm learning a bit about general purpose timers on my STM32F4Discovery board, and would like to know how I can configure the timer to invoke a timer interrupt each second, or at least have the auto-reload value reset to 0 every 1 second.

I know the MCU runs at 168MHz, and I'm using the internal clock as the TIM2 clock source. I would like to understand better how I can calculate the appropriate prescale value, period and clock division to achieve 1 sec.

TIM_HandleTypeDef timeBase;
timeBase.Instance = TIM2;
timeBase.Init.Prescaler = 0;
timeBase.Init.CounterMode = TIM_COUNTERMODE_UP;
timeBase.Init.Period = 168000000; // Hypothetical value (Period cannot be greater than 65535)
timeBase.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&timeBase);


Am I correct in saying that the above, with a prescaler of 0, period of 168000000 and clock division of 1 will cause a the timer auto-reload value to reset to 0 each 1 second?

Now, the Period has a max value of 0xFFFF (65535), so to me that means I need to manipulate the prescaler value, and period to achieve a 1 second auto-reload value reset.

Is there a formula for doing this?

• Are you using ST Micro's STM32F4 peripheral library, or the STM32CubeF4, or something else? IIRC both contains code to set each system clock, and put the timer into auto-reload mode. As you have calculated, you need to manipulate both the prescaler, and re-load value. 168,000,000 is about 28 bits, so two factors (numbers), about 14 bits each, would work, or any pair with one 16 bits or less, and the other 12 bits or more, which multiplied give 168,000,000. – gbulmer Oct 16 '15 at 15:17

You have two problems. The first is that the MCU runs at 168MHz if it has been set up that way, and your compiler may not do that by default. Setting up the clock is a bit arcane. ST provides an excel-based tool to help you create a setup file, and then the file needs to be put in the correct place and some other files need to be edited.

I recommend this site as a place to get all the relevant info. There is an ST page with instructions, but it isn't as clear as some of the other tutorials.

If you do this, the APB1 bus, the one that TIM2 is on, will run at 42MHz max, giving you an 84MHz TIM2 clock (it's doubled by PLL). If you need faster than that, you must use one of the timers on APB2, which goes twice as fast. Note that that bus doesn't have any 32-bit timers.

The second issue is, as you said, you exceeded a maximum value. Yes, you need to play with the two values. If you divide your clock by (42000-1) with the prescalar to give you a 2 kHz time base, and then set the period to (2000-1), there's your 1 second interval.

Of course, you must TURN ON THE CLOCK to the TIM2 peripheral, and then enable TIM2, or nothing will work.

• Thanks for the answer. This really helped a lot. I'm using CubeMX instead of the Excel sheet to configure my project, but does the same thing. – josef.van.niekerk Oct 16 '15 at 16:00
• Why are we subtracting 1 from 42000 and 2000? – josef.van.niekerk Oct 19 '15 at 21:09
• Because it starts at zero, and interrupts on the overflow – Scott Seidman Oct 19 '15 at 21:41
• Duh, right. :) Sometimes I live in a dream world. Thanks for that. – josef.van.niekerk Oct 20 '15 at 6:10

Also if you don't want to involve whit Setting up the clock by RCC registers, you can easily add the two following lines to your timer init function:

// This idea has been taken from "USART BRR Configuration" section in the USART_Init() function

RCC_ClocksTypeDef   RCC_ClocksStatus;
RCC_GetClocksFreq(&RCC_ClocksStatus);/*This line gives us System current frequency
Note that above function returns the frequencies of different on chip clocks; SYSCLK, HCLK,  PCLK1 and PCLK2.*/


and then for the Prescaler and Period you will have :

/* timer_tick_frequency for TIM4 = ( (2*APB1 frequency)/10000 )-1 */

TIM_TimeBaseInitStructure.TIM_Prescaler = (2*RCC_ClocksStatus.PCLK1_Frequency/10000-1);//Conter clock frequency (CK_CNT) is now 10KHz

TIM_TimeBaseInitStructure.TIM_Period    = (10000-1);//Update Event occurs every 1 Seconds


So if you suppose that APB1 frequency is 42MHz then Prescaler value is :

(2*42000000)/10000 - 1 = 8400 -1 = 8399

then you can go through IRQn handler every 1 second to do what you want.