8. ATmega328P Hardware: Timers and Counters – Arduino Software Internals: A Complete Guide to How Your Arduino Language and Hardware Work Together

© Norman Dunbar 2020
N. DunbarArduino Software Internalshttps://doi.org/10.1007/978-1-4842-5790-6_8

8. ATmega328P Hardware: Timers and Counters

Norman Dunbar1 
(1)
Rawdon, West Yorkshire, UK
 

This chapter and the next look at the hardware features of the ATmega328P and should link up with the information presented in Chapters 2 and 3. You should, I hope, see how the Arduino Language talks to the hardware described in these chapters. This chapter starts by looking, long and hard, at the facilities of the ATmega’s timer/counters, while the following chapter delves into the ADC and serial communications hardware, the USART.

8.1 Timer/Counters

The Atmega328P has a total of three timer/counters named Timer/counter 0, Timer/counter 1, and Timer/counter 2. The first and last of these are both 8-bit timer/counters and have a maximum value of 255, while Timer/Counter 1 is 16 bits and its maximum is 65,535.

At power on, or reset, all timer/counters are disabled and must be enabled in software. The Arduino’s init() function does a lot of timer/counter initialization so that the millis(), micros(), and analogWrite() functions work.

Timer/counters are so called because they have two separate functions. They can
  • Count up and down depending on the mode, with a regular clock source based off of the AVR microcontroller’s system clock. This is when it acts as a timer.

  • Count up, and down, based on an external rising or falling edge attached to a specific pin. This is when it acts as a counter.

    The data sheet for the ATmega328P advises that when setting various timer/counter modes, any output pins affected should be set to OUTPUT after setting the required modes.

In much of what follows, you may see references to TOP, MAX, and/or BOTTOM. These are definitions that are used in the data sheet for the ATmega328P and refer to the following:
  • BOTTOM is easy. It is always zero.

  • MAX is also easy. It is always the maximum value that can be held in the timer/counter’s TCNTn register according to however many bits the timer/counter is configured for. This is calculated as 2bits – 1.

    For Timer/counters 0 and 2, this is always 8 bits, and so MAX always equals 255. For Timer/counter 1, MAX varies as follows:
    • In 8-bit mode, MAX = 255.

    • In 9-bit mode, MAX = 511.

    • In 10-bit mode, MAX = 1,023.

    • In 16-bit mode, MAX = 65,535.

  • TOP depends on the timer/counter’s mode and is either MAX for some modes or as defined by various other timer/counter registers such as OCRnA, OCRnB, ICR1, etc.

8.1.1 Timer/Counter 0 (8 Bits)

This timer/counter has eight different modes of operation defined by the Waveform Generation bits WGM02:0 in the registers TCCR0A and TCCR0B (Timer/counter 0 Control Registers A and B). Bit WGM02 is found in TCCR0B, while WGM01 and WGM00 are in TCCR0A.

Table 8-1 shows the various settings for the modes available in Timer/counter 0.
Table 8-1

Timer/counter 0 modes

Mode

WGM02–WGM00

TOP

OCR0x Updated

TOV0 Set at

Mode of Operation

0

000

255

NOW

255

Normal

1

001

255

TOP

0

PWM, Phase Correct

2

010

OCR0A

NOW

255

CTC

3

011

255

0

255

PWM, Fast

5

101

OCR0A

TOP

0

PWM, Phase Correct

7

111

OCR0A

0

TOP

PWM, Fast

Modes 4 and 6 are reserved and should not be configured.

When you write a new value to register OCR0x, the value doesn’t get written until the timer/counter’s value TCNT0 reaches that shown in the preceding table, where “NOW” means that the new value is written as soon as your code executes it and any other value means that the new value will be written when TCNT0 reaches that given value.

The various timer/counter modes are explained later in this chapter.

8.1.2 Timer/Counter 1 (8, 9, 10, and/or 16 Bits)

This timer/counter has 16 different modes of operation defined by the Waveform Generation bits WGM13:0 in the registers TCCR1A and TCCR1B (Timer/counter 1 Control Registers A and B). Bits WG13 and WGM12 are found in TCCR1B, while WGM11 and WGM10 are in TCCR1A.

Table 8-2 shows the various settings for the modes available in Timer/counter 1.
Table 8-2

Timer/counter 1 modes

Mode

WGM13–WGM10

TOP

OCR1x Updated

TOV1 Set at

Mode of Operation

0

0000

65535

NOW

65535

Normal

1

0001

255

TOP

0

PWM, Phase Correct 8 bit

2

0010

511

TOP

0

PWM, Phase Correct 9 bit

3

0011

1023

TOP

0

PWM, Phase Correct 10 bit

4

0100

OCR1A

NOW

65535

CTC

5

0101

255

0

TOP

PWM, Fast 8 bit

6

0101

511

0

TOP

PWM, Fast 9 bit

7

0101

1023

0

TOP

PWM, Fast 10 bit

8

1000

ICR1

0

0

PWM, Phase and Frequency Correct

9

1001

OCR1A

0

0

PWM, Phase and Frequency Correct

10

1010

ICR1

TOP

0

PWM, Phase Correct

11

1011

OCR1A

TOP

0

PWM, Phase Correct

12

1100

ICR1

NOW

65535

CTC

14

1110

ICR1

0

TOP

PWM, Fast

15

1111

OCR1A

0

TOP

PWM, Fast

Mode 13 is reserved and should not be configured.

When you write a new value to register OCR1x, the value doesn’t get written until the timer/counter’s value TCNT1 reaches that shown in the preceding table, where “NOW” means that the new value is written as soon as your code executes it and any other value means that the new value will be written when TCNT1 reaches that given value.

Timer/counter 1 has an extra control register, TCCR1C, which the other two timer/counters don’t have.

The various timer/counter modes are explained later in this chapter.

8.1.3 Timer/Counter 2 (8 Bits)

This timer/counter has eight different modes of operation defined by the Waveform Generation bits WGM22:0 in the registers TCCR2A and TCCR2B (Timer/counter 2 Control Registers A and B). Bit WGM22 is found in TCCR2B, while WGM21 and WGM20 are in TCCR2A.

Table 8-3 shows the various settings for the modes available in Timer/counter 2.
Table 8-3

Timer/counter 2 modes

Mode

WGM22–WGM20

TOP

OCR2x Updated

TOV2 Set at

Mode of Operation

0

000

255

NOW

255

Normal

1

001

255

TOP

0

PWM, Phase Correct

2

010

OCR2A

NOW

255

CTC

3

011

255

0

255

PWM, Fast

5

101

OCR2A

TOP

0

PWM, Phase Correct

7

111

OCR2A

0

TOP

PWM, Fast

Modes 4 and 6 are reserved and should not be configured.

When you write a new value to register OCR2x, the value doesn’t get written until the timer/counter’s value TCNT2 reaches that shown in the preceding table, where “NOW” means that the new value is written as soon as your code executes it and any other value means that the new value will be written when TCNT2 reaches that given value.

The various timer/counter modes are explained later in this chapter.

8.1.4 Timer/Counter Clock Sources

The timer/counters all have their own clock sources, most of which are based on the system clock, and each timer/counter has its own dedicated prescaler and this can be set to various values, to divide the system clock giving the timer/counter’s clock speed or, alternatively, to clock on an external pin’s rising, or falling, edge.

While all three timer/counters have mostly the same prescaler settings, Timer/counter 2 does not have the ability to be externally clocked, but it does have the ability to run with divide-by-32 and divide-by-128 prescalers, which the others cannot. It can also be configured to run in asynchronous mode with a 32.768 KHz crystal attached to the TOSCn pins. This is beyond the scope of this book, however, as the Arduino uses those two pins for a 16 MHz crystal, thus rendering asynchronous mode unusable.

Table 8-4 shows the various clock sources for the three timer/counters.
Table 8-4

Timer/counter clock sources

Prescaler

Timer 0 CS02–CS0

Timer 1 CS12–CS0

Timer 2 CS22–CS0

Frequency

Period

Disabled

000

000

000

-

-

Divide by 1

001

001

001

16 MHz

0.0625 microseconds

Divide by 8

010

010

010

2 MHz

0.5 microseconds

Divide by 32

-

-

011

500 KHz (0.5 MHz)

2 microseconds

Divide by 64

011

011

100

250 KHz (0.25 MHz)

4 microseconds

Divide by 128

-

-

101

125 KHz (0.125 MHz)

8 microseconds

Divide by 256

100

100

110

62.5 KHz

16 microseconds

Divide by 1024

101

101

111

15.625 KHz

64 microseconds

External falling

110 pin T0

110 pin T1

-

-

-

External rising

111 pin T0

111 pin T1

-

-

-

The preceding Pin T0 is physical pin 6 on the ATmega328P, which is PD4 in AVR terminology or D4 in the Arduino Language. Pin T1 is physical pin 11, also known as PD5 in the AVR terminology, and corresponds to Arduino pin D5.

8.1.5 Timer/Counter Operating Modes

As you have seen earlier, the three timer/counters can operate in a number of different modes. Not all timer/counters have the same modes though. Tables 8-1 through 8-3 show the modes available for each timer/counter individually.

8.1.5.1 Timers Disabled

This is not really a timer/counter mode, but setting the CSn2, CSn1, and CSn0 bits to zero in register TCCRnB will disable the timer/counters. The preceding “n” refers to the timer/counter in question.

Disabling Timer/counter 0 will disable the ability to use the millis() and micros() functions if you are using the Arduino Language. It will also prevent the use of analogWrite() on pins D5 and D6.

Disabling Timer/counter 1 will prevent the use of analogWrite() on pins D9 and D10.

Disabling Timer/counter 2 will prevent the use of analogWrite() on pins D3 and D11 and will also affect the ability of the tone() function to be used as that needs Timer/counter 2.

Due to the usefulness of the various timer/counters, it is unlikely that they will ever be disabled. However, should your code not require any of the timer/counters, you can save a few microAmps of power consumption by disabling power to the timer/counters in the PRR, by setting the required bits PRTIMn, where, as ever, “n” refers to the timer/counter number. Section 7.4.2, “Power Reduction Register,” in Chapter 7 discusses the PRR in some detail.

Should you decide do this, Timer/counter 2 must be running either in synchronous mode off of the internal oscillator or on a 16 MHz crystal as per the Arduino. If the timer is running in asynchronous mode with a 32 KHz or higher crystal, plus AS2 set in register ASSR, then writing a 1binary to PRTIM2 in the PRR register will not stop Timer/counter 2.

This latter mode of operation is, of course, not possible on an Arduino board as the 16 MHz crystal is attached to the two pins that an external 32 KHz crystal needs to use for asynchronous mode. On a bare-bones AVR microcontroller though, this need not be the case.

