cancel
Showing results for 
Search instead for 
Did you mean: 

understanding timer terms

jhanc.11
Senior

I have a 32f769i-disco board that has limited pins exposed on an arduino connector. I need what is termed a "capture compare timer" and I'm not sure I understand it. the capture compare time was used on the arduino version of this code.

1) I've setup timers that overflow, reload and keep counting. No issues there. I've not been able to get the count by count interrupt but I can read the counter duing overflows.

2) I've setup pins with external interrupts and when interrupted, I can read the timer counter again. This pin is just an exti configured GPIO pin and has nothing to do with the timer.

3) If I understand it correctly, a capture compare timer runs along, generating interrupts on overflow but also can be interrupted on another pin and with low latency, provide the current timer count, correct? This interruption comes on a different pin from the timer as I'm using a highly accurate external signal for the counter.

4) When this 2nd pin is interrupted, I need a low latency count of the timer external interrupt pin, not the overflow. Then I would like to just let it keep running so as to not un-sync the timer. So the timer counts along and every 10ms it overflows. I can count the oflows, and grab the counter, no problem.

5) the 32f769 board doesn't have a lot of pins exposed and I've been using timer3. timer 3 has channels ch1-ch4, has itr0-4 pins and etr and filtered pins. I've read through the timer cookbook but I just don't seem to understand what pins I can feed a clock into and then what pin I should use as a trigger, if that is the proper term. It's not a gate. In the timer cookbook they have a drawing with all the pins and I've tried a lot of them. I can get the overflow interrupt but not the counter interrupt. I can read the counter of course but thought there is a better way than that below.

6)Is it really that much difference if I just save the overflows and timer count during an exti on an unassociated timer pin? Or is timer capture compare the bet way to do it??

7) Though I didn't set it up, on my last build, the system setup an overflow count that ticks as well on timer 6. It looks like it is reading an external pin, and gives me everything that I want but I don't see timer6 listed as being available for capture compare??

any hints would be appreciated.

Thanks in advance. Everyone been very helpful.

Jerry

7 REPLIES 7
jhanc.11
Senior

Here's the goal. I have a 5Mhz signal coming into the stm32f7. It is divided to produce interrupts every 10ms with a rollover and reload counter. At some point, an interrupt appears on a pin. At that point, i want to read the overflows and current count as accurately as possible.

