Huzzah32 ESP32: PWM Sounds using Micropython
Huzzah32 ESP32 has a lot of great features with Micropython. One of the simplest and most sensitively interesting projects is the PWM sounds using Micropython, which stands for Pulse Width Modulation, a technique for modulating pulse waves by varying their duty ratio, and is used in various electrical controls. This tutorial guides you on how to play PWM sounds using Micropython.
Scientific Pitch Notation:
In order to enable PWM sounds using Micropython, this can be accomplished by assigning each frequency as a value to a variable and storing the values as a list. The table of the note frequency is referred from Wiki.
Preliminary Preparations
Before getting started with this tutorial, please go through the setup tutorial of Micropython on Huzzah32 ESP32.
If you followed the tutorial on the preliminary preparations above, the directory tree should be as follows:
1 2 3 4 5 6 7 8 9 |
esp32-py |- bin |- include |- lib |- src |- tools |- flash.sh |- bin |- esp32-20220618-v1.19.1.bin |
Commands:
In order to define AMPY_PORT as an environment variable, you should use these commands:
1 2 |
ls /dev/tty.* # list the connected devices export AMPY_PORT=/dev/tty.usbserial-XXXXXXXX # export it as an environment variable |
Usages:
There are two ways to test the PWM sounds using Micropython: one is to copy and paste the code below by creating a file by yourself, and another is to git-clone the code from GitHub.
Way 1: Copy and Paste
The first way is to copy and paste the code below, but before that, please create a file that you would like to paste to. In this case, I will create a file named “pwmsound.py” under the “src” directory.
1 |
touch pwmsound.py |
Then, the directory tree should be as follows:
1 2 3 4 5 6 7 8 9 10 |
esp32-py |- bin |- include |- lib |- src |- tools |- flash.sh |- bin |- esp32-20220618-v1.19.1.bin |- pwmsound.py |
Open the file in your favorite IDE. In this tutorial, I use Microsoft Visual Studio. Next, copy and paste the code below into the file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
""" ampy run test.py """ from machine import Pin, PWM import time class Note(): NONE = 1.00000 C0 = 16.35160 CS0 = 17.32391 D0 = 18.35405 DS0 = 19.44544 E0 = 20.60172 F0 = 21.82676 FS0 = 23.12465 G0 = 24.49971 GS0 = 25.95654 A0 = 27.50000 AS0 = 29.13524 B0 = 30.86771 C1 = 32.70320 CS1 = 34.64783 D1 = 36.70810 DS1 = 38.89087 E1 = 41.20344 F1 = 43.65353 FS1 = 46.24930 G1 = 48.99943 GS1 = 51.91309 A1 = 55.00000 AS1 = 58.27047 B1 = 61.73541 C2 = 65.40639 CS2 = 69.29566 D2 = 73.41619 DS2 = 77.78175 E2 = 82.40689 F2 = 87.30706 FS2 = 92.49861 G2 = 97.99886 GS2 = 103.8262 A2 = 110.0000 AS2 = 116.5409 B2 = 123.4708 C3 = 130.8128 CS3 = 138.5913 D3 = 146.8324 DS3 = 155.5635 E3 = 164.8138 F3 = 174.6141 FS3 = 184.9972 G3 = 195.9977 GS3 = 207.6523 A3 = 220.0000 AS3 = 233.0819 B3 = 246.9417 C4 = 261.6256 CS4 = 277.1826 D4 = 293.6648 DS4 = 311.1270 E4 = 329.6276 F4 = 349.2282 FS4 = 369.9944 G4 = 391.9954 GS4 = 415.3047 A4 = 440.0000 AS4 = 466.1638 B4 = 493.8833 C5 = 523.2511 CS5 = 554.3653 D5 = 587.3295 DS5 = 622.2540 E5 = 659.2551 F5 = 698.4565 FS5 = 739.9888 G5 = 783.9909 GS5 = 830.6094 A5 = 880.0000 AS5 = 932.3275 B5 = 987.7666 C6 = 1046.502 CS6 = 1108.731 D6 = 1174.659 DS6 = 1244.508 E6 = 1318.510 F6 = 1396.913 FS6 = 1479.978 G6 = 1567.982 GS6 = 1661.219 A6 = 1760.000 AS6 = 1864.655 B6 = 1975.533 C7 = 2093.005 CS7 = 2217.461 D7 = 2349.318 DS7 = 2489.016 E7 = 2637.020 F7 = 2793.826 FS7 = 2959.955 G7 = 3135.963 GS7 = 3322.438 A7 = 3520.000 AS7 = 3729.310 B7 = 3951.066 C8 = 4186.009 CS8 = 4434.922 D8 = 4698.636 DS8 = 4978.032 E8 = 5274.041 F8 = 5587.652 FS8 = 5919.911 G8 = 6271.927 GS8 = 6644.875 A8 = 7040.000 AS8 = 7458.620 B8 = 7902.133 class Huzzah: def __init__(self, pinLED=13): self.pinLED = pinLED def ledOn(self): led = Pin(self.pinLED, Pin.OUT) led.value(1) def ledOff(self): led = Pin(self.pinLED, Pin.OUT) led.value(0) def blink(self): self.ledOn() time.sleep(1) self.ledOff() time.sleep(1) class Music: def __init__(self, pinPWM): self.pinPWM = pinPWM self.esp = Huzzah() def melody_list(self): mario = [ Note.E7, Note.E7, Note.NONE, Note.E7, Note.NONE, Note.C7, Note.E7, Note.NONE, Note.G7, Note.NONE, Note.NONE, Note.NONE, Note.G6, Note.NONE, Note.NONE, Note.NONE, Note.C7, Note.NONE, Note.NONE, Note.G6, Note.NONE, Note.NONE, Note.E6, Note.NONE, Note.NONE, Note.A6, Note.NONE, Note.B6, Note.NONE, Note.AS6, Note.A6, Note.NONE, Note.G6, Note.E7, Note.NONE, Note.G7, Note.A7, Note.NONE, Note.F7, Note.G7, Note.NONE, Note.E7, Note.NONE, Note.C7, Note.D7, Note.B6, Note.NONE, Note.NONE, Note.C7, Note.NONE, Note.NONE, Note.G6, Note.NONE, Note.NONE, Note.E6, Note.NONE, Note.NONE, Note.A6, Note.NONE, Note.B6, Note.NONE, Note.AS6, Note.A6, Note.NONE, Note.G6, Note.E7, Note.NONE, Note.G7, Note.A7, Note.NONE, Note.F7, Note.G7, Note.NONE, Note.E7, Note.NONE, Note.C7, Note.D7, Note.B6, Note.NONE, Note.NONE, Note.NONE, Note.G7, Note.FS7, Note.F7, Note.D7, Note.NONE, Note.E7, Note.NONE, Note.G6, Note.A6, Note.C7, Note.NONE, Note.A6, Note.C7, Note.D7, Note.NONE, Note.NONE, Note.G7, Note.FS7, Note.F7, Note.D7, Note.NONE, Note.E7, Note.NONE, Note.C8, Note.NONE, Note.C8, Note.C8, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.G7, Note.FS7, Note.F7, Note.D7, Note.NONE, Note.E7, Note.NONE, Note.G6, Note.A6, Note.C7, Note.NONE, Note.A6, Note.C7, Note.D7, Note.NONE, Note.NONE, Note.DS7, Note.NONE, Note.NONE, Note.D7, Note.NONE, Note.NONE, Note.C7, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.C7, Note.C7, Note.NONE, Note.C7, Note.NONE, Note.C7, Note.D7, Note.NONE, Note.E7, Note.C7, Note.NONE, Note.A6, Note.G6, Note.NONE, Note.NONE, Note.NONE, Note.C7, Note.C7, Note.NONE, Note.C7, Note.NONE, Note.C7, Note.D7, Note.E7, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.NONE, Note.C7, Note.C7, Note.NONE, Note.C7, Note.NONE, Note.C7, Note.D7, Note.NONE, Note.E7, Note.C7, Note.NONE, Note.A6, Note.G6, Note.NONE, Note.NONE, Note.NONE, Note.E7, Note.E7, Note.NONE, Note.E7, Note.NONE, Note.C7, Note.E7, Note.NONE, Note.G7, Note.NONE, Note.NONE, Note.NONE, Note.G6, Note.NONE, Note.NONE, Note.NONE, ] return mario def playPWM(self, melodies, delays=0.15, duty=50): pwm = PWM(Pin(self.pinPWM, Pin.OUT)) for note in melodies: print(note) if note > 1: self.esp.ledOn() else: self.esp.ledOff() pwm.freq(int(note)) pwm.duty(duty) time.sleep(delays) pwm.duty(0) pwm.deinit() if __name__ == '__main__': pinPWM = 33 music = Music(pinPWM) melodies = music.melody_list() music.playPWM(melodies) |
Eventually, execute the file using the ampy command. Please make sure you are in the src directory and already exported the AMPY_PORT as the environment variable.
1 |
ampy run pwmsound.py |
If no errors have occurred, you should be able to hear PWM sounds using Micropython!
Way 2: GitHub
This is a little bit advanced way to execute the script because it is assumed that you have already known how to use GitHub. First of all, clone the repository from my GitHub under the “src” directory.
1 |
git clone https://github.com/kntnk/esp32.git |
Then, the directory tree should be as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
esp32-py |- bin |- include |- lib |- src |- tools |- flash.sh |- bin |- esp32-20220618-v1.19.1.bin |- esp32 |- images |- examples |- pwmsound |- pwmsound.py |
Next, jump into the subdirectory named “pwmsound”.
1 |
cd esp32/examples/pwmsound |
Once you exported the AMPY_PORT as the environment variable successfully, you simply execute the script as follows:
1 |
ampy run pwmsound.py |