8.1.5.1.1 Disabling the Timers
Table 8-5 shows the settings required to disable the timer/counters.
Table 8-5

Disable timer/counter settings

Timer

Mode

TTCRnB Bits

Value

0

0

CS02–CS00

000binary

1

0

CS12–CS10

000binary

2

0

CS22–CS20

000binary

8.1.5.2 Normal Mode

In normal mode, a timer/counter starts at zero, but this can be changed by writing a new value to TCNTn, which counts upward by 1 every time its clock source ticks, until it reaches MAX – see preceding text for details of MAX, BOTTOM, and TOP in relation to the three timer/counters – which is 255 for Timer/counter 0 and 2 or 65,535 for Timer/counter 1 in this mode.

At MAX, the timer/counter’s value, in TCNTn, will roll over from MAX to zero – BOTTOM – on the following tick of the timer/counter’s clock.

A number of things happen when the timer/counter rolls over or overflows:
  • The Timer Overflow bit, TOVn, is set in the Timer Interrupt Flag Register, TIFRn, on the same clock tick as the timer/counter’s value became zero – after MAX + 1 counts – assuming that you didn’t change TCNTn. This flag is only ever set unless your program uses the timer/counter’s Overflow interrupt. It will remain set until manually cleared by your sketch by writing a 1binary to it.

  • The Timer Overflow interrupt will be fired, if the Timer Overflow interrupt enable bit, TOIEn, is set in the Timer Interrupt Mask Register TIMSKn and global interrupts are enabled. In this case, the TOVn bit will be cleared automatically when the interrupt service routine is entered.

  • Pin OCnA will perform an action. The action depends on the values in the COMnA1:0 bits, as described in Table 8-6, when TCNTn matches with OCRnA.
    Table 8-6

    COMnA1:0 settings in normal mode

    COMnA1-COMnA0

    Description

    00

    No effect on pin OCnA

    01

    Pin OCnA toggles on match with OCRnA

    10

    Pin OCnA is cleared (LOW) on match with OCRnA

    11

    Pin OCnA is set (HIGH) on match with OCRnA

  • Pin OCnB will perform an action. The action depends on the values in the COMnB1:0 bits, as described in Table 8-7, when TCNTn matches with OCRnB.

Table 8-7

COMnB1:0 settings in normal mode

COMnB1-COMnB0

Description

00

No effect on pin OCnB

01

Pin OCnB toggles on match with OCRnB

10

Pin OCnB is cleared (LOW) on match with OCRnB

11

Pin OCnB is set (HIGH) on match with OCRnB

While running in this mode, you can, if you wish, write a value to the timer/counter’s TCNTn register, which can reduce the time it takes for the Overflow bit to be set or the interrupt to be fired.

8.1.5.2.1 Setting Normal Mode
Table 8-8 shows the settings required to put the timer/counters into normal mode.
Table 8-8

Normal mode settings

Timer

Mode

Bits

Value

0

0

WGM02–WGM00

000binary

1

0

WGM13–WGM10

0000binary

2

0

WGM22–WGM20

000binary

Note that bits WGMn0 and WGMn1 are found in register TCCRnA, bit WGMn2 is found in TCCRnB and, for Timer/counter 1 only, WGM13 is also found in TCCR1B.

8.1.5.2.2 Example Sketch

Atmel/Microchip’s data sheets advise that the Output Compare unit can be used to generate interrupts at some given time, Using the Output Compare unit to generate waveforms in Normal mode is not recommended, since this will occupy too much of the CPU time.

So it sounds like we should use Overflow interrupts for useful purposes, and this is what the Arduino uses for its millis() function and so on, but can we use OCR0A and OCR0B to generate interrupts as well? Well, Listings 8-1 to 8-3 tell all.

I did originally write this code using Timer/counter 0, but as the TIMER0_OVF handling routine in the Arduino library is already using that timer/counter’s Overflow interrupt, I got linker errors due to there being two copies of the interrupt handler. Any Arduino code with this vector in use will not be able to be compiled with the IDE.

The sketch initializes Timer/counter 2 with three interrupts in setup(). The three interrupts are
  • The Overflow interrupt which will toggle an LED on pin D13

  • The Compare Match A interrupt which will toggle an LED on pin OC2A which is Arduino pin D12

  • The Compare Match B interrupt which will toggle an LED on pin OC2B which is Arduino pin D11

Listings 8-1, 8-2, and 8-3 show the setup(), loop(), and interrupt handler code, respectively.
//========================================================
// This sketch uses the Timer/Counter 2 as follows:
//
// Overflow Interrupt to toggle LED_BUILTIN (D13)
// COMPA Interrupt to toggle D12
// COMPB Interrupt to toggle D11.
//========================================================
void setup() {
    TCCR2A = 0;                              ①
    TIMSK2 = ((1 << OCIE2B) |                ②
              (1 << OCIE2A) |
              (1 << TOIE2));
    // Set up the compare values.            ③
    OCR2A = 8;
    OCR2B = 172;
    TCCR2B = ((1 << CS22) |                  ④
              (1 << CS21) |
              (1 << CS20));
    // D11, D12 and D13 are outputs.         ⑤
    pinMode(13, OUTPUT);
    pinMode(12, OUTPUT);
    pinMode(11,  OUTPUT);
}
Listing 8-1

Normal timer/counter mode setup() function

  •     ①    This clears the timer register to a known starting configuration. This enables normal mode.

  •     ②    This enables interrupts on Overflow and Compare Matches A and B.

  •     ③    This is a couple of random values to compare against, for the interrupts to trigger.

  •     ④    This sets the prescaler to 1024 and starts the timer.

  •     ⑤    This configures the LED pins as OUTPUT after setting the timer/counter configuration, as per the data sheet.

void loop() {
    // Nothing happening here, move along now!
}
Listing 8-2

Normal timer/counter mode loop() function

As you can see, the loop() function is empty – the timer/counter interrupts take care of flashing the LEDs without needing the loop() to do anything.
// Toggle pin D13 which is PortB pin 5.
ISR(TIMER2_OVF_vect) {
    // Fast pin toggle.
    PINB |= (1 << PINB5);
}
// Toggle pin D12 which is PortB pin 4.
ISR(TIMER2_COMPA_vect) {
    // Fast pin toggle.
    PINB |= (1 << PINB4);
}
// Toggle pin D13 which is PortB pin 3.
ISR(TIMER2_COMPB_vect) {
    // Fast pin toggle.
    PINB |= (1 << PINB3);
}
Listing 8-3

Normal timer/counter mode ISRs

If you set this up with an LED on pin D13 (or use the built-in LED), another on pin D12, and a third on pin D11, then they will all flash, so the interrupts are working. All three will flash at exactly the same rate because there is an Overflow interrupt every 256 clock ticks, and both OCR2A and OCR2B will match TCNT2 once every 256 clock ticks also.

The timer/counter is running with a frequency of
F_CPU / prescaler
= 16 MHz / 1024
= 15,625 Hz.
We are toggling every 256 counts of the clock, and it takes two toggles to make one flash of the LED, so that’s
F_CPU / prescaler / 256 / 2
= 16 MHz / 1024 / 256 / 2
= 30.5176 Hz

And that means we have a flash every 32.768 milliseconds. (The period is 1/frequency.)

Attaching my Labrador oscilloscope to the LEDs one at a time shows that they all have the same frequency, and it’s calculated as 31.03 Hz, so it’s not far off. It’s obviously my ability to accurately place the cursors to get the correct measurements that is affecting the results, but it’s close enough.

Don’t forget that when an interrupt fires, it disables further interrupts, plus it takes four clock cycles to process the interrupt handler jump and another four to return, and those delays are not being considered here.

