Arduino et Timer

Timers

  • Timer0 used for the timer functions, like delay(), millis() and micros(). If you change timer0 registers, this may influence the Arduino timer function. So you should know what you are doing.
  • Timer1: the Servo library uses timer1 on Arduino Uno (timer5 on Arduino Mega).
  • Timer2: the tone() function uses timer2.

Pins

Arduino UNO :

  • Timer 0 : pins 5 et 6 : 976.5625 Hz (8 bits > 256 values)
  • Timer 1 : pins 9 et 10 : 490.20 Hz (16 bits > 65536 values)
  • Timer 2 : pins 3 et 11 : 490.20 Hz (8 bits)

timer_and_counter_pins.jpg

Arduino MEGA :

  • Timer 0 : pins 4 et 13
  • Timer 1 : pins 11 et 12
  • Timer 2 : pins 9 et 10
  • Timer 3 : pins 2, 3 et 5 (16 bits)
  • Timer 4 : pins 6, 7 et 8 (16 bits)
  • Timer 5 : pins 46, 45 et 44 (16 bits)

Sur une Mega, chaque Tone simultané utilisera les timers dans cet ordre : 2, 3, 4, 5, 1, 0 (source)

Arduino Leonardo (no Timer 2!) : http://provideyourown.com/2012/arduino-leonardo-versus-uno-whats-new/ The Leonardo has 7 PWM pins instead of 6. ATmega32U4 also has a new timer, timer4 which has 10 bits and uses a PLL to count at 64MHz. Their mappings are different as well:

  • Timer 0 : pins 3 et 11 : 8 bits
  • Timer 1 : pins 5, 9, 10 : 16 bits
  • Timer 2 : no
  • Timer 3 : pins 5, 9, 10 : 16 bits
  • Timer 4 : pins 6, 13 (10 bits)

Tone et Leonardo problem :https://code.google.com/p/rogue-code/issues/detail?id=13

PWM Frequency

TCCR0B = TCCR0B & 0b11111000 | <setting>; //Timer 0 (PWM pins 5 & 6)
TCCR1B = TCCR1B & 0b11111000 | <setting>; //Timer 1 (PWM pins 9 & 10)
TCCR2B = TCCR2B & 0b11111000 | <setting>; //Timer 2 (PWM pins 3 & 11)
setting 5 & 6 3,11 & 9,10
0x01 62500 31250
0x02 7812 3906
0x03 976 488
0x04 244 122
0x05 61 30

Tone

When you use analogOut() to create pulsewidth modulation (PWM) on an output pin, you can change the on-off ratio of the output (also known as the duty cycle) but not the frequency. If you have a speaker connected to an output pin running analogOut(), you'll get a changing loudness, but a constant tone. To change the tone, you need to change the frequency. The tone() command does this for you.

tone() function uses at least timer2. You can’t use PWM on Pin 3,11 when you use the tone() function an Arduino and Pin 9,10 on Arduino Mega.

