Call for testing: tone() and Tone

Some people have reported that tone() is not working on the ATmega8’s and I need some help from those out there that have ATmega8’s.

Those that have some time to test it, try the following:

  1. Using built-in tone():
  • Use toneMelody.pde from the examples in Arduino IDE 0018.
  1. Using the Tone library:
  • Use this modified toneMelody sketch:
/*
  Melody
 
 Plays a melody 
 
 circuit:
 * 8-ohm speaker on digital pin 8

*/

#include <Tone.h>

Tone noteplayer;

// notes in the melody:
int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4,4,4,4,4 };

void setup() {
  noteplayer.begin(8);

  // iterate over the notes of the melody:
  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];
    noteplayer.play(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);
  }
}

void loop() {
  // no need to repeat the melody.
}

Let me know what differences you hear.

b

Hi, I've tested both versions an an ATmega8 board. No differences between 1. and 2., I can only hear and measure a single tone (about 250Hz). Greatings Peter

ok, thanks - I’ll dig around and see what’s going on.

check back here soon, I’ll have some fixes to test on the 'mega8.

b

Ok, I’ve done a second test. Making a tone sweep from 1…10000Hz in 10ms steps.

// Tone Sweep
int x;

void setup() 
{
}

void loop() 
{
  while(x<10000)
  {
    tone(8, x);
    delay(10);
    x++;
  }
}

The result is not a continous increasing of the frequency, it jumps in only 4 steps, depending on the CPU frequency.
With 1MHz internal clock:
30Hz, 60Hz, 240Hz, 1918Hz.

With 3.6864MHz external clock
113Hz, 225Hz, 900Hz, 7200Hz

no steps between. The frequency steps are 2x,4x,8x of the previous frequency. The CPU frequency divided by the following divisors gives the frequency: 16384, 4096, 512.

To be clear, using the 3.6864MHz clock, if you use tone(8, 400), you HEAR a 225 Hz tone?

b

correct, 225 Hz with a 3.6864 MHz clock.

Can you try this sketch and tell me if you also get a 225 Hz tone?

#include <avr/interrupt.h>
#include <pins_arduino.h>

volatile int32_t timer2_toggle_count;
volatile uint8_t *timer2_pin_port;
volatile uint8_t timer2_pin_mask;

#if defined(__AVR_ATmega8__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#endif

#define TONEPIN 8

void tonetest(uint16_t frequency)
{
  uint8_t prescalarbits = 0b001;
  uint32_t ocr = 0;

  ocr = F_CPU / frequency / 2 / 32 - 1;
  prescalarbits = 0b011;

  TCCR2B = prescalarbits;

  OCR2A = ocr;
  timer2_toggle_count = -1;
  bitWrite(TIMSK2, OCIE2A, 1);
}


void setup()
{
  TCCR2A = 0;
  TCCR2B = 0;
  bitWrite(TCCR2A, WGM21, 1);
  bitWrite(TCCR2B, CS20, 1);
  timer2_pin_port = portOutputRegister(digitalPinToPort(TONEPIN));
  timer2_pin_mask = digitalPinToBitMask(TONEPIN);

  tonetest(400);
}

void loop(){/*do nothing*/}

ISR(TIMER2_COMPA_vect)
{
  int32_t temp_toggle_count = timer2_toggle_count;

  if (temp_toggle_count != 0)
  {
    // toggle the pin
    *timer2_pin_port ^= timer2_pin_mask;

    if (temp_toggle_count > 0)
      temp_toggle_count--;
  }
  else
  {
    TIMSK2 = 0;   // disable the interrupt
    *timer2_pin_port &= ~(timer2_pin_mask);  // keep pin low after stop
  }
  
  timer2_toggle_count = temp_toggle_count;
}

b

no tone with this sketch only silence. Pin 8 stays LOW.

Now I get a signal, it is 225Hz like before. Sorry, one cable is broken.

Bingo, success, I have found the bug! I change the tonetest function:

void tonetest(uint16_t frequency)
{
  uint8_t prescalarbits = 0b001;
  uint32_t ocr = 0;

  ocr = F_CPU / frequency / 2 / 32 - 1;
  prescalarbits = 0b011;

  bitWrite(TCCR2B, CS20, 1);
  bitWrite(TCCR2B, CS21, 1);
//  TCCR2B = prescalarbits;

  OCR2A = ocr;
  timer2_toggle_count = -1;
  bitWrite(TIMSK2, OCIE2A, 1);
}

now the ToneTest works. ATMega8 has only a TCCR2 register, TCCR2A and TCCR2B like ATmegha168. The bug is writing the prescalerbits into TCCR2B overwrites other bits. Now lets see if the other examples works too. :)

Great! I figured it was going to be a problem like that.

I'll get the code fixed and post the changes.

Thanks for the help!

b

Sorry, but there is another problem with the tone lib and the ATMega8. Now the sketch gives out the correct frequency, but when the sketch uses the duration parameter of the tone command (like the toneMelody sketch), only the first note is played.

When I change the sketch without using the duration parameter and add a delay command, the sketch works as accepted. Any guess?

Greetings Peter

OK, I’ve found the second bug in the Tone Lib. Call me Mr. Bugkiller :wink:
Now everything is working fine with the ATmega8

Here is a corrected tone.cpp file for replacing the existing lib in Arduino018.

Dear Mr. Bugkiller,

Excellent work. I've submitted the changes to issue 292. Can you test the new Tone library (V0006) as well to verify the changes?

Thanks!

b