more docs, mostly usage examples
Hopefully, this should make it clear how to use the API for setting volume for speakers, headphones, or line-level output.
This commit is contained in:
parent
81c00085ec
commit
bc20f0b3c0
3 changed files with 250 additions and 9 deletions
|
|
@ -8,7 +8,7 @@
|
|||
CircuitPython driver for the TLV320DAC3100 I2S DAC
|
||||
|
||||
|
||||
* Author(s): Liz Clark
|
||||
* Author(s): Liz Clark, Sam Blenny
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
|
@ -24,20 +24,19 @@ Implementation Notes
|
|||
left, and headphone right start with the DAC, then they go through a mixer
|
||||
stage, an analog volume (attenuation) stage, and finally an analog amplifier
|
||||
stage. Parameters for each stage of each signal chain can be separately set
|
||||
with different properties.
|
||||
with different properties. But, you can ignore most of that if you use
|
||||
``speaker_output = True`` or ``headphone_output = True`` to load defaults.
|
||||
|
||||
* To understand how the different audio stages (DAC, volume, amplifier gain)
|
||||
relate to each other, it can help to look at the Functional Block Diagram in
|
||||
the TLV320DAC3100 datasheet:
|
||||
https://learn.adafruit.com/adafruit-tlv320dac3100-i2s-dac/downloads
|
||||
|
||||
* **CAUTION**: The TLV320 speaker amplifier has enough power to easily burn out
|
||||
small 1W speakers if you max out the volume and gain settings. To be safe,
|
||||
start with lower levels for ``speaker_volume`` and ``speaker_gain``, then work
|
||||
your way up to find a comfortable listening level. Similarly, for the
|
||||
headphone output, start low with ``headphone_volume``,
|
||||
``headphone_left_gain``, and ``headphone_right_gain``, then increase as
|
||||
needed.
|
||||
* **CAUTION**: The TLV320 amplifiers have enough power to easily burn out
|
||||
small 1W speakers or drive headphones to levels that could damage your
|
||||
hearing. To be safe, start with low volume and gain levels, then increase
|
||||
them carefully to find a comfortable listening level. This is why the
|
||||
default levels set by speaker_output and headphone_output are relatively low.
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
|
|
@ -45,6 +44,68 @@ Implementation Notes
|
|||
https://circuitpython.org/downloads
|
||||
|
||||
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
|
||||
|
||||
Usage Examples
|
||||
--------------
|
||||
|
||||
Fruit Jam Mini-Speaker
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This will start you off with a relatively low volume for the Fruit Jam's
|
||||
bundled 8-Ohm 1 Watt speaker. Your code can adjust the volume by increasing
|
||||
or decreasing ``dac_volume``. To use a higher wattage speaker that needs
|
||||
more power, you might want to increase ``speaker_volume``.
|
||||
|
||||
::
|
||||
|
||||
dac = TLV320DAC3100(board.I2C())
|
||||
dac.speaker_output = True # set defaults for speaker
|
||||
dac.dac_volume = dac.dac_volume + 1 # increase volume by 1 dB
|
||||
dac.dac_volume = dac.dac_volume - 1 # decrease volume by 1 dB
|
||||
|
||||
Low Impedance Earbuds
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This will start you off with a relatively low volume for low impedance
|
||||
earbuds (e.g. JVC Gumy) plugged into the Fruit Jam's headphone jack. Your
|
||||
code can adjust the volume by increasing or decreasing ``dac_volume``. To
|
||||
use high impedance headphones that need more power, you might want to
|
||||
increase ``headphone_volume``.
|
||||
|
||||
::
|
||||
|
||||
dac = TLV320DAC3100(board.I2C())
|
||||
dac.speaker_output = False # make sure speaker amp is off
|
||||
dac.headphone_output = True # set defaults for headphones
|
||||
dac.dac_volume = dac.dac_volume + 1 # increase volume by 1 dB
|
||||
dac.dac_volume = dac.dac_volume - 1 # decrease volume by 1 dB
|
||||
|
||||
Line Level Output to Mixer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For this one, the default headphone output volume will be way too low for
|
||||
use with a device that expects consumer line level input (-10 dBV). To fix
|
||||
that, you can increase ``dac_volume`` or ``headphone_volume``. If you want
|
||||
to experiment with different ways of setting the levels, check out the
|
||||
volume test example: `Volume test <../examples.html#volume-test>`_
|
||||
|
||||
::
|
||||
|
||||
dac = TLV320DAC3100(board.I2C())
|
||||
dac.speaker_output = False # make sure speaker amp is off
|
||||
dac.headphone_output = True # set defaults for headphones (note: too low!)
|
||||
|
||||
# Make it louder by increasing headphone_volume. We could also use
|
||||
# dac_volume, but doing it this way gives a better balance between
|
||||
# the speaker signal chain and the headphone jack signal chain. (think
|
||||
# of headphone_volume as a mixer channel's pad switch or gain trim knob
|
||||
# and dac_volume as the main volume control fader)
|
||||
#
|
||||
# CAUTION: This will be *way* too loud for earbuds, please be careful!
|
||||
dac.headphone_volume = -15.5 # default is -51.8 dB
|
||||
|
||||
API
|
||||
---
|
||||
"""
|
||||
|
||||
import time
|
||||
|
|
|
|||
|
|
@ -15,3 +15,12 @@ Demos advanced features of the library.
|
|||
.. literalinclude:: ../examples/tlv320_fulltest.py
|
||||
:caption: examples/tlv320_fulltest.py
|
||||
:linenos:
|
||||
|
||||
Volume test
|
||||
-----------
|
||||
|
||||
Test tone generator with interactive serial console volume controls
|
||||
|
||||
.. literalinclude:: ../examples/tlv320_volumetest.py
|
||||
:caption: examples/tlv320_volumetest.py
|
||||
:linenos:
|
||||
|
|
|
|||
171
examples/tlv320_volumetest.py
Normal file
171
examples/tlv320_volumetest.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Sam Blenny
|
||||
#
|
||||
import gc
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import displayio
|
||||
import supervisor
|
||||
import synthio
|
||||
from audiobusio import I2SOut
|
||||
from board import I2C, I2S_BCLK, I2S_DIN, I2S_MCLK, I2S_WS, PERIPH_RESET
|
||||
from digitalio import DigitalInOut, Direction, Pull
|
||||
from micropython import const
|
||||
|
||||
from adafruit_tlv320 import TLV320DAC3100
|
||||
|
||||
# DAC and Synthesis parameters
|
||||
SAMPLE_RATE = const(11025)
|
||||
CHAN_COUNT = const(2)
|
||||
BUFFER_SIZE = const(1024)
|
||||
|
||||
# DAC volume limits
|
||||
DV_MIN = -63.5
|
||||
DV_MAX = 24.0
|
||||
|
||||
# Headphone volume limits
|
||||
HV_MIN = -78.3
|
||||
HV_MAX = 0
|
||||
|
||||
# Headphone gain limits
|
||||
HG_MIN = 0
|
||||
HG_MAX = 9
|
||||
|
||||
# Speaker volume limits
|
||||
SV_MIN = -78.3
|
||||
SV_MAX = 0
|
||||
|
||||
# Speaker amp gain limits
|
||||
SG_MIN = 6
|
||||
SG_MAX = 24
|
||||
SG_STEP = 6
|
||||
|
||||
|
||||
def init_dac_audio_synth(i2c):
|
||||
"""Configure TLV320 I2S DAC for audio output and make a Synthesizer.
|
||||
|
||||
:param i2c: a reference to board.I2C()
|
||||
:return: tuple(dac: TLV320DAC3100, audio: I2SOut, synth: Synthesizer)
|
||||
"""
|
||||
# 1. Reset DAC (reset is active low)
|
||||
rst = DigitalInOut(PERIPH_RESET)
|
||||
rst.direction = Direction.OUTPUT
|
||||
rst.value = False
|
||||
time.sleep(0.1)
|
||||
rst.value = True
|
||||
time.sleep(0.05)
|
||||
# 2. Configure sample rate, bit depth, and output port
|
||||
dac = TLV320DAC3100(i2c)
|
||||
dac.configure_clocks(sample_rate=SAMPLE_RATE, bit_depth=16)
|
||||
dac.speaker_output = True
|
||||
dac.headphone_output = True
|
||||
# 4. Initialize I2S for Fruit Jam rev D
|
||||
audio = I2SOut(bit_clock=I2S_BCLK, word_select=I2S_WS, data=I2S_DIN)
|
||||
# 5. Configure synthio patch to generate audio
|
||||
vca = synthio.Envelope(
|
||||
attack_time=0, decay_time=0, sustain_level=1.0, release_time=0, attack_level=1.0
|
||||
)
|
||||
synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE, channel_count=CHAN_COUNT, envelope=vca)
|
||||
return (dac, audio, synth)
|
||||
|
||||
|
||||
def main(): # noqa: PLR0912, PLR0915, allow long function and long if statement
|
||||
# Turn off the default DVI display to free up CPU
|
||||
displayio.release_displays()
|
||||
gc.collect()
|
||||
|
||||
# Set up the audio stuff for a basic synthesizer
|
||||
i2c = I2C()
|
||||
(dac, audio, synth) = init_dac_audio_synth(i2c)
|
||||
audio.play(synth)
|
||||
|
||||
dv = dac.dac_volume # default DAC volume
|
||||
hv = dac.headphone_volume # default headphone analog volume
|
||||
hg = dac.headphone_left_gain # default headphone amp gain
|
||||
sv = dac.speaker_volume # default speaker analog volume
|
||||
sg = dac.speaker_gain # default speaker amp gain
|
||||
note = 60
|
||||
synth.press(note)
|
||||
|
||||
# Check for unbuffered keystroke input on the USB serial console
|
||||
print("""
|
||||
=== TLV320DAC Volume Tester ===
|
||||
|
||||
Controls:
|
||||
q/z: dac_volume +/- 1
|
||||
w/x: headphone_volume +/- 1
|
||||
e/c: headphone_left_gain headphone_right_gain +/- 1
|
||||
r/v: speaker_volume +/- 1
|
||||
t/b: speaker_gain +/- 6
|
||||
space: toggle speaker_output (amp power), this will reset volume & gain
|
||||
|
||||
For less headphone noise, turn off the speaker amp (spacebar)
|
||||
""")
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
if supervisor.runtime.serial_bytes_available:
|
||||
while supervisor.runtime.serial_bytes_available:
|
||||
c = sys.stdin.read(1)
|
||||
if c == "q":
|
||||
# Q = DAC Volume UP
|
||||
dv = min(DV_MAX, max(DV_MIN, dv + 1))
|
||||
dac.dac_volume = dv
|
||||
print(f"dv = {dv:.1f} ({dac.dac_volume:.1f})")
|
||||
elif c == "z":
|
||||
# Z = DAC Volume DOWN
|
||||
dv = min(DV_MAX, max(DV_MIN, dv - 1))
|
||||
dac.dac_volume = dv
|
||||
print(f"dv = {dv:.1f} ({dac.dac_volume:.1f})")
|
||||
elif c == "w":
|
||||
# W = Headphone Volume UP
|
||||
hv = min(HV_MAX, max(HV_MIN, hv + 1))
|
||||
dac.headphone_volume = hv
|
||||
print(f"hv = {hv:.1f} ({dac.headphone_volume:.1f})")
|
||||
elif c == "x":
|
||||
# X = Headphone Volume DOWN
|
||||
hv = min(HV_MAX, max(HV_MIN, hv - 1))
|
||||
dac.headphone_volume = hv
|
||||
print(f"hv = {hv:.1f} ({dac.headphone_volume:.1f})")
|
||||
elif c == "e":
|
||||
# E = Headphone Amp Gain UP
|
||||
hg = min(HG_MAX, max(HG_MIN, hg + 1))
|
||||
dac.headphone_left_gain = hg
|
||||
dac.headphone_right_gain = hg
|
||||
print(f"hg = {hg:.1f} ({dac.headphone_left_gain})")
|
||||
elif c == "c":
|
||||
# C = Headphone Amp Gain DOWN
|
||||
hg = min(HG_MAX, max(HG_MIN, hg - 1))
|
||||
dac.headphone_left_gain = hg
|
||||
dac.headphone_right_gain = hg
|
||||
print(f"hg = {hg:.1f} ({dac.headphone_left_gain})")
|
||||
|
||||
if c == "r":
|
||||
# R = Speaker Volume UP
|
||||
sv = min(SV_MAX, max(SV_MIN, sv + 1))
|
||||
dac.speaker_volume = sv
|
||||
print(f"sv = {sv:.1f} ({dac.speaker_volume:.1f})")
|
||||
elif c == "v":
|
||||
# V = Speaker Volume DOWN
|
||||
sv = min(SV_MAX, max(SV_MIN, sv - 1))
|
||||
dac.speaker_volume = sv
|
||||
print(f"sv = {sv:.1f} ({dac.speaker_volume:.1f})")
|
||||
elif c == "t":
|
||||
# T = Speaker Amp Gain UP
|
||||
sg = min(SG_MAX, max(SG_MIN, sg + SG_STEP))
|
||||
dac.speaker_gain = sg
|
||||
print(f"sg = {sg:.1f} ({dac.speaker_gain})")
|
||||
elif c == "b":
|
||||
# B = Speaker Amp Gain DOWN
|
||||
sg = min(SG_MAX, max(SG_MIN, sg - SG_STEP))
|
||||
dac.speaker_gain = sg
|
||||
print(f"sg = {sg:.1f} ({dac.speaker_gain})")
|
||||
elif c == " ":
|
||||
# Space = Toggle speaker amp enable/disable
|
||||
en = not dac.speaker_output
|
||||
dac.speaker_output = en
|
||||
print(f"speaker_output = {en}")
|
||||
|
||||
|
||||
main()
|
||||
Loading…
Reference in a new issue