Skip to main content
Eugenia Suarez
Associate III
April 19, 2017
Question

Choosing a timer and what mode for only counting time periods.

  • April 19, 2017
  • 13 replies
  • 8854 views
Posted on April 19, 2017 at 12:06

I'm using HAL_TIM library for my timer proposal. I would like to count 100 us. My idea is starting to run a MCU timer in free run mode and having and interruption every this timer period. I have read there are several timers in my st used (stm32L476), and every timer has 3 or 4 channels: pwm, output mode, input capture, compare, etc.. But I don't know which will be the best for my proposal. I guess I can discard PWM modes or input capture mode, cause I only want to be internally counting time being passed, I don't want to be outputing any signal or reading an input pin. 

Which is the channel or mode I must choose in order to have an interruption every 100us, 10us, or Xus? (of course I know I must handle the interruptions by sw but first I need to count period in the correct channel/mode)

  • input capture
  • output compare
  • pwm generation
  • one pulse mode output.

Any help will be appreciate. Thanks in advance.

#timer-channels #hal #stm32l4-timer #hal_tim
This topic has been closed for replies.

13 replies

Tesla DeLorean
Guru
April 19, 2017
Posted on April 19, 2017 at 15:07

You don't need any channels to get a periodic interrupt.

Set the Prescaler to clock the TIM at 1 MHz, set the Period to 100-1, enable the Update interrupt, and you'll get an interrupt every 100us

Depending on the APB clock, but Prescaler = (SystemCoreClock / 1000000) - 1   ie figure source divided by 1 MHz to get divisor for 1 MHz

If you run the TIM with maximal period, you can use and advance the channel triggers by 100 at each interrupt for similar effect, but it is more labour intensive.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Eugenia Suarez
Associate III
April 19, 2017
Posted on April 19, 2017 at 16:30

Is it possible to work with no channel? I thought I must select one of them.

Thanks.

S.Ma
Principal
April 19, 2017
Posted on April 19, 2017 at 17:29

You don t need a channel to create a delay or a timeout. As clive said, just set the timer to overflow which can trigger an interrupt.

Free running mode, autoincremented. A channel is used to generate a signal onto a pin, for example, or generate interrupts faster than the timer period.

S.Ma
Principal
April 19, 2017
Posted on April 19, 2017 at 15:23

Use a basic timer to do this, with interrupt on overflow. Use the smallest timebase for tuning the overflow. Then if you want to create a countdown, in the interrupt, decrease a 32 bit global variable unless it is 0xffffffff

From the main loop you will have a simple timeout counter that will self stop.

Eugenia Suarez
Associate III
April 19, 2017
Posted on April 19, 2017 at 16:27

but which channel must I choose? I would like to configure the timer handler struct or doing it through Cube app, but I must choose one of these 4 operation mode channels. I have never seen this before. Since I was working with 8 bit mcu timers where there was only one mode: free run, and you only (brievly said) must to save the value of the period you want to count.

However, thanks for your suggestions. I'm sure they will be usefull immediatly.

Elkin Granados
Associate II
April 19, 2017
Posted on April 19, 2017 at 18:07

Hi Eugenia,

The STM32 microcontrollers family have different timers with different features, but all of those with the basic feature of free counting. If you're using the STCubeMX software, in the pinout tab you can see the features of each timer, and for example you can see that TIM1 to TIM5 have the special features as PWM, output compare and input capture that includes the use of channels for signal input / output, if you don't need a signal then there is not necessary to set any channel. There are other timers that have only  the counting mode and the one pulse mode. If you want to make a time count I suggest to use the basic timers, you just check the option ''activated'' and set the parameters (prescaler and counter value that depens of the clock frequency) in the Configuration tab and the interruption. If you want to use a timer with the special features just for free counting in the pinout tab select the timer (for example the TIM1) and then just select the clock source, the TIM1 is now activated and you can set the p

arameters in the Configuration tab and the interruption (prescaler and counter value that depens of the clock frequency).