So we now know that interrupts work in normal mode. What about toggling the pins by setting the various COM2An and COM2Bn bits to toggle the pins when there’s a compare match? Listings 8-4 to 8-6 show an amended sketch to do just that. Note that while D13 still has the same connections, the LED on D12 has to be moved to D3 because now, we are using the timer/counter’s hardware to toggle the pins and not the interrupts. The pins that the hardware toggles for us are OC2A or D11 and OC2B or D3.
//========================================================
// This sketch uses the Timer/Counter 2 as follows:
//
// Overflow Interrupt to toggle LED_BUILTIN (D13)
// OC2A to toggle D11
// OC2B to toggle D3.
//========================================================
void setup() {
    // Initialise Timer/counter 2 in normal mode
    // with OC2A (D11) and OC2B (D3) toggling on match.
    TCCR2A = ((1 << COM2A0) | (1 << COM2B0));      ①
    // Enable overflow interrupt (on D13 = PB5)    ②
    TIMSK2 = (1 << TOIE2);
    // Set up the compare values.                  ③
    OCR2A = 8;
    OCR2B = 172;
    // Prescale by 1024, and start the timer.      ④
    TCCR2B = ((1 << CS22) |
              (1 << CS21) |
              (1 << CS20));
    // D11, D12 and D3 are outputs.                ⑤
    pinMode(13, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(3, OUTPUT);
}
Listing 8-4

Getting the timer to flash LEDs, setup()

  •     ①    Here we put the timer/counter into normal mode again, but configure it to also toggle pins OC2A and OC2B when there is a compare match. This does not require the use of interrupts – the toggling of the pins is controlled by the timer alone. The CPU is not involved.

  •     ②    We still use the Overflow interrupt to toggle D13 as before. The CPU will be involved here.

  •     ③    I’m using the same values as before.

  •     ④    The timer/counter’s clock source is configured as divided by 1024, and this starts the timer/counter running.

  •     ⑤    As before, we have to set the output pins after setting up the timer/counter.

As before, the loop() function is empty and has nothing to do.
void loop() {
    // Nothing to see here, move along now!
}
Listing 8-5

Getting the timer to flash LEDs, loop()

Finally, the code in Listing 8-6 now has a single ISR. This one is required for the Overflow interrupt. The two Compare Match interrupts are no longer required as the timer/counter will toggle the LEDs without the use of the main CPU.
// Toggle pin D13 which is PortB pin 5.
ISR(TIMER2_OVF_vect) {
    // Fast pin toggle.
    PINB |= (1 << PINB5);
}
Listing 8-6

Getting the timer to flash LEDs, ISR

It looks like those settings work too. The frequency and period of the flashing LEDs are exactly as before on all the pins – 30.5176 Hz on all three LEDs. We are still getting one flash every 256 counts on the timer.

8.1.6 Clear Timer on Compare Match Mode

In Clear Timer on Compare Match (CTC) mode, the timer/counter counts upward from BOTTOM (or from the value your code wrote to TCNTn) until it reaches TOP which is the value stored in OCRnA, whereupon, on the next timer clock pulse , the value in TCNTn will be cleared to zero. This is mode 2 for Timer/counter 0 and Timer/counter 2 and mode 4 for Timer/counter 1. Timer/counter 1 also has mode 12 CTC, which is discussed separately in the following.

You can change the values in OCRnA and/or OCRnB at any time, but you must be careful as double buffering is not enabled on those registers in this mode. Any changes you make are written directly to the register(s) at the time that your sketch does so. In other modes, these registers do not get changed until a certain point in the count – the values are held in a working register, buffer, until the specific point is reached. This prevents what the data sheet refers to as “glitches” in those other modes. There is no such protection in CTC mode.

If you change the value to a new value close(r) to BOTTOM (zero) while the counter is running with a low, or no prescaler, then CTC mode might miss a match if the current value in TCNTn is higher than the value just written to the OCRnx register. It will count right up to the timer/counter’s maximum value and then roll over to zero before it can start the normal sequence of events again – a glitch, in other words. It is better to control the changes to the OCRnx registers by utilizing the Overflow interrupt to make the changes – that way, it happens always at BOTTOM and should avoid the glitches.

At TOP, the timer/counter’s value, in TCNTn, will roll over from TOP to zero – BOTTOM – on the following tick of the timer/counter’s clock.

Some things happen when the timer/counter clears:
  • The Timer Overflow bit, TOVn, is set in the Timer Interrupt Flag Register, TIFRn, on the same clock tick as the timer/counter’s value became zero – after TOP + 1 counts, assuming that you didn’t change TCNTn. This flag is only ever set, and, unless your program has enabled the timer/counter’s Overflow interrupt, it will remain set until manually cleared by your sketch. You manually clear this bit by writing a 1binary to it.

  • The Timer Overflow interrupt will be fired, if the Timer Overflow interrupt enable bit, OCFnA, is set in the Timer Interrupt Mask Register TIMSKn and global interrupts are enabled. In this case, the TOVn bit will be cleared automatically when the interrupt service routine is entered.

  • Pin OCnA will perform an action. The action depends on the values in the COMnA1-0 bits, as described in Table 8-9, when TCNTn matches with OCRnA.
    Table 8-9

    COMnA1:0 settings in CTC mode

    COMnA1-COMnA0

    Description

    00

    No effect on pin OCnA

    01

    Pin OCnA toggles on match with OCRnA plus one clock pulse

    10

    Pin OCnA is cleared (LOW) on match with OCRnA plus one clock pulse

    11

    Pin OCnA is set (HIGH) on match with OCRnA plus one clock pulse

  • Pin OCnB will perform an action. The action depends on the values in the COMB1-0 bits, as described in Table 8-10, when TCNTn matches with OCRnB.
    Table 8-10

    COMnB1:0 settings in CTC mode

    COMnB1-COMnB0

    Description

    00

    No effect on pin OCnB

    01

    Pin OCnB toggles on match with OCRnB plus one clock pulse

    10

    Pin OCnB is cleared (LOW) on match with OCRnB plus one clock pulse

    11

    Pin OCnB is set (HIGH) on match with OCRnB plus one clock pulse

    The value in OCRnA is always the TOP value. If OCRnB is higher than the value in OCRnA, then there will be no effect on the OCnB pin, as the value in TCNTn will never reach the value in OCRnB. You will only see the desired effect on the OCnB pin if the value in OCRnB is less than, or equal to, the value in OCRnA.

    The data sheet for the ATmega328P doesn’t make this clear, and many online forums have lots of confusion on the matter.

Timer/counters 0 and 2 don’t have any other CTC modes, so the preceding description applies to those counters. Timer/counter 1 has two CTC modes, modes 4 and 12. In mode 4 CTC, Timer/counter 1 acts exactly as described earlier.

When Timer/counter 1 is configured in CTC mode 12, the TOP value is defined by the value in the ICR1 or Input Capture Register, and this is attached to the Input Capture Unit for this timer/counter, as described in Section 8.3, “Input Capture Unit.” The Input Capture Unit copies the Timer/counter 1 value from TCNT1 to the ICR1 register each time an “event” occurs. This value is then used as TOP in CTC mode 12 for Timer/counter 1.

In CTC mode 12, the following will occur when TCNT1 matches ICR1 :
  • Bit ICF1 is set in the Timer/counter 1 Interrupt Flag Register TIFR1. This bit will be cleared if the Input Capture interrupt is enabled by setting bit ICIE1 in register TIMSK1, when the interrupt routine is executed. If interrupts are not used, then your sketch must clear the ICF1 flag by writing a 1binary to it.

  • The Input Capture interrupt will be fired, automatically clearing the ICF1 flag, if configured to do so.

  • The effect of the COM1A1:0 and COM1B1:0 bits are exactly as described earlier.

While running any timer/counter in any CTC mode, you can, if you wish, write a value to the timer/counter’s counter register, TCNTn, which can reduce the time it takes for the Overflow bit to be set or the interrupt to be fired. The interrupt itself can write a new value to TCNTn if necessary.

8.1.6.1 Setting CTC Mode

Table 8-11 shows the settings required to put the timer/counters into CTC mode.
Table 8-11

CTC mode settings

Timer

Mode

Bits

Value

0

2

WGM02–WGM00

010binary

1

4

WGM13–WGM10

0100binary

1

12

WGM13–WGM10

1100binary

2

2

WGM22–WGM20

010binary

Bits WGMn0 and WGMn1 are found in register TCCRnA, bit WGMn2 is found in TCCRnB, and, for Timer/counter 1 only, WGM13 is also found in TCCR1B.

The maximum frequency at which the OCnA and/or OCnB pins will toggle is given by
F = F_CPU / (2 * prescaler * (1 + OCRnA))
This, if OCRnA is zero, makes the maximum frequency possible equal to
F_CPU / (2 * prescaler))
The value to be loaded into OCRnA is calculated as
OCRnA = (F_CPU / (F * 2 * prescaler)) - 1

for any desired frequency “F” and provided that the answer fits onto the appropriate timer/counter’s OCRnA register.

8.1.6.2 Example Sketch

Listings 8-7 and 8-8 illustrate a sketch which sets up Timer/counter 2 in CTC mode 2, turns off all interrupts from the timer/counter, and sets pins OC2A and OC2B to toggle whenever the value in TCNT2 matches either that of OCR2A or OCR2B. TCNT2 will be cleared to zero on the timer clock pulse after it equals OCR2A.

OCR2A defines the TOP value for this sketch. In Listing 8-7, it is set to 200, giving 201 counts per cycle. OCR2B is initialized to the value 86, which is less than that of OCR2A, so it will be affected by the running timer/counter and will flash. The prescaler is again 1024, giving a frequency of
F_CPU / (2 * prescaler * (1 + OCR2A))
Therefore, the expected frequency of both LEDs will be
16e6 / (2 * 1024 * (1 + 200))
=> 16e6 / (2048 * 201)
=> 16e6 / 411648
=  38.868159204 Hz
Listing 8-7 is the setup() function for the sketch.
//========================================================
// This sketch uses the Timer/Counter 2 in CTC mode 2 as
// follows:
//
// OC2A to toggle D11 when TCNT2 matches OCR2A.
// OC2B to toggle D3 when TCNT2 matches OCR2B.
//
// Frequency = F_CPU / (2 * prescaler * (OCR2A + 1)
//========================================================
void setup() {
    // Initialise Timer/counter 2 in CTC mode. (Mode 2) ①
    TCCR2A = ((1 << WGM21) |
              (1 << COM2A0) |
              (1 << COM2B0));
    // Disable interrupts on Timer 2.                   ②
    TIMSK2 = 0;
    // Set up the compare values.                       ③
    OCR2A = 200;
    OCR2B = 86;
    // Prescale by 1024, and start the timer.           ④
    TCCR2B = ((1 << CS22) |
              (1 << CS21) |
              (1 << CS20));
    // D11 and D3 are outputs.                          ⑤
    pinMode(11,  OUTPUT);
    pinMode(3, OUTPUT);
}
Listing 8-7

CTC example sketch, setup() function

  •     ①    Timer/counter 2 is configured here with CTC mode 2, and both the OC2A (D11) and OC2B (D3) pins toggle when there is a compare match between TCNT2 and either OCR2A or ORC2B.

  •     ②    All interrupts are disabled for Timer/counter 2.

  •     ③    The two required match values are set up here. As OCR2A is higher than OCR2B, both output pins will be affected when the counts match.

  •     ④    This is the point where the timer/counter’s prescaler is set to divide the system clock by 1024, which starts the timer/counter running.

  •     ⑤    The output pins are configured after the timer/counter, as stated in the data sheet.

Listing 8-8 shows a very empty loop() function.
void loop() {
    // Nothing happening here, move along now!
}
Listing 8-8

CTC example sketch, loop() function

Using my trusty Labrador oscilloscope, I measured a frequency of 39 Hz on both LEDs, so I was close to the expected 38.868159204 Hz.

You will notice that loop() is empty, again. The timer/counter hardware is doing all the hard work of toggling the LEDs for us. We could add some code to the loop to do something useful and still have the other two LEDS flashing away unaffected. Listings 8-9 and 8-10 show the changes that need to be made to Listings 8-6 and 8-7 to get the loop() function working hard!

Add the following line to the setup() function, just after the existing pinMode() calls.
pinMode(LED_BUILTIN, OUTPUT);
Listing 8-9

CTC example, setup() function changes

Change loop() to the following:
void loop() {
    // Toggle D13 and use a delay().
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
}
Listing 8-10

CTC example, loop() function changes

Compile and upload the sketch. The LED on D13 will toggle at the usual rate of once every second, controlled by loop(), while the other two LEDs are completely unaffected by the calls to delay() and continue “flashing” at a frequency of almost 39 Hz. I use quotes around “flashing” as the rate is quite fast on a 16 MHz Arduino, so the LEDs appear on if you stare at them directly. If you see them in your peripheral vision, you will make out a flashing.

As the frequency is roughly 39 Hz, the period is 25.64 milliseconds, or 12.82 milliseconds on and 12.82 milliseconds off. Pretty quick, but you can see it – in your peripheral vision. The human eye is truly amazing – sometimes.

Yes, I know I’m mixing and matching Arduino code and AVR code, but that’s what happens sometimes. I’ve seen many sketches where the vast majority was written in Arduino code – it’s far easier on the eye after all – and only the nitty gritty parts of the code were written in plain AVR language. This is usually because the facilities of the ATmega328P being used were not available in the Arduino Language.

8.1.7 PWM Modes

The timer/counters can be configured to generate pulse width modulation (PWM) on certain pins. As with the modes already discussed, the timer/counters have a given frequency – which can be changed (see PWM frequencies in the following) – however, unlike the other modes, the amount of time that the pins stay HIGH can also be changed, even on the fly as the code is running.

