Skip to main content
areify
Associate III
December 14, 2018
Question

How to correctly set up a micro second timer?

  • December 14, 2018
  • 19 replies
  • 6290 views

Hi there.

I know this question is already asked, but the topics I've read didn't worked for me, so I'm writing this in order to study mi concretely case.

I'm setting up my timer using TIM1 with the next parameters:

//Prescaler for 1 us
 uint32_t PrescalerValue = (uint32_t)(apb1clock / 1000000) - 1;
 
 //Other parameters
 timer_us_timhandle_.Init.Period = 1 - 1;
 timer_us_timhandle_.Init.Prescaler = PrescalerValue;
 timer_us_timhandle_.Init.ClockDivision = 0;
 timer_us_timhandle_.Init.CounterMode = TIM_COUNTERMODE_UP;

Where apb1clock is 9 MHz.

Am I doing wrong? Maybe a concept problem?

The result I'm having is that main line of code execution cannot go on because of the continous ISR calling. Am I overweighting my STM? (STM32F105VC).

P.S.: After the ISR call I set the flag to 0.

Thank you in advance.

This topic has been closed for replies.

19 replies

waclawek.jan
Super User
December 14, 2018

> timer_us_timhandle_.Init.Period = 1 - 1;

You have to set Period to nonzero.

Besides, interrupt entry/exit is around 24 cycles, so it's definitively a bad idea to try to invoke an interrupt every 9 cycles.

JW

fnicoli
Visitor II
October 5, 2019

I think your first statement is untrue.

I can't find anything on the documentation preventing the ARR register to be 0.

I've found the above equation:

Interrupt Period = (PSC+1)*(ARR+1) / TmerClockFreq

Do you have any references on that? I haven't found anything about this online.

Tesla DeLorean
Guru
October 5, 2019

The Prescaler can be zero (DIV1), setting Period to zero basically disables the count.

The TIM effectively acts as a pair of dividers.

UPDATE FREQ = (TIMCLK / (PSC+1)) / (ARR+1)

or

UPDATE FREQ = TIMCLK / ((PSC+1) * (ARR+1))

For N-states, the counter goes from 0 thru N-1

In silicon making a comparator for N-1 is easier, as you can flag that the next state will be zero. You don't want to wait to get to N and then react.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
areify
areifyAuthor
Associate III
December 14, 2018

So is not possible with 9MHz to set my microsecond timer? I have to use a faster speed for TIM1?

waclawek.jan
Super User
December 14, 2018

It's not practical to have microsecond *interrupts* even at 100MHz clock.

But what would you want to do in those interrupts? If you just want count microseconds, set the period to the maximum value and leave it running freely, with no interrupts.

JW

areify
areifyAuthor
Associate III
December 14, 2018

I need to generate a 1us ISR in order to link with a library for communications which works at 9600 bauds (so microseconds are needed).

I can't count to 104 because the callback I need to link is ready for a 1us interruption cycle

Tesla DeLorean
Guru
December 14, 2018

A software UART?

You can't do interrupts or callbacks at this rate.

Best to use freerunning TIM or DWT_CYCCNT to count off cycles in linear code.

Consider running in RAM, FLASH is a bit of a sloth on the F1 series.​

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
December 14, 2018

> callback I need to link is ready for a 1us interruption cycle

That's then a completely irrationally written library, and you should talk to its author and ask for comment.

I'd like to hear his comments here.

JW

Tesla DeLorean
Guru
December 14, 2018

Already at the intersection of Bad and Worse

0690X000006CpmxQAC.jpg

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
areify
areifyAuthor
Associate III
December 27, 2018

Sorry for not answering at all this time. I was modifying the library so now I can play correctly with timers.

I'm working with apb1 at 9MHz as I used to do. I'm setting up my TIM3 as a 1MHz pulse signal (every count has 1us width).

Now my ISR get called every X seconds (where X is the period value that I can set up).

I need to correctly count to 52, 100 and 104us. But if I set my period as 4 (the Maximum Common Divisor of those values) I have the same problem that was having: interrupts are called very fast

(every 4us).

I need:

