Skip to content

tone() causes division by zero and gets stuck in infinite loop if frequency is 0 #519

Closed
@adriaanb

Description

@adriaanb

General description

On AVR chips, the tone() function allowed for the introduction of pauses by using a frequency of 0 (see toneMelody.ino example). While this leads to a division by 0 both in the AVR and SAMD implementations of that function, the SAMD platform appears to handle divisions by 0 differently. This causes the sketch to crash.

Expected behavior

The frequency of 0 should result in silence/produce a pause.

Actual behavior

Calling the tone() function with a frequency of 0 results in a crash.

Steps to reproduce

Run the toneMelody.ino example or any other sketch resulting in passing frequency 0 to the tone() function.

Additional information

Adafruit solves this by substituting a frequency of 1 for every instance 0 is passed, see Adafruit's version of ArduinoCore-samd Tone.cpp:

 //if it's a rest, set to 1Hz (below audio range)
 frequency = (frequency > 0 ? frequency : 1); 

This, however, only works for tones shorter than ~500 milliseconds. If the tone duration is longer than that, the sketch produces a high-pitched whine. Using libraries that rely on or interfere with timer interrupts (such as FastLED or the Servo library) can cause additional audio glitches if a frequency of 1 is being used.

Tested on Arduino Nano 33 IoT and Adafruit Metro M0 Express.

Workarounds

Choosing a frequency above, instead of below the audible range, seems to produce more reliable results. 30000 appears to be a number that causes the least noticeable audible artifacts, based on very rudimentary testing.

A better solution, however, is to use noTone() to introduce a pause.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions