Skip to content

Commit

Permalink
major update to I2S examples
Browse files Browse the repository at this point in the history
- general improvements to code examples (e.g. use SDCard class from machine module)
- removed microphone code example that saved data to internal flash
- added uasyncio code example
- general improvements to github documentation
- added firmware binaries that support I2S features
- added photos of improved hardware test setup
  • Loading branch information
miketeachman committed May 20, 2020
1 parent 33ed0a4 commit 2549264
Show file tree
Hide file tree
Showing 18 changed files with 519 additions and 506 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
*.png binary
*.jpg binary
*.dxf binary
*.wav binary
*.wav binary
*.bin binary
197 changes: 111 additions & 86 deletions README.md

Large diffs are not rendered by default.

112 changes: 112 additions & 0 deletions examples/play-mono-wav-from-sdcard-uasyncio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# The MIT License (MIT)
# Copyright (c) 2020 Mike Teachman
# https://opensource.org/licenses/MIT

# Purpose:
# - read 16-bit audio samples from a mono formatted WAV file on SD card
# - write audio samples to an I2S amplifier or DAC module
#
# Uasyncio:
# - two co-routines are demonstrated
# - play the WAV file
# - write text to the REPL
# - Uasyncio version >= 3 is needed for this example
#
# Sample WAV files in wav_files folder:
# "taunt-16k-16bits-mono.wav"
# "taunt-16k-16bits-mono-12db.wav" (lower volume version)
#
# Hardware tested:
# - MAX98357A amplifier module (Adafruit I2S 3W Class D Amplifier Breakout)
# - PCM5102 stereo DAC module
#
# The WAV file will play continuously until a keyboard interrupt is detected or
# the ESP32 is reset

from machine import I2S
from machine import SDCard
from machine import Pin
import uasyncio as asyncio

if (asyncio.__version__)[0] < 3:
raise ImportError ('example requires uasyncio verion >= 3')

#======= USER CONFIGURATION =======
WAV_FILE = 'taunt-16k-16bits-mono-12db.wav'
SAMPLE_RATE_IN_HZ = 16000
#======= USER CONFIGURATION =======

async def play_wav():
bck_pin = Pin(21)
ws_pin = Pin(22)
sdout_pin = Pin(27)

# channelformat settings:
# mono WAV: channelformat=I2S.ONLY_LEFT
audio_out = I2S(
I2S.NUM0,
bck=bck_pin, ws=ws_pin, sdout=sdout_pin,
standard=I2S.PHILIPS,
mode=I2S.MASTER_TX,
dataformat=I2S.B16,
channelformat=I2S.ONLY_LEFT,
samplerate=SAMPLE_RATE_IN_HZ,
dmacount=10, dmalen=512)

# configure SD card
# slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2
# slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1
sd = SDCard(slot=3, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(4))
uos.mount(sd, "/sd")
wav_file = '/sd/{}'.format(WAV_FILE)
wav = open(wav_file,'rb')

# advance to first byte of Data section in WAV file
pos = wav.seek(44)

# allocate sample arrays
# memoryview used to reduce heap allocation in while loop
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)

print('Starting ... ')
# continuously read audio samples from the WAV file
# and write them to an I2S DAC

try:
while True:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
# end of WAV file?
if num_read == 0:
# advance to first byte of Data section
pos = wav.seek(44)
else:
# loop until all samples are written to the I2S peripheral
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv, timeout=0)
await asyncio.sleep_ms(10)
except (KeyboardInterrupt, Exception) as e:
print('caught exception {} {}'.format(type(e).__name__, e))
raise
finally:
wav.close()
uos.umount("/sd")
sd.deinit()
audio_out.deinit()
print('Done')

async def another_coro():
i = 0
while True:
print(i)
i+=1
await asyncio.sleep(1)

async def main():
play_wav_task = asyncio.create_task(play_wav())
another_task = asyncio.create_task(another_coro())
while True:
await asyncio.sleep(1)

asyncio.run(main())
84 changes: 84 additions & 0 deletions examples/play-mono-wav-from-sdcard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# The MIT License (MIT)
# Copyright (c) 2020 Mike Teachman
# https://opensource.org/licenses/MIT

# Purpose:
# - read 16-bit audio samples from a mono formatted WAV file on SD card
# - write audio samples to an I2S amplifier or DAC module
#
# Sample WAV files in wav_files folder:
# "taunt-16k-16bits-mono.wav"
# "taunt-16k-16bits-mono-12db.wav" (lower volume version)
#
# Hardware tested:
# - MAX98357A amplifier module (Adafruit I2S 3W Class D Amplifier Breakout)
# - PCM5102 stereo DAC module
#
# The WAV file will play continuously until a keyboard interrupt is detected or
# the ESP32 is reset

