Resetting Timers

Hello, I am currently working on a project, and in the portion I am currently working on, a sine wave is generated with a DAC and an interrupt. This portion is not my code, and I was wondering if someone could take a look at this. The problem I am having is that when I try to implement this code elsewhere, after the timer_setup function runs, a lot of features in my project begin to fail. For example, I cannot use the built in tone() function after the timer_setup function is run once. Is there any way i can reset the timer after the code runs for the desired amount of time?

#include <avr/interrupt.h>
#include <stdlib.h>
char sinetable [32];
volatile int myInt;
int  i ;

void ioinit (void)
{
  //Initialize output ports
  PORTD = B11111111;
  DDRD  = B11111111;

}

void timer_setup(){
  TCCR2A = 0;
  TCNT2= 0;    //455 outputs 1.007khz
  TCCR2B = B00000010;
  //Timer2 Overflow Interrupt Enable
  TIMSK2 = 1<<TOIE2;
}

void setup()  {
  ioinit();
  arraysetup();
  cli();
  timer_setup();
  i = 0;
  sei();
}

ISR(TIMER2_OVF_vect) {
  PORTD=(sinetable[i++]);
  TCNT2 = 455;
  if(i==32){
    i=0;
  }
}

void arraysetup(void){
  sinetable[0]=127;  // Put 32 step 8 bit sine table into array.
  sinetable[1]=152;
  sinetable[2]=176;
  sinetable[3]=198;
  sinetable[4]=217;
  sinetable[5]=233;
  sinetable[6]=245;
  sinetable[7]=252;
  sinetable[8]=254;
  sinetable[9]=252;
  sinetable[10]=245;
  sinetable[11]=233;
  sinetable[12]=217;
  sinetable[13]=198;
  sinetable[14]=176;
  sinetable[15]=152;
  sinetable[16]=128;
  sinetable[17]=103;
  sinetable[18]=79;
  sinetable[19]=57;
  sinetable[20]=38;
  sinetable[21]=22;
  sinetable[22]=10;
  sinetable[23]=3;
  sinetable[24]=0;
  sinetable[25]=3;
  sinetable[26]=10;
  sinetable[27]=22;
  sinetable[28]=38;
  sinetable[29]=57;
  sinetable[30]=79;
  sinetable[31]=103;
}
void loop()
{
       
}

