Author Topic: tone function  (Read 5587 times)

billprozac

  • Newbie
  • *
  • Posts: 2
tone function
« on: December 29, 2013, 12:39:50 pm »
I have a project that needs to generate a ~130kHz square wave and noticed the wonderful tone() function would do it.  It looks, however, that there is some issue and I was wondering if anyone else has used it.
What I am seeing are two issues, and I think they are related to the library casting the frequency as 16bit unsigned int.  The odd thing is the way the device acts with the larger data values.
These all assume a large frequency (above 65535, although I am doing everything with ~130000)
1. If the duration value is used, it has no effect on timing, but it seems to reduce the amplitude of the wave.  I don't have a oscope, but I am using this with a piezo transducer and water and the result is a "very weak mist".  I suspect that the value passed is causing a crash somewhere that leaves the tone playing.  For odd.

2. Even if I remove the duration and use a subsequent delay and noTone(), the mist is very weak unless the tone function call is immediately followed by an analogWrite() to some other pin.  I use pin1 for my tone and 0 as the analogWrite call.  Not sure what about that write changes anything on pin1, but it does.

For example:
Code: [Select]
void loop(){
  tone(1,130000,1500);
  delay(10000);
  noTone(1);
}
This should "play" the tone for 1.5s, then sleep for an additional 8.5s and then repeat.  It doesn't.  It emits a weak, but continuous stream of mist.

Code: [Select]
void loop(){
  tone(1,130000);
  delay(1500);
  noTone(1);
  delay(8500);
}
This should "play" the tone for 1.5s, then sleep for an additional 8.5s and then repeat.  It does, sort of.  It emits a weak mist for 1.5s and then sleeps and repeats as expected.

Code: [Select]
void loop(){
  tone(1,130000);
  analogWrite(0,64);
  delay(1500);
  noTone(1);
  delay(8500);
}
This should "play" the tone for 1.5s, then sleep for an additional 8.5s and then repeat.  It does, I just don't understand why.

FYI, for playing lower frequencies, ie. audible tones, all behaviors are as expected.  Any thoughts?

dougal

  • Sr. Member
  • ****
  • Posts: 289
Re: tone function
« Reply #1 on: December 29, 2013, 02:35:12 pm »
According to the documentation for the tone() function, as you noted, it uses an unsigned int for the frequency parameter. But an unsigned int is 16 bits, so only holds values 0 - 65535. To handle higher frequencies, I think you're going to need to use something else.

There is also a Tone library, but in the notes for that, it says:

Quote
After all is said and done, because play() only accepts unsigned integers for frequency, the maximum frequency that can be produced is 65535 Hz - which, after rounding, results in a 65573.77 Hz "tone" on a 16 MHz part. Even if play accepted larger values for frequency, you couldn't achieve better than around 80KHz with the Tone library because the pin toggling is done in software. Each toggle, in software, requires AT LEAST 50+ cycles.

I think you'll have to look into the hardware PWM to get higher frequencies.

Bluebie

  • Sr. Member
  • ****
  • Posts: 486
Re: tone function
« Reply #2 on: December 29, 2013, 03:31:41 pm »
You're making an ultrasonic mist generator with a digispark? This is very interesting to me!

billprozac

  • Newbie
  • *
  • Posts: 2
Re: tone function
« Reply #3 on: January 14, 2014, 08:58:17 pm »
Ok, I am sorry I let this stew so long, but I have been trying to troubleshoot this and finally got all the stuff to do it (got an xprotolab oscope).  Check this out, using the code posted above (ie. following the call to tone with an analogwrite to 0 (pin 5), I am getting an ACTUAL ~130kHz wave. (attached image) The really funny thing is that I am using the code below:
Code: [Select]
void playNote(unsigned int freq, unsigned int duration){
    tone(1, freq);
    analogWrite(0, 64);
    delay(duration);
    noTone(1);
}

playNote(34000, 10000);

So I am asking for a 34kHz wave and getting a full 130kHz.  I am not sure if this is actually a bug or something, but it is quite weird.  I am going to play around with other values and see where it breaks and what the wave looks like without the aWrite. 

On a side note, related to my project, I have almost everything as I want it, but I am way out of program space.  The USB libs take up a tone and when I add in libs for TinyWire et al, I am way over budget.  Is there any way to increase program space?  EEPROM?  Very little space is consumed by statics (I even pared down my LCD font to the bare minimum).  If not I am gonna have to step up to a micro or mini just for the space :(

digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: tone function
« Reply #4 on: January 14, 2014, 09:27:01 pm »
Regarding space: you can't use an EEPROM, but you can use the LittleWire firmware on the Digispark and have the attached computer do the heavy lifting, or you can wait for the Digispark Pro which will be on Kickstarter in the next month, which will have 16k of program space. Or as you said, you can grab a micro, mini, etc.