Timer/counter options and functions

This topic is about comparison between timer/counters and their functions.

-What is the meaning of these functions
-how do they relate to each other
-what are limitations between boards
-timer outputs compatibility

Goal is to replace timer/counter2 with timer/counter3 to be compatible with atmega32u4

Micro does not have timer2

Solution :

timer2 is replaced with timer3 but limitation is it has one output Digital pin5 for OC3A

replaced old variable ( prog_uchar ) with new ( const unsigned char )
replaced pin11 with pin5

Functional code with Arduino Micro ATMega32u4 and tested on oscilloscope :

/*
 *
 * DDS Sine Generator on ATMega32u4
 * Timer3 generates the  31250 KHz Clock Interrupt
 * 
 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM const unsigned char sine256[] = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

#define PWM_OUT_1 5 //PWM output pin 5
int ledPin = 13;                 // LED pin 7
int testPin = 7;
int t2Pin = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile byte icnt;              // var inside interrupt
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(PWM_OUT_1, OUTPUT);     // pin5= PWM  output / frequency output

  Setup_timer3();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK3,TOIE3);              // enable Timer3 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz

      cbi (TIMSK3,TOIE3);              // disble Timer3 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK3,TOIE3);              // enable Timer3 Interrupt 

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// timer3 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer3() {

// Timer3 Clock Prescaler to : 1
  sbi (TCCR3B, CS30);
  cbi (TCCR3B, CS31);
  cbi (TCCR3B, CS32);

  // Timer3 PWM Mode set to Phase Correct PWM
  cbi (TCCR3A, COM3A0);  // clear Compare Match
  sbi (TCCR3A, COM3A1);

  sbi (TCCR3A, WGM30);  // Mode 1  / Phase Correct PWM
  cbi (TCCR3A, WGM31);
  cbi (TCCR3B, WGM32);
}

//******************************************************************
// Timer3 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER3_OVF_vect) {

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  OCR3A=pgm_read_byte_near(sine256 + icnt);    

  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
}

sinusoid.ino (4.55 KB)

Please just post the code, don't attach it.
Use code tags.

I copied and pasted your code into the 1.0.5 version of the IDE, with the Mega selected as the device to generate code for. I got only one "error":

Binary sketch size: 6,736 bytes (of a 258,048 byte maximum)

What should be changed to make it work on Arduino Micro

Remove the AtMega328 chip and solder an AtMega2560 chip in its place. The Micro does not have a timer 2.

That means AtMega32u4 can't run with this code.

Correct, because that chip does not have a timer 2. (0, 1, and 3 it does have).

Can Timer2 be replaced with FrequencyTimer2 library ?

You could modify the code to use a different timer. But, it is likely that timer 2 is being used because of its characteristics, which may not be available on any of the (available) timers on the Micro. You'll need to look at the data sheets for the AtMega2560 and for the Micro's chip.

I think you could use a different timer for that pretty easily - it's not using any exotic features, unless the comments are aggressively inaccurate... just phase correct PWM mode with clear timer on compare match, and they're only using it in 8-bit mode, so... yeah. Just about any timer could be used. They probably picked timer2 because on the '328p, it's the least useful of the timers.

They probably picked timer2 because on the '328p, it's the least useful of the timers.

Oh? Timer 0 is used for millis() etc., and they didn't want to hog Timer 1, which is a 16-bit timer, so choosing Timer 2 seems pretty reasonable.

so choosing Timer 2 seems pretty reasonable.

Except that timer 2 is not available on all Arduinos. I'm not familiar with the characteristics of all of the timers for all of the Arduinos. Is there a timer, other than 0 or 1, that has the same characteristics as timer 2, but is available on all Arduinos?

PaulS:
Except that timer 2 is not available on all Arduinos.

There is that, of course.

Is there a timer, other than 0 or 1, that has the same characteristics as timer 2, but is available on all Arduinos?

Well we know the answer to that one. On the Atmega328 it would have to be timer 2. And the Atmega32U4 doesn't have Timer 2.

I imagine some #ifdef's would work around that easily enough.

Well, the 16-bit timers can be used for 8-bit pwm (indeed, that's how they're configured on Arduino by default) - I think the code changes necessary are small.

And yeah, I agree that it made sense for them to pick timer two - that's what I meant by it being the least useful of the timers.

Except that timer 2 is not available on all Arduinos.

KHM 2009

I think timer2 was available on "All Arduinos" at the time the code was written...