0690X00000606VgQAI.png0690X00000606h2QAA.png0690X00000606ozQAA.png0690X00000606j2QAA.png
Eugenia Suarez
Associate III
April 20, 2017
Posted on April 20, 2017 at 10:10

Thank you for your detailed explanation. It's very helpful. 

T J
Senior III
April 19, 2017
Posted on April 20, 2017 at 01:09

yes, in summary, you must use a single timer for your 100uS timerOverflow interrupt.

there is no point to use channel compare, because they go active at the count and deactivate at a count of zero, therefore the overflow rate is determining the frequency, not the channel 'compare value'

Eugenia Suarez
Associate III
April 20, 2017
Posted on April 20, 2017 at 09:31

For sure, that was the all I need!  thanks a lot!

all the answers has been too usefull.

Thanks to all of youuu. 

roseanne qiu
Associate III
June 21, 2018
Posted on June 21, 2018 at 22:42

Dear Sir/Madam:

I just found that I have similar problems.  there are limit timers . timer 1, timer9 and timer10 are different from other timers. I have used timer2, timer3, timer4, and timer5 and their interrupts . to each timer, I use internal clock ,

once timers expire, they will create interrupt. My questions are

1. each timer , I only use one channel, there are more channels available, but I want their periods are different,

in my understanding, if you use multiple channels from one timer, their period have to be the same?

if not same, how could I do that? and how could I enable or disable each channel to separate them?

2. if above 1 does not work for multiple channels from one timer, I try to use different timer for each event,

but I found that I could not make  timer1, timer9 and timer10 work for their interrupt

I could only make timer2, timer3, timer4 and timer5 interrupts work.

1. here are my configures for working timers' interrupt:

/*########## Configure TIMx x = 2,3,4,5 ######################################*/

void TIMx_IRQHandler()

{

HAL_TIM_IRQHandler(&TimxHandle);

}

// Timer is configured to rollover every 1 secs 

__TIMx_CLK_ENABLE();

TimxHandle.Init.Prescaler = 16400;

TimxHandle.Init.CounterMode = TIM_COUNTERMODE_UP;

TimxHandle.Init.Period = 5000;

TimxHandle.Instance = TIM2;

TimxHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

if ( HAL_TIM_Base_Init(&TimxHandle) != HAL_OK )

{

Error_Handler();

}

HAL_TIM_Base_Start_IT(&TimxHandle);

HAL_NVIC_SetPriority(TIMx_IRQn, 0, 1);

HAL_NVIC_EnableIRQ(TIMx_IRQn);

2. here are my configures for none working timers' interrupt:

/*########## Configure TIMy y = 1,9 ######################################*/

__TIMy_CLK_ENABLE();

TimyHandle.Init.Prescaler = 16400;

TimyHandle.Init.CounterMode = TIM_COUNTERMODE_UP;

TimyHandle.Init.Period = 2500;

TimyHandle.Instance = TIMy;

//TimyHandle.Channel = HAL_TIM_ACTIVE_CHANNEL_1; // it does not matter whether I set this

TimyHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

if ( HAL_TIM_Base_Init(&TimyHandle) != HAL_OK )

{

Error_Handler();

}

HAL_TIM_Base_Start_IT(&TimyHandle);

HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 0, 1);

HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);    // this make system hung

would you please help me for that.

now basically , I would need use at least 8 timers' interrupts. 

thanks for all of your

rose

0690X0000060LNDQA2.png
henry.dick
Associate II
June 21, 2018
Posted on June 21, 2018 at 22:56

'

if not same, how could I do that?'

easy.

1) set up the timer to free run;

2) set up a compare channel, and pick its matchpoint to be the timer's current value + N ticks away;

3) in the compare ISR, advance the matchpoint by another N ticks away;

4) set a flag to indicate overflow, or run a quick user code.

the timer will have a period of N ticks.

you can do this for as many channels as there are output compare channels on a given timer.

basic principles here: 

https://wordpress.com/post/dannyelectronics.wordpress.com/4097

 

code examples here: 

