first commit

This commit is contained in:
pandacraft 2025-03-21 16:04:17 +01:00
commit a5a0434432
1126 changed files with 439481 additions and 0 deletions

View file

@ -0,0 +1,195 @@
# 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 subprocess
import smbus
import Platform
def reverseByteOrder(data):
"""Reverses the byte order of an int (16-bit) or long (32-bit) value."""
# 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
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, **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, **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:
# 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 smbus library.
Allows reading and writing 8-bit, 16-bit, and byte array values to registers
on the device."""
def __init__(self, address, busnum):
"""Create an instance of the I2C device at the specified address on the
specified I2C bus number."""
self._address = address
self._bus = smbus.SMBus(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)

View file

@ -0,0 +1,188 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
#
# 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 time
# Register addresses.
MPR121_I2CADDR_DEFAULT = 0x5A
MPR121_TOUCHSTATUS_L = 0x00
MPR121_TOUCHSTATUS_H = 0x01
MPR121_FILTDATA_0L = 0x04
MPR121_FILTDATA_0H = 0x05
MPR121_BASELINE_0 = 0x1E
MPR121_MHDR = 0x2B
MPR121_NHDR = 0x2C
MPR121_NCLR = 0x2D
MPR121_FDLR = 0x2E
MPR121_MHDF = 0x2F
MPR121_NHDF = 0x30
MPR121_NCLF = 0x31
MPR121_FDLF = 0x32
MPR121_NHDT = 0x33
MPR121_NCLT = 0x34
MPR121_FDLT = 0x35
MPR121_TOUCHTH_0 = 0x41
MPR121_RELEASETH_0 = 0x42
MPR121_DEBOUNCE = 0x5B
MPR121_CONFIG1 = 0x5C
MPR121_CONFIG2 = 0x5D
MPR121_CHARGECURR_0 = 0x5F
MPR121_CHARGETIME_1 = 0x6C
MPR121_ECR = 0x5E
MPR121_AUTOCONFIG0 = 0x7B
MPR121_AUTOCONFIG1 = 0x7C
MPR121_UPLIMIT = 0x7D
MPR121_LOWLIMIT = 0x7E
MPR121_TARGETLIMIT = 0x7F
MPR121_GPIODIR = 0x76
MPR121_GPIOEN = 0x77
MPR121_GPIOSET = 0x78
MPR121_GPIOCLR = 0x79
MPR121_GPIOTOGGLE = 0x7A
MPR121_SOFTRESET = 0x80
MAX_I2C_RETRIES = 5
class MPR121(object):
"""Representation of a MPR121 capacitive touch sensor."""
def __init__(self):
"""Create an instance of the MPR121 device."""
# Nothing to do here since there is very little state in the class.
pass
def begin(self, address=MPR121_I2CADDR_DEFAULT, i2c=None, **kwargs):
"""Initialize communication with the MPR121.
Can specify a custom I2C address for the device using the address
parameter (defaults to 0x5A). Optional i2c parameter allows specifying a
custom I2C bus source (defaults to platform's I2C bus).
Returns True if communication with the MPR121 was established, otherwise
returns False.
"""
# Assume we're using platform's default I2C bus if none is specified.
if i2c is None:
import I2C
i2c = I2C
# Require repeated start conditions for I2C register reads. Unfortunately
# the MPR121 is very sensitive and requires repeated starts to read all
# the registers.
I2C.require_repeated_start()
# Save a reference to the I2C device instance for later communication.
self._device = i2c.get_i2c_device(address, **kwargs)
return self._reset()
def _reset(self):
# Soft reset of device.
self._i2c_retry(self._device.write8, MPR121_SOFTRESET, 0x63)
time.sleep(0.001) # This 1ms delay here probably isn't necessary but can't hurt.
# Set electrode configuration to default values.
self._i2c_retry(self._device.write8, MPR121_ECR, 0x00)
# Check CDT, SFI, ESI configuration is at default values.
c = self._i2c_retry(self._device.readU8, MPR121_CONFIG2)
if c != 0x24:
return False
# Set threshold for touch and release to default values.
self.set_thresholds(12, 6)
# Configure baseline filtering control registers.
self._i2c_retry(self._device.write8, MPR121_MHDR, 0x01)
self._i2c_retry(self._device.write8, MPR121_NHDR, 0x01)
self._i2c_retry(self._device.write8, MPR121_NCLR, 0x0E)
self._i2c_retry(self._device.write8, MPR121_FDLR, 0x00)
self._i2c_retry(self._device.write8, MPR121_MHDF, 0x01)
self._i2c_retry(self._device.write8, MPR121_NHDF, 0x05)
self._i2c_retry(self._device.write8, MPR121_NCLF, 0x01)
self._i2c_retry(self._device.write8, MPR121_FDLF, 0x00)
self._i2c_retry(self._device.write8, MPR121_NHDT, 0x00)
self._i2c_retry(self._device.write8, MPR121_NCLT, 0x00)
self._i2c_retry(self._device.write8, MPR121_FDLT, 0x00)
# Set other configuration registers.
self._i2c_retry(self._device.write8, MPR121_DEBOUNCE, 0)
self._i2c_retry(self._device.write8, MPR121_CONFIG1, 0x10) # default, 16uA charge current
self._i2c_retry(self._device.write8, MPR121_CONFIG2, 0x20) # 0.5uS encoding, 1ms period
# Enable all electrodes.
self._i2c_retry(self._device.write8, MPR121_ECR, 0x8F) # start with first 5 bits of baseline tracking
# All done, everything succeeded!
return True
def _i2c_retry(self, func, *params):
# Run specified I2C request and ignore IOError 110 (timeout) up to
# retries times. For some reason the Pi 2 hardware I2C appears to be
# flakey and randomly return timeout errors on I2C reads. This will
# catch those errors, reset the MPR121, and retry.
count = 0
while True:
try:
return func(*params)
except IOError as ex:
# Re-throw anything that isn't a timeout (110) error.
if ex.errno != 110:
raise ex
# Else there was a timeout, so reset the device and retry.
self._reset()
# Increase count and fail after maximum number of retries.
count += 1
if count >= MAX_I2C_RETRIES:
raise RuntimeError('Exceeded maximum number or retries attempting I2C communication!')
def set_thresholds(self, touch, release):
"""Set the touch and release threshold for all inputs to the provided
values. Both touch and release should be a value between 0 to 255
(inclusive).
"""
assert touch >= 0 and touch <= 255, 'touch must be between 0-255 (inclusive)'
assert release >= 0 and release <= 255, 'release must be between 0-255 (inclusive)'
# Set the touch and release register value for all the inputs.
for i in range(12):
self._i2c_retry(self._device.write8, MPR121_TOUCHTH_0 + 2*i, touch)
self._i2c_retry(self._device.write8, MPR121_RELEASETH_0 + 2*i, release)
def filtered_data(self, pin):
"""Return filtered data register value for the provided pin (0-11).
Useful for debugging.
"""
assert pin >= 0 and pin < 12, 'pin must be between 0-11 (inclusive)'
return self._i2c_retry(self._device.readU16LE, MPR121_FILTDATA_0L + pin*2)
def baseline_data(self, pin):
"""Return baseline data register value for the provided pin (0-11).
Useful for debugging.
"""
assert pin >= 0 and pin < 12, 'pin must be between 0-11 (inclusive)'
bl = self._i2c_retry(self._device.readU8, MPR121_BASELINE_0 + pin)
return bl << 2
def touched(self):
"""Return touch state of all pins as a 12-bit value where each bit
represents a pin, with a value of 1 being touched and 0 not being touched.
"""
t = self._i2c_retry(self._device.readU16LE, MPR121_TOUCHSTATUS_L)
return t & 0x0FFF
def is_touched(self, pin):
"""Return True if the specified pin is being touched, otherwise returns
False.
"""
assert pin >= 0 and pin < 12, 'pin must be between 0-11 (inclusive)'
t = self.touched()
return (t & (1 << pin)) > 0

View file

@ -0,0 +1,106 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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 platform
import re
# Platform identification constants.
UNKNOWN = 0
RASPBERRY_PI = 1
BEAGLEBONE_BLACK = 2
MINNOWBOARD = 3
def platform_detect():
"""Detect if running on the Raspberry Pi or Beaglebone Black and return the
platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN."""
# Handle Raspberry Pi
pi = pi_version()
if pi is not None:
return RASPBERRY_PI
# Handle Beaglebone Black
# TODO: Check the Beaglebone Black /proc/cpuinfo value instead of reading
# the platform.
plat = platform.platform()
if plat.lower().find('armv7l-with-debian') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-ubuntu') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-glibc2.4') > -1:
return BEAGLEBONE_BLACK
# Handle Minnowboard
# Assumption is that mraa is installed
try:
import mraa
if mraa.getPlatformName()=='MinnowBoard MAX':
return MINNOWBOARD
except ImportError:
pass
# Couldn't figure out the platform, just return unknown.
return UNKNOWN
def pi_revision():
"""Detect the revision number of a Raspberry Pi, useful for changing
functionality like default I2C bus based on revision."""
# Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History
with open('/proc/cpuinfo', 'r') as infile:
for line in infile:
# Match a line of the form "Revision : 0002" while ignoring extra
# info in front of the revsion (like 1000 when the Pi was over-volted).
match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE)
if match and match.group(1) in ['0000', '0002', '0003']:
# Return revision 1 if revision ends with 0000, 0002 or 0003.
return 1
elif match:
# Assume revision 2 if revision ends with any other 4 chars.
return 2
# Couldn't find the revision, throw an exception.
raise RuntimeError('Could not determine Raspberry Pi revision.')
def pi_version():
"""Detect the version of the Raspberry Pi. Returns either 1, 2 or
None depending on if it's a Raspberry Pi 1 (model A, B, A+, B+),
Raspberry Pi 2 (model B+), or not a Raspberry Pi.
"""
# Check /proc/cpuinfo for the Hardware field value.
# 2708 is pi 1
# 2709 is pi 2
# Anything else is not a pi.
with open('/proc/cpuinfo', 'r') as infile:
cpuinfo = infile.read()
# Match a line like 'Hardware : BCM2709'
match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo,
flags=re.MULTILINE | re.IGNORECASE)
if not match:
# Couldn't find the hardware, assume it isn't a pi.
return None
if match.group(1) == 'BCM2708':
# Pi 1
return 1
elif match.group(1) == 'BCM2709':
# Pi 2
return 2
else:
# Something else, not a pi.
return None

View file

@ -0,0 +1,7 @@
Grove I2C Touch Sensor
======================
Raspberry Pi Python i2c library for Grove I2C Touch sensor (http://www.seeedstudio.com/depot/Grove-I2C-Touch-Sensor-p-840.html)
The I2C Touch Sensor is based on FreeScale MPR121, it feels the touch or proximity of human being fingers.
The python library for this sensor is based on the Python library for interfacing with a MPR121 by Adafruit (https://github.com/adafruit/Adafruit_Python_MPR121)

View file

@ -0,0 +1,77 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
#
# 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 sys
import time
import MPR121
print('MPR121 Capacitive Touch Sensor Test')
# Create MPR121 instance.
cap = MPR121.MPR121()
# Initialize communication with MPR121 using default I2C bus of device, and
# default I2C address (0x5A). On BeagleBone Black will default to I2C bus 0.
if not cap.begin():
print('Error initializing MPR121. Check your wiring!')
sys.exit(1)
# Alternatively, specify a custom I2C address such as 0x5B (ADDR tied to 3.3V),
# 0x5C (ADDR tied to SDA), or 0x5D (ADDR tied to SCL).
#cap.begin(address=0x5B)
# Also you can specify an optional I2C bus with the bus keyword parameter.
#cap.begin(bus=1)
# Main loop to print a message every time a pin is touched.
print('Press Ctrl-C to quit.')
last_touched = cap.touched()
while True:
current_touched = cap.touched()
# Check each pin's last and current state to see if it was pressed or released.
for i in range(12):
# Each pin is represented by a bit in the touched value. A value of 1
# means the pin is being touched, and 0 means it is not being touched.
pin_bit = 1 << i
# First check if transitioned from not touched to touched.
if current_touched & pin_bit and not last_touched & pin_bit:
print('{0} touched!'.format(i))
# Next check if transitioned from touched to not touched.
if not current_touched & pin_bit and last_touched & pin_bit:
print('{0} released!'.format(i))
# Update last state and wait a short period before repeating.
last_touched = current_touched
time.sleep(0.1)
# Alternatively, if you only care about checking one or a few pins you can
# call the is_touched method with a pin number to directly check that pin.
# This will be a little slower than the above code for checking a lot of pins.
#if cap.is_touched(0):
# print 'Pin 0 is being touched!'
# If you're curious or want to see debug info for each pin, uncomment the
# following lines:
#print '\t\t\t\t\t\t\t\t\t\t\t\t\t 0x{0:0X}'.format(cap.touched())
#filtered = [cap.filtered_data(i) for i in range(12)]
#print 'Filt:', '\t'.join(map(str, filtered))
#base = [cap.baseline_data(i) for i in range(12)]
#print 'Base:', '\t'.join(map(str, base))