The frequency of a waveform is the number of times a second that it moves through a single wave – from crest to crest or trough to trough. The period is the time it takes to do so. If the frequency is 400 Hz, then the period is one over that, or 2.5 milliseconds.

In non-PWM modes, the pin connected to the waveform generator is HIGH for 50% of the time and LOW for the other 50%. With PWM waveforms, the time that the pin is HIGH in each period is adjustable and not stuck at 50%.

8.1.7.1 Duty Cycle

The amount of time that a pin stays high, during each period, is normally specified as a percentage and is called the duty cycle. On the Arduino, the duty cycle for the analogWrite() function calls is simply
(value * 100) / 256

Calling analogWrite(pin, 128) is setting a duty cycle of 50% – the pin will be HIGH for 50% of the period and LOW for 50%.

The image in Figure 8-1 was created on a Labrador oscilloscope which was monitoring pin D9 when the Arduino was executing the statement analogWrite(9, 128).
Figure 8-1

Phase Correct PWM with 50% duty cycle

In the top-right corner, you can see that the frequency (f) is listed as 489.22 Hz which is approximately 490 Hz as the Arduino documentation states. That will be the same on all PWM pins except D5 and D6. For those, as will be explained in the following, the image in Figure 8-2 applies.
Figure 8-2

Fast PWM with 25% duty cycle

This time, the frequency shows as 973.66 Hz and is roughly the approximate 980 Hz as mentioned in the Arduino documentation. The documentation is a bit too approximate though as the actual frequency is only 976.5625 – so my measurement is a tad closer! This example trace was taken from pin D6; and the statement executing this time, to give a different graph, was analogWrite(6, 64) for a 25% duty cycle.

The general calculation to work out a duty cycle is
DC = (Time HIGH * 100) / (Time HIGH + Time LOW)
The duty cycle is useful as it causes what appears to be an analogue voltage on the output pin, rather than a digital HIGH or LOW. The voltage that appears to be present on the pin, and can be measured, is given by the formula
DC * HIGH Voltage

So if, for example, the duty cycle is 50% and VCC is 5 V, we appear to see a voltage of 2.5 V on the output pin. If the duty cycle is 25%, then we appear to see only 1.25 V on the output pin. This is why an LED can be made to fade in brightness or a motor with an appropriate driver can be made to speed up or down.

8.1.7.2 PWM Frequencies

The Arduino is set up with two fixed PWM frequencies, as explained earlier, caused by the three timer/counters being run in 8-bit mode with a divide-by-64 prescaler. Table 8-12 shows the relationship between the prescaler values and the two PWM frequencies which correspond to the prescaler value.

If necessary, you can get faster or slower PWM frequencies if your specific project requires them, by taking over the timer/counters and changing things around. If you must do this, then the following table will help you avoid having to do the arithmetic. It assumes a 16 MHz system clock and an 8-bit counter, like the Arduino.
Table 8-12

Prescaler values and PWM frequencies

Prescaler

Fast PWM Frequency

Fast PWM Period

Phase Correct PWM Frequency

Phase Correct PWM Period

1

62.5000 KHz

16

31.3725 KHz

31.87

8

7.8125 KHz

128

3.9216 KHz

254.99

32

1.953125 KHz

512

980.3922 Hz

1,020

64

976.5625 Hz

1,024

490.1960 Hz

2,040

128

488.28125 Hz

2,048

245.098 Hz

4,080

256

244.1406 Hz

4,096

122.5490 Hz

8,160

1024

61.0352 Hz

16,384

30.6372 Hz

32,640

All periods in Table 8-12 are measured in microseconds, or millionths of a second.

Only Timer/counter 2 can use the 32 and 128 prescaler values in the preceding table.

Be aware that changing Timer/counter 0 in this fashion will mess up things like millis() and delay() and such things that rely on a prescaler of 64 for accuracy.

The data sheet advises that when measuring PWM waveforms, the period is deemed to be measured between each TOP (highest) value of the counter.

The PWM frequency, in any PWM mode, is changed by changing the timer/counter’s prescaler.

8.1.7.3 Fast PWM Mode

In Fast PWM mode, the value in register TCNTn will increment from zero – BOTTOM – until it reaches TOP. On the next clock pulse, TCNTn will be reset to zero, BOTTOM, and will then continue counting upward again. There are therefore TOP + 1 steps in each cycle. The TOP value is determined by the mode and can be
  • For all timer/counters, the value 255 – this is the Arduino default.

  • For all timer/counters, the value in register OCRnA.

  • For Timer/counter 1 only, the value 511.

  • For Timer/counter 1 only, the value 1023.

  • For Timer/counter 1 only, the value in register ICR1.

The data sheet advises that

When changing the TOP value the program must ensure that the new TOP value is higher or equal to the value of all of the Compare Registers. If the TOP value is lower than any of the Compare Registers, a compare match will never occur between the TCNTn and the OCRnx.

This PWM mode is called “single slope” as a graph of TCNTn’s value would slope upward and then fall immediately back down to zero like a saw tooth. Figure 8-3 shows the slope of the count in TCNTn as it rises and resets to zero.

Each timer/counter has two pins upon which it can generate PWM waveforms. The Arduino initialization carried out in the init() function discussed in Chapter 2, for each and every sketch, sets all three timer/counters to run in 8-bit mode with a prescaler of 64 and a TOP value of 255. Timer/counter 0 is configured to run in Fast PWM mode, while the other two are configured in Phase Correct PWM mode.

Timer/counters 0 and 2 have two Fast PWM modes, modes 3 and 7. The differences are as follows:
  • In mode 3, TOP is always 255 – this mode is used by the Arduino.

  • In mode 7, TOP is always the value in OCRnA.

Timer/counter 0 runs Fast PWM on Arduino pins D5 and D6, which correspond to the AVR pins named PD5 and PD6.

Timer/counter 1 has five different Fast PWM modes available for use, modes 5, 6, and 7, plus modes 14 and 15. The differences are as follows:
  • In mode 5, TOP is always 255 and the count in TCNT1 is always 8 bits – this mode is used by the Arduino.

  • In mode 6, TOP is always 511 and the count in TCNT1 is always 9 bits.

  • In mode 7, TOP is always 1023 and the count in TCNT1 is always 10 bits.

  • In mode 14, TOP is always the value in register ICR1, the Input Capture Unit register.

  • In mode 15, TOP is always the value in register OCR1A.

In these Fast PWM timer/counter modes
  • There are TOP + 1 cycles.

  • When TCNTn is zero, the appropriate PWM pin goes HIGH.

  • When TCNTn equals OCRnA or OCRnB, the pin will go LOW.

The AVR microcontroller can be configured to invert the PWM output pins OCnA and OCnB, so that they go LOW instead of HIGH and HIGH instead of LOW.

It should be obvious, when running in a Fast PWM mode where TOP is defined by OCRnA, that the value in OCRnB must be less than OCRnA or the PWM will not work on that pin.

Also, in modes where OCRnA defines TOP, then you will be somewhat restricted in what you can do with pin OCnA.

The Arduino configures Timer/counter 0 to run in Fast PWM mode with a prescaler of 64. The other two times/counters are configured in Phase Correct PWM Mode.

For Fast PWM mode, the PWM frequency is calculated as
F_CPU / (prescaler * (TOP + 1))

This works out on the Arduino boards as 16e6/(64 ∗ 256) or 976.5625 Hz, and this is the rate that Timer/counter 0 runs. Table 8-12 should save you the effort of working out the PWM frequencies and periods for any given prescaler.

Figure 8-3 shows the details of Fast PWM with TOP fixed at 255 which is mode 3 for Timer/counters 0 and 2 or mode 5 for Timer/counter 1.
Figure 8-3

8-bit Fast PWM with TOP at 255

In the preceding diagram, the value in OCRnA is constant as per the Arduino initialization code. It can be changed in code or in an interrupt handler, to vary the duty cycle of the PWM waveform, but this is not used on the Arduino.

In the following description, everything that applies to OCRnA and OCnA also applies to OCRnB and OCnB, but the latter are not shown in the diagram to avoid clutter.
  • The jagged line in Figure 8-3 is the value in TCNTn as it rises from zero (BOTTOM) to TOP which, in the case of an Arduino board, is set to 255 although this can be changed as per the data sheet. After 255, the value drops to zero on the next timer/counter clock pulse.

  • The horizontal line is the constant value in OCRnA; in this example, it is 255 as per Arduino initialization code. The value in OCRnA can be changed, usually by the interrupt handler, if the duty cycle is required to be varied. Changes to the value in OCRnA are double buffered and applied at BOTTOM when TCNTn has just become zero.

  • The two square wave lines at the bottom represent the non-inverting and the inverting waveforms generated on pin OCnA.

  • If you look at the line for pin OCnA, the non-inverting output will be HIGH when TCNTn is zero and will then go LOW when TCNTn equals OCRnA. At the same time as the match is made, the timer/counter’s Timer Compare Match interrupt flag is set.

  • The bottom square wave of the two shown is the inverting output line, and this is simply the opposite to pin OCnA.

  • The timer/counter’s overflow flag will be set when TCNTn reaches BOTTOM.

The data sheet advises that This high frequency makes the Fast PWM mode well suited for power regulation, rectification, and DAC applications. High frequency allows physically small sized external components (coils, capacitors), and therefore reduces total system cost. It is not advised for motors as they much prefer Phase Correct PWM.

So what happens in Fast PWM? There are many things:
  • When TCNTn equals TOP, the Timer n Overflow interrupt bit TOVn is set in register TIFRn, and if enabled, this interrupt can be used to update the value in the OCRnA and/or OCRnB registers to change the duty cycle of the PWM waveform. In this timer/counter mode, the OCRnA and OCRnB registers are double buffered; and the value written by your sketch, to these registers, will not be copied into the register until TCNTn resets to zero (BOTTOM). Only then do the register values change.

This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit TOIEn in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.
  • When TCNTn reaches OCRnA, then bit OCFnA is set in register TIFRn. This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit OCIEnA in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • Pin OCnA will perform an action. The action depends on the values in the COMnA1:0 bits, as described in Table 8-13, when TCNTn matches with OCRnA.
    Table 8-13

    COMnA1:0 settings in Fast PWM mode

    COMnA1-COMnA0

    Description

    00

    No effect on pin OCnA

    01

    • Pin OCnA, for Timer/counters 0 and 2, in mode 3, is not affected

    • In mode 7, then pin OCnA will toggle when TCNTn matches OCRnA

    • For Timer/counter 1 in mode 14, pin OC1A will toggle when TCNT1 matches ICR1. Pin OC1B will be unaffected

    • In mode 15, pin OC1A will toggle when TCNT1 matches OCR1A. Pin OC1B will be unaffected

    • In mode 5, 6, or 7, OC1A is unaffected

    10

    Pin OCnA is LOW on match with OCRnA and HIGH at BOTTOM. This is non-inverting mode

    11

    Pin OCnA is HIGH on match with OCRnA and LOW at BOTTOM. This is inverting mode

  • When TCNTn reaches OCRnB, then bit OCFnB is set in register TIFRn. This bit is not cleared unless your sketch clears it or the interrupt handler is enabled by setting bit OCIEnB in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • Pin OCnB will perform an action. The action depends on the values in the COMnB1:0 bits, as described in Table 8-14, when TCNTn matches with OCRnB.

