Atmel TinyAVR

TCD on the TinyAVR is an advanced control timer designed for motor and power control applications.


The Tiny1616 has four timers: TCA, TCB0, TCB1, and TCD. TCA is a 16-bit auto-reload timer with three compare channel outputs that can be used for PWM, or for periodic interrupts. This timer can be configured to count up, down, or up/down, and can also count external events (and divide them down, too). The Tiny1616 has two TCB modules, each one can be configured independently as a normal 16-bit auto-reload timer, an input capture module, or an 8-bit PWM output.

TCD is a 12-bit timer that two independent capture/compare units. This timer has separate “set” and “clear” registers, allowing arbitrary-phase PWM signals to be generated. It also has two inputs that can be programmed to capture the PWM value asynchronously, as well as to do different command functions (blanking, resetting, jumping to next compare cycle, etc).

What they don’t tell you

Not quite Single-Cycle

AVR is somewhere in the middle of Microchip’s true single-cycle performance, and the 8051 CISC


By default, -O1 is enabled, which is needed to get any sort of performance out of the part. With it, a line like this:

DDRB |= 0x10

Gets compiled into:

0000001C  LDI R24,0x37            Load immediate
0000001D  LDI R25,0x00            Load immediate
0000001E  LDI R18,0x37            Load immediate
0000001F  LDI R19,0x00            Load immediate
00000020  MOVW R30,R18            Copy register pair
00000021  LDD R18,Z+0             Load indirect with displacement
00000022  ORI R18,0x10            Logical OR with immediate
00000023  MOVW R30,R24            Copy register pair
00000024  STD Z+0,R18             Store indirect with displacement

With the optimizer on, it gets compiled into:
SBI DDRB, 4  ; set bit in I/O register

The problem is that with the optimizer at -O1, the debugger often gets confused, and breakpoints don’t fire. This has to do with the RISC nature of the processor. A line like this:

PORTB ^= 0x10;

Is decomposed into:

  • Load 0x10 into a register
  • Load PORTB into another register
  • XOR those two registers together
  • Output that result to PORTB
  • Jump back to the PORTB load.

Note that we only have to do the first operation once. The problem is that when we put a break-point on that line of C source code, it actually puts a breakpoint on the first instruction, i.e.:

But we’ll never execute that instruction again, thus our break-points won’t happen.

On a CISC architecture, we would have an instruction like:


Which directly translates to a line of C code. This is much easier for the debugger to handle.


Debugging is a bit of a mess on the AVR platform. Unlike Microchip and Silicon Labs, who both blur the line between in-circuit programming and in-circuit debugging, there’s a clear demarcation with the AVR: You’ll need the 3-wire SPI interface, plus the reset pin, just to get code on your chip or program the fuses. If you want to debug your code, this is done through the debugWIRE interface, shared with the reset pin. This is actually really cool – most MCU vendors require a two-wire or three-wire connection for debugging. Once you’re in debug-wire mode, you only need a single pin to upload code and debug.

The problems with debugWIRE are:

  • The lowest-cost debugger out there is the AVR Dragon, which, at $60, is a considerable cost to consider if you’re a hobbyist or student. There are no low-cost clones, and Atmel keeps the design heavily guarded. This differs from Microchip and Silicon Labs, which have schematics freely available; low-cost clones are readily available online.
  • debugWIRE can only be used to upload and debug code; not burn fuses. And AVR has a many system configuration settings in fuses — clock sources, clock dividers, watchdog timer settings, and brown-out detection.
  • Chicken-and-the-egg problem: To use debugWIRE, the DWEN fuse must be set, which requires the SPI-based ISP method. So you end up having to hook up the ISP lines, burn the DWEN fuse, and then you can use debugWIRE. Of course, once you’re in debugWIRE, you can’t program fuses until you unset the DWEN fuse and go back to ISP mode. There’s a special debugWIRE message that unsets the DWEN fuse.