from machine import I2S
from machine import SDCard
from machine import Pin

#======= USER CONFIGURATION =======
WAV_FILE = 'taunt-16k-16bits-mono-12db.wav'
SAMPLE_RATE_IN_HZ = 16000
#======= USER CONFIGURATION =======

bck_pin = Pin(21)
ws_pin = Pin(22)
sdout_pin = Pin(27)

# channelformat settings:
# mono WAV: channelformat=I2S.ONLY_LEFT
audio_out = I2S(
I2S.NUM0,
bck=bck_pin, ws=ws_pin, sdout=sdout_pin,
standard=I2S.PHILIPS,
mode=I2S.MASTER_TX,
dataformat=I2S.B16,
channelformat=I2S.ONLY_LEFT,
samplerate=SAMPLE_RATE_IN_HZ,
dmacount=10, dmalen=512)

# configure SD card
# slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2
# slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1
sd = SDCard(slot=3, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(4))
uos.mount(sd, "/sd")
wav_file = '/sd/{}'.format(WAV_FILE)
wav = open(wav_file,'rb')

# advance to first byte of Data section in WAV file
pos = wav.seek(44)

# allocate sample arrays
# memoryview used to reduce heap allocation in while loop
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)

print('Starting')
# continuously read audio samples from the WAV file
# and write them to an I2S DAC
while True:
try:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
# end of WAV file?
if num_read == 0:
# advance to first byte of Data section
pos = wav.seek(44)
else:
# loop until all samples are written to the I2S peripheral
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv, timeout=0)
except (KeyboardInterrupt, Exception) as e:
print('caught exception {} {}'.format(type(e).__name__, e))
break

wav.close()
uos.umount("/sd")
sd.deinit()
audio_out.deinit()
print('Done')
66 changes: 0 additions & 66 deletions examples/play-mono-wav.py

This file was deleted.

74 changes: 74 additions & 0 deletions examples/play-stereo-wav-from-internal-flash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# The MIT License (MIT)
# Copyright (c) 2020 Mike Teachman
# https://opensource.org/licenses/MIT

# Purpose:
# - read 16-bit audio samples from a stereo formatted WAV file
# stored in the internal MicroPython filesystem
# - write audio samples to an I2S amplifier or DAC module
#
# Sample WAV file in wav_files folder:
# "side-to-side-8k-16bits-stereo.wav"
#
# Hardware tested:
# - PCM5102 stereo DAC module
#
# The WAV file will play continuously until a keyboard interrupt is detected or
# the ESP32 is reset

from machine import I2S
from machine import Pin

#======= USER CONFIGURATION =======
WAV_FILE = 'side-to-side-8k-16bits-stereo.wav'
SAMPLE_RATE_IN_HZ = 8000
#======= USER CONFIGURATION =======

bck_pin = Pin(33)
ws_pin = Pin(25)
sdout_pin = Pin(32)

# channelformat setting:
# stereo WAV: channelformat=I2S.RIGHT_LEFT
audio_out = I2S(
I2S.NUM1,
bck=bck_pin, ws=ws_pin, sdout=sdout_pin,
standard=I2S.PHILIPS,
mode=I2S.MASTER_TX,
dataformat=I2S.B16,
channelformat=I2S.RIGHT_LEFT,
samplerate=SAMPLE_RATE_IN_HZ,
dmacount=10, dmalen=512)

wav = open(WAV_FILE,'rb')

# advance to first byte of Data section in WAV file
pos = wav.seek(44)

# allocate sample arrays
# memoryview used to reduce heap allocation in while loop
wav_samples = bytearray(2048)
wav_samples_mv = memoryview(wav_samples)

print('Starting')
# continuously read audio samples from the WAV file
# and write them to an I2S DAC
while True:
try:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
# end of WAV file?
if num_read == 0:
# advance to first byte of Data section
pos = wav.seek(44)
else:
# loop until all samples are written to the I2S peripheral
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv, timeout=0)
except (KeyboardInterrupt, Exception) as e:
print('caught exception {} {}'.format(type(e).__name__, e))
break

wav.close()
audio_out.deinit()
print('Done')
Loading

0 comments on commit 2549264

Please sign in to comment.