Skip to content

Commit dec7189

Browse files
committed
Initial commit--see note in README, not working for audio playback.
0 parents  commit dec7189

File tree

9 files changed

+617
-0
lines changed

9 files changed

+617
-0
lines changed

CODE_OF_CONDUCT.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, gender identity and expression, level of experience,
9+
nationality, personal appearance, race, religion, or sexual identity and
10+
orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at [email protected]. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at [http://contributor-covenant.org/version/1/4][version]
72+
73+
[homepage]: http://contributor-covenant.org
74+
[version]: http://contributor-covenant.org/version/1/4/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Tony DiCola for Adafruit Industries
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
Introduction
3+
============
4+
5+
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-VS1053/badge/?version=latest
6+
:target: https://circuitpython.readthedocs.io/projects/VS1053/en/latest/
7+
:alt: Documentation Status
8+
9+
.. image :: https://img.shields.io/discord/327254708534116352.svg
10+
:target: https://discord.gg/nBQh6qu
11+
:alt: Discord
12+
13+
Driver for interacting and playing media files with the VS1053 audio codec over
14+
a SPI connection.
15+
16+
NOTE: This is not currently working for audio playback of files. Only sine
17+
wave test currently works. The problem is that pure Python code is currently
18+
too slow to keep up with feeding data to the VS1053 fast enough. There's no
19+
interrupt support so Python code has to monitor the DREQ line and provide a
20+
small buffer of data when ready, but the overhead of the interpretor means we
21+
can't keep up. Optimizing SPI to use DMA transfers could help but ultimately
22+
an interrupt-based approach is likely what can make this work better (or C
23+
functions built in to custom builds that monitor the DREQ line and feed a
24+
buffer of data).
25+
26+
Dependencies
27+
=============
28+
This driver depends on:
29+
30+
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
31+
* `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
32+
33+
Please ensure all dependencies are available on the CircuitPython filesystem.
34+
This is easily achieved by downloading
35+
`the Adafruit library and driver bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle>`_.
36+
37+
Usage Example
38+
=============
39+
40+
See examples/sdfile_play.py.
41+
42+
Contributing
43+
============
44+
45+
Contributions are welcome! Please read our `Code of Conduct
46+
<https://github.com/adafruit/Adafruit_CircuitPython_VS1053/blob/master/CODE_OF_CONDUCT.md>`_
47+
before contributing to help this project stay welcoming.
48+
49+
API Reference
50+
=============
51+
52+
.. toctree::
53+
:maxdepth: 2
54+
55+
api

adafruit_vs1053.py

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2017 Tony DiCola for Adafruit Industries
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
"""
23+
`adafruit_vs1053`
24+
====================================================
25+
26+
Driver for interacting and playing media files with the VS1053 audio codec over
27+
a SPI connection.
28+
29+
NOTE: This is not currently working for audio playback of files. Only sine
30+
wave test currently works. The problem is that pure Python code is currently
31+
too slow to keep up with feeding data to the VS1053 fast enough. There's no
32+
interrupt support so Python code has to monitor the DREQ line and provide a
33+
small buffer of data when ready, but the overhead of the interpretor means we
34+
can't keep up. Optimizing SPI to use DMA transfers could help but ultimately
35+
an interrupt-based approach is likely what can make this work better (or C
36+
functions built in to custom builds that monitor the DREQ line and feed a
37+
buffer of data).
38+
39+
* Author(s): Tony DiCola
40+
"""
41+
import digitalio
42+
import time
43+
44+
from adafruit_bus_device.spi_device import SPIDevice
45+
46+
47+
_COMMAND_BAUDRATE = const(250000) # Speed for command transfers (MUST be slow)
48+
_DATA_BAUDRATE = const(8000000) # Speed for data transfers (fast!)
49+
50+
_VS1053_SCI_READ = const(0x03)
51+
_VS1053_SCI_WRITE = const(0x02)
52+
53+
_VS1053_REG_MODE = const(0x00)
54+
_VS1053_REG_STATUS = const(0x01)
55+
_VS1053_REG_BASS = const(0x02)
56+
_VS1053_REG_CLOCKF = const(0x03)
57+
_VS1053_REG_DECODETIME = const(0x04)
58+
_VS1053_REG_AUDATA = const(0x05)
59+
_VS1053_REG_WRAM = const(0x06)
60+
_VS1053_REG_WRAMADDR = const(0x07)
61+
_VS1053_REG_HDAT0 = const(0x08)
62+
_VS1053_REG_HDAT1 = const(0x09)
63+
_VS1053_REG_VOLUME = const(0x0B)
64+
65+
_VS1053_GPIO_DDR = const(0xC017)
66+
_VS1053_GPIO_IDATA = const(0xC018)
67+
_VS1053_GPIO_ODATA = const(0xC019)
68+
69+
_VS1053_INT_ENABLE = const(0xC01A)
70+
71+
_VS1053_MODE_SM_DIFF = const(0x0001)
72+
_VS1053_MODE_SM_LAYER12 = const(0x0002)
73+
_VS1053_MODE_SM_RESET = const(0x0004)
74+
_VS1053_MODE_SM_CANCEL = const(0x0008)
75+
_VS1053_MODE_SM_EARSPKLO = const(0x0010)
76+
_VS1053_MODE_SM_TESTS = const(0x0020)
77+
_VS1053_MODE_SM_STREAM = const(0x0040)
78+
_VS1053_MODE_SM_SDINEW = const(0x0800)
79+
_VS1053_MODE_SM_ADPCM = const(0x1000)
80+
_VS1053_MODE_SM_LINE1 = const(0x4000)
81+
_VS1053_MODE_SM_CLKRANGE = const(0x8000)
82+
83+
84+
class VS1053:
85+
86+
# Class-level buffer for read and write commands.
87+
# This is NOT thread/re-entrant safe (by design, for less memory hit).
88+
_SCI_SPI_BUFFER = bytearray(4)
89+
90+
def __init__(self, spi, cs, xdcs, dreq):
91+
# Create SPI device for VS1053
92+
self._cs = digitalio.DigitalInOut(cs)
93+
self._vs1053_spi = SPIDevice(spi, self._cs, baudrate=_COMMAND_BAUDRATE, polarity=0, phase=0)
94+
# Setup control lines.
95+
self._xdcs = digitalio.DigitalInOut(xdcs)
96+
self._xdcs.switch_to_output(value=True)
97+
self._dreq = digitalio.DigitalInOut(dreq)
98+
self._dreq.switch_to_input()
99+
# Reset chip.
100+
self.reset()
101+
# Check version is 4 (VS1053 ID).
102+
if self.version != 4:
103+
raise RuntimeError('Expected version 4 (VS1053) but got: {} Check wiring!'.format(self.version))
104+
105+
def _sci_write(self, address, value):
106+
# Write a 16-bit big-endian value to the provided 8-bit address.
107+
self._SCI_SPI_BUFFER[0] = _VS1053_SCI_WRITE
108+
self._SCI_SPI_BUFFER[1] = address & 0xFF
109+
self._SCI_SPI_BUFFER[2] = (value >> 8) & 0xFF
110+
self._SCI_SPI_BUFFER[3] = value & 0xFF
111+
with self._vs1053_spi as spi:
112+
spi.configure(baudrate=_COMMAND_BAUDRATE)
113+
spi.write(self._SCI_SPI_BUFFER)
114+
115+
def _sci_read(self, address):
116+
# Read a 16-bit big-endian value from the provided 8-bit address.
117+
# Write a 16-bit big-endian value to the provided 8-bit address.
118+
self._SCI_SPI_BUFFER[0] = _VS1053_SCI_READ
119+
self._SCI_SPI_BUFFER[1] = address & 0xFF
120+
with self._vs1053_spi as spi:
121+
spi.configure(baudrate=_COMMAND_BAUDRATE)
122+
spi.write(self._SCI_SPI_BUFFER, end=2)
123+
time.sleep(0.00001) # Delay 10 microseconds (at least)
124+
spi.readinto(self._SCI_SPI_BUFFER, end=2)
125+
return (self._SCI_SPI_BUFFER[0] << 8) | self._SCI_SPI_BUFFER[1]
126+
127+
def soft_reset(self):
128+
"""Perform a quick soft reset of the VS1053."""
129+
self._sci_write(_VS1053_REG_MODE, _VS1053_MODE_SM_SDINEW | _VS1053_MODE_SM_RESET)
130+
time.sleep(0.1)
131+
132+
def reset(self):
133+
"""Perform a longer full reset with clock and volume reset too."""
134+
self._xdcs.value = True
135+
self.soft_reset()
136+
time.sleep(0.1)
137+
self._sci_write(_VS1053_REG_CLOCKF, 0x6000)
138+
self.set_volume(40, 40)
139+
140+
def set_volume(self, left, right):
141+
"""Set the volume of the left and right channels to the provided byte
142+
value (0-255), the lower the louder.
143+
"""
144+
volume = ((left & 0xFF) << 8) | (right & 0xFF)
145+
self._sci_write(_VS1053_REG_VOLUME, volume)
146+
147+
@property
148+
def ready_for_data(self):
149+
"""Return True if the VS1053 is ready to accept data, false otherwise.
150+
"""
151+
return self._dreq.value
152+
153+
@property
154+
def version(self):
155+
"""Return the status register version value."""
156+
return (self._sci_read(_VS1053_REG_STATUS) >> 4) & 0x0F
157+
158+
@property
159+
def decode_time(self):
160+
"""Return the decode time register value. This is the amount of time
161+
the current file has been played back in seconds."""
162+
return self._sci_read(_VS1053_REG_DECODETIME)
163+
164+
@decode_time.setter
165+
def decode_time(self, value):
166+
"""Set the decode time register value."""
167+
# From datasheet, set twice to ensure it is correctly set (pg. 43)
168+
self._sci_write(_VS1053_REG_DECODETIME, value)
169+
170+
@property
171+
def byte_rate(self):
172+
"""Return the bit rate in bytes per second (computed each second).
173+
Useful to know if a song is being played and how fast it's happening.
174+
"""
175+
self._sci_write(_VS1053_REG_WRAMADDR, 0x1e05)
176+
return self._sci_read(_VS1053_REG_WRAM)
177+
178+
def start_playback(self):
179+
"""Prepare for playback of a file. After calling this check the
180+
ready_for_data property continually until true and then send in
181+
buffers of music data to the play_data function.
182+
"""
183+
# Reset playback.
184+
self._sci_write(_VS1053_REG_MODE, _VS1053_MODE_SM_LINE1 | _VS1053_MODE_SM_SDINEW)
185+
# Resync.
186+
self._sci_write(_VS1053_REG_WRAMADDR, 0x1e29)
187+
self._sci_write(_VS1053_REG_WRAM, 0)
188+
# Set time to zero.
189+
self.decode_time = 0
190+
191+
def stop_playback(self):
192+
"""Stop any playback of audio."""
193+
self._sci_write(_VS1053_REG_MODE, _VS1053_MODE_SM_LINE1 | _VS1053_MODE_SM_SDINEW | _VS1053_MODE_SM_CANCEL)
194+
195+
def play_data(self, data_buffer, start=0, end=None):
196+
"""Send a buffer of file data to the VS1053 for playback. Make sure
197+
the ready_for_data property is True before calling!
198+
"""
199+
try:
200+
if end is None:
201+
end = len(data_buffer)
202+
self._xdcs.value = False
203+
with self._vs1053_spi as spi:
204+
spi.configure(baudrate=_DATA_BAUDRATE)
205+
spi.write(data_buffer, start=start, end=end)
206+
finally:
207+
self._xdcs.value = True
208+
209+
def sine_test(self, n, seconds):
210+
"""Play a sine wave for the specified number of seconds. Useful to
211+
test the VS1053 is working.
212+
"""
213+
self.reset()
214+
mode = self._sci_read(_VS1053_REG_MODE)
215+
mode |= 0x0020
216+
self._sci_write(_VS1053_REG_MODE, mode)
217+
while not self.ready_for_data:
218+
pass
219+
try:
220+
self._xdcs.value = False
221+
with self._vs1053_spi as spi:
222+
spi.configure(baudrate=_DATA_BAUDRATE)
223+
spi.write(bytes([0x53, 0xEF, 0x6E, n & 0xFF, 0x00, 0x00,
224+
0x00, 0x00]))
225+
finally:
226+
self._xdcs.value = True
227+
time.sleep(seconds)
228+
try:
229+
self._xdcs.value = False
230+
with self._vs1053_spi as spi:
231+
spi.configure(baudrate=_DATA_BAUDRATE)
232+
spi.write(bytes([0x45, 0x78, 0x69, 0x74, 0x00, 0x00, 0x00,
233+
0x00]))
234+
finally:
235+
self._xdcs.value = True

api.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
.. If you created a package, create one automodule per module in the package.
3+
4+
.. automodule:: adafruit_vs1053
5+
:members:

0 commit comments

Comments
 (0)