MEGA 2560 Tone conflict width PWM

Hi
I have a problem as i want to have a Tone out of the Arduino MEGA 2560.
It has to go from around 10 HZ to 350 HZ
But it conflits width PWM on PIN 10 and tone on pin 46. (The tone jumps out of control when PWM is turned on and off).

Well then i tryed to change the code in TONE.CPP to use timer "5"

#define USE_TIMER5 //Here i wrote 5 instedt of 2
const uint8_t PROGMEM tone_pin_to_timer_PGM = { 5 /, 3, 4, 5, 1, 0 / }; //Here i wrote 5 instedt of 2

That made it work but it now and then falls out, no tone for around 100 mS (this only happens when i smooth change the tone up and down from 10 to 350 HZ)

Any idea would be greatly appreciated.

Ole

~32Hz is the minimum frequency available from tone.

Hi
Works fine below 32 HZ, as it is a 16 bit timer (but i am not sure i know what i am talking about.)

But the Code below gives the same problem fallout in 100 mS

int X = 0;

void setup() {
}

void loop() {
X = analogRead(14)-300;
if( X < 33 ){ X = 33;}
if( X > 300 ){ X = 300;}
tone(46 , X);
}

sldiesel:
But the Code below gives the same problem fallout in 100 mS

Can you explain what you mean by "fallout in 100 mS"?

Try this...

int X = 0;
Int Xp;

void setup() {
}

void loop() {
  X = analogRead(14)-300;
  if( X < 33 ){ X = 33;}
  if( X > 300 ){ X = 300;}
  if ( X != Xp )
  {
    tone(46 , X);
    Xp = X;
  }
}

Yes there is no activity on the tone pin at all for a short time.
tryed to record it on the shitty small scope :slight_smile:

But it is more easy to see on the speedo i am trying to drive.

Thanks for the help, just tryed you code, No change still no activity for short time :frowning:
But remember i am now using timer5

"This video is private"

Not anymore :wink:

I can reproduce your problem, just trying to work out why. :slight_smile:

You don't know how glad i am to hear that :wink:

I think I know roughly what is going wrong, I can't put my finger on the fix. The timer is a 16-bit timer, so if it happens to overshoot the count (which would tend to happen when the frequency decreases) then it counts all the way up to 65535 before matching. This is confirmed by:

62.5e-9 * 65536 * 64 = 0.262144

So you might expect a gap of around 262 mS if this happens. And indeed I am measuring pauses along those lines.

For example, if it was previously counting up to 500, and it had reached 450, but you change the count to 300, it has already overshot 300, so it counts all the way up to 65535, giving a much longer gap.

So far my attempts to fix it have been spectacularly unsuccessful. Some of the gaps are gone, but the ones that remain blow out to 1.5 seconds! There must be more to this than meets the eye. :slight_smile:

The theory is to do this, while the timer is stopped:

      TCNT5H = 0;
      TCNT5L = 0;

That should reset the counter so it doesn't overshoot.

Vow You are a HERO :wink:
I put them in the Code and run those for every 200 mS,
And it works Great
Thanks ALOT for your help :slight_smile: :slight_smile:

Here's my more general solution. :slight_smile:

Use the hardware timer to output the tone. You'll get a better result anyway, because it isn't affected by jitter from interrupts.

int Hz = 0;
int prevHz;

void setup() 
  {
  pinMode (46, OUTPUT);  // OC5A
  }

void myTone (unsigned int wantedHz)
  {
  // allow for prescaler of 64, and it takes two toggles for one "cycle"
  unsigned int ocr = F_CPU / wantedHz / 64 / 2;
  
  // stop timer
  TCCR5A = 0;
  TCCR5B = 0;
  
  // reset counter
  TCNT5H = 0;
  TCNT5L = 0;
  
  // what to count up to
  OCR5AH = highByte (ocr);
  OCR5AL = lowByte (ocr);
  
  TCCR5A = _BV (COM5A0);             // toggle output pin: OC5A
  TCCR5B = _BV (WGM52) |             // CTC
           _BV (CS50) | _BV (CS51);  // prescaler of 64
    
  }  // end of myTone
  
void loop() 
  {
  Hz = analogRead (14) - 300;
  
  if( Hz < 33 )
    Hz = 33;
  if( Hz > 300 ) 
    Hz = 300;

  if ( abs (Hz - prevHz) > 2 )
    {
    myTone (Hz);
    prevHz = Hz;
    }  // end of frequency change
    
  }  // end ofloop

This doesn't use the Tone library at all. It just manipulates the timer (5) directly, to output the wanted frequency.

Cool i was thinking of using the timer directly, but my programming skills, are not Close to yours :slight_smile:
I will try to test this tomorrow.
Its getting late here on the other side of the Earth.
I will get back width result

I've turned the fiddling around with registers into a library.

http://www.gammon.com.au/Arduino/TonePlayer.zip

Now you can just use that:

#include <TonePlayer.h>

int Hz = 0;
int prevHz;

TonePlayer tone5 (TCCR5A, TCCR5B, OCR5AH, OCR5AL, TCNT5H, TCNT5L);

void setup() 
  {
  pinMode (46, OUTPUT);  // OC5A
  }
 
void loop() 
  {
  Hz = analogRead (14) - 300;
  
  if( Hz < 10 )
    Hz = 33;
  if( Hz > 5000 ) 
    Hz = 5000;

  if ( abs (Hz - prevHz) > 5 )
    {
    tone5.tone (Hz);
    prevHz = Hz;
    }  // end of frequency change
    
  }  // end ofloop

It supports Timers 1, 3, 4, 5. (The Uno only has Timer 1 out of that lot). The comments in the library show how to use the other timers.

Hi I have just implemented that in my code and now have a rock solid TACHO driver.
I think that this tread can be useful for many people. having problem width timers on the Mega

I must say i have newer expected to get that kind of help in a Forum, Thanks alot.

Here is a video of it working

Just wanted to give proof that this is still useful after all those years. It really saved my day, going from 'What the hell?!?!' directly to 'Eureka'! ;-D
Two thumbs up!!!