summaryrefslogtreecommitdiff
path: root/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py
diff options
context:
space:
mode:
Diffstat (limited to 'Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py')
-rw-r--r--Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py b/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py
new file mode 100644
index 0000000..765ed82
--- /dev/null
+++ b/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py
@@ -0,0 +1,202 @@
+# Copyright (c) 2014 Adafruit Industries
+# Author: Tony DiCola
+# Based on Adafruit_I2C.py created by Kevin Townsend.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+import logging
+import os
+import subprocess
+
+import Adafruit_GPIO.Platform as Platform
+
+
+def reverseByteOrder(data):
+ """DEPRECATED: See https://github.com/adafruit/Adafruit_Python_GPIO/issues/48"""
+ # # Courtesy Vishal Sapre
+ # byteCount = len(hex(data)[2:].replace('L','')[::2])
+ # val = 0
+ # for i in range(byteCount):
+ # val = (val << 8) | (data & 0xff)
+ # data >>= 8
+ # return val
+ raise RuntimeError('reverseByteOrder is deprecated! See: https://github.com/adafruit/Adafruit_Python_GPIO/issues/48')
+
+def get_default_bus():
+ """Return the default bus number based on the device platform. For a
+ Raspberry Pi either bus 0 or 1 (based on the Pi revision) will be returned.
+ For a Beaglebone Black the first user accessible bus, 1, will be returned.
+ """
+ plat = Platform.platform_detect()
+ if plat == Platform.RASPBERRY_PI:
+ if Platform.pi_revision() == 1:
+ # Revision 1 Pi uses I2C bus 0.
+ return 0
+ else:
+ # Revision 2 Pi uses I2C bus 1.
+ return 1
+ elif plat == Platform.BEAGLEBONE_BLACK:
+ # Beaglebone Black has multiple I2C buses, default to 1 (P9_19 and P9_20).
+ return 1
+ else:
+ raise RuntimeError('Could not determine default I2C bus for platform.')
+
+def get_i2c_device(address, busnum=None, i2c_interface=None, **kwargs):
+ """Return an I2C device for the specified address and on the specified bus.
+ If busnum isn't specified, the default I2C bus for the platform will attempt
+ to be detected.
+ """
+ if busnum is None:
+ busnum = get_default_bus()
+ return Device(address, busnum, i2c_interface, **kwargs)
+
+def require_repeated_start():
+ """Enable repeated start conditions for I2C register reads. This is the
+ normal behavior for I2C, however on some platforms like the Raspberry Pi
+ there are bugs which disable repeated starts unless explicitly enabled with
+ this function. See this thread for more details:
+ http://www.raspberrypi.org/forums/viewtopic.php?f=44&t=15840
+ """
+ plat = Platform.platform_detect()
+ if plat == Platform.RASPBERRY_PI and os.path.exists('/sys/module/i2c_bcm2708/parameters/combined'):
+ # On the Raspberry Pi there is a bug where register reads don't send a
+ # repeated start condition like the kernel smbus I2C driver functions
+ # define. As a workaround this bit in the BCM2708 driver sysfs tree can
+ # be changed to enable I2C repeated starts.
+ subprocess.check_call('chmod 666 /sys/module/i2c_bcm2708/parameters/combined', shell=True)
+ subprocess.check_call('echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined', shell=True)
+ # Other platforms are a no-op because they (presumably) have the correct
+ # behavior and send repeated starts.
+
+
+class Device(object):
+ """Class for communicating with an I2C device using the adafruit-pureio pure
+ python smbus library, or other smbus compatible I2C interface. Allows reading
+ and writing 8-bit, 16-bit, and byte array values to registers
+ on the device."""
+ def __init__(self, address, busnum, i2c_interface=None):
+ """Create an instance of the I2C device at the specified address on the
+ specified I2C bus number."""
+ self._address = address
+ if i2c_interface is None:
+ # Use pure python I2C interface if none is specified.
+ import Adafruit_PureIO.smbus
+ self._bus = Adafruit_PureIO.smbus.SMBus(busnum)
+ else:
+ # Otherwise use the provided class to create an smbus interface.
+ self._bus = i2c_interface(busnum)
+ self._logger = logging.getLogger('Adafruit_I2C.Device.Bus.{0}.Address.{1:#0X}' \
+ .format(busnum, address))
+
+ def writeRaw8(self, value):
+ """Write an 8-bit value on the bus (without register)."""
+ value = value & 0xFF
+ self._bus.write_byte(self._address, value)
+ self._logger.debug("Wrote 0x%02X",
+ value)
+
+ def write8(self, register, value):
+ """Write an 8-bit value to the specified register."""
+ value = value & 0xFF
+ self._bus.write_byte_data(self._address, register, value)
+ self._logger.debug("Wrote 0x%02X to register 0x%02X",
+ value, register)
+
+ def write16(self, register, value):
+ """Write a 16-bit value to the specified register."""
+ value = value & 0xFFFF
+ self._bus.write_word_data(self._address, register, value)
+ self._logger.debug("Wrote 0x%04X to register pair 0x%02X, 0x%02X",
+ value, register, register+1)
+
+ def writeList(self, register, data):
+ """Write bytes to the specified register."""
+ self._bus.write_i2c_block_data(self._address, register, data)
+ self._logger.debug("Wrote to register 0x%02X: %s",
+ register, data)
+
+ def readList(self, register, length):
+ """Read a length number of bytes from the specified register. Results
+ will be returned as a bytearray."""
+ results = self._bus.read_i2c_block_data(self._address, register, length)
+ self._logger.debug("Read the following from register 0x%02X: %s",
+ register, results)
+ return results
+
+ def readRaw8(self):
+ """Read an 8-bit value on the bus (without register)."""
+ result = self._bus.read_byte(self._address) & 0xFF
+ self._logger.debug("Read 0x%02X",
+ result)
+ return result
+
+ def readU8(self, register):
+ """Read an unsigned byte from the specified register."""
+ result = self._bus.read_byte_data(self._address, register) & 0xFF
+ self._logger.debug("Read 0x%02X from register 0x%02X",
+ result, register)
+ return result
+
+ def readS8(self, register):
+ """Read a signed byte from the specified register."""
+ result = self.readU8(register)
+ if result > 127:
+ result -= 256
+ return result
+
+ def readU16(self, register, little_endian=True):
+ """Read an unsigned 16-bit value from the specified register, with the
+ specified endianness (default little endian, or least significant byte
+ first)."""
+ result = self._bus.read_word_data(self._address,register) & 0xFFFF
+ self._logger.debug("Read 0x%04X from register pair 0x%02X, 0x%02X",
+ result, register, register+1)
+ # Swap bytes if using big endian because read_word_data assumes little
+ # endian on ARM (little endian) systems.
+ if not little_endian:
+ result = ((result << 8) & 0xFF00) + (result >> 8)
+ return result
+
+ def readS16(self, register, little_endian=True):
+ """Read a signed 16-bit value from the specified register, with the
+ specified endianness (default little endian, or least significant byte
+ first)."""
+ result = self.readU16(register, little_endian)
+ if result > 32767:
+ result -= 65536
+ return result
+
+ def readU16LE(self, register):
+ """Read an unsigned 16-bit value from the specified register, in little
+ endian byte order."""
+ return self.readU16(register, little_endian=True)
+
+ def readU16BE(self, register):
+ """Read an unsigned 16-bit value from the specified register, in big
+ endian byte order."""
+ return self.readU16(register, little_endian=False)
+
+ def readS16LE(self, register):
+ """Read a signed 16-bit value from the specified register, in little
+ endian byte order."""
+ return self.readS16(register, little_endian=True)
+
+ def readS16BE(self, register):
+ """Read a signed 16-bit value from the specified register, in big
+ endian byte order."""
+ return self.readS16(register, little_endian=False)