diff options
Diffstat (limited to 'Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py')
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py | 202 |
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) |