timer2 is normally used for tone. Your timer_setup() function reconfigures that timer to generate SPWM, or something like that (I didn't read in depth enough).

You cannot have timer2 doing that and also use it to generate tones at the same time.

DrAzzy:
timer2 is normally used for tone. Your timer_setup() function reconfigures that timer to generate SPWM, or something like that (I didn't read in depth enough).

You cannot have timer2 doing that and also use it to generate tones at the same time.

Would it be possible to reset the timer after it is used to generate the sine wave? If not, do you know how to configure the current code for a different timer? I am not too familiar with interrupt programming, or of the lower level timing structure

Yeah - just back up the values of the relevant registers (TCCR2A, TCCR2B) first, and then set them back to those values afterwards

DrAzzy:
Yeah - just back up the values of the relevant registers (TCCR2A, TCCR2B) first, and then set them back to those values afterwards

Here is what I added to my code, but it still isn't working:

if (state == 0) {
temp_TCCR2A = TCCR2A;
temp_TCCR2B = TCCR2B;
myInt = 420;
timer_setup();
sei();
delay(1000);
cli();
TCCR2A = temp_TCCR2A;
TCCR2B = temp_TCCR2B;
}

The problem I am having is that when I try to implement this code elsewhere, after the timer_setup function runs, a lot of features in my project begin to fail.

What else besides tone() is failing?

Is there any way i can reset the timer after the code runs for the desired amount of time?
Would it be possible to reset the timer after it is used to generate the sine wave?

What do you mean by this?

Do you want to output the 32 values once and then free the timer for use by tone()? How do you want to manage the sine wave output coordinated with the rest of the program?

Are you currently using Timer 1 for anything?

You may be better off posting your complete code.

First off, timer2 is an 8 bit timer so TCNT2 = 455 isn't going to get you anywhere unless 200 is what you really want. If you're trying to get to 455 you need to set TCNT2 to 255, wait for the OVF and then reset to 200.

ISR(TIMER2_OVF_vect) {
PORTD=(sinetable[i++]);
TCNT2 = 455;
if(i==32){
i=0;
}

If you need timer2 for that and still want tones, have a look at

this allows you to instantiate tones with any timer, presumably only for the duration of the tone. I haven't looked at it but I have built many function generators and creating a fixed-frequency tone for a fixed duration is not rocket science.

cattledog:
What else besides tone() is failing?

What do you mean by this?

Do you want to output the 32 values once and then free the timer for use by tone()? How do you want to manage the sine wave output coordinated with the rest of the program?

Are you currently using Timer 1 for anything?

You may be better off posting your complete code.

Once I run the sine wave component once, the square wave component fails, and I also cannot re-run the sine wave component. I was going to try and reset the timers after the sine wave runs for the desired duration, so that they could be used for the square wave.

I am not using timer one for anything right now btw

#include <PS2Keyboard.h>
#include <avr/interrupt.h>
#include <stdlib.h>
PS2Keyboard keyboard;

//Initializing Variables

float frequency = 0.000;
int count;
int position;
const int DataPin = 8;
const int IRQpin =  3;  //Valid irq pins: 2, 3
int lastButtonState = 0;
int buttonState = 0;
int buttonPin;
int state = 1;
byte temp_TCCR2A;
byte temp_TCCR2B;
int outputPin;
int cycles;



//------------------------------- FUNCTIONS FOR INTERRUPT METHOD -----------------------------------------------

char sinetable [32];
volatile int myInt;
int  i ;

void ioinit (void)
{
 //Initialize output ports
 PORTD = B11110111;
 DDRD  = B11110111;
}

void timer_setup(){
 TCCR2A = 0;
 TCCR2B = B00000010;
 TCNT2 = myInt;
 //Timer2 Overflow Interrupt Enable
 TIMSK2 = 1<<TOIE2;
}

ISR(TIMER2_OVF_vect) {
 PORTD=(sinetable[i++]);
 TCNT2 = myInt;
 if(i==32){
   i=0;
 }
}

void arraysetup(void){
 sinetable[0]=127;  // Put 32 step 8 bit sine table into array.
 sinetable[1]=152;
 sinetable[2]=176;
 sinetable[3]=198;
 sinetable[4]=217;
 sinetable[5]=233;
 sinetable[6]=245;
 sinetable[7]=252;
 sinetable[8]=254;
 sinetable[9]=252;
 sinetable[10]=245;
 sinetable[11]=233;
 sinetable[12]=217;
 sinetable[13]=198;
 sinetable[14]=176;
 sinetable[15]=152;
 sinetable[16]=128;
 sinetable[17]=103;
 sinetable[18]=79;
 sinetable[19]=57;
 sinetable[20]=38;
 sinetable[21]=22;
 sinetable[22]=10;
 sinetable[23]=3;
 sinetable[24]=0;
 sinetable[25]=3;
 sinetable[26]=10;
 sinetable[27]=22;
 sinetable[28]=38;
 sinetable[29]=57;
 sinetable[30]=79;
 sinetable[31]=103;
}

//---------------------------------------------------------------------------------------------------


/////////////// FOR GENERATING DIFFERENT FREQUENCIES FOR DIFFERENT INPUT KEYS///////////////////////

//EDIT WHEN ADDING NOTES
const int arysz = 17;
float frequencyArray[] = {261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.25};
char letterArray[] = {'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 'a', 's', 'd', 'f', 'g'};

int searchArray(char c) {
 int i = 0;
 char wantedval = c;
 int wantedpos;
 for (int i=0; i<arysz; i++) {
   if (wantedval == letterArray[i]) {
     wantedpos = i;
     break;
  }
  if (i == 8)  {
   wantedpos = arysz - 1;
  }
}
return wantedpos;
}

void squareTone(int outputPin, float frequency, float duration) {
 cycles = 0;
 while(duration*frequency >= cycles) {
   digitalWrite(outputPin, HIGH);
   delayMicroseconds(1000000/(2*frequency));
   digitalWrite(outputPin, LOW);
   delayMicroseconds(1000000/(2*frequency));
   cycles++;
   }
 
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////


// ***************************************** MAIN CODE ***********************************************
void setup() {
 buttonPin = 10;
 Serial.begin(9600);
 Serial.println("Keyboard Test:");
 arraysetup(); 
 keyboard.begin(DataPin, IRQpin);
 
}
void loop() {
 
// ------------------------------------------ SWITCHING STATE -----------------------------------------
 buttonState = digitalRead(buttonPin);
 if (state == 1) {
   digitalWrite(12, HIGH);
 }
 if(buttonState != lastButtonState)  {
   if(buttonState == HIGH) {
      if (state == 0) {
       //SINE WAVE
       state = 1;
       digitalWrite(12, HIGH);
       myInt = 430;
       ioinit();
       timer_setup();
      }
      else {
       //SQUARE WAVE
       state = 0;
       digitalWrite(12, LOW);
       
      }
   }
   lastButtonState = buttonState;
 }

 //-------------------------------------------------------------------------------------------------------
 
 if (keyboard.available()) {
   
   char c = keyboard.read();   // read the next key
   Serial.print(c);
   

   //////////TONE GENERATION////////////
   
   //Sine Wave (state = 0), light off
   if (state == 0)  {
     temp_TCCR2A = TCCR2A;
     temp_TCCR2B = TCCR2B;
     
     sei();
     delayMicroseconds(1000000);
     cli();
     TCCR2A = temp_TCCR2A;
     TCCR2B = temp_TCCR2B;
     }
   //Square Wave (state = 1), light on
   if (state == 1) {position = searchArray(c);
       frequency = frequencyArray[position];
       squareTone(11, frequency, 0.25);
     }
     
   ////////////////////////////////////  
   } 
 }


 
/*
// check for some of the special keys
   if (c == PS2_ENTER) {
     Serial.println();
   } else if (c == PS2_TAB) {
     Serial.print("[Tab]");
   } else if (c == PS2_ESC) {
     Serial.print("[ESC]");
   } else if (c == PS2_PAGEDOWN) {
     Serial.print("[PgDn]");
   } else if (c == PS2_PAGEUP) {
     Serial.print("[PgUp]");
   } else if (c == PS2_LEFTARROW) {
     Serial.print("[Left]");
   } else if (c == PS2_RIGHTARROW) {
     Serial.print("[Right]");
   } else if (c == PS2_UPARROW) {
     Serial.print("[Up]");
   } else if (c == PS2_DOWNARROW) {
     Serial.print("[Down]");
   } else if (c == PS2_DELETE) {
     Serial.print("[Del]");
   } else {
     Serial.print(c);
     
   } */