AVR Hardware Timer Tricked Into One-Shot

[Josh] has written up two posts that those of you who use AVRs might find handy. The first post documents a C library that implements a jitter-free one-shot timer. The second post explains how it works. We think it’s such a good idea that we’re going to spoil it for you, but go ahead and read his links and check out his code.

A one-shot is a pulse generator that runs once and only once. You trigger it, it produces the desired pulse, and that’s all she wrote. Why is this handy? Many external ICs that you’ll interface with have minimum durations for signal pulses that must be respected. You could program the AVR to toggle a pin high and then sit around and wait until it’s time to toggle the pin low again, but this wastes valuable CPU time, isn’t going to be very precise, and is susceptible to timing discrepancies if interrupt routines fire in the mean time.

You’d think that you could use the hardware timers for this, but it’s not straightforward. Normally, the timers are free-running; the counter that’s keeping track of time rolls over the top and starts over again. But we just want one pulse.

[Josh]’s very clever idea abuses the timer/counter’s TOP and MATCH values in “Fast PWM” mode. Essentially you trick the counter into never matching by setting TOP below MATCH. This means that the counter spins in its loop between zero and TOP forever, doing nothing.

To break it out of its loop and enable the one-shot, you manually set the counter to a value above TOP and let it go. As it counts up, it’ll eventually hit MATCH, turn on your pin, and then keep counting. When it rolls over the top (255 + 1 = 0 for the 8-bit AVRs), your pin will be correctly turned off again and then the counter re-enters its loop. The one-shot won’t fire until you manually set the counter higher than TOP again.

So there you have it, a one-shot depending only on the hardware timer/counter module and thus immune to jitter and consuming no CPU time at all. Our hats off to you, [Josh]. Clever hack.

