diff --git a/adafruit_seesaw/attiny8x7.py b/adafruit_seesaw/attiny8x7.py new file mode 100644 index 0000000..a51e00c --- /dev/null +++ b/adafruit_seesaw/attiny8x7.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# pylint: disable=missing-docstring,invalid-name,too-many-public-methods,too-few-public-methods + +""" +`adafruit_seesaw.attiny8x7` - Pin definition for Adafruit ATtiny8x7 Breakout with seesaw +================================================================================== +""" + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" + + +class ATtiny8x7_Pinmap: + """This class is automatically used by `adafruit_seesaw.seesaw.Seesaw` when + a ATtiny8x7 Breakout is detected. + + It is also a reference for the capabilities of each pin.""" + + #: The pins capable of analog output + analog_pins = (0, 1, 2, 3, 6, 7, 18, 19, 20) + + """The effective bit resolution of the PWM pins""" + pwm_width = 16 # we dont actually use all 16 bits but whatever + + """The pins capable of PWM output""" + pwm_pins = (0, 1, 9, 12, 13) + + """No pins on this board are capable of touch input""" + touch_pins = () diff --git a/adafruit_seesaw/seesaw.py b/adafruit_seesaw/seesaw.py index 1e003a0..d42f746 100644 --- a/adafruit_seesaw/seesaw.py +++ b/adafruit_seesaw/seesaw.py @@ -107,7 +107,8 @@ def const(x): _TOUCH_CHANNEL_OFFSET = const(0x10) -_HW_ID_CODE = const(0x55) +_SAMD09_HW_ID_CODE = const(0x55) +_ATTINY8X7_HW_ID_CODE = const(0x87) _EEPROM_I2C_ADDR = const(0x3F) _ENCODER_STATUS = const(0x00) @@ -126,33 +127,30 @@ class Seesaw: :param ~busio.I2C i2c_bus: Bus the SeeSaw is connected to :param int addr: I2C address of the SeeSaw device - :param ~digitalio.DigitalInOut drdy: Pin connected to SeeSaw's 'ready' output""" + :param ~digitalio.DigitalInOut drdy: Pin connected to SeeSaw's 'ready' output + :param bool reset: Whether to do a software reset on init""" INPUT = const(0x00) OUTPUT = const(0x01) INPUT_PULLUP = const(0x02) INPUT_PULLDOWN = const(0x03) - def __init__(self, i2c_bus, addr=0x49, drdy=None): + def __init__(self, i2c_bus, addr=0x49, drdy=None, reset=True): self._drdy = drdy if drdy is not None: drdy.switch_to_input() self.i2c_device = I2CDevice(i2c_bus, addr) - self.sw_reset() - - def sw_reset(self): - """Trigger a software reset of the SeeSaw chip""" - self.write8(_STATUS_BASE, _STATUS_SWRST, 0xFF) - time.sleep(0.500) + if reset: + self.sw_reset() - chip_id = self.read8(_STATUS_BASE, _STATUS_HW_ID) + self.chip_id = self.read8(_STATUS_BASE, _STATUS_HW_ID) - if chip_id != _HW_ID_CODE: + if self.chip_id not in (_ATTINY8X7_HW_ID_CODE, _SAMD09_HW_ID_CODE): raise RuntimeError( "Seesaw hardware ID returned (0x{:x}) is not " - "correct! Expected 0x{:x}. Please check your wiring.".format( - chip_id, _HW_ID_CODE + "correct! Expected 0x{:x} or 0x{:x}. Please check your wiring.".format( + self.chip_id, _SAMD09_HW_ID_CODE, _ATTINY8X7_HW_ID_CODE ) ) @@ -166,12 +164,21 @@ def sw_reset(self): from adafruit_seesaw.robohat import MM1_Pinmap self.pin_mapping = MM1_Pinmap - else: + elif self.chip_id == _SAMD09_HW_ID_CODE: from adafruit_seesaw.samd09 import SAMD09_Pinmap self.pin_mapping = SAMD09_Pinmap + elif self.chip_id == _ATTINY8X7_HW_ID_CODE: + from adafruit_seesaw.attiny8x7 import ATtiny8x7_Pinmap + + self.pin_mapping = ATtiny8x7_Pinmap # pylint: enable=import-outside-toplevel + def sw_reset(self): + """Trigger a software reset of the SeeSaw chip""" + self.write8(_STATUS_BASE, _STATUS_SWRST, 0xFF) + time.sleep(0.500) + def get_options(self): """Retrieve the 'options' word from the SeeSaw board""" buf = bytearray(4) @@ -241,9 +248,14 @@ def analog_read(self, pin): if pin not in self.pin_mapping.analog_pins: raise ValueError("Invalid ADC pin") + if self.chip_id == _ATTINY8X7_HW_ID_CODE: + offset = pin + elif self.chip_id == _SAMD09_HW_ID_CODE: + offset = self.pin_mapping.analog_pins.index(pin) + self.read( _ADC_BASE, - _ADC_CHANNEL_OFFSET + self.pin_mapping.analog_pins.index(pin), + _ADC_CHANNEL_OFFSET + offset, buf, ) ret = struct.unpack(">H", buf)[0] @@ -334,20 +346,19 @@ def digital_write_bulk_b(self, pins, value): def analog_write(self, pin, value): """Set the value of an analog output by number""" - pin_found = False + if pin not in self.pin_mapping.pwm_pins: + raise ValueError("Invalid PWM pin") + + if self.chip_id == _ATTINY8X7_HW_ID_CODE: + offset = pin + elif self.chip_id == _SAMD09_HW_ID_CODE: + offset = self.pin_mapping.pwm_pins.index(pin) + if self.pin_mapping.pwm_width == 16: - if pin in self.pin_mapping.pwm_pins: - pin_found = True - cmd = bytearray( - [self.pin_mapping.pwm_pins.index(pin), (value >> 8), value & 0xFF] - ) + cmd = bytearray([offset, (value >> 8), value & 0xFF]) else: - if pin in self.pin_mapping.pwm_pins: - pin_found = True - cmd = bytearray([self.pin_mapping.pwm_pins.index(pin), value]) + cmd = bytearray([offset, value]) - if pin_found is False: - raise ValueError("Invalid PWM pin") self.write(_TIMER_BASE, _TIMER_PWM, cmd) time.sleep(0.001) diff --git a/examples/seesaw_analogin_test.py b/examples/seesaw_analogin_test.py new file mode 100644 index 0000000..5d53173 --- /dev/null +++ b/examples/seesaw_analogin_test.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Simple seesaw test reading analog value +# on SAMD09, analog in can be pins 2, 3, or 4 +# on Attiny8x7, analog in can be pins 0, 1, 2, 3, 6, 7, 18, 19, 20 +# +# See the seesaw Learn Guide for wiring details: +# https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test + +import time +import board +from adafruit_seesaw.seesaw import Seesaw +from adafruit_seesaw.analoginput import AnalogInput + +i2c_bus = board.I2C() +ss = Seesaw(i2c_bus) + +analogin_pin = 2 +analog_in = AnalogInput(ss, analogin_pin) + +while True: + print(analog_in.value) + time.sleep(0.1) diff --git a/examples/seesaw_digitalio_test.py b/examples/seesaw_digitalio_test.py new file mode 100644 index 0000000..767b19b --- /dev/null +++ b/examples/seesaw_digitalio_test.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Simple seesaw test using an LED attached to Pin 5 and a button on pin 2 +# +# See the seesaw Learn Guide for wiring details: +# https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test + +import time +import board +import digitalio +from adafruit_seesaw.seesaw import Seesaw +from adafruit_seesaw.digitalio import DigitalIO + +i2c_bus = board.I2C() +ss = Seesaw(i2c_bus) + +button_pin = 2 +led_pin = 5 + +button = DigitalIO(ss, button_pin) +button.direction = digitalio.Direction.INPUT +button.pull = digitalio.Pull.UP + +led = DigitalIO(ss, led_pin) +led.direction = digitalio.Direction.OUTPUT + +while True: + # simply set the LED to the same 'value' as the button pin + led.value = button.value + time.sleep(0.1) diff --git a/examples/seesaw_eeprom_test.py b/examples/seesaw_eeprom_test.py new file mode 100644 index 0000000..aee917f --- /dev/null +++ b/examples/seesaw_eeprom_test.py @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Simple seesaw test reading and writing the internal EEPROM +# The ATtiny8xx series has a true 128 byte EEPROM, the SAMD09 mimics it in flash with 64 bytes +# THE LAST BYTE IS USED FOR I2C ADDRESS CHANGE! +# +# See the seesaw Learn Guide for wiring details: +# https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test + +import time +import board +from adafruit_seesaw import seesaw + +i2c_bus = board.I2C() +ss = seesaw.Seesaw(i2c_bus) + +val = ss.eeprom_read8(0x02) # read from address 2 +print("Read 0x%02x from EEPROM address 0x02" % val) + +print("Incremening value") +ss.eeprom_write8(0x02, val + 1) + +val = ss.eeprom_read8(0x02) # read from address 2 +print("Second read 0x%02x from EEPROM address 0x02" % val) + +while True: + # Do not write EEPROM in a loop, it has 100k cycle life + time.sleep(1) diff --git a/examples/seesaw_neopixel_test.py b/examples/seesaw_neopixel_test.py new file mode 100644 index 0000000..f25e3ba --- /dev/null +++ b/examples/seesaw_neopixel_test.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Simple seesaw test writing NeoPixels +# Can use any valid GPIO pin, up to 60 pixels! +# +# See the seesaw Learn Guide for wiring details: +# https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test + +import time +import board +from rainbowio import colorwheel +from adafruit_seesaw import seesaw, neopixel + +i2c_bus = board.I2C() +ss = seesaw.Seesaw(i2c_bus) + +NEOPIXEL_PIN = 6 # change to any pin +NEOPIXEL_NUM = 30 # no more than 60! +pixels = neopixel.NeoPixel(ss, NEOPIXEL_PIN, NEOPIXEL_NUM) +pixels.brightness = 0.3 # not so brite! + +color_offset = 0 # start at red + +# cycle through all colors along the strip +while True: + for i in range(NEOPIXEL_NUM): + rc_index = (i * 256 // NEOPIXEL_NUM) + color_offset + pixels[i] = colorwheel(rc_index & 255) + pixels.show() + color_offset += 1 + time.sleep(0.01) diff --git a/examples/seesaw_pwmout_test.py b/examples/seesaw_pwmout_test.py new file mode 100644 index 0000000..dbb2d6b --- /dev/null +++ b/examples/seesaw_pwmout_test.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Simple seesaw test for writing PWM outputs +# On the SAMD09 breakout these are pins 5, 6, and 7 +# On the ATtiny8x7 breakout these are pins 0, 1, 9, 12, 13 +# +# See the seesaw Learn Guide for wiring details: +# https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test + +import time +import board +from adafruit_seesaw import seesaw, pwmout + +i2c_bus = board.I2C() +ss = seesaw.Seesaw(i2c_bus) + +PWM_PIN = 9 # change to a valid PWM output! +pwm = pwmout.PWMOut(ss, PWM_PIN) + +while True: + # the API PWM range is 0 to 65535, but we increment by 256 since our + # resolution is often only 8 bits underneath + pwm.duty_cycle = (pwm.duty_cycle + 256) % 65536 + time.sleep(0.01)