https://github.com/dannyf00/My-MCU-Libraries---2nd-try/tree/master/STM32F1xx

  look for those timXoc.h/.c files, X=1, 2, 3, 4, ...
roseanne qiu
Associate III
June 21, 2018
Posted on June 21, 2018 at 23:13

Dear Dhenry:

Thanks for your quick response!

I just went to your link and check the setting for the timer different channels. 

but I found you do not use HAL lib, I am using HAL lib,

I would like to know what Hal API to use, and also in Hal lib, there are timer structure:

============================================

typedef struct

{

TIM_TypeDef *Instance; /*!< Register base address */

TIM_Base_InitTypeDef Init; /*!< TIM Time Base required parameters */

HAL_TIM_ActiveChannel Channel; /*!< Active channel */

DMA_HandleTypeDef *hdma[7]; /*!< DMA Handlers array

This array is accessed by a @ref DMA_Handle_index */

HAL_LockTypeDef Lock; /*!< Locking object */

__IO HAL_TIM_StateTypeDef State; /*!< TIM operation state */

}TIM_HandleTypeDef;

=================================

I know how to set basic parameters, and channels, but do not know how to set what you mentioned.

especial to HAL API?

any one could give me examples for HAL lib?

thanks

rose

roseanne qiu
Associate III
June 21, 2018
Posted on June 21, 2018 at 23:22

Dear Dhenry:

further reading your response, I guess :

in my settings , i have period value for a timer, and then I could set 

channel = channel1|chnnel2...; 

period = n tickes; // I guess this is ticks, or period

in the timer interrupt,

suppose channel 1 has period n ticks , channel 2 has 2n ticks

1. check whether it is the timer I configure

2. check whether it is channel1, if so check its counting? (like n) if so, it is for channel1?

3. check whether it is channel2, if so check its counting (like 2n) if so, it is for channel2?

am I correct?

since I use HAL lib, I may need to read __HAL_TIM_GET_COUNTER(&TimxHandle) inside ISR

to get countings?

thanks 

roseanne

henry.dick
Associate II
June 22, 2018
Posted on June 22, 2018 at 00:04

'

am I correct?'

not exactly. go through the link / code I provided earlier and try to understand how they work. it helps with a thorough understanding of the device / datasheet.

roseanne qiu
Associate III
June 22, 2018
Posted on June 22, 2018 at 14:58

dear Eklin and Clive:

yes, I have to use timer interrupts for some time sensitive modules(tasks) inside the interrupt routine, the current tasks' levels(main loop without OS), some tasks take too long, and make other tasks, which need to process some data in exactly time, miss executions and results are bad. this is one reason, another reason, in the task level, it is related to communication with outside interface, we have to use timer to avoid waiting time out, there are other reasons.

this is micro controller which handle 3 hardware serial interfaces to communication outside, and adc and dac interface involved and some math calculation. I have to weight all the tasks and interrupt routines...

Elkin Granados
Associate II
June 22, 2018
Posted on June 22, 2018 at 19:06

Hi

roseanne.qiu461

‌, based in the needes I would suggest to you the following if you are using HAL and CubeMX:

* Define in your program the periods that need to be counting at same time, I´m quite sure that there are instants where all 8 timers don't need to be counting at same time.

* Set all the timers with an initial period, enable all interruptions, set all in freerun mode, be sure that preescaler value is able to handle required times, and set different priorities for each timer.

* As programming

recommendation

, set macros to enable and disable interrupts, start and stop timers and change counting periods, there is an example of one code I made:

0690X0000060Bm6QAE.png

* In the main loop set the periods and the timers in the moment that are needed, enable the timers interrupts and start the counting.

* Using the HAL you must to take on count that there is just one function to handle all timers callbacks, so you must to check from which timer comes the interrruption with some like this:

0690X0000060BpsQAE.png

* You should disable some interruptions to avoid that could be called meanwhile the interruption function is in execution.

* In order to check not only from which timer come the interrupt, you should declare a global flag to know which task is in execution (In the case that you are setting a timer with different periods).