46 thoughts on “AVR Hardware Timer Tricked Into One-Shot

  1. This could potentially be worked into some very nice stepper motion control code, output jitter and doing headstands to deal with interrupts coming from every direction are the current state of RepRap motion control code.

  2. You can also just have the timer overflow ISR clear its own bit in the interrupt mask. That will also give a jitter free one shot and you can use any of the timers, not just the ones that support fast PWM. (Just sayin’…)

    1. This technique should work on any timer, I just used Timer1 because it is likely to be free on a normal Arduino. Using an overflow ISR to turn off the timer after a single shot is the normal way to do this sort of thing, but has the draw backs of (1) the jump to ISR itself will necessarily disable interrupts for many cycles, and (2) there is always a chance that you could miss your latency deadline on the overflow interrupt because of other interrupts that might be going on at the same time. With this one-shot technique, you never turn off interrupts at all (not for a single cycle!) and you never, ever miss the deadline – the shot will never, ever repeat without you re-triggering it.

      1. Right now I am using Freescale Kinetis L and K. Monostable hardware timers can be choosen from a list of peripherals and high level functions, from a RAD environment called Processor Expert. You just click on the component, fill in the various parameters and in 5 minutes it’s done.
        You can do the same by directly accessing the registers, of course.

        1. I love an ARM M0 as much as the next guy, but sometimes a little AVR can be the best choice for the job. You can buy an ATTINY in a DIP package for $1 and plug it into your breadboard and connect a battery and have something working immediately. The Freescale Kinetis L and K are fine chips, but they are not as hacker friendly. Perhaps more importantly, there is a huge community built up around the AVRs which can make it so much easier to get a head start on almost anything you are trying to get done.

          1. there is a kinetis for $0.95, and other ARM’s even cheaper. ARM has a massive following in the hacker community. the archimedes is the follow on from hacker friendly bbc micro. they have gcc/gdb support etc.

      1. Maybe because the Lambo costs less and it saves you a lot of time doing software tricks? Maybe because the REAL world is going ARM all the way, and the sooner you learn using it the better?

        1. Or maybe it’s because there is an established user base of several million. Yea I think that’s why they use outdated, overpriced microcontrollers. I get the whole trailblazing idea, but some people prefer a proven technology. Arm chips are going to take over, and that’s well understood, but not everyone wants to go that route yet. Remember when 64 bit processors hit the stage? Everyone was like ‘go 64 bit, it’s what everyone is going to.’ I’m pretty sure the support was dismal. I seem to remember driver problems were commonplace.

          1. Most of the several million are just blinking LEDs. Employed people working for a living seldom uses old CPUs for new products, when they have a choice. This is because you end saving software hours with a powerful CPU. In a Christmas tree light blinking project this doesn’t matter, but here we are talking about some advanced topics.
            It is not just a matter of Windows 32 vs 64, newer CPUs are totally changing the game, and Atmel knows this and the newer products are ARM based.

          2. Huh? Since when did a one shot pulse become an advanced topic?
            At any rate, you are right: It’s a shame that underpowered, over price uC’s dont have them.

          3. If you absolutely *must* use Arduino code (despite all the smart Alecs telling you to code it all in 6502 assembler or use a 555) and you want to *also* use an Arm processor, then this might interest you.

            http://forum.arduino.cc/index.php?topic=265904.0 – although it is 136 pages long, so you might be quicker learning 6502 mnemonics after all. }:¬) For those with a longer attention span, who perhaps already know 6502 assembler, and have a few 555s already in our parts drawers, its worth the read. It allows you to use your Arduino code on those cheap $4 STM32L103XXXX boards.. Its a work in progress, but some pretty impressive work is being done.

          1. Agreed. The 8 bit microcontroller has almost gained monolithic component status, like the 7805 regulator. It does a low-end task easily and with minimal fuss, so people will continue to use it. For the regulator analogy…sure, efficient buck converters that can handle 20 amps exist, but sometimes if you just have a ~12V supply and need 5V at 80mA there are few reasons to worry about switchmode calculations, coil saturation currents, and FET gate capacitance. Throw in a 7805.

          2. I’ve taken apart high-end devices made only a few years ago (was it an HDTV?) still using *4* bit microcontrollers. Sure, there was an ARM in there, as well (or was it MIPS?) for the major-processing, but apparently 4bit did the job for what they needed it to do.

      2. >Yeah.. when in doubt.. HORSEPOWER!!!

        It’s nothing to do with HORSEPOWER is it. This is like slicing bread with a spoon opposed to a bread knife. You can slice bread with the spoon if you really want but a knife is a much better suited tool.

      1. I didn’t mean to sit around and wait for the timer to expire. Instead, continue doing other things, and clear the output in the interrupt handler. That way, no CPU time is wasted.

          1. That depends entirely on what you did with the INT registers in the meantime, you could let it keep running but as long as it doesn’t cause an INT to actually trigger it doesn’t matter, messy yes but it doesn’t mean the output will necessarily get triggered again without stopping the timer from free-running.

            Also the INT in this case is disabling the output, so basically each time it triggers, if it does, it’s going to tell the signal that is already off to ‘shut off’ each time it triggers, esentially doing nothing until you re-arm the output and hopefully are weary enough to clear the timer and reload things if they were left free-running.

    1. Of course you’re right.

      The simpler solution is the obvious one. And for clarity, I probably would do it the obvious way most of the time unless I had a good reason not to.

      But, it’s not simpler if you’re using the interrupt for something else. It’s not simpler if you’re writing a mainline that is timing sensitive and you’re strictly controlling the number of processor cycles you’re spending in certain places. I’m thinking of a particular project bit-banging a serial protocol waaaay to close to the clock speed to be sane. I probably won’t find myself in that situation again.

      But if there’s ever a place to show off with your optimizations, it’s embedded programming of tiny controllers. :)

      This is just beautiful, and I can think of at least one place I’d have used it to solve timing problems I’ve lost hair and sleep over.

      Nah, who am I kidding? I’ll be using this purely to show off.

      I love it.

      1. “But, it’s not simpler if you’re using the interrupt for something else”

        This solution basically requires you to dedicate a timer, so it’s going to be even harder to use the interrupt for something else.

  3. First thing to do when working with MCU is reading datasheet. There is no need for that kind of trick because OC can be programmed in non PWM mode . One can configure the OC so that it clear/set/toggle an output at compare match and that pulse would not repeat until the OC is resetted programmatically . Even the humble AtTiny13a can do that.
    want a single pulse?
    setup ——————-
    0) configure the timercounter clk source and divider
    1) set OCR0A for desired pulse width
    2) set Waveform generator mode to 2 (register TCCR0A, TCNT mode)
    3) set output compare mode to 2 (register TCCR0A, clear on match mode)
    repeat for each wanted pulse
    4) clear TCNT0
    5) set bit FOC0A to 1 in register TCCR0B to set pin to 1
    when timercounter==OCR0A OCx pin is cleared and stay cleared

    want another pulse?
    repeat step 4 and 5 (2 instructions)

    1. sorry made a mistake in my description

      forget step 3 above
      repeat for each wanted pulse
      3) set TCCR0A mode 3
      5) set bit FOC0A to 1 (set output pin and clear TCNT0)
      6) set TCCR0A mode 2

      Not tested but should work.

      1. 1. How would you set FOC0A to 1 and also clear TCNT0 in a single atomic step? I think this would take at least 2 steps in the AVR timers I have seen.
        2. What happens if there is an interrupt between step #5 and #6? If your shot is shorter than the interrupt is long (the shortest ISR on AVR is ~10 cycles in theory and hundreds of cycles in practice) then the counter will have blown past you by the time you set TCCR0A, so you’d miss the clear and end up having to cycle all the way around to MAX and thereby make an erroneously long pulse.
        Again, you could make all the above steps atomic by turning off all interrupts, but that is what we are trying to avoid in the first place.
        Make sense?
        Thanks for the deep analysis- not many folks know these timers well enough to bring up points like these!

    2. Agreed!- I think the high quality data sheets for these parts are part of the reason they are so successful!While very interesting and thought provoking, I do not think the above strategy will work in practice for 2 reasons…1. Your steps #4 and #5 are not atomic. There will always be at least 2 cycles between them (which you could mathematically account for when assigning OCR0A, but this limits your minimum pulse width and is it is also brittle to compiler optimizations), and there are potentially an unpredictable number of cycles between the steps if an interrupt occurs after you clear TCNT0 but before you strobe the FOC0A. These lost cycles would unpredictably shorten your pulse (or even lengthen it if you missed OCR0A altogether and had to come around again). There are only two ways around this that I can see; (a) disable interrupts around steps #4 and #5, which is what we were trying to avoid in the first place, and (b) stop the clock by clearing the CS bits before you get to step #4, then start the clock again atomically by setting the FOC0A and CS bits in a single instruction. This will only work on certian chips/timers that happen to have the CS and FOC bits in the same register (Timer1 on the ATMEGAxxA chips we are working with here, for example, splits these bits across different registers and so would not be suitable for atomic assignment). Unfortunately, even if you limited this solution to only suitable timers on suitable chips, I think you’d still have a deal-breaker because…2. The force output compare (FOC) strobe in your step #5 would not actually set the pin to 1. My understanding is that the FOC will simulate a match and do whatever is specified in the current Output Compare Mode, which was set to “clear on match” in step #3. From the datasheet: When writing a logical one to the FOC0A bit, an immediate Compare Match is forced on the Waveform Generation unit. The OC0A output is changed according to its COM0A1:0 bits setting. Note that the FOC0A bit is implemented as a strobe. Therefore it is the value present in the COM0A1:0 bits that determines the effect of the forced compare. If this is true, then the output would just stay 0 forever rather than making a one-shot. Please let me know if I am missing something here (likely!) since these timers are complex and you clearly know them deeply! Thanks!

      1. Your analysis is all right. Maybe you replied before I posted my correction regarding FOC0A strobe. The problem is solved by changing output compare mode to 3 before strobing, then setting it back to mode 2. But this correction doesn’t solve the jitter caused by interrupt. For the other the OCR0A count, as you mentionned, it could be adjusted. C optimisation can be solved by embedded assembly on this part of the code.
        So the real problem is the jitter caused by interrupt

  4. Interesting idea. I just got pissed off at the AVR trying that once and just built a one shot from a 555 ( actually I needed two so I used a 556) and was done with it. I already had the AVR circuit built so I packed it into a ferrite bead shell and put it inline to where it needed to go.

    1. Of course 555’s are made of awesomeness, but ultimately they are just an RC and so have severely limited bandwidth and accuracy. I think the shortest pulse you can reasonably generate with a 555 is on the order of 1us, whereas the one-shot trick here can generate a pulse as short as 63ns. I also think that you’d be lucky to get accuracy within 5% from a 555, whereas a typical AVR running with a cheap crystal is accurate to within [0.005%](http://electronics.stackexchange.com/questions/160921/when-we-need-external-crystal-for-atmega/160943#160943).
      Also, my articles have recently been trying to make the case for replacing hardware with software for reasons outlined [here](http://wp.josh.com/2014/06/23/no-external-pull-up-needed-for-ds18b20-temp-sensor/#why).

  5. *sigh* I can’t believe I didn’t think about this… http://hackaday.io/project/4159-mishmash1-sdramthing30-logic-analyzer/log/15872-one-shots-revisited

    There’s one place this technique could be *quite* handy, that the ISR examples, above, couldn’t handle…
    (besides being awesome in that it’s only one instruction-cycle *total*)

    When using a PLL-based AVR Timer and a *really short* pulse-width (e.g. 1 PLL clock wide).
    The Timer would overflow at-most every 256 counts, but that’s only 16 AVR clock cycles. Not enough time to jump into your ISR before it loops.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.