If you used a 16 bit timer (e.g. timer 1, or timers 3,4,5 on '1280), you could generate “tones” down to 1/8 Hz (one cycle every 8 seconds), although the library only accepts integers for frequency.

After all is said and done, because play() only accepts unsigned integers for frequency, the maximum frequency that can be produced is 65535 Hz - which, after rounding, results in a 65573.77 Hz “tone” on a 16 MHz part. Even if play accepted larger values for frequency, you couldn't achieve better than around 80KHz with the Tone library because the pin toggling is done in software. Each toggle, in software, requires AT LEAST 50+ cycles.

PWM

Chaque Timer controle deux sorties PWM.

Since all PWM channels, via the same timer, share the same waveform generator then the only thing that dfferentiates each channel is the 'comparator' value. All timers have associated with them three registers, TOP, BOTTOM and MAX

Par exemple, : analogWrite(pin, 128); Outputs a square wave

is compared against the value in an 8-bit counter. When the counter is less than the PWM value, the pin outputs a HIGH; when the counter is greater than the PWM value, the pin outputs a LOW. In the example above, a square wave is generate because the pin is HIGH from counts 0 to 127, and LOW from counts 128 to 255, so it is HIGH for the same amount of time it is LOW.

C'est pourquoi on ne peut dépasser 255 !

Modes

  • Normal
  • PWM, Phase Correct
  • Fast PWM (ATMega328P datasheet p152-153)
  • CTC (Clear Timer on Compare Match)

Fast PWM

This is useful in many power regulating circuits, or in circuits where small inductive or capacitive components are used. Atmega328 microcontroller is able to generate two types of fast PWM. In one mode Counter counts from 0 to 255 and in second mode counter counts from 0 to value stored in OCR0A.

Registres

  • TCCRx - Timer/Counter Control Register. The prescaler can be configured here.
  • TCNTx - Timer/Counter Register. The actual timer value is stored here.
  • OCRx - Output Compare Register
  • ICRx - Input Capture Register (only for 16bit timer)
  • TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts.
  • TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt

The Timer/Counter Control Registers hold several bit groups. These are:

  • WGM - Waveform Generation Mode bits
  • CS - Clock Select bits
  • COMnA & COMnB - Compare Match Output bits

Prescaler

system clock is 16MHz Il s’agit en fait de diviser l’horloge du timer : il s’agit de l’horloge des entrées/sorties (ou I/O clock) et pas de l’horloge système qui est à la fréquence du quartz, soit 16 MHz.

For pins 6 and 5 (OC0A and OC0B): For pins 9, 10, 11 and 3 (OC1A, OC1B, OC2A, OC2B):

TCCR2B = TCCR2B & 0b11111000 | 0x01 ;

Période minimale : 1 / 16 000 000 = 0,000000062 = 6,2 ns

Target Timer Count = (Input Frequency / (Prescaler * Target Frequency)) - 1

Target Timer Count = (16000000 / 1) -1

Those familiar with C will know that an unsigned eight bit value can store a value from 0 to 28 − 1, or 255, before running out of bits to use and becoming zero again. Similarly, an unsigned 16 bit value may store a value from 0 to 216 − 1, or 65535 before doing the same.

Exemple : 20Khz

// Réglage de la fréquence PWM du Timer 1
// vu sur : https://github.com/pololu/zumo-shield/blob/master/ZumoMotors/ZumoMotors.cpp
 
int mypwm = 200; // réglage de test avec max = 400 ici
 
void setup() {
  // PWM frequency calculation
  // 16MHz / 1 (prescaler) / 2 (phase-correct) / 400 (top) = 20kHz
  TCCR1A = 0b10100000;
  TCCR1B = 0b00010001;
  ICR1 = 400; // max
}
 
void loop() {
  OCR1B = mypwm; // 0-400
}

Interruptions

The program running on a controller is normally running sequentially instruction by instruction. An interrupt is an external event that interrupts the running program and runs a special interrupt service routine (ISR). After the ISR has been finished, the running program is continued with the next instruction. Instruction means a single machine instruction, not a line of C or C++ code.

Before a pending interrupt will be able to call a ISR the following conditions must be true:

  Interrupts must be generally enabled
  the according Interrupt mask must be enabled

Interrupts can generally (globally) enabled / disabled with the function interrupts() / noInterrupts(). By default in the Arduino firmware interrupts are enabled. Interrupt masks are enabled / disabled by setting / clearing bits in the Interrupt mask register (TIMSKx).

When an interrupt occurs, a flag in the interrupt flag register (TIFRx) is been set. This interrupt will be automatically cleared when entering the ISR or by manually clearing the bit in the interrupt flag register.

The Arduino functions attachInterrupt() and detachInterrupt() can only be used for external interrupt pins. These are different interrupt sources, not discussed here.

Liens