PWM-Based Audio Generation with ESP32: A Simple Guide to Sound Creation

PWM-based audio generation is a straightforward and efficient way to create sound using the ESP32 microcontroller. By manipulating the duty cycle of a PWM signal, you can generate a wide variety of audio tones without needing external audio hardware. This makes PWM-based audio generation a great solution for projects that require sound output but don’t have the resources for more complex audio systems.

In this article, we will walk you through how to use PWM to generate sound on the ESP32. We’ll cover setting up PWM, generating different tones, and controlling volume, all using MicroPython.


Table of Contents


Components Needed

Close-up image of a piezo buzzer with pins labeled for connection.
A piezo buzzer with clearly labeled pins for easy connection to an ESP32.
  • ESP32 Development Board: The microcontroller that will generate the PWM signals.
  • Buzzer or Small Speaker: To produce sound based on the PWM signals. A simple piezo buzzer will work well for basic audio output.
  • Resistor (optional): A 100-ohm resistor to limit current for the buzzer (optional, depending on your buzzer’s rating).
  • Breadboard and Jumper Wires: For connecting the components together.
  • Power Supply: The ESP32 typically operates at 3.3V, but for higher volume, you may need a 5V power supply for the speaker.

Circuit Pinout and Wiring Diagram

Here’s a simple table for the pinout and connections:

ESP32 development board with a piezo buzzer connected to pin 18 for PWM-based audio generation.
The ESP32 development board with a piezo buzzer attached to pin 18 for sound generation using PWM.
ComponentESP32 PinNotes
Buzzer/ SpeakerGPIO 18Connect the positive terminal to GPIO 18, and the negative terminal to GND.
Resistor (optional)Place the resistor in series with the buzzer to limit current if necessary.

Wiring Diagram:

  • Step 1: Connect the positive terminal of the buzzer to GPIO 25 (or any other available PWM-capable pin on the ESP32).
  • Step 2: Connect the negative terminal of the buzzer to the GND pin on the ESP32.
  • Step 3: (Optional) Use a 100-ohm resistor in series with the buzzer to prevent excessive current draw, especially if using a larger speaker.

Note: While the ESP32 operates at 3.3V, you can use a 5V supply for the speaker if you need a higher volume output. In such cases, ensure that the speaker can handle 5V, or use an appropriate amplifier circuit.


Setting Up PWM on ESP32

Before we dive into PWM-based audio generation, let’s first understand how to set up PWM on the ESP32. A PWM signal is essentially a square wave, and by varying its duty cycle, we can control the sound’s volume and frequency. Here’s how you can set up PWM on an ESP32 to generate sound:

from machine import Pin, PWM
import time

# Set up PWM on pin 18
pwm = PWM(Pin(18), freq=1000, duty=512)  # 1 kHz frequency, 50% duty cycle

# Play sound for 1 second
time.sleep(1)

# Stop the sound
pwm.deinit()

This code initializes PWM on pin 25 with a frequency of 1000 Hz, producing a mid-range tone, and a 50% duty cycle to control the volume. The pwm.deinit() method stops the sound after 1 second.


Generating Different Tones

PWM-based audio generation allows you to change the pitch of the sound by adjusting the PWM frequency. The higher the frequency, the higher the pitch. Here’s how you can generate a sequence of tones using different frequencies:

def play_tone(frequency, duration):
    pwm.freq(frequency)
    time.sleep(duration)
    pwm.deinit()

# Set up the PWM signal
pwm = PWM(Pin(18), duty=512)

# Play different tones
play_tone(262, 0.5)  # Middle C
play_tone(294, 0.5)  # D
play_tone(330, 0.5)  # E
play_tone(349, 0.5)  # F
play_tone(392, 0.5)  # G

By adjusting the frequency in the play_tone function, you can produce a variety of notes using PWM-based audio generation on your ESP32.


Controlling Volume with Duty Cycle

The duty cycle of a PWM signal not only controls the frequency but also the volume of the sound produced. A higher duty cycle results in a louder sound, while a lower duty cycle makes the sound quieter. You can use this feature to modify the volume of your audio output.

# Adjust volume with duty cycle
def set_volume(volume):
    pwm.duty(volume)

# Set up the PWM signal
pwm = PWM(Pin(18), freq=1000)

# Play a tone at different volumes
for volume in [1024, 512, 256, 128]:
    set_volume(volume)
    play_tone(440, 1)  # A4 note at different volumes

In this example, we change the duty cycle to control the volume and play the same tone at different loudness levels.


Practical Uses of PWM-Based Audio Generation

PWM-based audio generation is a versatile tool for various applications, especially in embedded systems and IoT projects. Some practical uses include:

  1. Simple Alerts and Alarms: Use PWM to generate alert sounds for notifications or warnings in IoT devices.
  2. Games and Interactive Projects: Add simple sound effects to your games or interactive projects.
  3. Educational Tools: Teach the basics of sound generation and signal processing through hands-on projects using PWM-based audio generation.

Conclusion

PWM-based audio generation is a powerful yet simple method for adding sound to your ESP32 projects. By adjusting the PWM frequency and duty cycle, you can generate different tones and control the volume, making it an ideal solution for creating sound in embedded systems. Whether you’re designing an alarm, adding sound effects to a game, or teaching about audio generation, PWM on the ESP32 offers an efficient and easy-to-implement solution.

For more resources and tutorials on ESP32 and embedded development, visit our ESP32 guide series.

Leave a Comment