You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: esp32/tone.md
+55-15
Original file line number
Diff line number
Diff line change
@@ -87,15 +87,15 @@ void noTone(uint8_t pin)
87
87
{: .fs-1 }
88
88
-->
89
89
90
-
This tone API is simple and well-understood. It's implemented core Arduino, including for AVR-based microcontrollers—[ArduinoCore-avr](https://github.com/arduino/ArduinoCore-avr) ([Tone.cpp](https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Tone.cpp))—and SAMD-based microcontrollers— [ArduinoCore-samd](https://github.com/arduino/ArduinoCore-samd) ([Tone.cpp](https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/Tone.cpp)).
90
+
This tone API is simple and well-understood. It's implemented in core Arduino, including for AVR-based microcontrollers—[ArduinoCore-avr](https://github.com/arduino/ArduinoCore-avr) ([Tone.cpp](https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Tone.cpp))—and SAMD-based microcontrollers— [ArduinoCore-samd](https://github.com/arduino/ArduinoCore-samd) ([Tone.cpp](https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/Tone.cpp)). When using Arduino, we expect [`tone()`](https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/) to be available!
91
91
92
-
To generate the PWM waveforms and to track play tone duration, the tone library uses hardware timers. However, these hardware timers and the functionality therein differs widely depending on microcontroller chip. The Atmel AVR microcontrollers like the [ATmega328](https://www.microchip.com/wwwproducts/en/ATmega328) used on the Arduino Uno and [ATmega32u4](https://www.microchip.com/wwwproducts/en/atmega32u4) handle them one way while the Atmel [SAMD21 microcontrollers](https://www.seeedstudio.com/blog/2020/01/09/samd21-arduino-boards-which-one-should-you-use/) handle them another. Even for just AVR-based microcontrollers, there is a lot of nuance and differences—see the `#ifdef` in [Tone.cpp](https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Tone.cpp) for [ArduinoCore-avr](https://github.com/arduino/ArduinoCore-avr).
92
+
To generate the PWM waveforms and to track play tone duration, the tone library uses hardware timers (aka timer interrupts). However, these hardware timers and the functionality therein differs widely depending on microcontroller chip. The Atmel AVR microcontrollers like the [ATmega328](https://www.microchip.com/wwwproducts/en/ATmega328) used on the Arduino Uno and [ATmega32u4](https://www.microchip.com/wwwproducts/en/atmega32u4) used on the Arduino Leonardo handle them one way while the Atmel [SAMD21 microcontrollers](https://www.seeedstudio.com/blog/2020/01/09/samd21-arduino-boards-which-one-should-you-use/) handle them another. Even for just AVR-based microcontrollers, there is a lot of nuance and differences—see the `#ifdef` in [Tone.cpp](https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Tone.cpp) for [ArduinoCore-avr](https://github.com/arduino/ArduinoCore-avr).
93
93
94
-
And, most relevantly for us, Expressif decided **not** to implement tone into [arduino-esp32](https://github.com/espressif/arduino-esp32). So, what can we do?
94
+
Most relevantly for us, Expressif decided **not** to implement `tone()` into [arduino-esp32](https://github.com/espressif/arduino-esp32). While we're not sure why, what can we do about it?
95
95
96
96
## Playing tones on ESP32
97
97
98
-
Even though [`tone()`](https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/) is not available on the ESP32, things are not as dire as they seem. As Thomas Countz points out on [GitHub Issue #1720](https://github.com/espressif/arduino-esp32/issues/1720#issuecomment-782876308), the [LEDC PWM library](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.c)—which we used in our [ESP32 LED Fade lesson](led-fade.md)—actually has tone related methods, including:
98
+
Fear not, things are not as dire as they seem. As Thomas Countz points out on [GitHub Issue #1720](https://github.com/espressif/arduino-esp32/issues/1720#issuecomment-782876308), the [LEDC PWM library](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.c)—which we used in our [ESP32 LED Fade lesson](led-fade.md)—actually has tone related methods, including:
99
99
100
100
{% highlight C %}
101
101
double ledcWriteTone(uint8_t chan, double freq)
@@ -114,9 +114,21 @@ typedef enum {
114
114
**Code.** See [esp32-hal-ledc.h](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.h) and [esp32-hal-ledc.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.c) from the [arduino-esp32 repo](https://github.com/espressif/arduino-esp32).
115
115
{: .fs-1 }
116
116
117
-
To use either `ledcWriteTone` and `ledcWriteNote`, we can follow a similar approach to what we did for fading an LED.
117
+
To use either `ledcWriteTone` and `ledcWriteNote`, we can follow a similar approach to what we did for fading an LED. First, let's build our circuit.
118
118
119
-
First, we need to "attach" our piezo buzzer pin to one of the 16 PWM channels available on the ESP32 using the `ledcAttachPin` function. In this case, we'll use Pin 26 and PWM channel 0.
119
+
### Example circuit
120
+
121
+
Our circuit is as simple as they come. Simply attach your piezo buzzer to a GPIO pin. In this case, we're using GPIO Pin 26. In our courses, we often use the [TDK PS1240 ](https://product.tdk.com/system/files/dam/doc/product/sw_piezo/sw_piezo/piezo-buzzer/catalog/piezoelectronic_buzzer_ps_en.pdf) piezo buzzers (about $0.46 [Mouser](https://www.mouser.com/ProductDetail/810-PS1240P02BT) or $1.35 at [Adafruit](https://www.adafruit.com/product/160)). These buzzers work with both 3V and 5V square waves. Their resonant frequency (loudest tone) is 4kHz but you can drive them with a far larger range (we've tested from 32Hz up to 10Khz, at which point the sound is ear piercing). As non-polarized devices, they can be connected in either orientation (like resistors).
**Figure.** Circuit diagram to hook up [PS1240](https://www.adafruit.com/product/160) piezo buzzer with the ESP32. We've wired the buzzer to GPIO Pin 26. Image made in Fritzing and PowerPoint.
125
+
{: .fs-1 }
126
+
127
+
### Example code
128
+
129
+
Now, let's write the code.
130
+
131
+
First, we need to "attach" our piezo buzzer pin to one of the 16 PWM channels available on the ESP32 using the `ledcAttachPin` function. In this case, we'll use Pin 26 and PWM channel 0. Recall that the ESP32 has 16 PWM channels (0-15) and each can be configured independently to drive different PWM waveforms. In software, we "attach" pins to these PWM channels to receive the waveform.
120
132
121
133
{% highlight C %}
122
134
// Change this depending on where you put your piezo buzzer
@@ -132,7 +144,9 @@ void setup() {
132
144
}
133
145
{% endhighlight C %}
134
146
135
-
And then we can simply play a note (using `ledcWriteNote`) or frequency (using `ledcWriteTone`). For example, the code below loops through playing middle C using `ledcWriteNote` and then the frequency 800 Hz using `ledcWriteTone` with 500ms pauses in between.
147
+
Great, now we've attached Pin 26 on PWM channel 0.
148
+
149
+
Now, we can simply play a note using `ledcWriteNote` or raw frequency using `ledcWriteTone`. For example, the code below loops through playing middle C using `ledcWriteNote` and then the frequency 800 Hz using `ledcWriteTone` with 500ms pauses in between.
136
150
137
151
{% highlight C %}
138
152
void loop() {
@@ -144,7 +158,7 @@ void loop() {
144
158
}
145
159
{% endhighlight C %}
146
160
147
-
That's it!
161
+
That's it!
148
162
149
163
Now, those with a keen eye may have noticed that there are no functions that take in a `duration` parameter. Yes, this is a small problem. Yes, we will address this!
150
164
@@ -184,13 +198,12 @@ Let's get making!
184
198
185
199
## Let's make stuff
186
200
187
-
In the activities below, we are going to first play a scale and various raw frequencies before introducing the Tone32.hpp class, which helps abstract some complexity. Though we try to embed mp4 videos directly into our lessons, we are going to be using YouTube embeds here instead so you can more easily control the sound. So, make sure you have your sound on (and possibly wear headphones, to limit annoyance to others around you).
201
+
In the activities below, we are going to first play a scale and various raw frequencies before introducing the Tone32.hpp class, which helps abstract some complexity. Generally, we try to embed mp4 videos directly into our lessons. To more easily control playback and sound, we are going to be using YouTube embeds here. So, make sure you have your sound on (and possibly wear headphones, to limit annoyance to others around you).
188
202
189
-
<!-- TODO: add in circuit diagrams of everything here -->
190
203
191
204
### Playing the C scale
192
205
193
-
First, let's play a simple C major scale based on Thomas Countz's comment on [GitHub Issue 1720](https://github.com/Thomascountz). While we could use an array to step through notes, let's keep things super simple and just write out each note directly. The full code is:
206
+
Using the same circuit as before, let's write code to play a simple C major scale based on Thomas Countz's comment on [GitHub Issue 1720](https://github.com/Thomascountz). While we could use an array to step through notes, let's keep things super simple and just write out each note directly. The full code is:
194
207
195
208
{% highlight C %}
196
209
// Change this depending on where you put your piezo buzzer
@@ -233,7 +246,19 @@ And a video demo below:
233
246
234
247
### Reading analog input, outputting raw frequencies
235
248
236
-
OK, now let's make a slightly more complicated version that reads in an analog input and translates this value into an output frequency. In our demo video below, we are using a potentiometer.
249
+
OK, now let's make a slightly more complicated version that reads in an analog input and translates this value into an output frequency. For our demo, we are using a potentiometer. But, of course, any analog input would work!
250
+
251
+
#### Build the circuit
252
+
253
+
We need to slightly modify our circuit by adding a potentiometer—in this case, a 10K potentiometer.
**Figure.** Circuit diagram of Huzzah32 with piezo buzzer and potentiometer. Image made in Fritzing and PowerPoint.
257
+
{: .fs-1 }
258
+
259
+
#### Write the code
260
+
261
+
Now, let's write code to take in the analog input and use this to set the frequency of the PWM output waveform.
237
262
238
263
{% highlight C %}
239
264
// Change this depending on where you put your piezo buzzer
@@ -285,7 +310,7 @@ There are a few key differences with: [`tone()`](https://www.arduino.cc/referenc
285
310
286
311
- First, we use an object-oriented approach. To create a Tone32 object, simply call `Tone32 tone32(pin, pwmChannel)`, which creates a Tone32 object with the given output pin and PWM channel.
287
312
288
-
- Second, while [`tone()`](https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/) uses timer interrupts to track play durations—and automatically stops playing after a duration has expired—we use a "polling" approach. So, you must call `update()` on each `loop()`. This is essential if you are using the duration parameters.
313
+
- Second, while [`tone()`](https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/) uses timer interrupts to track play durations—and automatically stops playing after a duration has expired—we use a "polling" approach. So, you must call `update()` on each `loop()`. This is essential if you are using the duration parameters. Note: I encourage others to adapt Tone32 to use timer interrupts but polling is fine for our purposes (as long as you consistently call update() with limited time between calls)
289
314
290
315
- Third, unlike [`tone()`](https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/), you play tones via either `playNote` or `playTone`, both of which are overloaded functions with `duration` options.
291
316
@@ -383,7 +408,7 @@ Let's try building some stuff with [Tone32.hpp](https://github.com/makeabilityla
383
408
384
409
#### Demonstrating Tone32 tone durations
385
410
386
-
To demonstrate using durations, we wrote [AnalogInputTone32.ino](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/AnalogInputTone32/AnalogInputTone32.ino), which walks up and down the C scale using an analog input (we used a potentiometer). When you "land" on a new note, we play the note's frequency for 500 ms.
411
+
To demonstrate using durations, we wrote [AnalogInputTone32.ino](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/AnalogInputTone32/AnalogInputTone32.ino), which walks up and down the C scale using an analog input (we used a potentiometer). When you "land" on a new note, we play the note's frequency for 500 ms. We will use the same piezo buzzer + potentiometer circuit as before but with new code.
387
412
388
413
Here's the whole code:
389
414
@@ -412,6 +437,7 @@ const int PLAY_NOTE_DURATION_MS = 500;
412
437
// The ESP32 has a 12-bit ADC, so our max analog value is 4095
Here's a video demonstrationof [AnalogInputTone32.ino](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/AnalogInputTone32/AnalogInputTone32.ino):
472
+
Here's a video demonstration. Notice how we're displaying the `duration` remaining for each tone on the OLED—this is to help highlight the duration functionality of the [Tone32.hpp](https://github.com/makeabilitylab/arduino/blob/master/MakeabilityLab_Arduino_Library/src/Tone32.hpp) library.
447
473
448
474
<iframewidth="736"height="414"src="https://www.youtube.com/embed/zFg1fSFGL7o"title="YouTube video player"frameborder="0"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"allowfullscreen></iframe>
449
475
**Video.** A video demonstrating [AnalogInputTone32](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/AnalogInputTone32/AnalogInputTone32.ino). Note that this video is running a slight variation with OLED output called [AnalogInputTone32WithOLED.ino](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/AnalogInputTone32WithOLED/AnalogInputTone32WithOLED.ino). Make sure your sound is on.
450
476
{: .fs-1 }
451
477
478
+
#### Bonus Ball Bounce Video
479
+
480
+
Finally, we've included a bonus [simple ball bounce demo](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/BallBounceTone32WithOLED/BallBounceTone32WithOLED.ino) using the Tone32.hpp library, again highlighting the play `duration` functionality. Here, we play a brief tone when the ball bounces off the floor or ceiling.
481
+
482
+
<iframewidth="736"height="414"src="https://www.youtube.com/embed/cy7Jeri7vOA"title="YouTube video player"frameborder="0"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"allowfullscreen></iframe>
483
+
**Video.** A video demonstrating [BallBounceTone32WithOLED.ino](https://github.com/makeabilitylab/arduino/blob/master/ESP32/Tone/BallBounceTone32WithOLED/BallBounceTone32WithOLED.ino). Make sure your sound is on.
484
+
{: .fs-1 }
485
+
486
+
## Resources
487
+
488
+
-[Tone was Not Declared in this Scope](https://github.com/espressif/arduino-esp32/issues/1720), arduino-esp32 GitHub Issue #1720
489
+
490
+
-[Arduino Tone for ESP32](https://www.thomascountz.com/2021/02/21/arduino-tone-for-esp32), Thomas Countz
491
+
452
492
## Next Lesson
453
493
454
494
In the [next lesson](capacitive-touch-sensing.md), we will learn about and use the ESP32's built-in capacitive touch sensing module.
0 commit comments