0

I needed to use TC1 for input capture, but also analogWrite() and an approximate 1 ms interrupt to poll the user interface (encoder, button).

The Arduino Nano's ATmega328p (datasheet, beware: a lot of bit symbol typos) has three timers:

  1. TC0
  2. TC1
  3. TC2

It is not easy to find information on the "Arduino core" structure and it's use of peripherals. The Arduino Reference does not seem to refer to any information. Nor does Arduino Hacking.

Some info can be found on

https://arduino-info.wikispaces.com/Timers-Arduino

but I am not sure it's up to date. For instance, I find disabling TC2 also disables the analogWrite() PWM. Trying to use TC0 results in an error, as TIMER0_OVF_vect is already being used ("multiple definition of `__vector_16'").

How can I use the timers (and their interrupts) that are already used for the core?

  • The overflow vector might be used, but both compare match vectors A and B are free. You can schedule comp interrupt anytime in period so it's not fired at the same time as OVF interrupt. – KIIV Sep 18 '17 at 13:08
  • @KIIV Yes, but the CMs might be used by analogWrite on their respective output pin (the answers explain why). – handle Sep 21 '17 at 7:14
  • Luckily it just changes "when" the interrupt happens. The period will be different once(or twice) after the change. But for polling buttons and encoder it doesn't matter. – KIIV Sep 21 '17 at 7:52
4

Here is a summary of all this. On an ATmega328P (Arduino Uno, Nano, etc.), the Arduino core library uses the timers as follows:

  • Timer 0
    • timing and delay functions, using the TIMER0_OVF interrupt
    • “fast” PWM at 980 Hz on pins 5 and 6 (PD5 and PD6)
  • Timer 1
    • “phase-correct” PWM at 490 Hz on pins 9 and 10 (PB1 and PB2)
  • Timer 2
    • “phase-correct” PWM at 490 Hz on pins 3 and 11 (PD3 and PB3)

All three timers have their prescalers set to 64. TIMER0_OVF is the only timer interrupt enabled by default.

Note that libraries can use the timers for their own purposes. Servo for instance uses Timer 1 for doing interrupt-based PWM.

2

"Reimplementing" the interrupt handlers to free Timer/Counter resources would require changes to the Arduino core firmware. But there may be a workaround:

The source code shows how init() and loop() are used:

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/main.cpp

and the basic timer initialization is here:

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring.c#L45

and init() is there as well, which also configures all the other timers for phase-correct PWM...

analogWrite() is in https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_analog.c

I thought that at just 490/980 Hz it might use software-PWM, but in fact it selects the corresponding timer output compare pin (that also means the CPU can be powered down while the PWM still is being generated).

It does that via a runtime lookup in the board header's digital_pin_to_timer_PGM, e.g. https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/variants/standard/pins_arduino.h

which seems to be a (conditional) list of all pins.

So there is a limited, indirect choice on which timer is being used for PWM:
PD5 and PD6 are served by TC0, so using one of these as analogWrite() output pin frees TC2 for my purposes (~1 kHz polling).

Works for me!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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