Thanks again,

  1. First, read the timer chapter in RM. Then read it again, this time comparing description of the registers with the narrative. In what I write below, I refer to concepts which are described in RM and I don't intend to repeat the RM.
  2. You may be better off ditching Cube and programming registers directly. With anything you can't click directly in CubeMX chances are, that Cube will get into your way.
  3. You understand how to set up relevant clocks in RCC and relevant pins in GPIO, don't you. If not, try first make a loopdelay-blinky, and then a blinky from one timer channel in Output Compare mode. Note, that you don't need to write programs to try the latter, you can simply play with registers in debugger while the processor is stopped. You can also try most of the following in the same way (of course except interrupt handling).
  4. You appear to want to use external clock. For that, you can use either TIMx_ETR and then External clock mode 2, or TIMx_CH1 or TIMx_CH2 through the Slave-mode Controller's facilities, ie. External clock mode 1 - that of course precludes from using that same channel also for Capture and is perhaps more cumbersome. In some STM32, TIMx_ETR and TIMx_CH1 are on the same pin, so then you again can't use TIMx_CH1 for Capture even if you use External clock mode 2. Any of External clock mode are set in various fields of TIMx_SMCR.
  5. Set desired reload value into TIMx_ARR (although I don't see any reason to use anything other than maximum, which is the default value anyway, so you in fact don't need to touch it) and enable counter by setting TIMx_CEN. In debugger, you should see TIMx_CNT changing.
  6. Now choose a channel for the Capture, set up that channel for Capture in TIMx_CCMRx (and the respective pin in GPIO of course), and enable it in TIMx_CCER. You should see in debugger values in TIMx_CCRx changing, when an edge to that channel arrives (a fun thing to try is to use a channel with a pusbutton).
  7. Enable the interrupts from Update (=overflow) and selected channel by setting UIE and CCxIE in TIMx_DIER. Enable the timer interrupt in NVIC and write an interrupt handler to handle the interrupts (again I recommend not using Cube/HAL's convoluted ways, write your interrupt handler entirely). In the handler, read TIMx_SR, store to a local variable, invert it, optionally mask for unused interrupts and write back to TIMx_SR to clear the status flags. Then from the SR copy, if UIF was set, increment overflow counter. From same stored SR copy, if CCxIF was set, read out TIMx_CCRx.
  8. Note, that if in the stored copy of TIMx_SR both flags are set, overflow setting the UIF may have happened just before the capture or just after, and there's no direct way to determine, which way this was. Indirectly, you can infer this from the read out value of TIMx_CCR (is it smaller or larger than half of period/TIMx_ARR?) and assuming that the interrupt latency is less than half of period. Then use value of overflow counter accordingly, i.e. use one less if the read out value of TIMx_CCR is above half period.
  9. Note that 8 assumes that there is no further capture until the first has been read out, i.e. the edges are far enough apart that the ISR is executed fully between the edges. If this is not the case, things get very complicated and you may consider using a 32-bit timer, decrease resolution by prescaling the timer's counter, try to resolve in software by utilizing the overcapture flags (I recommend to draw timing diagrams with all possible sequence of events). This all depends on the nature of signal and your application.

> Is it really that much difference if I just save the overflows and timer count during an exti on an unassociated timer pin?

Quantify "that much". The difference is in the time it takes to start to execute the EXTI interrupt until you read out the current TIMx_CNT value (a.k.a. interrupt latency). It's at least 12 cycles of the interrupt entry sequence, plus whatever time it takes the software to get to the point of readout, plus interrupt latency (and that may be an extremely varying value depending on what software you run and what other interrupts you have and their mutual priorities). Handling of the capture-edge-came-close-before-or-after-overflow problem may get more complicated, too, again involving drawing diagrams for all possible sequence of events.

> Though I didn't set it up, on my last build, the system setup an overflow count that ticks as well on timer 6.

If you want control, ditch Cube which does things for you. If you want comfort, keep using Cube and be content with the occasional mysteries.

JW

jhanc.11
Senior

Jan,

The first thing i need to do is resolve #4 by listing all my available pins to see what mode I can use. I'll go back and read the chapter you mention now that I have context. the last problem I'm having is that the ETR pin for the timer I am trying to use (TIM3) on this eval board is on the SDRAM port which I wanted to use too. So then I tried to use ch1 and ch3 but something isn't set right. I don't know why I didn't scrap cube already. I appreciate your detailed reply.

jhanc.11
Senior

I went back and tracked the exposed pins on the board, TIM1_ETR is the only ETR available. They also expose TIM1_CH4 so I switched to tim1. I'm using a pushbutton to trigger it and it triggers. The overflow looks right. for some reason, the special function registers are no longer available on debug, I had them when it wasn't working, regardless, I guess at that point I should read the tim1_ccr register directly (my guess) and not use the timer get count function?

Thanks again.

Jerry

Jerry,

> I guess at that point I should read the tim1_ccr register directly (my guess) and not use the timer get count function?

Yes, if the capture on channel 4 works properly, the hardware copies value of TIM1_CNT into TIM1_CCR4 exactly at the edge. Reading TIM1_CNT in software would come the mentioned interrupt latency later, it would be the same than using the EXTI interrupt.

JW

If I wanted to restart the timer using the same load but with a zero count:
/* stop tim1 */
HAL_TIM_Base_Stop_IT(&htim1); // can probably be done with a register write
HAL_TIM_IC_Stop_IT(&htim1, TIM_CHANNEL_4); // this too
/* zero the counter? */
TIM1->CCR4 = 0x00; // is there a more proper way?`
/* set the reload value */
TIM2->ARR = oflowCount; // probably don’t need to do this
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_4);
jhanc.11
Senior

As the timer is counting up, is it possible to inject another value into the counter? The timer is reading an external 2.5Mhz clock and counting to 25000 (actually 24999). This makes an interrupt pretty much every 10ms. At the start of the timing, the prior code set the timer to 5ms for the first capture point by injecting a value of 12500 into the counter so no matter where the counter was, the next capture trigger will happen in 5ms.. Can I do that on this processor and if so, should I turn off interrupts ( I would think so). By pushing the counter along for the first capture, I don't have to mess with the reload register. I can test it, just one fewer to do.

Thanks