Problems with tone on Uno. Hardware issue?

I think this is a Uno hardware issue, not a programming issue, so I posted in this forum.

My understanding was that tone(X, Y) would generate a square wave tone at Y Hz on line X

What I find is that the tone isn't Y Hz and doesn't shift in 1Hz steps:

Examples:

tone (10, 1500) puts a tone of 1504.9 Hz out on line 10
tone (10, 1498) also generates a 1054.9 Hz tone
tone (10, 1497) generates a 1495.9 Hz tone
Values from 1497 to 1488 all generate the same 1495.6 Hz tone
then at tone(10,1487) a 1487.0 tone is generated.

I'm not so worried about the actual frequency that's being generated being slightly off as the fact that the tone doesn't change in ~1Hz steps when the value in the tone function changes by 1. It seems to need to be changed by 10, at least over this short span I'm looking at, and that shifts the frequency by about 10 Hz, not 1Hz.

This isn't what the manual says (or at least implies).

This is the entire program:

void setup() {
}
void loop() {
tone (10, 1482); // 1482 Hz?
}

Is this some hardware limitation of the Arduino? I presume tone uses some sort of internal counter. Am I misreading the manual? I need to generate tones at 1Hz intervals (1500, 1499, 1498 etc.) but apparently I can't do this with "tone". I could do it in software with loops, delays, counters etc., but the manual suggests it can be done with tone.

tone() was for creating audible tones on cheap piezo elements and speakers. The kind that Hz of precision nor frequency accuracy would matter. It's why it is called tone() and not frequency().

This isn't a "hardware issue." It's how the software is implemented to use the hardware.

The way the frequency is generated is by scaling the clock which is driving an 8-bit counter. There's finite resolution available which results in some amount of error.

If you need precision frequency generation, you probably want to look at a clock generator or frequency synthesizer, which could be controlled by the microcontroller.

For the record, mine is just as inaccurate (but functioning correctly) as yours.

Plus a typical arduino uses a ceramic resonator as it's frequency reference - typicaly +/- 3 %.

This is not suitable for precision stuff.

How accurate do you need to be?

Allan

As I said I'm not worried about the exact frequency so much as the step size. I'd assumed from the documentation that the step size was 1Hz, but it isn't. It's more like 9Hz.

They might call it "tone" not "frequency" but when the definition says:

tone(pin, frequency)
frequency: the frequency of the tone in hertz - unsigned int

you'd kind of expect tone(10, 1500) to generate a 1500 Hz signal and tone(10, 1501) to generate a different signal about 1Hz different from the first one. It doesn't. They are the same and around 1505Hz.

I need 1Hz steps. Accuracy is secondary but it would be nice to be within 1 or 2 Hz. If I make 100 1Hz steps I want a 100 Hz frequency change in 100 roughly equal steps.

After some searching I found a "NewTone" (NewTone Library - Plug-in replacement for Tone library - Better, smaller, faster - Libraries - Arduino Forum) library that does things the was that tone should do according to the documentation! The step size dithers around a bit but is close to 1Hz. The frequency dithers a bit too (since the step size dithers) but is always within 0.5Hz of the set frequency, i.e. round(actual frequency) is always equal to the requested frequency.

I suppose could get better precision by generating 8x the frequency I need and then dividing by 8 in hardware. Since I'm working at around 1500Hz, dividing isn't an issue since 8x is only 12000Hz, well inside the audio range. Not sure that the max frequency is that NewTone can handle.- but since it's said to be a replacement for tone it may go to 65535 Hz.

I appreciate that this isn't really a hardware issue. It's an issue of software using hardware in a way which limits accuracy and precision. Not enough bits!