/ adafruit_max9744.py
adafruit_max9744.py
  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_max9744`
 24  ====================================================
 25  
 26  CircuitPython module for the MAX9744 20W class D amplifier.  See
 27  examples/simpletest.py for a demo of the usage.
 28  
 29  * Author(s): Tony DiCola
 30  
 31  Implementation Notes
 32  --------------------
 33  
 34  **Hardware:**
 35  
 36  * Adafruit `MAX9744 Stereo 20W Class D Audio Amplifier
 37    <https://www.adafruit.com/product/1752>`_ (Product ID: 1752)
 38  
 39  **Software and Dependencies:**
 40  
 41  * Adafruit CircuitPython firmware for the ESP8622 and M0-based boards:
 42    https://github.com/adafruit/circuitpython/releases
 43  """
 44  from micropython import const
 45  
 46  __version__ = "0.0.0-auto.0"
 47  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MAX9744.git"
 48  
 49  
 50  # pylint: disable=bad-whitespace
 51  # Internal constants:
 52  _MAX9744_DEFAULT_ADDRESS = const(0b01001011)
 53  _MAX9744_COMMAND_VOLUME = const(0b00000000)
 54  _MAX9744_COMMAND_FILTERLESS = const(0b01000000)
 55  _MAX9744_COMMAND_CLASSIC_PWM = const(0b01000001)
 56  _MAX9744_COMMAND_VOLUME_UP = const(0b11000100)
 57  _MAX9744_COMMAND_VOLUME_DOWN = const(0b11000101)
 58  # pylint: enable=bad-whitespace
 59  
 60  
 61  class MAX9744:
 62      """MAX9744 20 watt class D amplifier.
 63  
 64      :param i2c: The I2C bus for the device.
 65  
 66      :param address: (Optional) The address of the device if it has been overridden from the
 67                      default with the AD1, AD2 pins.
 68      """
 69  
 70      # Global buffer for writing data.  This saves memory use and prevents
 71      # heap fragmentation.  However this is not thread-safe or re-entrant by
 72      # design!
 73      _BUFFER = bytearray(1)
 74  
 75      def __init__(self, i2c, *, address=_MAX9744_DEFAULT_ADDRESS):
 76          # This device doesn't use registers and instead just accepts a single
 77          # command string over I2C.  As a result we don't use bus device or
 78          # other abstractions and just talk raw I2C protocol.
 79          self._i2c = i2c
 80          self._address = address
 81  
 82      def _write(self, val):
 83          # Perform a write to update the amplifier state.
 84          try:
 85              # Make sure bus is locked before write.
 86              while not self._i2c.try_lock():
 87                  pass
 88              # Build bytes to send to device with updated value.
 89              self._BUFFER[0] = val & 0xFF
 90              self._i2c.writeto(self._address, self._BUFFER)
 91          finally:
 92              # Ensure bus is always unlocked.
 93              self._i2c.unlock()
 94  
 95      def _set_volume(self, volume):
 96          # Set the volume to the specified level (0-63).
 97          assert 0 <= volume <= 63
 98          self._write(_MAX9744_COMMAND_VOLUME | (volume & 0x3F))
 99  
100      # pylint: disable=line-too-long
101      volume = property(
102          None,
103          _set_volume,
104          "Set the volume of the amplifier.  Specify a value from 0-63 where 0 is muted/off and 63 is maximum volume.",
105      )
106      # pylint: enable=line-too-long
107  
108      def volume_up(self):
109          """Increase the volume by one level."""
110          self._write(_MAX9744_COMMAND_VOLUME_UP)
111  
112      def volume_down(self):
113          """Decrease the volume by one level."""
114          self._write(_MAX9744_COMMAND_VOLUME_DOWN)