Table 8-14

COMnB1:0 settings in Fast PWM mode

COMnB1-COMnB0

Description

00

No effect on pin OCnB

01

• Reserved – do not use on Timer/counters 0 and 2

• For Timer/counter 1 in mode 14, pin OC1A will toggle when TCNT1 matches ICR1. Pin OC1B will be unaffected

• In mode 15, pin OC1A will toggle when TCNT1 matches OCR1A. Pin OC1B will be unaffected

• In mode 5, 6, or 7, OC1A is unaffected

In other words, this setting only affects channel A on Timer/counter 1

10

Pin OCnB is LOW on match with OCRnB and HIGH at BOTTOM. This is non-inverting mode

11

Pin OCnB is HIGH on match with OCRnB and LOW at BOTTOM. This is inverting mode

8.1.7.3.1 Setting Fast PWM Mode
Table 8-15 shows the settings required to put the timer/counters into Fast PWM mode.
Table 8-15

Fast PWM mode settings

Timer

Mode

Bits

Value

0

3

WGM02–WGM00

011binary

0

7

WGM02–WGM00

111binary

1

5

WGM13–WGM10

0101binary

1

6

WGM13–WGM10

0110binary

1

7

WGM13–WGM10

0111binary

1

14

WGM13–WGM10

1110binary

1

15

WGM13–WGM10

1111binary

2

3

WGM22–WGM20

011binary

2

7

WGM22–WGM20

111binary

Note that bits WGMn0 and WGMn1 are found in register TCCRnA, bit WGMn2 is found in TCCRnB, and, for Timer/counter 1 only, WGM13 is also found in TCCR1B.

You should be aware that because the PWM pins always go HIGH, at least in non-inverting mode, at BOTTOM, then they are always HIGH at the start of each cycle and LOW at the end, no matter what value is used for TOP. Sometimes this isn’t suitable – motors apparently don’t like this – and for that, you would use Phase Correct PWM instead.

8.1.7.3.2 Example Sketch

As mentioned earlier, Fast PWM is set up by the Arduino init() function for every sketch, on Timer/counter 0. The sketch in Listings 8-11, 8-12, and 8-13 is effectively what the init() function does to set up Timer/counter 0, but without the Overflow interrupt handler that updates millis() and micros(),and with a slower prescaler.

You might need to adjust the delay at the end of loop() if you can’t see the fade up and down of the LEDs.

Listing 8-11 is a number of #defines, used to reduce the amount of bit shifting in the main code. It simply creates a definition for the two channels on Timer/counter 0, for both the HIGH and LOW states. These are used when the PWM value is 255 or 0.
//========================================================
// This sketch uses the Timer/Counter 0 in Fast PWM mode
// to fade down an LED on pin D5 while fading up an LED
// on D6. The prescaler is 1,024.
//========================================================
#define PWM_A_LOW (~(1 << PORTD5))
#define PWM_A_HIGH ((1 << PORTD5))
#define PWM_B_LOW (~(1 << PORTD6))
#define PWM_B_HIGH ((1 << PORTD6))
Listing 8-11

Fast PWM sketch, defines

The preceding definitions could have been declared as const uint8_t PWM_A_LOW = (~(1 << PORTD5)) and so on, which would have had the same effect. Listing 8-12 is the setup() function for the sketch.
void setup() {
    // Set Timer 0 into Fast PWM mode 3
    // with TOP = 255 and OC0A and OC0B
    // toggling on match
    TCCR0A = ((1 << WGM01)  |            ①
              (1 << WGM00)  |
              (1 << COM0A1) |
              (1 << COM0B1));
    // Timer 0 prescaler = 1,024.        ②
    TCCR0B = ((1 << CS02) | (1 << CS00));
    // Need to set the pins to output.   ③
    DDRD = ((1<< DDD5) | (1 << DDD6));
}
Listing 8-12

Fast PWM sketch, setup() function

  •     ①    This sets Timer/counter 0 into Fast PWM mode, with TOP = 255. This is the same as the Arduino init() function usually does. In addition, pins OC0A and OC0B will toggle on a compare match. These equate to pins PD5 and PD6, or Arduino pins D5 and D6.

  •     ②    Unlike the Arduino’s init() function, the prescaler here is set to divide by 1024.

  •     ③    This is simply pinMode(5, OUTPUT); and pinMode(6, OUTPUT); but both pins are set in one statement, not two.

The code in Listing 8-13 is that of the loop() function, which is where the hard work of fading the two LEDs up and down takes place. In the code, checks have to be made for the limits of the timer/counter – 0 and 255 – as the data sheet advises against setting those values for a PWM waveform. The analogWrite() function also checks for these values and, if found, calls digitalWrite() to set the pin LOW or HIGH as appropriate and ignores the PWM for those values.
void loop() {
   // Current PWM duty cycle and increments.
    static uint8_t a = 0;                   ①
    static uint8_t b = 255;
    uint8_t increment = 1;
    if ((a != 0) && (a != 255)) {           ②
        OCR0A = a;
        OCR0B = b;
    } else {                                ③
        if (a == 255) {     // then b == 0
            PORTD |= PWM_A_HIGH;
            PORTD |= PWM_B_LOW;
        } else {            // then b == 255
            PORTD |= PWM_A_LOW;
            PORTD |= PWM_B_HIGH;
        }
    }
    a += increment;                         ④
    b -= increment;
    // Even at 1,024 prescaling, it's too quick!
    delay(1);                               ⑤
}
Listing 8-13

Fast PWM sketch, loop() function

  •     ①    Declaring variables in a function as static means that they are initialized with the given value on the first call to the function. Then on the next call to the function, they have the value from the previous call – they retain their value across function call and exit, in other words.

  •     ②    If a is not on a PWM limit (0 or 255), then b is not either, so simply set the OCR0x registers with the values of a and b – we have two valid PWM values which we can use.

  •     ③    If a is on a limit, then b must be on the other limit. In this case, we simply do what analogWrite() would do and effectively digitalWrite() a LOW or HIGH to the appropriate pins, depending on which limit a and b are on.

  •     ④    The fade values in a and b are incremented and decremented by the current amount.

  •     ⑤    As even the biggest prescaler runs the timer/counter way too quickly, there is a small delay to allow the fading effect to be seen. Feel free to adjust this if necessary.

The preceding code is effectively the same as analogWrite() which checks for values of 0 or 255, which the data sheet advises avoiding, and handles those separately. All other values get written to the OCR0A and OCR0B registers to control the duty cycle of the square wave generated on pins D5 and D6. An LED (and 330 Ohm resistor!) on these two pins should fade up on D5 and fade down on D6.

As variable a and b are unsigned 8-bit variables, they will roll over when increment is added or subtracted, which is why I only need to check explicitly for 0 or 255 in the code. Even if you change the increment value, it will still work.

If you run the preceding code on a normal Arduino, it might be flashing far too quickly to see properly, but one LED should be fading up while the other fades down. On a breadboard setup with the AVR microcontroller running at 8 MHz, the flashing is more obvious. You can change the delay() statement at the end of the loop() to slow things down a little, if necessary.

The LEDs will reset to their starting values when they reach the end of their fade – a will toggle from full on to full off, while b does the opposite. This means that D5 will start off, fade up to full brightness, and then drop to off again, while D6 does the opposite.

8.1.7.4 Phase Correct PWM Mode

Phase Correct PWM is called “dual slope” because the counter, TCNTn, counts from zero, BOTTOM, up to TOP and then counts back down again to BOTTOM. It takes twice as long to repeat the cycle and, thus, runs at half the frequency of the Fast PWM. The graph of the timer/counter’s value against time slopes upward and then back down again and doesn’t exhibit the sudden drop from TOP to BOTTOM that Fast PWM does. Figure 8-4 shows the slope of the count in TCNTn as it rises and falls back to zero.
Figure 8-4

8-bit Phase Correct PWM with TOP at 255

The TOP value is determined by the mode and can be
  • For all timer/counters, the value 255 – this is the Arduino default.

  • For all timer/counters, the value in register OCRnA.

  • For Timer/counter 1 only, the value 511.

  • For Timer/counter 1 only, the value 1023.

  • For Timer/counter 1 only, the value in register ICR1.

The data sheet advises that

When changing the TOP value the program must ensure that the new TOP value is higher or equal to the value of all of the Compare Registers. If the TOP value is lower than any of the Compare Registers, a compare match will never occur between the TCNT1 and the OCR1x.

It should be obvious, as with Fast PWM, that when running in a mode where TOP is defined by OCRnA or ICR1, the value in OCRnB must be less than OCRnA or the PWM will not work on that pin.

Also, in modes where OCRnA defines TOP, then you will be somewhat restricted in what you can do with pin OCnA.

On an Arduino, Timer/counter 1 runs Phase Correct PWM mode 1 on Arduino pins D9 and D10, which correspond to the AVR pins named PB1 and PB2. Timer/counter 2 runs Phase Correct PWM mode 1 on Arduino pins D3 and D11, which correspond to the AVR pins named PD3 and PB3.

Figure 8-4 shows the details for Phase Correct PWM with TOP fixed at 255 – mode 1 on all three timer/counters.

In the preceding diagram, the value in OCRnA is a constant, as per the Arduino. It can be changed in code or in an interrupt handler and so vary the duty cycle of the PWM waveform.

In the following description, everything that applies to OCRnA and OCnA applies also to OCRnB and OCnB, but the latter are not shown in the diagram to avoid clutter.
  • The triangular line is the value in TCNTn as it rises from zero (BOTTOM) to TOP which, in the case of an Arduino board, is set to 255 although this can be changed as per the data sheet. After TOP, the value counts back down to zero (BOTTOM) and then repeats as shown in the diagram. (Only two full cycles are shown here.)

  • The horizontal line is the constant value in OCRnA, in this example. The value in OCRnA can be changed, usually by the interrupt handler, if the duty cycle is required to be varied. Changes to the value in OCRnA are double buffered and applied at TOP when TCNTn is at 255 on Arduino boards.

  • The two square wave lines at the bottom represent the non-inverting and the inverting waveform generated on pin OCnA.

  • If you look at the line for pin OCnA, the non-inverting output , you should see that when TCNTn reaches OCRnA while counting upward, the appropriate output pin will go LOW. It stays LOW until TCNTn hits OCRnA again while counting downward whereupon it goes HIGH. At the same time as the match is made, the timer/counter’s Timer Compare Match interrupt flag is set.

  • The bottom square wave of the two shown is the inverting output line, and this is simply the opposite to pin OCnA.

  • The timer/counter’s overflow flag will be set when TCNTn reaches BOTTOM.

