cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly set up a micro second timer?

areify
Associate II

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.

19 REPLIES 19
Bob S
Principal

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
}

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.

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.

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
Up vote any posts that you find helpful, it shows what's working..

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.

areify
Associate II

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?

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.

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
Up vote any posts that you find helpful, it shows what's working..

0690X000009k4nPQAQ.png

JW

Understood...

Thank you!

Replying to

How to correctly set up a micro second timer?

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.

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.