Go Down

Topic: Setting up Timer1 causes nothing but pain (Micro). (Read 776 times) previous topic - next topic

cbmeeks

Hello.  I'm new to the whole Arduno scene. 

A while back I bought an Arduino Micro from ADA Fruit. 
http://arduino.cc/en/Main/ArduinoBoardMicro

I've had a lot of fun but I've moved on to working with timers and that's where I run into problems.

I'm trying to build an audio circuit (that will, hopefully, one day go into an Apple IIe). 

I am following the tutorial here:
http://makezine.com/projects/make-35/advanced-arduino-sound-synthesis/

Seems like every tutorial I find assumes I have a different Arduino than the Micro and reference timers or settings that are different.  Anyway...

The tutorial above has the follow section of code:

Code: [Select]

/****Set timer1 for 8-bit fast PWM output ****/
pinMode(9, OUTPUT); // Make timer's PWM pin an output
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);

/******** Set up timer2 to call ISR ********/
TCCR2A = 0; // No options in control register A
TCCR2B = (1 << CS21); // Set prescaler to divide by 8
TIMSK2 = (1 << OCIE2A); // Call ISR when TCNT2 = OCRA2
OCR2A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!


Well, I'm pretty sure that the Micro (or, more accurately, the ATmega32u4) doesn't have Timer2.  But I believe it does have Timer0 and Timer1.

I also assume that Timer0 is 8bit and Timer1 is 16bit.

So, I changed the above code to:

Code: [Select]

/******** Set timer1 for 8-bit fast PWM output ********/
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);

/******** Set up timer0 to call ISR ********/
TCCR0A = 0; // No options in control register A
TCCR0B = (1 << CS01); // Set prescaler to divide by 8
TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0
OCR0A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!



When I try to upload it, everything breaks.  Including the IDE can no longer find the USB port!

I found the following line is the line that breaks everything:

Code: [Select]

TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0


When I comment it out, all is fine and I can upload.  BUT, the timer does not work.  At least not that I can tell.

Here is the code that I have for the ISR:

Code: [Select]

/******** Called every time TCNT1 = OCR1A ********/
ISR(TIMER1_COMPA_vect) { // Called when TCNT1 == OCR1A
static byte index=0; // Points to each table entry
OCR1AL = wave[index++]; // Update the PWM output
// asm("NOP;NOP"); // Fine tuning
TCNT1 = 6; // Timing to compensate for ISR run time
}


I had to comment out the "asm" line because I got an error about "NOP;" not being defined.

But, from what I can tell, that code isn't being called anyway.

So, my questions are:

1)  Where can I go to learn about these timers for the Arduino and MICRO (NOTE, MICRO and/or ATmega32u4) ?  Preferably something that doesn't assume I'm already a 40 year veteran in electrical engineering.  lol

2) Can anyone find what is wrong with the code shown below? 

BTW, I have pin 9 attached to a piezo speaker.  I have confirmed that I can play tones through the circuit when I don't use interrupts but use straight "tone" instead.

Thanks!

Code: [Select]

// Tone.ino

#include <avr/interrupt.h> // Use timer interrupt library
#include <notes.h>

/******** Sine wave parameters ********/
#define PI2 6.283185 // 2*PI saves calculation later
#define AMP 127 // Scaling factor for sine wave
#define OFFSET 128 // Offset shifts wave to all >0 values


/******** Lookup table ********/
#define LENGTH 256 // Length of the wave lookup table
byte wave[LENGTH]; // Storage for waveform

const int TxPin = 8;
const int pwmPin = 9;

int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4
};


int noteDurations[] = {
  4, 8, 8, 4,4,4,4,4
};


void setupTimers() {

/******** Set timer1 for 8-bit fast PWM output ********/
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);

/******** Set up timer0 to call ISR ********/
TCCR0A = 0; // No options in control register A
TCCR0B = (1 << CS01); // Set prescaler to divide by 8
TIMSK0 = (1 << OCIE0A); // Call ISR when TCNT0 = OCRA0
OCR0A = 32; // Set frequency of generated wave
sei(); // Enable interrupts to generate waveform!
}



void setup() {

Serial1.begin(9600);
delay(50);

clear();
backlightOn();

printStr("Ready...");

pinMode(TxPin, OUTPUT);
pinMode(pwmPin, OUTPUT);
delay(50);

/* Populate the waveform table with a sine wave */
for (int i=0; i<LENGTH; i++) { // Step across wave table
float v = (AMP*sin((PI2/LENGTH)*i)); // Compute value
wave[i] = int(v+OFFSET); // Store value as integer
}

for (int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote],noteDuration);

// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(8);
}

setupTimers();

clear();
printStr("Timers");
cr();
printStr("  initialized...");

}


/******** Called every time TCNT1 = OCR1A ********/
ISR(TIMER1_COMPA_vect) { // Called when TCNT1 == OCR1A
static byte index=0; // Points to each table entry
OCR1AL = wave[index++]; // Update the PWM output
// asm("NOP;NOP"); // Fine tuning
TCNT1 = 6; // Timing to compensate for ISR run time
}




void backlightOn() {
Serial1.write(17);
delay(50);
}

void backlightOff() {
Serial1.write(18);
delay(50);
}


void clear() {
Serial1.write(12);
delay(50);
}

void cr() {
Serial1.write(13);
delay(50);
}

void playTone(int duration, int scale, int note) {

duration = constrain(duration, 208, 214);
scale = constrain(scale, 215, 219);
note = constrain(note, 220, 232);

    Serial1.write(scale);
    Serial1.write(note);
    Serial1.write(duration);
    delay(50);
}

void printStr(String str) {
Serial1.print(str);
delay(50);
}

void loop() {

}



Caltoa

TIMER0 is used for the timing of millis().
I don't know if the software serial-over-usb or the bootloader uses TIMER0.
As far as I know, any library that uses TIMER2 can not be used with the Leonardo/Micro.

If you want to do sound synthesis, use a ATmega328p based Arduino.

Go Up