The data sheet advises that due to the symmetric feature of the dual-slope PWM modes, these modes are preferred for motor control applications.

Each timer/counter has two pins upon which it can generate PWM waveforms. The Arduino initialization for each and every sketch sets the timers to all run in 8-bit mode with a prescaler of 64; however, only Timer/counters 1 and 2 are set to run in Phase Correct PWM mode.

Timer/counters 0 and 2 have two Phase Correct PWM modes, modes 1 and 5. The differences are as follows:
  • In mode 1, TOP is always 255.

  • In mode 5, TOP is always the value in OCRnA.

Timer/counter 1 has five different Phase Correct PWM modes available for use, modes 1, 2, and 3, plus modes 10 and 11. The differences are as follows:
  • In mode 1, TOP is always 255 and the count in TCNT1 is always 8 bits.

  • In mode 2, TOP is always 511 and the count in TCNT1 is always 9 bits.

  • In mode 3, TOP is always 1023 and the count in TCNT1 is always 10 bits.

  • In mode 10, TOP is always the value in register ICR1, the Input Capture Unit register.

  • In mode 11, TOP is always the value in register OCR1A.

In these timer modes
  • There are TOP ∗ 2 cycles.

  • When TCNTn equals OCRnA or OCRnB while counting upward, the appropriate PWM pin goes LOW.

  • When TCNTn equals OCRnA or OCRnB when counting downward, the appropriate PWM pin will go HIGH.

The AVR microcontroller can be configured to invert the output PWM pins, so that they go LOW and HIGH opposite to that specified in the preceding text.

For Phase Correct PWM mode, the PWM frequency is calculated as
F_CPU / (prescaler * (TOP * 2))

This works out on the Arduino boards as 16e6/(64 ∗ 510) or 490.196078431 Hz, and this is the rate that Timer/Counters 1 and 2 run. The period of the PWM frequency is, for Phase Correct PWM configured as per the Arduino code, 2040 microseconds, or, 2.04 milliseconds.

Table 8-12 should save you the effort of working out the PWM frequencies and periods for any given prescaler.

The following lists the various changes that occur in Phase Correct PWM:
  • TCNTn is only ever at TOP or BOTTOM for one clock. It will hold the value of all other counter values twice, once while counting up, once when counting down.

  • When TCNTn equals BOTTOM, the Timer n Overflow interrupt bit TOVn is set in register TIFRn, and if enabled, this interrupt can be used to update the value in the OCRnA and/or OCRnB registers to change the duty cycle of the PWM waveform. In this timer mode, the OCRnA and OCRnB registers are again double buffered; and the value written by your sketch, to these registers, will not be copied into the register until TCNTn hits TOP. Only then do the register values change.

    This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit TOIEn in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • When TCNTn reaches OCRnA, then bit OCFnA is set in register TIFRn. This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit OCIEnA in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • Pin OCnA will perform an action. The action depends on the values in the COMnA1-0 bits, as described in Table 8-16, when TCNTn matches with OCRnA.

  • When TCNTn reaches OCRnB, then bit OCFnB is set in register TIFRn. This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit OCIEnB in register TIMSKn in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • Pin OCnB will perform an action. The action depends on the values in the COMnB1-0 bits, as described in Table 8-17, when TCNTn matches with OCRnB.

  • Only when TCNTn matches TOP are any changes made by the sketch to OCRnA or OCRnB applied.

Table 8-16

COMnA1:0 settings in Fast PWM mode

COMnA1-COMnA0

Description

00

No effect on pin OCnA

01

• Pin OCnA, for Timer/counters 0 and 2, in mode 1, is not affected

• In mode 5, pin OCnA will toggle when TCNTn matches OCRnA

• For Timer/counter 1 in mode 11, pin OC1A will toggle when TCNT1 matches OCR1A, and pin OC1B will be unaffected

• In modes 10, 1, 2, and 3, OC1A is unaffected

10

Pin OCnA is LOW on match with OCRnA when counting upward and HIGH on match with OCRnA when counting downward. This is non-inverting mode

11

Pin OCnA is HIGH on match with OCRnA when counting upward and LOW on match with OCRnA when counting downward. This is inverting mode

Table 8-17

COMnB1:0 settings in Fast PWM mode

COMnB1-COMnB0

Description

00

No effect on pin OCnB

01

• Reserved – do not use on Timer/counters 0 and 2

• For Timer/counter 1 in mode 9, pin OC1A will toggle when TCNT1 matches OCR1A, and pin OC1B will be unaffected.

• In mode 1, 2, 3, or 8, OC1B is unaffected (in other words, exactly as Table 8-16)

10

Pin OCnB is LOW on match with OCR1B when counting upward and HIGH on match with OCR1B when counting downward. This is non-inverting mode

11

Pin OCnB is HIGH on match with OCR1B when counting upward and LOW on match with OCR1B when counting downward. This is inverting mode

8.1.7.4.1 Setting Phase Correct PWM Mode
Table 8-18 shows the settings required to put the timer/counters into Phase Correct PWM mode.
Table 8-18

Phase Correct PWM mode settings

Timer

Mode

Bits

Value

0

1

WGM02–WGM00

001binary

0

3

WGM02–WGM00

011binary

1

1

WGM13–WGM10

0001binary

1

2

WGM13–WGM10

0010binary

1

3

WGM13–WGM10

0011binary

1

10

WGM13–WGM10

1010binary

1

11

WGM13–WGM10

1011binary

2

1

WGM22–WGM20

001binary

2

3

WGM22–WGM20

011binary

Note that bits WGMn0 and WGMn1 are found in register TCCRnA, bit WGMn2 is found in TCCRnB, and, for Timer/counter 1 only, WGM13 is also found in TCCR1B.

8.1.7.4.2 Example Sketch

As mentioned in the preceding text, Phase Correct PWM is set up by the Arduino init() function for every sketch, on Timer/counters 1 and 2. The sketch in Listings 8-14, 8-15, and 8-16 is effectively what the init() function does to set up Timer/counters 1 and 2 for use with the analogWrite() function , but in the example, I’m hijacking Timer/counter 0 instead – just to be different!

Manipulating the PWM mode of Timer/counter 0 in this manner is harmless on the ATmega328P, but for some microcontrollers – the ATmega8 or ATmega168, for example – this will affect the accuracy of the millis() counter and all that which relies upon it.

You might need to adjust the delay at the end of loop() if you can’t see the fade up and down of the LEDs.

Listing 8-14 is a number of #defines, used to reduce the amount of bit shifting in the main code. It simply creates a definition for the two channels on Timer/counter 0, for both the HIGH and LOW states. These are used when the PWM value is 255 or 0.
//========================================================
// This sketch uses the Timer/Counter 0 in Phase Correct
// PWM mode to fade down an LED on pin D6 while fading up
// an LED on D5. The prescaler is 1,024.
//========================================================
#define PWM_A_LOW (~(1 << PORTD5))
#define PWM_A_HIGH ((1 << PORTD5))
#define PWM_B_LOW (~(1 << PORTD6))
#define PWM_B_HIGH ((1 << PORTD6))
Listing 8-14

Phase Correct PWM sketch, defines

The preceding code could have been declared as const uint8_t PWM_A_LOW = (~(1 << PORTD5)) and so on, which would have had the same effect. Listing 8-15 is the setup() function for the demonstration sketch.
void setup() {
    // Set Timer 0 into Phase Correct PWM mode 1
    // with OC0A and OC0B toggling on match
    // and TOP = 255.
    TCCR0A = ((1 << WGM00)  |           ①
              (1 << COM0A1) |
              (1 << COM0B1));
    // Timer 0 prescaler = 1,024.       ②
    TCCR0B = ((1 << CS02) | (1 << CS00));
    // Need to set the pins to output.
    // Using AVR speak here.
    DDRD = ((1<< DDD5) | (1 << DDD6));  ③
}
Listing 8-15

Phase Correct PWM sketch, setup() function

  •     ①    This sets Timer/counter 0 into Phase Correct PWM mode, with TOP = 255. This is similar as the Arduino init() function usually does for the other two timer/counters. In addition, pins OC0A and OC0B are configured to toggle on a compare match. These equate to pins PD5 and PD6, or Arduino pins D5 and D6.

  •     ②    Unlike the Arduino’s init() function, the prescaler here is set to divide by 1024.

  •     ③    This is simply pinMode(5, OUTPUT); and pinMode(6, OUTPUT); but both pins are set in one statement, not two.

The code in Listing 8-16 is that of the loop() function, which is where the task of fading the two LEDs up and down lies. As we did with Fast PWM, checks have to be made for the limits of the timer/counter – 0 and 255 – as the data sheet advises against setting those values for a PWM waveform. If found, the code effectively calls digitalWrite() to set the pin LOW or HIGH as appropriate and ignores the PWM for those values.
void loop() {
   // Current PWM duty cycle and increments.
    static uint8_t a = 0;                    ①
    static uint8_t b = 255;
    uint8_t increment = 1;
    if ((a != 0) && (a != 255)) {            ②
        OCR0A = a;
        OCR0B = b;
    } else {                                 ③
        if (a == 255) {     // then b == 0
            PORTD |= PWM_A_HIGH;
            PORTD |= PWM_B_LOW;
        } else {            // then b == 255
            PORTD |= PWM_A_LOW;
            PORTD |= PWM_B_HIGH;
        }
    }
    a += increment;                         ④
    b -= increment;
    // Even at 1,024 prescaling, it's too quick!
    delay(1);                               ⑤
}
Listing 8-16

Phase Correct PWM sketch, setup() function

  •     ①    Declaring variables in a function as static means that they are initialized with the given value on the first call to the function. Then on the next call to the function, they have the value from the previous call – they retain their value across function call and exit, in other words.

  •     ②    If a is not on a PWM limit (0 or 255), then b is not either, so simply set the OCR0x registers with the values of a and b – we have two valid PWM values which we can use.

  •     ③    If a is on a limit, then b must be on the other limit. In this case, we effectively digitalWrite() a LOW or HIGH to the appropriate pins, depending on which limit a and b are on.

  •     ④    The fade values in a and b are incremented and decremented by the current amount.

  •     ⑤    As even the biggest prescaler runs the timer/counter way too quickly, there is a small delay to allow the fading effect to be seen. Feel free to adjust this if necessary.