* Don't make long codes in the callback function, instead set or clear flags that could be related in the main loop, I suggest to do the main loop as a state machine, if you make the state machine diagram of all your code you could see clearly where you have to set and start the timers.

Not sure if that could help to you, but works for me. Thanks

roseanne qiu
Associate III
June 22, 2018
Posted on June 22, 2018 at 14:59

Dear Dhenry:

thanks, I will read your codes in more details.

thanks

roseanne qiu
Associate III
June 22, 2018
Posted on June 22, 2018 at 20:34

Dear Eklin:

thanks for your reply. 

So far I do not have problems to set most interrupts and balance between tasks level  and interrupt. The balances among interrupt latency and context switch are all very good so far which really solve our purely poll 's structure .  HAL api gives very good interrupts' flag cleaning and setting . The only problem is limit timers I could use. So now I have to utilize multiple channels for each timer . I am still reading Mr. Dhenry's examples to know how to use HAL's API to set each channel of one timer .

since we also have ADC interface, if I could use ADC interrupt for its timing, I may not need to use so many timer's interrupts. 

will let you know how about my progress.

thanks

roseanne

roseanne qiu
Associate III
June 22, 2018
Posted on June 22, 2018 at 22:41

Dear Elkin and Dhenry:

I used the similar function you gave for Hal callback function for timer update(expire), I do not have the problem so far

I am struggling to try to use multiple channels of one timerf 

I read back HAL lib: 

void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)

{

/* Capture compare 1 event */

if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)

{

if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)

{

{

__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);

htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;

/* Input capture event */

if((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)

{

HAL_TIM_IC_CaptureCallback(htim); <===========I believe in my case I do not use this one for multiple channels of                                                                                           one time 

}

/* Output compare event */

else

{

HAL_TIM_OC_DelayElapsedCallback(htim); <==========I believe in my case, I need to use this one for multiple 

                                                                                                channels of one timer

HAL_TIM_PWM_PulseFinishedCallback(htim); <==========I believe in my case I do not use this one

}

htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;

}

}

}

.....

/* TIM Update event */

if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)

{

if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) !=RESET)

{

__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);

HAL_TIM_PeriodElapsedCallback(htim);  <--------------this is regular interrupt I am using now , to multiple channels of 

                                                                                      one timer, I do not think that I need to use this one.

}

}

....

=======================================================

so if I am correct, I will use 

HAL_TIM_OC_Start_IT(&Tim3Handle, TIM_CHANNEL_1); <==========enable channel 1 interrupt of timer 3

HAL_TIM_OC_Start_IT(&Tim3Handle, TIM_CHANNEL_2);<============enable channel 2 interrupt of timer 3

HAL_TIM_Base_Start_IT(&Tim3Handle); <===========I do not need to use this one for channel interrupt, this is only

                                                                                           used for a timer expire, not for their channel

by reading from your codes, it seems that 

every time , once interrupt happen for a channels , I need to update output compare register count inside compare interrupt of 

HAL_TIM_OC_DelayElapsedCallback(htim);, but if compare register's data is over flow, I may need to reset the data again.

I am still trying to test this, if I am wrong, please let me know.

thanks for your help

thanks

rose

henry.dick
Associate II
June 23, 2018
Posted on June 23, 2018 at 01:37

'

by reading from your codes, it seems that 

every time , once interrupt happen for a channels , I need to update output compare register count inside compare interrupt

 '

I said as much, plainly,

you have two choices:

1. take my code / structure and implement it with HAL-equivalents;

2) take my code, include it in your code and hit the compile button and it will just work - with minimum changes if you are on a different chip.

once the code is up and running, using it is easy:

  tim1_init(1); //initialize tim1 as 1:1 prescaler

  tim1_setpr1(1000); //set channel 1 period to 1000x1 ticks;

  tim1_act1(task1); //user handler, task1(), is invoked every 1000x1 ticks;

  tim1_setpr3(20000); //set channel 3 period to 20000x1 ticks;

  tim1_act3(task2); //user handler, task2(), is invoked every 20000x1 ticks

  ...

that's all there is.