- To work with interrupts. THIS IS VERY IMPORTANT. Sequential code is not valid for this case.

- To have an accuracy count of time.

- To have 'paralelism'. I mean: maybe I could be counting to 52 at the same time I'm counting to 100, for example.

Is possible to achieve all this objectives?

Thank you.

S.Ma
Principal
December 30, 2018

There is a separate thread for SW emulated USART.

Use a Timer which can perform DMA on channels for future optimisation.

When using time critical interrupts, get ready to use LL (low layer).

Use Timer input capture interrupt to get the timestamp of the start bit edge.

From there, you can program (optionnaly by DMA) all the RX level scan times by output compare.

If you want to transmit TX, you can either use output compare bit by bit or toggle the output by DMA RAM toggle array timestamp sequence.

If you are lazy and it's ok to disable interrupts for 1 msec, you could also have an EXTI over RX and once you get the start bit, you make microsecond delays to sense the pin level each bit time. This won't work with USB, for example.

Tesla DeLorean
Guru
December 27, 2018

You can accurately measure time from a free running timer.

If you succeed at interrupting at 1 MHz, it will be ALL the processor is doing.

Perhaps think this through, and consider a CPLD for tight signal recovery. ​

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Bob S
Super User
December 27, 2018

Why aren't you using a real UART/USART for this?

Presuming this is standard async NRZ data (like a UART handles), you don't need an interrupt every microsecond. Here is pseudo code for a general idea of what you can do to receive data. I leave it as an exercise to flesh this out into real code. To transmit data (doesn't look like you are doing that), you only need a consistent 104us interrupt to output each bit.

softwareuart_init()
{
 // Configure TIM3 to count in 1us increments, count reg = 0
 // TIM3 interrupt atfer 52 count (i.e. ARR = 52, or is it 52-1?)
 // DO NOT START TIM3 yet
 
 // Configure GPIO to interrupt on falling edge of software uart RX pin
}
 
softwareuart_GPIO_IRQ()
{
 // Got falling edge (possible beginning of start bit)
 
 // Start TIM3
 // DIsable GPIO interrupt
 // Set software uart RX state to "start bit"
}
 
softwareuart_TIM3_IRQ()
{
 // NOTE: TIM3 is free-running, you never stop it or reset the count register.
 // All interrupts durations are relative to the previous match value.
 
 // If state is "start bit"
 // if GPIO RX pin is low
 // Set TIM3 ARR = ARR + 104 and interrupt
 // set software uart RX state to "data bits"
 // else
 // Pin is high again, not a valid start bit
 // Disable TIM3
 // softwareuart_init() - go search for another start bit
 // endif
 // else if state is "data bits"
 // Read GPIO RX pin, shift into data byte
 // if got 8 data bits
 // set software uart RX state to "stop bit"
 // endif
 // Set TIM3 ARR = ARR + 104 and interrupt
 // else if state is "stop bit"
 // if GPIO RX pin is high
 // Got valid byte, store it somewhere
 // else
 // Bad stop bit, report framing error
 // endif
 // disable TIM3
 // softwareuart_init()
 // endif
}

areify
areifyAuthor
Associate III
December 28, 2018

It's a RZ communication, where logics 1s are at high voltage level during the whole period (104us) and logics 0s are composed as a half-period (52us) low level and a half-period high level.

Communication also have an special bit at the start of each frame which needs to be read with a 100us delay (I can't explain more about this because of confidentiality agreement).

So I need to be able to have non-sequential access into my ISR in order to get this different values of timer.

As I said, it's not possible to read during the normal execution of the code, because a lot of instructions needs to be processed without stopping.

Tesla DeLorean
Guru
December 28, 2018

I'd probably look to using the TIM to measure the timestamp of the edges or use the PWM input mode. Might also look at sampling pin to pattern buffer and decoding that.

Work with the device vendor directly to construct a driver, and provide other examples and support. ​

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
areify
areifyAuthor
Associate III
January 8, 2019

What would be the correct form of have a continuous running timer (without period interrupts) which only calls ISR when CCR values are reached? I mean, using HAL functions...

I need to setup my timer as output compare mode?