The preceding code is effectively the same as analogWrite() which checks for values of 0 or 255, which the data sheet advises avoiding, and handles those separately. All other values get written to the OCR0A and OCR0B registers to control the duty cycle of the square wave generated on pins D5 and D6. An LED (and 330 Ohm resistor!) on these two pins should fade up on D5 and fade down on D6.

As variable a and b are unsigned 8-bit variables, they will roll over when increment is added or subtracted, which is why I only need to check explicitly for 0 or 255 in the code. Even if you change the increment value, it will still work.

If you run the preceding code on a normal Arduino, it might be flashing far too quickly to see properly, but one LED should be fading up while the other fades down. On a breadboard setup with the AVR microcontroller running at 8 MHz, the flashing is more obvious. You can change the delay() statement at the end of the loop() to slow things down a little, if necessary.

The LEDs will reset to their starting values when they reach the end of their fade – a will toggle from full on to full off, while b does the opposite. This means that D5 will start off, fade up to full brightness, and then drop to off again, while D6 does the opposite.

While the sketch is running, you should, hopefully, notice that the flickering of the LEDs is different with Phase Correct PWM from that of Fast PWM – this is noticeable when both sketches use the same delay() at the end of the loop.

8.1.7.5 Phase and Frequency Correct PWM Mode

Timer/counter 1 has an additional mode, well two modes, that the other timer/counters do not have. This is Phase and Frequency Correct PWM and is mostly identical to the previously mentioned Phase Correct PWM modes. The main difference is that the PWM generated is always symmetrical around the TOP value. This is because the OCR1A and/or ICR1 registers are updated with new values at BOTTOM, unlike Phase Correct PWM, which updates the OCRnA registers at TOP. Because of the update at BOTTOM, the count upward from BOTTOM to TOP is always the same as the count downward from TOP to BOTTOM.

The data sheet advises that

When changing the

TOP value the program must ensure that the new TOP value is higher or equal to the value of all of the Compare Registers. If the TOP value is lower than any of the Compare Registers, a compare match will never occur between the TCNT1 and the OCR1x.

The data sheet also states that there is little difference between Phase Correct and Phase and Frequency Correct PMW modes, when using a fixed TOP value. However, it also states that if you need to vary the TOP value, then Phase and Frequency Correct mode is best as it is _symmetrical about TOP.

What exactly is symmetrical about this mode? As the data sheet says

The PWM period begins and ends at TOP. This means that the falling slope of the waveform, is determined by the old TOP value while the rising slope that follows, is determined by the new value in TOP. At the point where the two TOP values are different, the slopes will have a different length and thus, the period of the output waveform will be different.

This is not a problem on the Arduino boards – none of the timer/counters are configured to run in this PWM mode.

On Timer/counter 1, the only one which has this PWM mode, the two Phase and Frequency Correct PWM modes are modes 8 and 9. The differences are as follows:
  • In mode 8, TOP is always the value in register ICR1, the Input Capture Register.

  • In mode 9, TOP is always the value in OCR1A.

So what happens in Phase and Frequency Correct PWM?
  • TCNT1 is only ever at TOP or BOTTOM for one clock. It will hold the value of all other counter values twice, once while counting up, once when counting down. This is identical to Phase Correct PWM.

  • When TCNT1 equals BOTTOM, any new value for OCR1A or OCR1B will be written into the appropriate register. Also, the Timer 1 Overflow interrupt bit TOV1 is set in register TIFR1, and if enabled, this interrupt can be used to update the value in the OCR1A and/or OCR1B registers to change the duty cycle of the PWM waveform. In this timer mode, the OCR1A and OCR1B registers are again double buffered; and the value written by your sketch, to these registers, will not be copied into the register until TCNT1 hits BOTTOM.

    This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit TOIE1 in register TIMSK1 in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • When TCNT1 reaches TOP, then the OCF1A or ICF1 bit is set in register TIFR1. The bit set depends on which mode the timer/counter is executing. In mode 8, TIF1 will be set; in mode 9, it will be OCF1A.

    These two bits are not cleared unless your sketch clears them or the appropriate interrupt handler is enabled by setting bit ICIE1 in mode 8 or OCIE1A in mode 9, in register TIMSK1. In this case, assuming also that global interrupts are enabled, the bits will be automatically cleared. To clear the bits manually, in a sketch, you must write a 1binary to them.

  • Pin OCnA will perform an action. The action depends on the values in the COMnA1-0 bits, as described in Table 8-19, when TCNTn matches with OCRnA.

  • When TCNT1 reaches OCR1B, then bit OCF1B is set in register TIFR1. This bit is not cleared unless your sketch clears it or if the interrupt handler is enabled by setting bit OCIE1B in register TIMSK1 in which case, assuming also that global interrupts are enabled, the bit will be automatically cleared. To clear the bit manually, in a sketch, you must write a 1binary to it.

  • Pin OCnB will perform an action. The action depends on the values in the COMnB1-0 bits, as described in Table 8-20, when TCNTn matches with OCRnB.

  • When TCNT1 matches BOTTOM, any changes made by the sketch to OCR1A or OCR1B are applied.

Table 8-19

COMnA1:0 settings in Phase and Frequency Correct PWM mode

COM1A1-COMnA0

Description

00

No effect on pin OC1A.

01

In mode 8 pin OC1A will be unaffected. In mode 9 pin OC1A will toggle when TCNT1 matches OCR1A. OC1B1 is unaffected

10

Pin OC1A is LOW on match with OCR1A when counting upward and HIGH on match with OCR1A when counting downward. This is non-inverting mode

11

Pin OC1A is HIGH on match with OCR1A when counting upward and LOW on match with OCR1A when counting downward. This is inverting mode

Table 8-20

COMnB1:0 settings in Phase and Frequency Correct PWM mode

COM1B1-COMnB0

Description

00

No effect on pin OC1B

01

This setting is exactly the same as setting bits COM1A1-0 as described earlier. Only pin OC1A is affected. In mode 8 pin OC1A will be unaffected. In mode 9 pin OC1A will toggle when TCNT1 matches OCR1A. OC1B1 is unaffected in either mode

10

Pin OC1B is LOW on match with OCR1B when counting upward and HIGH on match with OCR1B when counting downward. This is non-inverting mode

11

Pin OC1B is HIGH on match with OCR1B when counting upward and LOW on match with OCR1B when counting downward. This is inverting mode

8.1.7.5.1 Setting Phase and Frequency Correct PWM Mode
Table 8-21 shows the settings required to put the timer/counters into Phase and Frequency Correct PWM mode.
Table 8-21

Phase and Frequency Correct PWM mode settings

Timer

Mode

Bits

Value

1

8

WGM13–WGM10

1000binary

1

9

WGM13–WGM10

1001binary

Note that bits WGM10 and WGM11 are found in register TCCR1A, while bits WGM12 and WGM13 are found in TCCR1B.

8.1.8 Too Much to Remember? Try AVRAssist

So many timer/counters, so many modes, so many bits to be set or cleared, etc. Does it have to be this hard?

If you point your favorite browser at https://github.com/NormanDunbar/AVRAssist which is the AVRAssist GitHub page, you will come across my very easy to use AVR header files. These headers can be #included in your own source files, which will make life a lot easier when setting up timer/counters and the like.

In use, you end up with something like Listing 8-17.
#include <timer0.h>
using namespace AVRAssist;
ISR(TIMER0_OVF_vect) {
    ...
}
...
Timer0::initialise(MODE_FAST_PWM_255,
                Timer0::CLK_PRESCALE_64,
                Timer0::OCOA_TOGGLE | OCOB_TOGGLE,
                INT_OVERFLOW
                );
...
Listing 8-17

Setting up Timer 0 with AVRAssist

The preceding code will set Timer/counter 0 to have PWM on both pins D5 and D6 as per the Arduino init() function, with a prescaler of 64 and with an interrupt handler for the Timer 0 Overflow interrupt enabled, which, I think, is a little better to read and understand than a number of separate instructions listing various bit and register names, one after the other.

The preceding code should set up Timer/counter 0 in the mode specified and with all the settings that the Arduino sets up in the background for Timer/counter 0 when you compile a sketch. However, the preceding code will not compile and link when used in a sketch compiled with the Arduino IDE. This is because the IDE silently includes an interrupt handler for the Timer/counter 0 Overflow interrupt, and that means that any code in a sketch, compiled by the IDE, cannot specify an interrupt handler for that same interrupt.

If you do try this, you will get a linker error telling you that there are two separate interrupt handlers for the Overflow interrupt. Ask me how I know!

If you still wish to do something like this, you will need to compile your code outside of the Arduino IDE, and this means without using any of the Arduino Language. You will need to code in AVR C++ instead. The preceding code works perfectly in the PlatformIO environment – if, and only if, you remember to enable global interrupts – for example, and an interrupt handler for the Overflow interrupt can be defined. But then, if you do it that way, you lose the millis() function and all that depend on it from the Arduino environment. Decisions, decisions!

There are a few more details about AVRAssist in Appendix K.

8.2 Counting

Previously in this chapter, you learned, in some detail, all about the three timer/counters in the ATmega328P. However, all you learned about were the timer modes. They can also be used as counters; and instead of being triggered by a regular clock signal, generated from the main system clock via a prescaler, the value in TCNTn can be incremented according to an external rising or falling edge on a pair of specific pins.

Only Timer/counters 0 and 1 have this ability. Timer/counter 2 has other features, not available on Timer/counters 0 and 1.

8.2.1 Setting External Counting

Table 8-22 shows the configuration required to set the timer/counters into counter mode.
Table 8-22

Setting timer/counters into counting mode

CSn1-CSn0

Value

Description

110

6

External clock on Tn pin, counts on a falling edge

111

5

External clock on Tn pin, counts on a rising edge.

Pin T0 is physical pin 6 on the ATmega328P, Arduino pin D4, or AVR pin PD4. Pin T1 is physical pin 11 on the ATmega328P, Arduino pin D5, or AVR pin PD5. These are the only two pins that can be used in this way. If your sketch is using the pins as counter stimulus, then they obviously cannot be used as normal I/O pins.

All the Waveform Generation modes are still available when clocking from the external pins, and usually, it would be expected that some form of clock signal, perhaps generated by the ubiquitous 555 timer, would be utilized to run the counter – if a regular count was required. On the other hand, it could be used to count the number of times a door was opened in a given time – it’s down to the maker to decide.

All the interrupts, matching on OCRnA or OCRnB, overflow bit setting, etc., work as expected when running in counter mode.

8.2.2 Counter Example

The circuit in Figure 8-5 and the corresponding sketch in Listings 8-18 and 8-19 show a simple model of a door counter system – the serial monitor will record “door openings” each time the switch is pressed. In real use, the switch would be debounced and mounted in such a position as to record the door opening.
Figure 8-5

Door counter circuit

As I have not debounced the switch, it will also show how bouncy the particular switch I’m using happens to be.

