3
\$\begingroup\$

I'm trying to create a simple countdown timer (without using interrupts) - to use to check for timeout while waiting for an external event to occur.

Ideally, I'd like to preload a timer counter with a specific value and have it count down and stop once it gets to zero - so that I can poll for a zero counter value in my while loop.

I'm struggling to get the timer to run, and none of the examples I can see in the reference manual is this simple.

Can anyone point me towards a simple example of a one shot countdown timer implementation?

\$\endgroup\$
5
  • \$\begingroup\$ Why exactly don't you want to use an interrupt? It would be great to use an interrupt to have the timer stop at 0 - otherwise the other code in the while loop may be so long that he doesn't check while the timer is at 0 and then it proceeded to 255 already. \$\endgroup\$
    – user17592
    Aug 6, 2014 at 8:39
  • \$\begingroup\$ This is a piece of code that I'm running at startup, and I want it to be as "safe" as possible - check a pin for a period and then carry on, or go back to sleep. I'd rather not use an interrupt for this as it adds complexity and "risk". I'd just like the counter to start from a value, count down to zero and then stop (without reloading). I've done this sort of thing on other micros before. The STM timers are very powerful - sometimes that's great, but in this case, I'm finding it hard to make them do something very simple. Thx. \$\endgroup\$
    – Jon Mills
    Aug 6, 2014 at 8:45
  • \$\begingroup\$ Why use a timer then? What about the good old busy loop to delay for some time? Even less complex/risky. - How fast should your timer tick? Can it be slowed down so that you will never miss a tick? Or can you check the underflow, like if (timer == 0 || timer > START_VALUE) { ...}? \$\endgroup\$
    – JimmyB
    Aug 6, 2014 at 10:48
  • \$\begingroup\$ I've initially implemented it as a busy loop, but I'd like to have more accuracy, so I wanted to implement it using a timer. I have got it working, so I'll add my solution as the answer, although someone may have a better solution. \$\endgroup\$
    – Jon Mills
    Aug 6, 2014 at 11:09
  • \$\begingroup\$ If you don't get a good answer here, you might try the STM32 Forum. There are some good experts over there. \$\endgroup\$
    – Tut
    Aug 6, 2014 at 11:31

2 Answers 2

2
\$\begingroup\$

After some investigation, it seems like I can't have a down counter which stops at zero without using interrupts (as far as I can discover). It also seems that down counters are not possible unless I'm running in centre-aligned or encoder mode.

As a result, I've gone for the following implementation, which uses an up-counter. It seems to work fine, although I'm slightly nervous that the counter has the slight possibility to automatically reload before my while loop has seen that it has gone over the threshold - but as long as my check value is well below the automatic reload value I should be fine.

There may be better ways to do this.

/* Set timer prescaler (0 = no divide - clk = 8MHz) */
TIM2->PSC = 0;

/* Set reload register well above the longest time that we're interested in */
TIM2->ARR = 0xFFFF;

/* Enable the timer */
TIM2->CR1 |= TIM_CR1_CEN;

/* Wait for 1ms */
TIM2->CNT = 0u;
while (TIM2->CNT < 8000u) {}
\$\endgroup\$
5
  • \$\begingroup\$ I'm no STM expert, but aren't you supposed to turn the clock on for the timer first? \$\endgroup\$
    – Dzarda
    Aug 6, 2014 at 12:03
  • \$\begingroup\$ Yes - I'd omitted that code from my example above, its RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; \$\endgroup\$
    – Jon Mills
    Aug 6, 2014 at 15:14
  • \$\begingroup\$ Now you still can slow down the timer and lower your threshold correspondingly to, like, 10. Then you have all the time in the world to detect the overflow before the timer reaches 0xffff or whatever. \$\endgroup\$
    – JimmyB
    Aug 6, 2014 at 19:49
  • \$\begingroup\$ That's a good idea Hanno, thanks. I don't need too much resolution/accuracy on the timer, so slowing it down would be fine, and reduce the risk of a missed rollover. \$\endgroup\$
    – Jon Mills
    Aug 7, 2014 at 7:21
  • \$\begingroup\$ If you don't want to use interrupts and want to avoid rollover, you can poll the corresponding flag in TIM2->SR register; specifically zero bit will be set up on reload event and will stay up until you clear it yourself. That's the proper way to do it, not the threshold. In stm32 every interrupt has a corresponding flag in some status register. Counting down is also possible, just set bit 4 in TIM2->CR1 to 1. \$\endgroup\$
    – Amomum
    Dec 21, 2015 at 16:44
1
\$\begingroup\$

It sounds like the SysTick is ideal for your purposes.

SysTick is a timer which is loaded with a customizable value. Every instruction, it gets decremented by one. When the value reaches 0, it gets reset to it's load value and started again. Also, a status flag is set. You can poll this status flag in software.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.