On the new generation of ATmega and ATtiny (for example, the ATmega3208), there is only one timer/counter (TCA) with more than one compare channel. All the others (TCB0, TCB1, TCB2, ...) lack the multiple compare channels earlier generations of Atmel processors had (which had 2 compare channels on every timer/counter)

Still, the TCB can be used to generate a PWM signal. It has a dedicated PWM mode. However, I could not find any good way of stopping the PWM cleanly, as this timer/counter does not have a possibility to raise an interrupt except on an overflow.

On earlier generation Atmel processors, there were two compare channels: A and B. The PWM worked by using one of them to define the duty cycle and the other to define the period. Both could generate interrupts. So in order to use the PWM as a signal generator (for example, a servo controller, or for a custom communication protocol) I could use the compare channel of the duty cycle to prepare the new times for the next cycle. And if I wanted to stop the PWM signal, I could still use the compare channel of the duty cycle to stop the timer, as there would be plenty of time until it would start again. This way I could also use arbitrarily short pulses and change the duty cycle at B, because there was plenty of time for it to take effect until the cycle restarted at the next A.


simulate this circuit – Schematic created using CircuitLab

So, if I wanted to stop the PWM, I could just do so in the "compare B interrupt".

However, the new generation of AVR8X processors only have one single interrupt set condition: on overflow. This means if I stop the timer in the interrupt, the output was already set to high before the interrupt can start executing, so I will have an unwanted spike at the end:


simulate this circuit

Is there any way to avoid this? For a timer/counter used for signal generation, there would be a much higher need for an interrupt source on a compare event instead of an overflow event, so I have no clue what went on in the minds of the designers when they provided an interrupt solely for the overflow event.

I tried fumbling with the event system, without any success. For now it seems the only way to cleanly stop a PWM signal is to use a secondary timer/counter which is set to somewhere between the duty cycle and the period of my PWM signal, which I start on the beginning of my last impulse in order for it to stop my PWM generator. But this way I waste an entire different timer/counter just in order to use the PWM generator which the TCB was allegedly also designed to support!

(and the lack of a compare interrupt on the duty cycle prevents me from using short pulses in a signal generator, as I won't have the time to set the new values if I can only interact with the signal in the overflow interrupt)

A possible solution would be to change the timer from PWM to single-shot on the beginning of the last pulse, but this would make the last pulse less accurate, as I'll have to set the new countdown inside the interrupt.

  • \$\begingroup\$ I just have read the datasheet and agree: This TCB module is a poor implementation. Forget all the clever tricks coded for the previous generation. \$\endgroup\$
    – Jens
    Jun 23 at 22:18

2 Answers 2


So if I understand your question right, you are asking how to stop the PWM while the output is low. That's not very difficult. According to the dodgy (*) docuentation the output is SET at BOTTOM and CLEARED at CCMPH. Right after an OVF interrupt you are somewhere early in the HIGH part of the period. Enter a loop that waits for the counter to reach CCMPH and stop the PWM:

// Wait until CCMPH is reached - end of high level
while(CNT <= CCMPH) ;

This means that you will waste CPU time during the last high part of the signal.

Edit: You could probably set up a pin change interrupt for the falling edge, and stop the PWM in the interrupt handler.

(*) The documentation is not Atmel quality anymore: "The period (T) is controlled by CCMPH, while CCMPL controls the duty cycle of the waveform. The counter will continuously count from BOTTOM to CCMPL, and the output will be set at BOTTOM and cleared when the counter reaches CCMPH."

If the counter goes from BOTTOM to CCMPL then this is the period. If the output is cleared at CCMPH then this is the duty cycle. And not as the first sentence states. This is DS40002174A pages 237, 238.


Yes, the TCB is rather simple in comparison to the TC1/2 in earlier models. I think the intent is more to use it for basic timing applications: timing / clock reference, non-critical PWM (may generate excess or runt pulses when updated/terminated asynchronously by CPU), one-shot, and a few others.

TCA is maybe the richer equivalent of TC1/2. There may be fewer of them present, however; they are a precious resource.

If you need more precise waveforms, then, take stock of what you have available: if TCAs are all used, then perhaps the CCL (Configurable Custom Logic) can be turned to your advantage. For example, the TCB output can be inverted, generating an interrupt on the falling edge; two channels can be used as an R-S latch and enable, to eliminate start/end runt pulses; one TCB can be used as a clock source and another as a one-shot (with software-controlled enable/disable), i.e. basically you build your own "WGM" circuitry around the basic counter blocks -- there are many possibilities!

Also, if your timing is that critical, perhaps you have externalities as well, like responding to fault currents in a motor drive circuit. Consider using TCD for this -- which also includes gate-drive generation (PWM and dead time), enable/fault, buffered registers, multiple phases, etc.

The documentation (at least when I was deep into it a couple years ago) is unfortunately quite poorly organized, and often implies things are much more complicated than they really are. (Especially for TCB, which they could've drawn almost the entire logic diagram, it's just a few gates and muxes I think; but instead they left it as a mysterious "Control Logic"!) My advice is to expect to spend some weeks just concentrating on the datasheet (take a look at peripheral application notes too if you like). Set up an interactive debugging environment (use a debugger per se, or write a REPL ("read-eval-print loop"). Plan experiments to test and verify operation, and include some means of testing various potential timing issues (for example, run an outer loop with a variable number of NOPs before the trigger event, or trigger the test from another (variably delayed) counter pulse, etc.).

And always check the errata!


Your Answer

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

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