Figure 8-5 shows the breadboard layout for this example. The circuit is very simple: the “high” side of SW1 is connected to 5 V from the Arduino. The “low” side of the switch, SW1, is connected to R1 which is a 10 K pulldown resister to GND and also to the Arduino pin D5 which is Timer/counter 1’s T1 pin. The LED and R2, which is 330 Ohms, are connected between D13 and GND in the normal manner.

void setup() {
    // Serial monitor is required.
    Serial.begin(9600);
    // Initialise Timer/counter 1 to be triggered externally
    // by a rising edge on pin D5. The timer runs in normal
    // mode as we don't need waveforms.
    TCCR1A = 0;     // Sets WGM11 and WGM10 to zero.
    // Disable interrupts on Timer 1.
    TIMSK1 = 0;
    // Clocked on a rising edge, and start the timer.
    TCCR1B = ((1 << CS12) | (1 << CS11) | (1 << CS10));
    // Make sure everything is reset.
    TCNT1 = 0;
    // T1=PD5=D5 is an input. PB5=D13 an Output.
    DDRB |= (1 << DDB5);
    DDRD |= (1 << DDD5);
}
Listing 8-18

The door counter sketch setup()

Listing 8-18 sets up Timer/counter 1 to be clocked externally on a rising edge on pin T1 and with the timer/counter’s interrupts disabled. Listing 8-19 displays the count of the number of times the door was opened.
void loop() {
    // Save the previous value of TCNT1.
    static uint16_t lastTCNT1 = 0;
    uint16_t thisTCNT1 = TCNT1;
    if (thisTCNT1 != lastTCNT1) {
        Serial.print("TCNT1 = ");
        Serial.println(thisTCNT1);
        lastTCNT1 = thisTCNT1;
    }
    // Flash the LED and delay ...
    // ... to show that the timer still works.
    PINB |= (1 << PINB5);
    delay(2000);
}
Listing 8-19

The door counter sketch loop()

Each time through the loop, the current value of TCNT1 is sent to the serial monitor if it changed since the previous count. Regardless of any changes, loop() always toggles the LED on Arduino pin D13 and then delays for 2 seconds. The delay is simply there to show that the timer/counter will still record switch presses during a delay which is tying up the main CPU.

When the LED is on, or off, press the switch a few times quickly. When the delay is complete, the next value displayed in the serial monitor will show multiple hits have taken place and been recorded.

The following list shows the first ten results I obtained with a random switch from my spares box. These were all single presses, and the results appear quite good, not many bounces. I was of course suspicious! Surely cheap switches shouldn’t be this good?
TCNT1 = 1
TCNT1 = 2
TCNT1 = 3
TCNT1 = 6
TCNT1 = 7
TCNT1 = 8
TCNT1 = 9
TCNT1 = 11
TCNT1 = 12
TCNT1 = 14

I tried a few more times with single presses, and it seems that I had picked the best switch in the world. I mostly only ever got a single increment. Is something wrong with the sketch? Or do I just have a really good switch?

I decided to check and remove the wire from 5 V to the high side of the switch. I then touched it to the switch side of R1, the pulldown resistor. That’s better. It bounced – a lot!

Don’t touch the 5 V wire to the GND side of the resistor. You will short out the power supply and might destroy your Arduino.
TCNT1 = 31
TCNT1 = 32
TCNT1 = 33
TCNT1 = 35
TCNT1 = 36
TCNT1 = 104
TCNT1 = 148
TCNT1 = 243
TCNT1 = 401
TCNT1 = 417

The preceding first five presses used the button, and I rarely saw a bounce. The remaining five used the wire to bypass the switch. Those touches bounced massively!

You can purchase guaranteed non-bounce switches, it appears. Getting hold of one and testing it against the sketch in Listings 8-18 and 8-19 might prove interesting.

In summary, as you can plainly see, setting a timer/counter to run as a counter is far, far simpler than setting one to run as timer.

8.3 Input Capture Unit

Timer/counter 1, as you know, is the only 16-bit timer on the ATmega328P. It is also the only timer/counter which has an input capture unit. The data sheet advertises this feature as

… an Input Capture unit that can capture external events and give them a time-stamp indicating time of occurrence. The external signal indicating an event, or multiple events, can be applied via the ICP1 pin or alternatively, via the analog-comparator unit. The time-stamps can then be used to calculate frequency, duty-cycle, and other features of the signal applied. Alternatively the time-stamps can be used for creating a log of the events.

As you will see, this is not quite as useful as it sounds, but let’s carry on with the data sheet, which goes on to state that:

When a change of the logic level (an event) occurs on the Input Capture pin (ICP1), alternatively on the Analog Comparator output (ACO), and this change confirms to the setting of the edge detector, a capture will be triggered.

When a capture is triggered, the 16-bit value of the counter (TCNT1) is written to the Input Capture Register (ICR1). The Input Capture Flag (ICF1) is set at the same system clock as the TCNT1 value is copied into [the] ICR1 Register.

If enabled (ICIE1 = 1), the Input Capture Flag generates an Input Capture interrupt. The ICF1 Flag is automatically cleared when the interrupt is executed. Alternatively the ICF1 Flag can be cleared by software by writing a logical one to its I/O bit location.

Sounds useful? Maybe! Think about Timer/counter 1. It has a number of prescaler values we can use to slow down its counting frequency, the biggest of these being 1024. The Arduino’s main clock runs at 16 MHz which at full speed will cause Timer/counter 1 to overflow after only 0.004096 second.

So we need to slow it down. The biggest prescaler value for Timer/counter 1 is 1024. Now it overflows every 4.194304 seconds, which is still pretty much unusable as a timestamp, as intimated in the data sheet.

We could use a uint16_t variable in our code to store the timestamp values and increment another uint16_t variable as an overflow counter every time Timer/counter 1 overflows – there’s a handy interrupt that would take care of that – and use the overflow counter as the high 16 bits and the value from ICR1 in the low 16 bits. That would work, no?

Maybe. The 16-bit count of overflows would increment every 4.194304 seconds and can store up to 65,536 of those before it too overflows. That’s a total of 274,877.9069 seconds which works out at 4,581.298449 minutes or 76 hours, 21 minutes, and 17.9069 seconds.

So, as long as all the events you wish to record, and timestamp, arrive within that time span, then having a spare 16-bit counter around to hold the overflow counts should work.

If 76 hours is still too short a time span for all the expected events, would using an unsigned 32-bit variable to hold the overflow count and a separate 16-bit variable to hold the TCNT1 value be any better? How long do we have to record all our events now?

We still overflow every 4.194304 seconds, but we can now accommodate 232 of them. Doing the calculations, I think that works out as follows:
4.194304 Seconds * 2^32
=> 1.8014398e10 seconds
=> 300,239,975.2 minutes
=>   5,003,999.586 hours
=>     208,499.9827 days
=      570 years 307 days.

That should be long enough surely?

I have yet to see any AVR or Arduino code that uses the input capture unit. For further details of using the unit, please refer to the data sheet; however, I can’t leave you in suspense, so Listings 8-20 and 8-21 show a small sketch that demonstrates using the input capture unit.
//========================================================
// This sketch uses the Timer/Counter 1 input capture
// unit to "timestamp" the arrival of a rising edge on
// Arduino pin D8, AVR pin ICP1/PB0, physical pin 14 on
// the ATmega328P.
//========================================================
void setup() {
    // Initialise the LED pin (D13) as OUTPUT and
    // pin D8/PB8/ICP1 as INPUT_PULLUP.
    DDRB = (1 << DDB5);        // D13/PB5 as output.         ①
    PORTB = (1 << PORTB0);     // PB0/ICP1 as input pullup.  ②
    // Initialise the ICU to no scaler, no noise cancel,
    // and rising edge detection.
    TCCR1A = 0;                // Normal mode.               ③
    TCCR1B = ((1 << ICES1) | (1 << CS10));                   ④
    Serial.begin(9600);
}
Listing 8-20

Input capture unit, setup()

  •     ①    This sets all of PORTB as input, with pin PB5, aka D13, aka LED_BUILTIN as output. I’m using the built-in LED as a “flag” to show that something is happening while we wait for an event to happen.

  •     ②    Writing to the PORT pin for an input pin enables the internal pullup resistor. This pin will be held HIGH unless pulled to ground externally.

  •     ③    Timer/counter 1 is in normal mode.

  •     ④    ICES1 enables input capture on a rising edge. CS10 enables full-speed Timer/counter clock based on the system clock.

void loop() {
    // This is a polled wait, so it's inefficient! However
    // this loop() is not doing much else.
    //
    // Wait for ICF1 to be set in TIFR1 then send
    // ICR1 to the serial port. Toggle the built
    // in LED while we wait. (Very quickly!)
    while (!(TIFR1 & (1 << ICF1)))                        ①
        PINB |= (1 << PINB5);
        // Clear the ICF1 bit (no interrupts running you see)
        TIFR1 &= (1 << ICF1);                             ②
        // Grab the timestamp.
        Serial.println(ICR1);                             ③
}
Listing 8-21

Input capture unit, loop()

  • ① Wait here, just toggling the LED, until ICF1 goes HIGH to signal an event. That event copies the TCNT1 value into the ICR1 register while the timer carries on counting. This is a tight loop, and so the LED will appear on all the time, with the odd occasional flicker.

  • ② Because we are not running Input Capture interrupts, we must write a 1binary to the ICF1 bit to clear it for the next event.

  • ③ Grab the event timestamp from ICR1 and write it to the serial port.

Compile and upload the sketch as shown in the preceding text and plug a jumper wire into pin D8 on your Arduino board and plug the other end into the GND location on the header.

Now open the serial monitor, which will reset the board and start the sketch running. Nothing should appear on the monitor window.

Pull the jumper wire out of the GND, the pullup resistor will start to pull the pin HIGH, and the ICU will register that as an event. The LED might flicker, briefly, and a couple of numbers will appear on the monitor output. I got these:
3802
4474

If you see only one number, well done! You managed to not cause any bounce when you removed the jumper wire.

Plug the jumper back into GND again. This will pull the pin LOW, and there should be no more numbers. However, given the slowness of a human being, in contrast with an AVR microcontroller running at 16 MHz, the chances are slim. You will see a few more numbers hitting the serial monitor output. Mine read
60412
60488
17441
19431

Note how the numbers count up and then appear lower, but counting up again? That’s a demonstration of my point about the period available for grabbing all your events and timestamping them.

Oh, by the way, the built-in LED will appear to be always on, but it’s flashing (toggling) every time loop() gets called from main().

Your numbers might be bigger than mine or roll over faster. My test bed for this experiment was a breadboard NormDuino – see Appendix H – running on an internal 8 MHz oscillator, to free up the two pins normally used for the 16 MHz crystal.