What tone() borrows
tone() is cheap on your loop and not free on your board. On an Uno it takes Timer2, so PWM on D3 and D11 stops while a note plays; on an ESP32-S3 it takes one of eight LEDC channels. Both play one tone at a time, and a second call replaces the note on an Uno but queues behind it on an ESP32.
Something has to make the wave
A square wave at 2700 Hz is 5400 edges a second. A loop could make them, and
it would do nothing else, so tone() hands the job to a piece of the chip
that counts time on its own. Which piece depends on the board.
On an Uno: Timer2
The Uno's chip has three timers. tone() uses Timer2 and flips the pin on
its tick, and Timer2 is also what makes analogWrite work on D3 and D11. So
while a note plays, those two pins lose their PWM. It is the same clash the
common IR libraries cause on an Uno, and for the same reason: they want
Timer2 too.
A second tone() call on an Uno replaces the note that is playing, at once.
On an ESP32-S3: an LEDC channel
The ESP32-S3 makes PWM with its LEDC block, which has eight channels.
tone() attaches the pin to one of them, and the other seven stay free for
analogWrite and ledcWrite. Nothing else stops working.
It also works differently inside. Each call is posted to a small task, and a
call with a length plays to its end before the next one starts. So a second
tone() queues behind the first instead of cutting it off, and noTone()
clears whatever is waiting.
One at a time, on both
Neither board plays two tones at once with tone(). On the ESP32, a call for
a second pin while the first is still attached is refused, with an error in
the log. For a chord, or two buzzers, drive each pin with ledcAttach and
ledcWriteTone directly, one channel each.
When it does not work
On an Uno, tone() runs on Timer2, and Timer2 is also what makes the PWM on D3 and D11. While a note plays, analogWrite on those two pins does not work. Move the LED to D5, D6 or D10; D9 is the buzzer in this book.
The common IR libraries also use Timer2 on an Uno by default, so the two fight over it. Some IR libraries can be moved to another timer; otherwise use a board with more timers, such as an ESP32.
tone() drives one pin at a time. Calling it for a second pin while the first still owns it logs an error and does nothing. Call noTone() on the first pin before starting the second, or drive the second with ledcAttach and ledcWriteTone.
Calls with a length are queued and played in order, so a loop that calls tone() faster than its notes last builds up a backlog that plays on. Wait out each note, as the melody sketch does, or call noTone(), which clears the queue.
Symptom first: what the LED and the sound say about where it went wrong.
When it is silent →Edit this page — content/books/passive-buzzer/what-tone-borrows.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Passive Buzzer
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.