From 66aa12c74183471ec447f435b8d69dc45aa59645 Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 16 Nov 2018 09:20:35 +0100 Subject: [PATCH 01/91] first starts on multi driver. Not Working. --- adafruit_tlc59711_mutli.py | 500 +++++++++++++++++++++++++++++++++++++ 1 file changed, 500 insertions(+) create mode 100644 adafruit_tlc59711_mutli.py diff --git a/adafruit_tlc59711_mutli.py b/adafruit_tlc59711_mutli.py new file mode 100644 index 0000000..4c08436 --- /dev/null +++ b/adafruit_tlc59711_mutli.py @@ -0,0 +1,500 @@ + +# The MIT License (MIT). +# +# Copyright (c) 2017 Tony DiCola for Adafruit Industries +# Copyright (c) 2018 Stefan Krüger s-light.eu +# +# 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. + +""" +`adafruit_tlc59711_multi`. + +==================================================== + +CircuitPython module for the +TLC59711 or TLC5971 16-bit 12 channel LED PWM driver. +See examples/simpletest_multi.py for a demo of the usage. + +* Author(s): Tony DiCola, Stefan Kruger + +Implementation Notes +-------------------- + +**Hardware:** + +* Adafruit `12-Channel 16-bit PWM LED Driver - SPI Interface - TLC59711 + `_ (Product ID: 1455) + or TLC5971 + +**Software and Dependencies:** + +* this is a variant with multi-chip support. + The API is mostly compatible to the DotStar / NeoPixel Libraries + and is therefore also compatible with FancyLED. + for thsi see examples/fancy_multi.py + +* Adafruit CircuitPython firmware for the ESP8622, M0 or M4-based boards: + https://github.com/adafruit/circuitpython/releases +""" +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" + + +# Globally disable invalid-name check as this chip by design has short channel +# and register names. It is confusing to rename these from what the datasheet +# refers to them as. +# pylint: disable=invalid-name + +# Globally disable too many instance attributes check. Again this is a case +# where pylint doesn't have the right context to make this call. The chip by +# design has many channels which must be exposed. +# pylint: disable=too-many-instance-attributes + +# Globally disable protected access. Once again pylint can't figure out the +# context for using internal decorate classes below. +# In these cases protectected access is by design for the internal class. +# pylint: disable=protected-access + +# Yet another pylint issue, it fails to recognize a decorator class by +# definition has no public methods. Disable the check. +# pylint: disable=too-few-public-methods + + +import ctypes + + +def _shift_in(target_byte, val): + # Shift in a new bit value to the provided target byte. The byte will be + # shift one position left and a new bit inserted that's a 1 if val is true, + # of a 0 if false. + target_byte <<= 1 + if val: + target_byte |= 0x01 + return target_byte + + +def _get_7bit_uint(buffer, start): + """Return 7bit interpreted as unsigned integer.""" + # 0b1111111 + pass + + +class TLC59711: + """Multi TLC59711 16-bit 12 channel LED PWM driver. + + This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. + The class has an interface compatible with the FancyLED. + and with this is similar to the NeoPixel and DotStar Interfaces. + + :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. + The clock and MOSI/outout must be set, the MISO/input is unused. + Maximal data clock frequence is: + - TLC59711: 10MHz + - TLC5971: 20MHz + :param bool pixel_count: Number of RGB-LEDs (=Pixels) are connected. + """ + + """ + TLC5971 data / register structure + + some detailed information on the protocol based on + http://www.ti.com/lit/ds/symlink/tlc5971.pdf + 8.5.4 Register and Data Latch Configuration (page 23ff) + 9.2.2.3 How to Control the TLC5971 (page27) + + How to send: + the first data we send are received by the last device in chain. + Device Nth (244Bit = 28Byte) + Write Command (6Bit) + WRCMD (fixed: 25h) + Function Control Data (5 x 1Bit = 5Bit) + OUTTMG 1bit + GS clock edge select + 1=rising edge, 0= falling edge + EXTGCK 1bit + GS reference clock select + 1=SCKI clock, 0=internal oscillator + TMGRST 1bit + display timing reset mode + 1=OUT forced of on latchpulse, 0=no forced reset + DSPRPT 1bit + display repeat mode + 1=auto repeate + 0=Out only turned on after Blank or internal latchpulse + BLANK 1bit; + 1=blank (outputs off) + 0=Out on - controlled by GS-Data + ic power on sets this to 1 + BC-Data (3 x 7Bits = 21Bit) + BCB 7bit; + BCG 7bit; + BCR 7bit; + GS-Data (12 x 16Bits = 192Bit) + GSB3 16bit; + GSG3 16bit; + GSR3 16bit; + GSB2 16bit; + GSG2 16bit; + GSR2 16bit; + GSB1 16bit; + GSG1 16bit; + GSR1 16bit; + GSB0 16bit; + GSG0 16bit; + GSR0 16bit; + Device Nth-1 (244Bit = 28Byte) + Device .. + Device 2 + Device 1 + short break of 8x period of clock (666ns .. 2.74ms) + to generate latchpulse + + 1.34uS + than next update. + """ + + ########################################## + # helper + ########################################## + + CHIP_BUFFER_LENGTH = 28 + CHIP_BUFFER_FC_OFFSET = 6 + CHIP_BUFFER_BC_OFFSET = CHIP_BUFFER_FC_OFFSET + 5 + + class _GS_Value: + # Internal decorator to simplify exposing each 16-bit LED PWM channel. + # These will get/set the appropriate bytes in the shift register with + # the specified values. + + def __init__(self, byte_offset): + # Keep track of the byte within the shift register where this + # 16-bit value starts. Luckily these are all aligned on byte + # boundaries. Note the byte order is big endian (MSB first). + self._byte_offset = byte_offset + + def __get__(self, obj, obj_type): + # Grab the 16-bit value at the offset for this channel. + return (obj._buffer[self._byte_offset] << 8) | \ + obj._buffer[self._byte_offset+1] + + def __set__(self, obj, val): + # Set the 16-bit value at the offset for this channel. + assert 0 <= val <= 65535 + obj._buffer[self._byte_offset] = (val >> 8) & 0xFF + obj._buffer[self._byte_offset+1] = val & 0xFF + + class _FC_bits(ctypes.LittleEndianStructure): + """ + Function Control Data (5 x 1Bit = 5Bit). + + OUTTMG 1bit + GS clock edge select + 1 = rising edge + 0 = falling edge + EXTGCK 1bit + GS reference clock select + 1 = SCKI clock + 0 = internal oscillator + TMGRST 1bit + display timing reset mode + 1 = OUT forced of on latchpulse + 0 = no forced reset + DSPRPT 1bit + display repeat mode + 1 = auto repeate + 0 = Out only turned on after Blank or internal latchpulse + BLANK 1bit; + ic power on sets this to 1 + 1 = blank (outputs off) + 0 = Out on - controlled by GS-Data + """ + + _fields_ = [ + ("OUTTMG", ctypes.c_uint8, 1), # asByte & 1 + ("EXTGCK", ctypes.c_uint8, 1), # asByte & 2 + ("TMGRST", ctypes.c_uint8, 1), # asByte & 4 + ("DSPRPT", ctypes.c_uint8, 1), # asByte & 8 + ("BLANK", ctypes.c_uint8, 1), # asByte & 16 + ] + + # pylama:ignore=E0602 + + class _FC(ctypes.Union): + _anonymous_ = ("bit",) + _fields_ = [ + ("bit", _FC_bits), + ("asByte", ctypes.c_uint8) + ] + + class _BC_bits(ctypes.LittleEndianStructure): + _fields_ = [ + ("BCB", ctypes.c_uint8, 7), # asByte & 1 + ("BCG", ctypes.c_uint8, 7), # asByte & 2 + ("BCR", ctypes.c_uint8, 7), # asByte & 4 + ] + + class _BC(ctypes.Union): + _anonymous_ = ("bit",) + _fields_ = [ + ("bit", _BC_bits), # pylint: disable=undefined-name + ("asByte", ctypes.c_uint32) + ] + + ########################################## + + def __init__(self, spi, pixel_count=1): + """Init.""" + self._spi = spi + # how many pixels are there? + self.pixel_count = pixel_count + # calculate how many chips are connected + self.chip_count = self.pixel_count // 4 + + # This device is just a big 28 byte long shift register without any + # fancy update protocol. Blast out all the bits to update, that's it! + # create raw output data + self._buffer = bytearray(CHIP_BUFFER_LENGTH * self.chip_count) + + # Initialize the brightness channel values to max (these are 7-bit + # values). + self._bcr = 127 + self._bcg = 127 + self._bcb = 127 + + # Initialize external user-facing state for the function control + # bits of the chip. These aren't commonly used but available and + # match the nomenclature from the datasheet. + # you must manually call update_fc() after changing them + # (reduces the need to make frivolous memory-hogging properties). + # Default set + # OUTTMG, TMGRST, and DSPRPT to on + # like in Arduino library. + # these are set for all chips + self.outtmg = True + self.extgclk = False + self.tmgrst = True + self.dsprpt = True + self.blank = False + + # preparation done + # now initialize buffer to default values + self._init_buffer() + + def _init_buffer(self): + for chip_index in range(self.chip_count): + # set Write Command (6Bit) WRCMD (fixed: 25h) + buffer_start = chip_index * CHIP_BUFFER_LENGTH + self._buffer[buffer_start] = 0x25 + + self._chip_set_FunctionControl(chip_index) + self.chip_set_BCData( + chip_index, BCR=self._bcr, BCG=self._bcg, BCB=self._bcb) + + def _chip_set_FunctionControl(self, chip_index): + """ + Set Function Control Bits in Buffer. + + values from object global parameters are used. + + :param int chip_index: Index of Chip to set. + """ + buffer_start = ( + (chip_index * CHIP_BUFFER_LENGTH) + + CHIP_BUFFER_FC_OFFSET + ) + fc = _FC() + fc.asByte = self._buffer[buffer_start] + + def update_fc(self): + """ + Update Function Control Bits for all Chips in Buffer. + + need to be called after you changed on of the + Function Control Bit Parameters. + (outtmg, extgclk, tmgrst, dsprpt, blank) + """ + for chip_index in range(self.chip_count): + self._chip_set_FunctionControl(chip_index) + + def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): + """ + Set BC-Data. + + :param int chip_index: Index of Chip to set. + :param int bcr: 7-bit value from 0-127 (default=127) + :param int bcg: 7-bit value from 0-127 (default=127) + :param int bcb: 7-bit value from 0-127 (default=127) + """ + buffer_start = ( + (chip_index * CHIP_BUFFER_LENGTH) + CHIP_BUFFER_BC_OFFSET + ) + bc = _BC() + bc.asByte = self._buffer[buffer_start] + + def _write(self): + # Write out the current state to the shift register. + try: + # Lock the SPI bus and configure it for the shift register. + while not self._spi.try_lock(): + pass + self._spi.configure(baudrate=10000000, polarity=0, phase=0) + # Update the preamble of chip state in the first 4 bytes (32-bits) + # with the write command, function control bits, and brightness + # control register values. + self._buffer[0] = 0x25 # 0x25 in top 6 bits initiates write. + # Lower two bits control OUTTMG and EXTGCLK bits, set them + # as appropriate. + self._buffer[0] = _shift_in(self._buffer[0], self.outtmg) + self._buffer[0] = _shift_in(self._buffer[0], self.extgclk) + # Next byte contains remaining function control state and start of + # brightness control bits. + self._buffer[1] = 0x00 + self._buffer[1] = _shift_in(self._buffer[1], self.tmgrst) + self._buffer[1] = _shift_in(self._buffer[1], self.dsprpt) + self._buffer[1] = _shift_in(self._buffer[1], self.blank) + # Top 5 bits from BC blue channel. + self._buffer[1] <<= 5 + self._buffer[1] |= (self._bcb >> 2) & 0b11111 + # Next byte contains lower 2 bits from BC blue channel and upper 6 + # from BC green channel. + self._buffer[2] = (self._bcb) & 0b11 + self._buffer[2] <<= 6 + self._buffer[2] |= (self._bcg >> 1) & 0b111111 + # Final byte contains lower 1 bit from BC green and 7 bits from BC + # red channel. + self._buffer[3] = self._bcg & 0b1 + self._buffer[3] <<= 7 + self._buffer[3] |= self._bcr & 0b1111111 + # The remaining bytes in the shift register are the channel PWM + # values that have already been set by the user. + # Now write out the the entire set of bytes. + # Note there is no latch or other explicit line to tell the chip + # when finished, it expects 28 bytes. + self._spi.write(self._buffer) + finally: + # Ensure the SPI bus is unlocked. + self._spi.unlock() + + def show(self): + """Write out the current LED PWM state to the chip.""" + self._write() + + # Define properties for global brightness control channels. + @property + def red_brightness(self): + """ + Red brightness for all channels on all chips. + + This is a 7-bit value from 0-127. + """ + return self._bcr + + @red_brightness.setter + def red_brightness(self, val): + assert 0 <= val <= 127 + self._bcr = val + if self.auto_show: + self._write() + + @property + def green_brightness(self): + """ + Green brightness for all channels on all chips. + + This is a 7-bit value from 0-127. + """ + return self._bcg + + @green_brightness.setter + def green_brightness(self, val): + assert 0 <= val <= 127 + self._bcg = val + if self.auto_show: + self._write() + + @property + def blue_brightness(self): + """ + Blue brightness for all channels on all chips. + + This is a 7-bit value from 0-127. + """ + return self._bcb + + @blue_brightness.setter + def blue_brightness(self, val): + assert 0 <= val <= 127 + self._bcb = val + if self.auto_show: + self._write() + + # Define index and length properties to set and get each channel as + # atomic RGB tuples. This provides a similar feel as using neopixels. + def __len__(self): + """Retrieve the total number of Pixels available.""" + return self.pixel_count + + def __getitem__(self, key): + # pylint: disable=no-else-return + # Disable should be removed when refactor can be tested + """ + Retrieve the R, G, B values for the provided channel as a 3-tuple. + + Each value is a 16-bit number from 0-65535. + """ + if 0 < key > (self.pixel_count-1): + raw_data_start = 14*(key / 12) + key % 12 + self._buffer[raw_data_start] + return (self.r0, self.g0, self.b0) + else: + raise IndexError + + def __setitem__(self, key, val): + """ + Set the R, G, B values for the provided channel. + + Specify a 3-tuple of R, G, B values that are each 16-bit numbers + (0-65535). + """ + # Do this check here instead of later to + # prevent accidentally keeping auto_show + # turned off when a bad key is provided. + assert 0 <= key <= 3 + + assert len(val) == 3 + assert 0 <= val[0] <= 65535 + assert 0 <= val[1] <= 65535 + assert 0 <= val[2] <= 65535 + # Temporarily halt auto write to perform an atomic update of all + # the channel values. + old_auto_show = self.auto_show + self.auto_show = False + # Update appropriate channel values. + if key == 0: + self.r0, self.g0, self.b0 = val + elif key == 1: + self.r1, self.g1, self.b1 = val + elif key == 2: + self.r2, self.g2, self.b2 = val + elif key == 3: + self.r3, self.g3, self.b3 = val + # Restore auto_show state. + self.auto_show = old_auto_show + # Write out new values if in auto_show state. + if self.auto_show: + self._write() From 80cc33ec5d0b6cfd51c320e83c9691d9203b898e Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Dec 2018 20:12:29 +0100 Subject: [PATCH 02/91] fix nameing --- adafruit_tlc59711_mutli.py => adafruit_tlc59711_multi.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename adafruit_tlc59711_mutli.py => adafruit_tlc59711_multi.py (100%) diff --git a/adafruit_tlc59711_mutli.py b/adafruit_tlc59711_multi.py similarity index 100% rename from adafruit_tlc59711_mutli.py rename to adafruit_tlc59711_multi.py From dc0978f314e883acb1eaf0e4a604614b38f326d0 Mon Sep 17 00:00:00 2001 From: s-light Date: Wed, 26 Dec 2018 12:28:49 +0100 Subject: [PATCH 03/91] prepared multifile version --- adafruit_tlc59711.py => adafruit_tlc59711/adafruit_tlc59711.py | 0 .../adafruit_tlc59711_multi.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename adafruit_tlc59711.py => adafruit_tlc59711/adafruit_tlc59711.py (100%) rename adafruit_tlc59711_multi.py => adafruit_tlc59711/adafruit_tlc59711_multi.py (100%) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711/adafruit_tlc59711.py similarity index 100% rename from adafruit_tlc59711.py rename to adafruit_tlc59711/adafruit_tlc59711.py diff --git a/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py similarity index 100% rename from adafruit_tlc59711_multi.py rename to adafruit_tlc59711/adafruit_tlc59711_multi.py From 38afd725ba108fba9b07a060a04c594afdc3a207 Mon Sep 17 00:00:00 2001 From: s-light Date: Wed, 26 Dec 2018 12:38:17 +0100 Subject: [PATCH 04/91] make pylama happy :-) --- adafruit_tlc59711/adafruit_tlc59711.py | 54 ++++++++++++++------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711.py b/adafruit_tlc59711/adafruit_tlc59711.py index e056ab9..3ac74de 100644 --- a/adafruit_tlc59711/adafruit_tlc59711.py +++ b/adafruit_tlc59711/adafruit_tlc59711.py @@ -48,21 +48,21 @@ # Globally disable invalid-name check as this chip by design has short channel # and register names. It is confusing to rename these from what the datasheet # refers to them as. -#pylint: disable=invalid-name +# pylint: disable=invalid-name # Globally disable too many instance attributes check. Again this is a case # where pylint doesn't have the right context to make this call. The chip by # design has many channels which must be exposed. -#pylint: disable=too-many-instance-attributes +# pylint: disable=too-many-instance-attributes # Globally disable protected access. Once again pylint can't figure out the -# context for using internal decorate classes below. In these cases protectected -# access is by design for the internal class. -#pylint: disable=protected-access +# context for using internal decorate classes below. +# In these cases protectected access is by design for the internal class. +# pylint: disable=protected-access # Yet another pylint issue, it fails to recognize a decorator class by # definition has no public methods. Disable the check. -#pylint: disable=too-few-public-methods +# pylint: disable=too-few-public-methods def _shift_in(target_byte, val): @@ -83,12 +83,13 @@ class TLC59711: independent channel by name (r0, g0, b0, r1, b1, etc.) as properties for fine-grained control. - :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. The clock and - MOSI/outout must be set, the MISO/input is unused. - :param bool auto_show: This is a boolean that defaults to True and indicates any - change to a channel value will instantly be written to the chip. You might wish to - set this to false if you desire to perform your own atomic operations of channel - values. In that case call the show function after making updates to channel state. + :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. + The clock and MOSI/outout must be set, the MISO/input is unused. + :param bool auto_show: This is a boolean that defaults to True and + indicates any change to a channel value will instantly be written + to the chip. You might wish to set this to false if you desire + to perform your own atomic operations of channel values. In that case + call the show function after making updates to channel state. """ class _GS_Value: @@ -105,13 +106,13 @@ def __init__(self, byte_offset): def __get__(self, obj, obj_type): # Grab the 16-bit value at the offset for this channel. return (obj._shift_reg[self._byte_offset] << 8) | \ - obj._shift_reg[self._byte_offset+1] + obj._shift_reg[self._byte_offset + 1] def __set__(self, obj, val): # Set the 16-bit value at the offset for this channel. assert 0 <= val <= 65535 obj._shift_reg[self._byte_offset] = (val >> 8) & 0xFF - obj._shift_reg[self._byte_offset+1] = val & 0xFF + obj._shift_reg[self._byte_offset + 1] = val & 0xFF # Write out the new values if auto_show is enabled. if obj.auto_show: obj._write() @@ -139,7 +140,7 @@ def __set__(self, obj, val): r0 = _GS_Value(26) - def __init__(self, spi, *, auto_show=True): + def __init__(self, spi, *, auto_show=True): # noqa self._spi = spi # This device is just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! @@ -220,8 +221,9 @@ def show(self): # Define properties for global brightness control channels. @property def red_brightness(self): - """The red brightness for all channels (i.e. R0, R1, R2, and R3). This is a 7-bit - value from 0-127. + """The red brightness for all channels (i.e. R0, R1, R2, and R3). + + This is a 7-bit value from 0-127. """ return self._bcr @@ -234,8 +236,9 @@ def red_brightness(self, val): @property def green_brightness(self): - """The green brightness for all channels (i.e. G0, G1, G2, and G3). This is a - 7-bit value from 0-127. + """The green brightness for all channels (i.e. G0, G1, G2, and G3). + + This is a 7-bit value from 0-127. """ return self._bcg @@ -248,8 +251,9 @@ def green_brightness(self, val): @property def blue_brightness(self): - """The blue brightness for all channels (i.e. B0, B1, B2, and B3). This is a 7-bit - value from 0-127. + """The blue brightness for all channels (i.e. B0, B1, B2, and B3). + + This is a 7-bit value from 0-127. """ return self._bcb @@ -287,9 +291,11 @@ def __setitem__(self, key, val): """Set the R, G, B values for the provided channel. Specify a 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). """ - assert 0 <= key <= 3 # Do this check here instead of later to - # prevent accidentally keeping auto_show - # turned off when a bad key is provided. + # Do this check here instead of later to + # prevent accidentally keeping auto_show + # turned off when a bad key is provided. + assert 0 <= key <= 3 + assert len(val) == 3 assert 0 <= val[0] <= 65535 assert 0 <= val[1] <= 65535 From 52fa830cf9013d3753d4b5f3523dae2eaa80eb33 Mon Sep 17 00:00:00 2001 From: s-light Date: Wed, 26 Dec 2018 12:43:08 +0100 Subject: [PATCH 05/91] make pylama happy :-) --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 24 +++++++++----------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 4c08436..c2b062c 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -190,13 +190,13 @@ def __init__(self, byte_offset): def __get__(self, obj, obj_type): # Grab the 16-bit value at the offset for this channel. return (obj._buffer[self._byte_offset] << 8) | \ - obj._buffer[self._byte_offset+1] + obj._buffer[self._byte_offset + 1] def __set__(self, obj, val): # Set the 16-bit value at the offset for this channel. assert 0 <= val <= 65535 obj._buffer[self._byte_offset] = (val >> 8) & 0xFF - obj._buffer[self._byte_offset+1] = val & 0xFF + obj._buffer[self._byte_offset + 1] = val & 0xFF class _FC_bits(ctypes.LittleEndianStructure): """ @@ -268,7 +268,7 @@ def __init__(self, spi, pixel_count=1): # This device is just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data - self._buffer = bytearray(CHIP_BUFFER_LENGTH * self.chip_count) + self._buffer = bytearray(self.CHIP_BUFFER_LENGTH * self.chip_count) # Initialize the brightness channel values to max (these are 7-bit # values). @@ -298,7 +298,7 @@ def __init__(self, spi, pixel_count=1): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - buffer_start = chip_index * CHIP_BUFFER_LENGTH + buffer_start = chip_index * self.CHIP_BUFFER_LENGTH self._buffer[buffer_start] = 0x25 self._chip_set_FunctionControl(chip_index) @@ -313,11 +313,9 @@ def _chip_set_FunctionControl(self, chip_index): :param int chip_index: Index of Chip to set. """ - buffer_start = ( - (chip_index * CHIP_BUFFER_LENGTH) + - CHIP_BUFFER_FC_OFFSET - ) - fc = _FC() + buffer_start = (chip_index * self.CHIP_BUFFER_LENGTH) + \ + self.CHIP_BUFFER_FC_OFFSET + fc = self._FC() fc.asByte = self._buffer[buffer_start] def update_fc(self): @@ -341,9 +339,9 @@ def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): :param int bcb: 7-bit value from 0-127 (default=127) """ buffer_start = ( - (chip_index * CHIP_BUFFER_LENGTH) + CHIP_BUFFER_BC_OFFSET + (chip_index * self.CHIP_BUFFER_LENGTH) + self.CHIP_BUFFER_BC_OFFSET ) - bc = _BC() + bc = self._BC() bc.asByte = self._buffer[buffer_start] def _write(self): @@ -457,8 +455,8 @@ def __getitem__(self, key): Each value is a 16-bit number from 0-65535. """ - if 0 < key > (self.pixel_count-1): - raw_data_start = 14*(key / 12) + key % 12 + if 0 < key > (self.pixel_count - 1): + raw_data_start = 14 * (key / 12) + key % 12 self._buffer[raw_data_start] return (self.r0, self.g0, self.b0) else: From f92abd2cc616ffbbfcc1813586a254f3f497d812 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 01:37:01 +0100 Subject: [PATCH 06/91] debugging... --- .gitignore | 3 +- adafruit_tlc59711/adafruit_tlc59711_multi.py | 605 ++++++++++++------- examples/tlc59711_multi_simpletest.py | 81 +++ 3 files changed, 481 insertions(+), 208 deletions(-) create mode 100644 examples/tlc59711_multi_simpletest.py diff --git a/.gitignore b/.gitignore index 55f127b..45fa8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.mpy .idea +*.idea.py __pycache__ _build *.pyc @@ -9,4 +10,4 @@ bundles *.DS_Store .eggs dist -**/*.egg-info \ No newline at end of file +**/*.egg-info diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index c2b062c..0d17282 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -47,7 +47,7 @@ * this is a variant with multi-chip support. The API is mostly compatible to the DotStar / NeoPixel Libraries and is therefore also compatible with FancyLED. - for thsi see examples/fancy_multi.py + for this see examples/fancy_multi.py * Adafruit CircuitPython firmware for the ESP8622, M0 or M4-based boards: https://github.com/adafruit/circuitpython/releases @@ -76,26 +76,10 @@ # pylint: disable=too-few-public-methods -import ctypes +# this is not available in CircuitPython +# import uctypes as ctypes - -def _shift_in(target_byte, val): - # Shift in a new bit value to the provided target byte. The byte will be - # shift one position left and a new bit inserted that's a 1 if val is true, - # of a 0 if false. - target_byte <<= 1 - if val: - target_byte |= 0x01 - return target_byte - - -def _get_7bit_uint(buffer, start): - """Return 7bit interpreted as unsigned integer.""" - # 0b1111111 - pass - - -class TLC59711: +class TLC59711Multi: """Multi TLC59711 16-bit 12 channel LED PWM driver. This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. @@ -173,8 +157,42 @@ class TLC59711: ########################################## CHIP_BUFFER_LENGTH = 28 - CHIP_BUFFER_FC_OFFSET = 6 - CHIP_BUFFER_BC_OFFSET = CHIP_BUFFER_FC_OFFSET + 5 + WRITE_COMMAND = 0b100101 + WRITE_COMMAND_BIT_COUNT = 6 + + COLORS_PER_PIXEL = 3 + PIXEL_PER_CHIP = 4 + CHANNEL_PER_CHIP = COLORS_PER_PIXEL * PIXEL_PER_CHIP + BUFFER_BYTES_PER_COLOR = 2 + BUFFER_BYTES_PER_PIXEL = BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL + + @staticmethod + def set_bit_with_mask(v, mask, x): + """Set bit with help of mask.""" + # clear + v &= ~mask + if x: + # set + v |= mask + return v + + @staticmethod + def set_bit(v, index, x): + """Set bit - return new value. + + Set the index:th bit of v to 1 if x is truthy, + else to 0, and return the new value. + https://stackoverflow.com/a/12174051/574981 + """ + # Compute mask, an integer with just bit 'index' set. + mask = 1 << index + # Clear the bit indicated by the mask (if x is False) + v &= ~mask + if x: + # If x was True, set the bit indicated by the mask. + v |= mask + # Return the result, we're done. + return v class _GS_Value: # Internal decorator to simplify exposing each 16-bit LED PWM channel. @@ -198,62 +216,139 @@ def __set__(self, obj, val): obj._buffer[self._byte_offset] = (val >> 8) & 0xFF obj._buffer[self._byte_offset + 1] = val & 0xFF - class _FC_bits(ctypes.LittleEndianStructure): - """ - Function Control Data (5 x 1Bit = 5Bit). + ########################################## + # class _FC(): + """ + Function Control Data (5 x 1Bit = 5Bit). + + OUTTMG 1bit + GS clock edge select + 1 = rising edge + 0 = falling edge + EXTGCK 1bit + GS reference clock select + 1 = SCKI clock + 0 = internal oscillator + TMGRST 1bit + display timing reset mode + 1 = OUT forced of on latchpulse + 0 = no forced reset + DSPRPT 1bit + display repeat mode + 1 = auto repeate + 0 = Out only turned on after Blank or internal latchpulse + BLANK 1bit; + ic power on sets this to 1 + 1 = blank (outputs off) + 0 = Out on - controlled by GS-Data + """ - OUTTMG 1bit - GS clock edge select - 1 = rising edge - 0 = falling edge - EXTGCK 1bit - GS reference clock select - 1 = SCKI clock - 0 = internal oscillator - TMGRST 1bit - display timing reset mode - 1 = OUT forced of on latchpulse - 0 = no forced reset - DSPRPT 1bit - display repeat mode - 1 = auto repeate - 0 = Out only turned on after Blank or internal latchpulse - BLANK 1bit; - ic power on sets this to 1 - 1 = blank (outputs off) - 0 = Out on - controlled by GS-Data - """ + _FC_CHIP_BUFFER_BIT_OFFSET = WRITE_COMMAND_BIT_COUNT + _FC_BIT_COUNT = 5 + _FC_FIELDS = { + "OUTTMG": { + "offset": 0, + "length": 1, + "mask": 0b1, + }, + "EXTGCK": { + "offset": 1, + "length": 1, + "mask": 0b1, + }, + "TMGRST": { + "offset": 2, + "length": 1, + "mask": 0b1, + }, + "DSPRPT": { + "offset": 3, + "length": 1, + "mask": 0b1, + }, + "BLANK": { + "offset": 4, + "length": 1, + "mask": 0b1, + }, + } + + ########################################## + # class _BC(): + """ + BC-Data (3 x 7Bits = 21Bit). - _fields_ = [ - ("OUTTMG", ctypes.c_uint8, 1), # asByte & 1 - ("EXTGCK", ctypes.c_uint8, 1), # asByte & 2 - ("TMGRST", ctypes.c_uint8, 1), # asByte & 4 - ("DSPRPT", ctypes.c_uint8, 1), # asByte & 8 - ("BLANK", ctypes.c_uint8, 1), # asByte & 16 - ] - - # pylama:ignore=E0602 - - class _FC(ctypes.Union): - _anonymous_ = ("bit",) - _fields_ = [ - ("bit", _FC_bits), - ("asByte", ctypes.c_uint8) - ] - - class _BC_bits(ctypes.LittleEndianStructure): - _fields_ = [ - ("BCB", ctypes.c_uint8, 7), # asByte & 1 - ("BCG", ctypes.c_uint8, 7), # asByte & 2 - ("BCR", ctypes.c_uint8, 7), # asByte & 4 - ] - - class _BC(ctypes.Union): - _anonymous_ = ("bit",) - _fields_ = [ - ("bit", _BC_bits), # pylint: disable=undefined-name - ("asByte", ctypes.c_uint32) - ] + BCB 7bit; + BCG 7bit; + BCR 7bit; + """ + _BC_CHIP_BUFFER_BIT_OFFSET = WRITE_COMMAND_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT = 3 * 7 + # this holds the chip offset and + _BC_FIELDS = { + "BCB": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCR": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, + } + + ######## + CHIP_BUFFER_HEADER_BIT_COUNT = \ + WRITE_COMMAND_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT + CHIP_BUFFER_HEADER_BYTE_COUNT = CHIP_BUFFER_HEADER_BIT_COUNT // 8 + + ########################################## + + def set_chipheader_bits_in_buffer( + self, + *, # noqa + chip_index=0, + part_bit_offset=0, + field={"mask": 0, "length": 0, "offset": 0}, + value=0 + ): + """Set chip header bits in buffer.""" + print( + "chip_index={} " + "part_bit_offset={} " + "field={} " + "value={} " + "".format( + chip_index, + part_bit_offset, + field, + value + ) + ) + offset = part_bit_offset + field["offset"] + # restrict value + value &= field["mask"] + # move value to position + value = value << offset + # calculate header start + header_start = chip_index * self.CHIP_BUFFER_LENGTH + # get chip header + header = 0xFFFFFFFF & self._buffer[header_start] + # 0xFFFFFFFF == 0b11111111111111111111111111111111 + # create/move mask + mask = field["mask"] << offset + # clear + header &= ~mask + # set + header |= value + # write header back + self._buffer[header_start] = header ########################################## @@ -265,7 +360,7 @@ def __init__(self, spi, pixel_count=1): # calculate how many chips are connected self.chip_count = self.pixel_count // 4 - # This device is just a big 28 byte long shift register without any + # THe chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data self._buffer = bytearray(self.CHIP_BUFFER_LENGTH * self.chip_count) @@ -286,24 +381,28 @@ def __init__(self, spi, pixel_count=1): # like in Arduino library. # these are set for all chips self.outtmg = True - self.extgclk = False + self.extgck = False self.tmgrst = True self.dsprpt = True self.blank = False # preparation done # now initialize buffer to default values + + self._debug_print_buffer() + print("init buffer..") self._init_buffer() + self._debug_print_buffer() def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) buffer_start = chip_index * self.CHIP_BUFFER_LENGTH - self._buffer[buffer_start] = 0x25 + self._buffer[buffer_start] = 0x25 << 2 self._chip_set_FunctionControl(chip_index) - self.chip_set_BCData( - chip_index, BCR=self._bcr, BCG=self._bcg, BCB=self._bcb) + # self.chip_set_BCData( + # chip_index, bcr=self._bcr, bcg=self._bcg, bcb=self._bcb) def _chip_set_FunctionControl(self, chip_index): """ @@ -313,10 +412,32 @@ def _chip_set_FunctionControl(self, chip_index): :param int chip_index: Index of Chip to set. """ - buffer_start = (chip_index * self.CHIP_BUFFER_LENGTH) + \ - self.CHIP_BUFFER_FC_OFFSET - fc = self._FC() - fc.asByte = self._buffer[buffer_start] + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["OUTTMG"], + value=self.outtmg) + # self.set_chipheader_bits_in_buffer( + # chip_index=chip_index, + # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + # field=self._FC_FIELDS["EXTGCK"], + # value=self.extgck) + # self.set_chipheader_bits_in_buffer( + # chip_index=chip_index, + # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + # field=self._FC_FIELDS["TMGRST"], + # value=self.tmgrst) + # self.set_chipheader_bits_in_buffer( + # chip_index=chip_index, + # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + # field=self._FC_FIELDS["DSPRPT"], + # value=self.dsprpt) + # self.set_chipheader_bits_in_buffer( + # chip_index=chip_index, + # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + # field=self._FC_FIELDS["BLANK"], + # value=self.blank) def update_fc(self): """ @@ -324,7 +445,7 @@ def update_fc(self): need to be called after you changed on of the Function Control Bit Parameters. - (outtmg, extgclk, tmgrst, dsprpt, blank) + (outtmg, extgck, tmgrst, dsprpt, blank) """ for chip_index in range(self.chip_count): self._chip_set_FunctionControl(chip_index) @@ -338,51 +459,33 @@ def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): :param int bcg: 7-bit value from 0-127 (default=127) :param int bcb: 7-bit value from 0-127 (default=127) """ - buffer_start = ( - (chip_index * self.CHIP_BUFFER_LENGTH) + self.CHIP_BUFFER_BC_OFFSET - ) - bc = self._BC() - bc.asByte = self._buffer[buffer_start] + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCR"], + value=bcr) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCG"], + value=bcg) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCB"], + value=bcb) + + ########################################## def _write(self): # Write out the current state to the shift register. + self._debug_print_buffer() try: # Lock the SPI bus and configure it for the shift register. while not self._spi.try_lock(): pass self._spi.configure(baudrate=10000000, polarity=0, phase=0) - # Update the preamble of chip state in the first 4 bytes (32-bits) - # with the write command, function control bits, and brightness - # control register values. - self._buffer[0] = 0x25 # 0x25 in top 6 bits initiates write. - # Lower two bits control OUTTMG and EXTGCLK bits, set them - # as appropriate. - self._buffer[0] = _shift_in(self._buffer[0], self.outtmg) - self._buffer[0] = _shift_in(self._buffer[0], self.extgclk) - # Next byte contains remaining function control state and start of - # brightness control bits. - self._buffer[1] = 0x00 - self._buffer[1] = _shift_in(self._buffer[1], self.tmgrst) - self._buffer[1] = _shift_in(self._buffer[1], self.dsprpt) - self._buffer[1] = _shift_in(self._buffer[1], self.blank) - # Top 5 bits from BC blue channel. - self._buffer[1] <<= 5 - self._buffer[1] |= (self._bcb >> 2) & 0b11111 - # Next byte contains lower 2 bits from BC blue channel and upper 6 - # from BC green channel. - self._buffer[2] = (self._bcb) & 0b11 - self._buffer[2] <<= 6 - self._buffer[2] |= (self._bcg >> 1) & 0b111111 - # Final byte contains lower 1 bit from BC green and 7 bits from BC - # red channel. - self._buffer[3] = self._bcg & 0b1 - self._buffer[3] <<= 7 - self._buffer[3] |= self._bcr & 0b1111111 - # The remaining bytes in the shift register are the channel PWM - # values that have already been set by the user. - # Now write out the the entire set of bytes. - # Note there is no latch or other explicit line to tell the chip - # when finished, it expects 28 bytes. self._spi.write(self._buffer) finally: # Ensure the SPI bus is unlocked. @@ -392,107 +495,195 @@ def show(self): """Write out the current LED PWM state to the chip.""" self._write() - # Define properties for global brightness control channels. - @property - def red_brightness(self): - """ - Red brightness for all channels on all chips. - - This is a 7-bit value from 0-127. - """ - return self._bcr - - @red_brightness.setter - def red_brightness(self, val): - assert 0 <= val <= 127 - self._bcr = val - if self.auto_show: - self._write() + def _debug_print_buffer(self): + print("buffer: [", end="") + for index in range(self.chip_count): + print("{}: ".format(index), end="") + # print() + # self._debug_print_tlc59711_bin() + # print() + # self._debug_print_tlc59711_hex() + self._debug_print_tlc59711() + print("]") + + def _debug_print_tlc59711_bin(self): + for index in range(len(self._buffer)): + print("{:08b}".format(self._buffer[index]), end="") + + def _debug_print_tlc59711_hex(self): + for index in range(len(self._buffer)): + print("x{:02X}, ".format(self._buffer[index]), end="") + + def _debug_print_tlc59711(self): + self._debug_print_tlc59711_header() + self._debug_print_tlc59711_ch() + + def _debug_print_tlc59711_header(self): + print( + "self.CHIP_BUFFER_HEADER_BYTE_COUNT", + self.CHIP_BUFFER_HEADER_BYTE_COUNT) + print("header: '", end="") + for index in range(self.CHIP_BUFFER_HEADER_BYTE_COUNT): + print("{:08b} ".format(self._buffer[index]), end="") + print("' ", end="") + + def _debug_print_tlc59711_ch(self): + print("ch: [", end="") + for index in range( + self.CHIP_BUFFER_HEADER_BYTE_COUNT, len(self._buffer) + ): + print("x{:02X}, ".format(self._buffer[index]), end="") + print("]", end="") - @property - def green_brightness(self): - """ - Green brightness for all channels on all chips. - - This is a 7-bit value from 0-127. - """ - return self._bcg - - @green_brightness.setter - def green_brightness(self, val): - assert 0 <= val <= 127 - self._bcg = val - if self.auto_show: - self._write() - - @property - def blue_brightness(self): - """ - Blue brightness for all channels on all chips. - - This is a 7-bit value from 0-127. - """ - return self._bcb + # Define properties for global brightness control channels. + # @property + # def red_brightness(self): + # """ + # Red brightness for all channels on all chips. + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcr + # + # @red_brightness.setter + # def red_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcr = val + # if self.auto_show: + # self._write() + # + # @property + # def green_brightness(self): + # """ + # Green brightness for all channels on all chips. + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcg + # + # @green_brightness.setter + # def green_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcg = val + # if self.auto_show: + # self._write() + # + # @property + # def blue_brightness(self): + # """ + # Blue brightness for all channels on all chips. + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcb + # + # @blue_brightness.setter + # def blue_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcb = val + # if self.auto_show: + # self._write() + + def _get_16bit_value_from_buffer(self, buffer_start): + return ( + (self._buffer[buffer_start + 0] << 8) | + self._buffer[buffer_start + 1] + ) - @blue_brightness.setter - def blue_brightness(self, val): - assert 0 <= val <= 127 - self._bcb = val - if self.auto_show: - self._write() + def _set_16bit_value_in_buffer(self, buffer_start, value): + assert 0 <= value <= 65535 + # print("buffer_start", buffer_start, "value", value) + # self._debug_print_buffer() + self._buffer[buffer_start + 0] = (value >> 8) & 0xFF + self._buffer[buffer_start + 1] = value & 0xFF + + @staticmethod + def _convert_01_float_to_16bit_integer(value): + """Convert 0..1 Float Value to 16bit (0..65535) Range.""" + # check if values are in range + assert 0 <= value <= 1 + # convert to 16bit value + return int(value * 65535) + + @classmethod + def _convert_if_float(cls, value): + """Convert if value is Float.""" + if isinstance(value, float): + value = cls._convert_01_float_to_16bit_integer(value) + return value + + def _set_channel_16bit_value(self, channel_index, value): + buffer_index = ( + self.CHIP_BUFFER_LENGTH * (channel_index // self.CHANNEL_PER_CHIP) + + channel_index % self.CHANNEL_PER_CHIP + ) + buffer_index *= self.BUFFER_BYTES_PER_COLOR + buffer_index += self.CHIP_BUFFER_HEADER_BYTE_COUNT + self._set_16bit_value_in_buffer(buffer_index, value) # Define index and length properties to set and get each channel as # atomic RGB tuples. This provides a similar feel as using neopixels. def __len__(self): - """Retrieve the total number of Pixels available.""" + """Retrieve TLC5975 the total number of Pixels available.""" return self.pixel_count def __getitem__(self, key): - # pylint: disable=no-else-return - # Disable should be removed when refactor can be tested """ Retrieve the R, G, B values for the provided channel as a 3-tuple. Each value is a 16-bit number from 0-65535. """ - if 0 < key > (self.pixel_count - 1): - raw_data_start = 14 * (key / 12) + key % 12 - self._buffer[raw_data_start] - return (self.r0, self.g0, self.b0) + if 0 <= key < self.pixel_count: + return ( + self._get_16bit_value_from_buffer(key + 0), + self._get_16bit_value_from_buffer(key + 2), + self._get_16bit_value_from_buffer(key + 4) + ) else: - raise IndexError + raise IndexError("index {} out of range".format(key)) - def __setitem__(self, key, val): + def __setitem__(self, key, value): """ Set the R, G, B values for the provided channel. - Specify a 3-tuple of R, G, B values that are each 16-bit numbers - (0-65535). + Specify a 3-tuple of R, G, B values that are each + - 16-bit numbers (0-65535) + - or 0..1 floats """ - # Do this check here instead of later to - # prevent accidentally keeping auto_show - # turned off when a bad key is provided. - assert 0 <= key <= 3 - - assert len(val) == 3 - assert 0 <= val[0] <= 65535 - assert 0 <= val[1] <= 65535 - assert 0 <= val[2] <= 65535 - # Temporarily halt auto write to perform an atomic update of all - # the channel values. - old_auto_show = self.auto_show - self.auto_show = False - # Update appropriate channel values. - if key == 0: - self.r0, self.g0, self.b0 = val - elif key == 1: - self.r1, self.g1, self.b1 = val - elif key == 2: - self.r2, self.g2, self.b2 = val - elif key == 3: - self.r3, self.g3, self.b3 = val - # Restore auto_show state. - self.auto_show = old_auto_show - # Write out new values if in auto_show state. - if self.auto_show: - self._write() + if 0 <= key < self.pixel_count: + # print("value", value) + # convert to list + value = list(value) + # print("value", value) + # print("rep:") + # repr(value) + # print("check length..") + assert len(value) == 3 + # check if we have float values + value[0] = self._convert_if_float(value[0]) + value[1] = self._convert_if_float(value[1]) + value[2] = self._convert_if_float(value[2]) + # print("value", value) + + # check if values are in range + assert 0 <= value[0] <= 65535 + assert 0 <= value[1] <= 65535 + assert 0 <= value[2] <= 65535 + # update buffer + # print("key", key, "value", value) + # we change channel order here: + # buffer channel order is blue, green, red + pixel_start = key * self.COLORS_PER_PIXEL + self._set_channel_16bit_value( + pixel_start + 0, + value[0]) + self._set_channel_16bit_value( + pixel_start + 1, + value[1]) + self._set_channel_16bit_value( + pixel_start + 2, + value[2]) + else: + raise IndexError("index {} out of range".format(key)) + +########################################## diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py new file mode 100644 index 0000000..ff8ce8e --- /dev/null +++ b/examples/tlc59711_multi_simpletest.py @@ -0,0 +1,81 @@ +"""TLC5971 / TLC59711 Multi.""" + +__doc__ = """ +tlc59711_multi.py - TLC59711TLC59711Multi minimal example. + +Enjoy the colors :-) +""" + +import time + +import board +import busio + +# from adafruit_tlc59711.adafruit_tlc59711 import TLC59711 +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + + +########################################## +pixel_count = 4 + +spi = busio.SPI(board.SCK, MOSI=board.MOSI) +pixels = TLC59711Multi(spi, pixel_count=pixel_count) + + +########################################## +# test function + +offset = 0 +value_high = 65535 + + +def channelcheck_update(): + """ChannelCheck.""" + global offset #noqa + print("offset", offset) + + # pixels[offset] = (value_high, 0, 0) + pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) + pixels.show() + + offset += 1 + if offset >= pixel_count: + offset = 0 + set_all_black() + time.sleep(5) + print() + + +def set_all_black(): + """Set all Pixel to Black.""" + set_all((0, 0, 0)) + + +def set_all(color): + """Set all Pixel to color.""" + for i in range(pixel_count): + # pixels[i // 4][i % 4] = color + pixels[i] = color + + +def test_main(): + """Test Main.""" + print() + print(42 * '*') + print(__doc__) + print(42 * '*') + print() + time.sleep(0.5) + print(42 * '*') + + while True: + # channelcheck_update() + time.sleep(1) + + +########################################## +# main loop + +if __name__ == '__main__': + + test_main() From 6f0eec1515103e686c3d82af6a42d04982e64b71 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 02:20:34 +0100 Subject: [PATCH 07/91] working :joy: --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 255 ++++++++++++------- examples/tlc59711_multi_simpletest.py | 16 +- 2 files changed, 168 insertions(+), 103 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 0d17282..c874dd2 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -157,8 +157,6 @@ class TLC59711Multi: ########################################## CHIP_BUFFER_LENGTH = 28 - WRITE_COMMAND = 0b100101 - WRITE_COMMAND_BIT_COUNT = 6 COLORS_PER_PIXEL = 3 PIXEL_PER_CHIP = 4 @@ -216,6 +214,36 @@ def __set__(self, obj, val): obj._buffer[self._byte_offset] = (val >> 8) & 0xFF obj._buffer[self._byte_offset + 1] = val & 0xFF + ########################################## + # class _BC(): + """ + BC-Data (3 x 7Bits = 21Bit). + + BCB 7bit; + BCG 7bit; + BCR 7bit; + """ + _BC_CHIP_BUFFER_BIT_OFFSET = 0 + _BC_BIT_COUNT = 3 * 7 + # this holds the chip offset and + _BC_FIELDS = { + "BCB": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCR": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, + } + ########################################## # class _FC(): """ @@ -243,15 +271,15 @@ def __set__(self, obj, val): 0 = Out on - controlled by GS-Data """ - _FC_CHIP_BUFFER_BIT_OFFSET = WRITE_COMMAND_BIT_COUNT + _FC_CHIP_BUFFER_BIT_OFFSET = _BC_BIT_COUNT _FC_BIT_COUNT = 5 _FC_FIELDS = { - "OUTTMG": { + "BLANK": { "offset": 0, "length": 1, "mask": 0b1, }, - "EXTGCK": { + "DSPRPT": { "offset": 1, "length": 1, "mask": 0b1, @@ -261,12 +289,12 @@ def __set__(self, obj, val): "length": 1, "mask": 0b1, }, - "DSPRPT": { + "EXTGCK": { "offset": 3, "length": 1, "mask": 0b1, }, - "BLANK": { + "OUTTMG": { "offset": 4, "length": 1, "mask": 0b1, @@ -274,38 +302,26 @@ def __set__(self, obj, val): } ########################################## - # class _BC(): - """ - BC-Data (3 x 7Bits = 21Bit). + # class _WRITE_COMMAND(): + """WRITE_COMMAND.""" - BCB 7bit; - BCG 7bit; - BCR 7bit; - """ - _BC_CHIP_BUFFER_BIT_OFFSET = WRITE_COMMAND_BIT_COUNT + _FC_BIT_COUNT - _BC_BIT_COUNT = 3 * 7 - # this holds the chip offset and - _BC_FIELDS = { - "BCB": { + _WC_CHIP_BUFFER_BIT_OFFSET = _FC_BIT_COUNT + _BC_BIT_COUNT + _WC_BIT_COUNT = 6 + _WC_FIELDS = { + "WRITE_COMMAND": { "offset": 0, - "length": 7, - "mask": 0b01111111, - }, - "BCG": { - "offset": 7, - "length": 7, - "mask": 0b01111111, - }, - "BCR": { - "offset": 14, - "length": 7, - "mask": 0b01111111, + "length": 6, + "mask": 0b111111, }, } + WRITE_COMMAND = 0b100101 + ########################################## + + ######## CHIP_BUFFER_HEADER_BIT_COUNT = \ - WRITE_COMMAND_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT + _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT CHIP_BUFFER_HEADER_BYTE_COUNT = CHIP_BUFFER_HEADER_BIT_COUNT // 8 ########################################## @@ -319,18 +335,18 @@ def set_chipheader_bits_in_buffer( value=0 ): """Set chip header bits in buffer.""" - print( - "chip_index={} " - "part_bit_offset={} " - "field={} " - "value={} " - "".format( - chip_index, - part_bit_offset, - field, - value - ) - ) + # print( + # "chip_index={} " + # "part_bit_offset={} " + # "field={} " + # "value={} " + # "".format( + # chip_index, + # part_bit_offset, + # field, + # value + # ) + # ) offset = part_bit_offset + field["offset"] # restrict value value &= field["mask"] @@ -339,7 +355,8 @@ def set_chipheader_bits_in_buffer( # calculate header start header_start = chip_index * self.CHIP_BUFFER_LENGTH # get chip header - header = 0xFFFFFFFF & self._buffer[header_start] + header = self._get_32bit_value_from_buffer(header_start) + # print("{:032b}".format(header)) # 0xFFFFFFFF == 0b11111111111111111111111111111111 # create/move mask mask = field["mask"] << offset @@ -348,7 +365,7 @@ def set_chipheader_bits_in_buffer( # set header |= value # write header back - self._buffer[header_start] = header + self._set_32bit_value_in_buffer(header_start, header) ########################################## @@ -389,20 +406,51 @@ def __init__(self, spi, pixel_count=1): # preparation done # now initialize buffer to default values - self._debug_print_buffer() + # self._debug_print_buffer() print("init buffer..") self._init_buffer() - self._debug_print_buffer() + # self._debug_print_buffer() def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - buffer_start = chip_index * self.CHIP_BUFFER_LENGTH - self._buffer[buffer_start] = 0x25 << 2 + # buffer_start = chip_index * self.CHIP_BUFFER_LENGTH + # self._buffer[buffer_start] = 0x25 << 2 + self._debug_print_buffer() + self.chip_set_BCData( + chip_index, bcr=self._bcr, bcg=self._bcg, bcb=self._bcb) + self._debug_print_buffer() self._chip_set_FunctionControl(chip_index) - # self.chip_set_BCData( - # chip_index, bcr=self._bcr, bcg=self._bcg, bcb=self._bcb) + self._debug_print_buffer() + self._chip_set_WriteCommand(chip_index) + self._debug_print_buffer() + + def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): + """ + Set BC-Data. + + :param int chip_index: Index of Chip to set. + :param int bcr: 7-bit value from 0-127 (default=127) + :param int bcg: 7-bit value from 0-127 (default=127) + :param int bcb: 7-bit value from 0-127 (default=127) + """ + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCR"], + value=bcr) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCG"], + value=bcg) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCB"], + value=bcb) def _chip_set_FunctionControl(self, chip_index): """ @@ -418,26 +466,26 @@ def _chip_set_FunctionControl(self, chip_index): part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["OUTTMG"], value=self.outtmg) - # self.set_chipheader_bits_in_buffer( - # chip_index=chip_index, - # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, - # field=self._FC_FIELDS["EXTGCK"], - # value=self.extgck) - # self.set_chipheader_bits_in_buffer( - # chip_index=chip_index, - # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, - # field=self._FC_FIELDS["TMGRST"], - # value=self.tmgrst) - # self.set_chipheader_bits_in_buffer( - # chip_index=chip_index, - # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, - # field=self._FC_FIELDS["DSPRPT"], - # value=self.dsprpt) - # self.set_chipheader_bits_in_buffer( - # chip_index=chip_index, - # part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, - # field=self._FC_FIELDS["BLANK"], - # value=self.blank) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["EXTGCK"], + value=self.extgck) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["TMGRST"], + value=self.tmgrst) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["DSPRPT"], + value=self.dsprpt) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["BLANK"], + value=self.blank) def update_fc(self): """ @@ -450,31 +498,16 @@ def update_fc(self): for chip_index in range(self.chip_count): self._chip_set_FunctionControl(chip_index) - def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): + def _chip_set_WriteCommand(self, chip_index): """ - Set BC-Data. - - :param int chip_index: Index of Chip to set. - :param int bcr: 7-bit value from 0-127 (default=127) - :param int bcg: 7-bit value from 0-127 (default=127) - :param int bcb: 7-bit value from 0-127 (default=127) + Set WRITE_COMMAND. """ # set all bits self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCR"], - value=bcr) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCG"], - value=bcg) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCB"], - value=bcb) + part_bit_offset=self._WC_CHIP_BUFFER_BIT_OFFSET, + field=self._WC_FIELDS["WRITE_COMMAND"], + value=self.WRITE_COMMAND) ########################################## @@ -496,14 +529,21 @@ def show(self): self._write() def _debug_print_buffer(self): - print("buffer: [", end="") + indent = " " + if self.chip_count == 1: + print("buffer: [", end="") + indent = "" + else: + print("buffer: [") for index in range(self.chip_count): - print("{}: ".format(index), end="") + print("{}{}: ".format(indent, index), end="") # print() # self._debug_print_tlc59711_bin() # print() # self._debug_print_tlc59711_hex() self._debug_print_tlc59711() + if self.chip_count > 1: + print() print("]") def _debug_print_tlc59711_bin(self): @@ -519,9 +559,9 @@ def _debug_print_tlc59711(self): self._debug_print_tlc59711_ch() def _debug_print_tlc59711_header(self): - print( - "self.CHIP_BUFFER_HEADER_BYTE_COUNT", - self.CHIP_BUFFER_HEADER_BYTE_COUNT) + # print( + # "self.CHIP_BUFFER_HEADER_BYTE_COUNT", + # self.CHIP_BUFFER_HEADER_BYTE_COUNT) print("header: '", end="") for index in range(self.CHIP_BUFFER_HEADER_BYTE_COUNT): print("{:08b} ".format(self._buffer[index]), end="") @@ -584,6 +624,23 @@ def _debug_print_tlc59711_ch(self): # if self.auto_show: # self._write() + def _get_32bit_value_from_buffer(self, buffer_start): + return ( + (self._buffer[buffer_start + 0] << 24) | + (self._buffer[buffer_start + 1] << 16) | + (self._buffer[buffer_start + 2] << 8) | + self._buffer[buffer_start + 3] + ) + + def _set_32bit_value_in_buffer(self, buffer_start, value): + assert 0 <= value <= 0xFFFFFFFF + # print("buffer_start", buffer_start, "value", value) + # self._debug_print_buffer() + self._buffer[buffer_start + 0] = (value >> 24) & 0xFF + self._buffer[buffer_start + 1] = (value >> 16) & 0xFF + self._buffer[buffer_start + 2] = (value >> 8) & 0xFF + self._buffer[buffer_start + 3] = value & 0xFF + def _get_16bit_value_from_buffer(self, buffer_start): return ( (self._buffer[buffer_start + 0] << 8) | @@ -676,13 +733,13 @@ def __setitem__(self, key, value): pixel_start = key * self.COLORS_PER_PIXEL self._set_channel_16bit_value( pixel_start + 0, - value[0]) + value[2]) self._set_channel_16bit_value( pixel_start + 1, value[1]) self._set_channel_16bit_value( pixel_start + 2, - value[2]) + value[0]) else: raise IndexError("index {} out of range".format(key)) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index ff8ce8e..902ff0b 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -34,16 +34,24 @@ def channelcheck_update(): global offset #noqa print("offset", offset) - # pixels[offset] = (value_high, 0, 0) - pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) + pixels[offset] = (value_high, 0, 0) + # clear last pixel + last = offset-1 + if last < 0: + last = pixel_count-1 + pixels[last] = (0, 0, 0) + # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) pixels.show() offset += 1 if offset >= pixel_count: offset = 0 + print("clear") set_all_black() - time.sleep(5) + time.sleep(1) + pixels.show() print() + time.sleep(4) def set_all_black(): @@ -69,7 +77,7 @@ def test_main(): print(42 * '*') while True: - # channelcheck_update() + channelcheck_update() time.sleep(1) From a60dbdbd81029b489c6cc572040cef4fa5d253ac Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 02:34:52 +0100 Subject: [PATCH 08/91] fix multichip calculations & remove debugging --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 15 +++++++++------ examples/tlc59711_multi_simpletest.py | 15 ++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index c874dd2..2857846 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -410,6 +410,7 @@ def __init__(self, spi, pixel_count=1): print("init buffer..") self._init_buffer() # self._debug_print_buffer() + print("-> done") def _init_buffer(self): for chip_index in range(self.chip_count): @@ -417,14 +418,15 @@ def _init_buffer(self): # buffer_start = chip_index * self.CHIP_BUFFER_LENGTH # self._buffer[buffer_start] = 0x25 << 2 - self._debug_print_buffer() + # self._debug_print_buffer() self.chip_set_BCData( chip_index, bcr=self._bcr, bcg=self._bcg, bcb=self._bcb) - self._debug_print_buffer() + # self._debug_print_buffer() self._chip_set_FunctionControl(chip_index) - self._debug_print_buffer() + # self._debug_print_buffer() self._chip_set_WriteCommand(chip_index) - self._debug_print_buffer() + # self._debug_print_buffer() + # loop end def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): """ @@ -513,7 +515,7 @@ def _chip_set_WriteCommand(self, chip_index): def _write(self): # Write out the current state to the shift register. - self._debug_print_buffer() + # self._debug_print_buffer() try: # Lock the SPI bus and configure it for the shift register. while not self._spi.try_lock(): @@ -671,7 +673,8 @@ def _convert_if_float(cls, value): def _set_channel_16bit_value(self, channel_index, value): buffer_index = ( - self.CHIP_BUFFER_LENGTH * (channel_index // self.CHANNEL_PER_CHIP) + (self.CHIP_BUFFER_LENGTH // self.BUFFER_BYTES_PER_COLOR) + * (channel_index // self.CHANNEL_PER_CHIP) + channel_index % self.CHANNEL_PER_CHIP ) buffer_index *= self.BUFFER_BYTES_PER_COLOR diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index 902ff0b..ae5c5d1 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -16,7 +16,7 @@ ########################################## -pixel_count = 4 +pixel_count = 16 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = TLC59711Multi(spi, pixel_count=pixel_count) @@ -26,7 +26,7 @@ # test function offset = 0 -value_high = 65535 +value_high = 1000 def channelcheck_update(): @@ -39,19 +39,20 @@ def channelcheck_update(): last = offset-1 if last < 0: last = pixel_count-1 - pixels[last] = (0, 0, 0) + pixels[last] = (0, 0, 1) # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) pixels.show() offset += 1 if offset >= pixel_count: + time.sleep(0.5) offset = 0 print("clear") - set_all_black() - time.sleep(1) + # set_all_black() + set_all((0, 1, 0)) pixels.show() print() - time.sleep(4) + time.sleep(2) def set_all_black(): @@ -78,7 +79,7 @@ def test_main(): while True: channelcheck_update() - time.sleep(1) + time.sleep(0.5) ########################################## From 640790e2ee6d0c7a597a7eea48081e51932f34fc Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:08:34 +0100 Subject: [PATCH 09/91] add timing tests --- examples/tlc59711_multi_dev.py | 202 +++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 examples/tlc59711_multi_dev.py diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py new file mode 100644 index 0000000..b258df5 --- /dev/null +++ b/examples/tlc59711_multi_dev.py @@ -0,0 +1,202 @@ +"""TLC5971 / TLC59711 Multi.""" + +__doc__ = """ +tlc59711_multi.py - TLC59711TLC59711Multi minimal example. + +Enjoy the colors :-) +""" + +import time + +import board +import busio + +# from adafruit_tlc59711.adafruit_tlc59711 import TLC59711 +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + + +########################################## +pixel_count = 16*8 + +spi = busio.SPI(board.SCK, MOSI=board.MOSI) +pixels = TLC59711Multi(spi, pixel_count=pixel_count) + + +########################################## +# test function + +offset = 0 +value_high = 1000 + + +def channelcheck_update(): + """ChannelCheck.""" + global offset #noqa + # print("offset", offset) + + pixels[offset] = (value_high, 0, 0) + # clear last pixel + last = offset-1 + if last < 0: + last = pixel_count-1 + pixels[last] = (0, 0, 1) + # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) + pixels.show() + + offset += 1 + if offset >= pixel_count: + # time.sleep(0.5) + offset = 0 + # print("clear") + # set_all_black() + # set_all((0, 1, 0)) + pixels.show() + # print() + # time.sleep(2) + + +def set_all_black(): + """Set all Pixel to Black.""" + set_all((0, 0, 0)) + + +def set_all(color): + """Set all Pixel to color.""" + for i in range(pixel_count): + # pixels[i // 4][i % 4] = color + pixels[i] = color + + +########################################## + +def time_meassurement_call(test_function, loop_count=1000): + """Meassure timming.""" + duration = 0 + start_time = time.monotonic() + for _index in range(loop_count): + start_time = time.monotonic() + test_function() + end_time = time.monotonic() + duration += end_time - start_time + # print( + # "duration:\n" + # "\t{}s for {} loops\n" + # "\t{:.2f}ms per call" + # "".format( + # duration, + # loop_count, + # (duration/loop_count)*1000 + # ) + # ) + print( + "\t{:.2f}ms per call" + "".format((duration / loop_count) * 1000) + ) + + +def time_meassurement_pixels_show(): + """Meassure timming.""" + print("pixels show:") + loop_count = 1000 + + def _test(): + pixels.show() + print("'pixels.show()'") + time_meassurement_call(_test, loop_count) + + +def time_meassurement_pixels_set(): + """Meassure timming pixels set.""" + print("pixels set:") + loop_count = 1000 + + def _test(): + pixels[3] = (0, 0, 1000) + print("'pixels[3] = (0, 0, 1000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + pixels[3] = (500, 40500, 1000) + print("'pixels[3] = (500, 40500, 1000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + pixels[12] = (0.5, 0.5, 0.5) + print("'pixels[12] = (0.5, 0.5, 0.5)'") + time_meassurement_call(_test, loop_count) + + def _test(): + for i in range(16): + pixels[i] = (0.5, 0.5, 0.5) + print("'pixels[for 0..16] = (0.5, 0.5, 0.5)'") + time_meassurement_call(_test, 100) + + def _test(): + for i in range(pixel_count): + pixels[i] = (0.5, 0.5, 0.5) + print("'pixels[for 0..{}] = (0.5, 0.5, 0.5)'".format(pixel_count)) + time_meassurement_call(_test, 10) + + +def time_meassurement_channel_set(): + """Meassure timming channel set.""" + print("channel set:") + loop_count = 1000 + + def _test(): + pixels._set_channel_16bit_value(0, 10000) + print("'_set_channel_16bit_value(0, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + pixels._set_channel_16bit_value(0, 10000) + pixels._set_channel_16bit_value(1, 10000) + pixels._set_channel_16bit_value(2, 10000) + print("'_set_channel_16bit_value(0..2, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + for i in range(pixel_count * 3): + pixels._set_channel_16bit_value(i, 500) + print( + "'_set_channel_16bit_value(for 0..{}, 10000)'" + "".format(pixel_count * 3) + ) + time_meassurement_call(_test, 10) + + +def time_meassurement(): + """Meassure timming.""" + print("meassure timming:") + time_meassurement_pixels_show() + time_meassurement_pixels_set() + time_meassurement_channel_set() + +########################################## + + +def test_main(): + """Test Main.""" + print() + print(42 * '*') + print(__doc__) + print(42 * '*') + print() + time.sleep(0.5) + print(42 * '*') + + time_meassurement() + time.sleep(0.5) + print(42 * '*') + + while True: + channelcheck_update() + time.sleep(0.01) + + +########################################## +# main loop + +if __name__ == '__main__': + + test_main() From d994b23115354a1efc16f07b37df3706025727de Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:09:03 +0100 Subject: [PATCH 10/91] add lookup variant --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 25 ++++++++++++++--- examples/tlc59711_multi_dev.py | 28 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 2857846..46caca6 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -374,6 +374,7 @@ def __init__(self, spi, pixel_count=1): self._spi = spi # how many pixels are there? self.pixel_count = pixel_count + self.channel_count = self.pixel_count * self.COLORS_PER_PIXEL # calculate how many chips are connected self.chip_count = self.pixel_count // 4 @@ -412,6 +413,9 @@ def __init__(self, spi, pixel_count=1): # self._debug_print_buffer() print("-> done") + self._buffer_index_lookuptable = [] + self._init_lookuptable() + def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) @@ -501,9 +505,7 @@ def update_fc(self): self._chip_set_FunctionControl(chip_index) def _chip_set_WriteCommand(self, chip_index): - """ - Set WRITE_COMMAND. - """ + """Set WRITE_COMMAND.""" # set all bits self.set_chipheader_bits_in_buffer( chip_index=chip_index, @@ -511,6 +513,17 @@ def _chip_set_WriteCommand(self, chip_index): field=self._WC_FIELDS["WRITE_COMMAND"], value=self.WRITE_COMMAND) + def _init_lookuptable(self): + for channel_index in range(self.channel_count): + buffer_index = ( + (self.CHIP_BUFFER_LENGTH // self.BUFFER_BYTES_PER_COLOR) + * (channel_index // self.CHANNEL_PER_CHIP) + + channel_index % self.CHANNEL_PER_CHIP + ) + buffer_index *= self.BUFFER_BYTES_PER_COLOR + buffer_index += self.CHIP_BUFFER_HEADER_BYTE_COUNT + self._buffer_index_lookuptable.append(buffer_index) + ########################################## def _write(self): @@ -681,6 +694,12 @@ def _set_channel_16bit_value(self, channel_index, value): buffer_index += self.CHIP_BUFFER_HEADER_BYTE_COUNT self._set_16bit_value_in_buffer(buffer_index, value) + def _set_channel_16bit_value__lookup(self, channel_index, value): + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[channel_index], + value + ) + # Define index and length properties to set and get each channel as # atomic RGB tuples. This provides a similar feel as using neopixels. def __len__(self): diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b258df5..afc47ec 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -165,12 +165,40 @@ def _test(): time_meassurement_call(_test, 10) +def time_meassurement_channel_set_lookup(): + """Meassure timming channel set.""" + print("channel set lookup:") + loop_count = 1000 + + def _test(): + pixels._set_channel_16bit_value__lookup(0, 10000) + print("'_set_channel_16bit_value__lookup(0, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + pixels._set_channel_16bit_value__lookup(0, 10000) + pixels._set_channel_16bit_value__lookup(1, 10000) + pixels._set_channel_16bit_value__lookup(2, 10000) + print("'_set_channel_16bit_value__lookup(0..2, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + for i in range(pixel_count * 3): + pixels._set_channel_16bit_value__lookup(i, 500) + print( + "'_set_channel_16bit_value__lookup(for 0..{}, 10000)'" + "".format(pixel_count * 3) + ) + time_meassurement_call(_test, 10) + + def time_meassurement(): """Meassure timming.""" print("meassure timming:") time_meassurement_pixels_show() time_meassurement_pixels_set() time_meassurement_channel_set() + time_meassurement_channel_set_lookup() ########################################## From 21eccb4d0716dcd1ad54df6c72a2cddd69037631 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:12:30 +0100 Subject: [PATCH 11/91] switch to lookup variant --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 10 ------- examples/tlc59711_multi_dev.py | 28 -------------------- 2 files changed, 38 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 46caca6..57c6b8b 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -685,16 +685,6 @@ def _convert_if_float(cls, value): return value def _set_channel_16bit_value(self, channel_index, value): - buffer_index = ( - (self.CHIP_BUFFER_LENGTH // self.BUFFER_BYTES_PER_COLOR) - * (channel_index // self.CHANNEL_PER_CHIP) - + channel_index % self.CHANNEL_PER_CHIP - ) - buffer_index *= self.BUFFER_BYTES_PER_COLOR - buffer_index += self.CHIP_BUFFER_HEADER_BYTE_COUNT - self._set_16bit_value_in_buffer(buffer_index, value) - - def _set_channel_16bit_value__lookup(self, channel_index, value): self._set_16bit_value_in_buffer( self._buffer_index_lookuptable[channel_index], value diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index afc47ec..b258df5 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -165,40 +165,12 @@ def _test(): time_meassurement_call(_test, 10) -def time_meassurement_channel_set_lookup(): - """Meassure timming channel set.""" - print("channel set lookup:") - loop_count = 1000 - - def _test(): - pixels._set_channel_16bit_value__lookup(0, 10000) - print("'_set_channel_16bit_value__lookup(0, 10000)'") - time_meassurement_call(_test, loop_count) - - def _test(): - pixels._set_channel_16bit_value__lookup(0, 10000) - pixels._set_channel_16bit_value__lookup(1, 10000) - pixels._set_channel_16bit_value__lookup(2, 10000) - print("'_set_channel_16bit_value__lookup(0..2, 10000)'") - time_meassurement_call(_test, loop_count) - - def _test(): - for i in range(pixel_count * 3): - pixels._set_channel_16bit_value__lookup(i, 500) - print( - "'_set_channel_16bit_value__lookup(for 0..{}, 10000)'" - "".format(pixel_count * 3) - ) - time_meassurement_call(_test, 10) - - def time_meassurement(): """Meassure timming.""" print("meassure timming:") time_meassurement_pixels_show() time_meassurement_pixels_set() time_meassurement_channel_set() - time_meassurement_channel_set_lookup() ########################################## From e6502d961e57dc40fb042beb7fc2878e9e66c890 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:30:01 +0100 Subject: [PATCH 12/91] add set_channel --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 32 ++++++++++++ examples/tlc59711_multi_dev.py | 55 ++++++++++++++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 57c6b8b..95e0d12 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -690,6 +690,38 @@ def _set_channel_16bit_value(self, channel_index, value): value ) + # channel access + def set_channel(self, channel_index, value): + """ + Set the value for the provided channel. + + :param int channel_index: 0..(channel_count) + :param int value: 0..65535 + """ + if 0 <= channel_index < (self.channel_count): + # check if values are in range + assert 0 <= value <= 65535 + # temp = channel_index + # we change channel order here: + # buffer channel order is blue, green, red + # pixel_index_offset = channel_index % self.COLORS_PER_PIXEL + # if pixel_index_offset == 0: + # channel_index += 2 + # if pixel_index_offset == 2: + # channel_index -= 2 + # print("{:>2} → {:>2}".format(temp, channel_index)) + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[channel_index], + value + ) + else: + raise IndexError( + "channel_index {} out of range (0..{})".format( + channel_index, + self.channel_count + ) + ) + # Define index and length properties to set and get each channel as # atomic RGB tuples. This provides a similar feel as using neopixels. def __len__(self): diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b258df5..857bbb2 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -29,8 +29,8 @@ value_high = 1000 -def channelcheck_update(): - """ChannelCheck.""" +def channelcheck_update_pixel(): + """ChannelCheck pixel.""" global offset #noqa # print("offset", offset) @@ -50,11 +50,29 @@ def channelcheck_update(): # print("clear") # set_all_black() # set_all((0, 1, 0)) - pixels.show() + # pixels.show() # print() # time.sleep(2) +def channelcheck_update(): + """ChannelCheck.""" + global offset #noqa + # print("offset", offset) + + pixels.set_channel(offset, value_high) + # clear last set channel + last = offset-1 + if last < 0: + last = pixels.channel_count-1 + pixels.set_channel(last, 0) + pixels.show() + + offset += 1 + if offset >= pixels.channel_count: + offset = 0 + + def set_all_black(): """Set all Pixel to Black.""" set_all((0, 0, 0)) @@ -143,6 +161,33 @@ def time_meassurement_channel_set(): print("channel set:") loop_count = 1000 + def _test(): + pixels.set_channel(0, 10000) + print("'set_channel(0, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + pixels.set_channel(0, 10000) + pixels.set_channel(1, 10000) + pixels.set_channel(2, 10000) + print("'set_channel(0..2, 10000)'") + time_meassurement_call(_test, loop_count) + + def _test(): + for i in range(pixel_count * 3): + pixels.set_channel(i, 500) + print( + "'set_channel(for 0..{}, 10000)'" + "".format(pixel_count * 3) + ) + time_meassurement_call(_test, 10) + + +def time_meassurement_channel_set_internal(): + """Meassure timming channel set internal.""" + print("channel set internal:") + loop_count = 1000 + def _test(): pixels._set_channel_16bit_value(0, 10000) print("'_set_channel_16bit_value(0, 10000)'") @@ -171,6 +216,8 @@ def time_meassurement(): time_meassurement_pixels_show() time_meassurement_pixels_set() time_meassurement_channel_set() + time_meassurement_channel_set_internal() + set_all((0, 1, 1)) ########################################## @@ -191,7 +238,7 @@ def test_main(): while True: channelcheck_update() - time.sleep(0.01) + time.sleep(0.5) ########################################## From 6351051d599702c74ebc15c054c506e92b53d1ab Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:40:13 +0100 Subject: [PATCH 13/91] optimize set_pixel --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 95e0d12..d64b855 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -704,11 +704,11 @@ def set_channel(self, channel_index, value): # temp = channel_index # we change channel order here: # buffer channel order is blue, green, red - # pixel_index_offset = channel_index % self.COLORS_PER_PIXEL - # if pixel_index_offset == 0: - # channel_index += 2 - # if pixel_index_offset == 2: - # channel_index -= 2 + pixel_index_offset = channel_index % self.COLORS_PER_PIXEL + if pixel_index_offset == 0: + channel_index += 2 + elif pixel_index_offset == 2: + channel_index -= 2 # print("{:>2} → {:>2}".format(temp, channel_index)) self._set_16bit_value_in_buffer( self._buffer_index_lookuptable[channel_index], @@ -775,14 +775,14 @@ def __setitem__(self, key, value): # we change channel order here: # buffer channel order is blue, green, red pixel_start = key * self.COLORS_PER_PIXEL - self._set_channel_16bit_value( - pixel_start + 0, + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[pixel_start + 0], value[2]) - self._set_channel_16bit_value( - pixel_start + 1, + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[pixel_start + 1], value[1]) - self._set_channel_16bit_value( - pixel_start + 2, + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[pixel_start + 2], value[0]) else: raise IndexError("index {} out of range".format(key)) From 8b465f0754127fbfb7aa814f0f695fdd3e6e7c4e Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:45:02 +0100 Subject: [PATCH 14/91] fix spelling --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index d64b855..136b76b 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -672,7 +672,7 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): @staticmethod def _convert_01_float_to_16bit_integer(value): """Convert 0..1 Float Value to 16bit (0..65535) Range.""" - # check if values are in range + # check if value is in range assert 0 <= value <= 1 # convert to 16bit value return int(value * 65535) From a1e754bf5d41678452dd9f77057c2d5f49cf3408 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:52:35 +0100 Subject: [PATCH 15/91] optimize speed in set_pixel by inlining functions :-( faster: 0.16ms per pixel --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 25 +++++++++++++++++--- examples/tlc59711_multi_dev.py | 16 ++++++------- examples/tlc59711_multi_simpletest.py | 12 +++++----- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 136b76b..a20b2f1 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -760,10 +760,29 @@ def __setitem__(self, key, value): # repr(value) # print("check length..") assert len(value) == 3 + + # check if we have float values + # value[0] = self._convert_if_float(value[0]) + # value[1] = self._convert_if_float(value[1]) + # value[2] = self._convert_if_float(value[2]) + # optimized by inlining code : # check if we have float values - value[0] = self._convert_if_float(value[0]) - value[1] = self._convert_if_float(value[1]) - value[2] = self._convert_if_float(value[2]) + if isinstance(value[0], float): + # check if value is in range + assert 0 <= value[0] <= 1 + # convert to 16bit value + value[0] = int(value[0] * 65535) + if isinstance(value[1], float): + # check if value is in range + assert 0 <= value[1] <= 1 + # convert to 16bit value + value[1] = int(value[1] * 65535) + if isinstance(value[2], float): + # check if value is in range + assert 0 <= value[2] <= 1 + # convert to 16bit value + value[2] = int(value[2] * 65535) + # print("value", value) # check if values are in range diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 857bbb2..ee9d531 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -53,6 +53,7 @@ def channelcheck_update_pixel(): # pixels.show() # print() # time.sleep(2) + # def channelcheck_update(): @@ -215,8 +216,8 @@ def time_meassurement(): print("meassure timming:") time_meassurement_pixels_show() time_meassurement_pixels_set() - time_meassurement_channel_set() - time_meassurement_channel_set_internal() + # time_meassurement_channel_set() + # time_meassurement_channel_set_internal() set_all((0, 1, 1)) ########################################## @@ -224,13 +225,12 @@ def time_meassurement(): def test_main(): """Test Main.""" - print() - print(42 * '*') - print(__doc__) - print(42 * '*') - print() - time.sleep(0.5) + print(42 * '*', end="") + print(__doc__, end="") print(42 * '*') + # print() + # time.sleep(0.5) + # print(42 * '*') time_meassurement() time.sleep(0.5) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index ae5c5d1..ce57160 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -69,13 +69,13 @@ def set_all(color): def test_main(): """Test Main.""" - print() - print(42 * '*') - print(__doc__) - print(42 * '*') - print() - time.sleep(0.5) + # print() + print(42 * '*', end="") + print(__doc__, end="") print(42 * '*') + # print() + # time.sleep(0.5) + # print(42 * '*') while True: channelcheck_update() From a3c78eb1d0b1b76b27bbd3310acf8d736f328cb4 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 14:55:03 +0100 Subject: [PATCH 16/91] optimize set_pixel by only checking value range once --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index a20b2f1..1cd187b 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -663,7 +663,7 @@ def _get_16bit_value_from_buffer(self, buffer_start): ) def _set_16bit_value_in_buffer(self, buffer_start, value): - assert 0 <= value <= 65535 + # assert 0 <= value <= 65535 # print("buffer_start", buffer_start, "value", value) # self._debug_print_buffer() self._buffer[buffer_start + 0] = (value >> 8) & 0xFF @@ -765,6 +765,12 @@ def __setitem__(self, key, value): # value[0] = self._convert_if_float(value[0]) # value[1] = self._convert_if_float(value[1]) # value[2] = self._convert_if_float(value[2]) + + # check if values are in range + # assert 0 <= value[0] <= 65535 + # assert 0 <= value[1] <= 65535 + # assert 0 <= value[2] <= 65535 + # optimized by inlining code : # check if we have float values if isinstance(value[0], float): @@ -772,23 +778,25 @@ def __setitem__(self, key, value): assert 0 <= value[0] <= 1 # convert to 16bit value value[0] = int(value[0] * 65535) + else: + assert 0 <= value[0] <= 65535 if isinstance(value[1], float): # check if value is in range assert 0 <= value[1] <= 1 # convert to 16bit value value[1] = int(value[1] * 65535) + else: + assert 0 <= value[1] <= 65535 if isinstance(value[2], float): # check if value is in range assert 0 <= value[2] <= 1 # convert to 16bit value value[2] = int(value[2] * 65535) + else: + assert 0 <= value[2] <= 65535 # print("value", value) - # check if values are in range - assert 0 <= value[0] <= 65535 - assert 0 <= value[1] <= 65535 - assert 0 <= value[2] <= 65535 # update buffer # print("key", key, "value", value) # we change channel order here: From 3678d5964a02eec235ee272329e5e23bfba0e8d1 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 15:11:37 +0100 Subject: [PATCH 17/91] optimize set_pixel more inlinening.. --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 47 ++++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 1cd187b..aebf777 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -802,15 +802,44 @@ def __setitem__(self, key, value): # we change channel order here: # buffer channel order is blue, green, red pixel_start = key * self.COLORS_PER_PIXEL - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[pixel_start + 0], - value[2]) - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[pixel_start + 1], - value[1]) - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[pixel_start + 2], - value[0]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 0], + # value[2]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 1], + # value[1]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 2], + # value[0]) + # optimize: + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 0], + # value[2]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 1], + # value[1]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 2], + # value[0]) + # optimize2 + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 0] + 0 + ] = (value[2] >> 8) & 0xFF + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 0] + 1 + ] = value[2] & 0xFF + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 1] + 0 + ] = (value[1] >> 8) & 0xFF + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 1] + 1 + ] = value[1] & 0xFF + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 2] + 0 + ] = (value[0] >> 8) & 0xFF + self._buffer[ + self._buffer_index_lookuptable[pixel_start + 2] + 1 + ] = value[0] & 0xFF else: raise IndexError("index {} out of range".format(key)) From 849e45272d50d5a4fadc56c0f4ac17c29cdd6c83 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 15:12:15 +0100 Subject: [PATCH 18/91] make linter happy --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index aebf777..430e3a2 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -317,8 +317,6 @@ def __set__(self, obj, val): WRITE_COMMAND = 0b100101 ########################################## - - ######## CHIP_BUFFER_HEADER_BIT_COUNT = \ _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT From 0589b6defd5cdee14cda59f3bcdde5ae479104e9 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 15:30:52 +0100 Subject: [PATCH 19/91] optimize same more --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 39 +++++++++----------- examples/tlc59711_multi_dev.py | 24 ++++++------ 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 430e3a2..4869ec0 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -683,10 +683,14 @@ def _convert_if_float(cls, value): return value def _set_channel_16bit_value(self, channel_index, value): - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[channel_index], - value - ) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[channel_index], + # value + # ) + # optimized: + buffer_start = self._buffer_index_lookuptable[channel_index] + self._buffer[buffer_start + 0] = (value >> 8) & 0xFF + self._buffer[buffer_start + 1] = value & 0xFF # channel access def set_channel(self, channel_index, value): @@ -820,24 +824,15 @@ def __setitem__(self, key, value): # self._buffer_index_lookuptable[pixel_start + 2], # value[0]) # optimize2 - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 0] + 0 - ] = (value[2] >> 8) & 0xFF - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 0] + 1 - ] = value[2] & 0xFF - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 1] + 0 - ] = (value[1] >> 8) & 0xFF - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 1] + 1 - ] = value[1] & 0xFF - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 2] + 0 - ] = (value[0] >> 8) & 0xFF - self._buffer[ - self._buffer_index_lookuptable[pixel_start + 2] + 1 - ] = value[0] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[0] & 0xFF else: raise IndexError("index {} out of range".format(key)) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index ee9d531..30ba350 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -30,7 +30,7 @@ def channelcheck_update_pixel(): - """ChannelCheck pixel.""" + """Channel check pixel.""" global offset #noqa # print("offset", offset) @@ -57,7 +57,7 @@ def channelcheck_update_pixel(): def channelcheck_update(): - """ChannelCheck.""" + """Channel check.""" global offset #noqa # print("offset", offset) @@ -129,10 +129,10 @@ def time_meassurement_pixels_set(): print("pixels set:") loop_count = 1000 - def _test(): - pixels[3] = (0, 0, 1000) - print("'pixels[3] = (0, 0, 1000)'") - time_meassurement_call(_test, loop_count) + # def _test(): + # pixels[3] = (0, 0, 1000) + # print("'pixels[3] = (0, 0, 1000)'") + # time_meassurement_call(_test, loop_count) def _test(): pixels[3] = (500, 40500, 1000) @@ -144,11 +144,11 @@ def _test(): print("'pixels[12] = (0.5, 0.5, 0.5)'") time_meassurement_call(_test, loop_count) - def _test(): - for i in range(16): - pixels[i] = (0.5, 0.5, 0.5) - print("'pixels[for 0..16] = (0.5, 0.5, 0.5)'") - time_meassurement_call(_test, 100) + # def _test(): + # for i in range(16): + # pixels[i] = (0.5, 0.5, 0.5) + # print("'pixels[for 0..16] = (0.5, 0.5, 0.5)'") + # time_meassurement_call(_test, 100) def _test(): for i in range(pixel_count): @@ -217,7 +217,7 @@ def time_meassurement(): time_meassurement_pixels_show() time_meassurement_pixels_set() # time_meassurement_channel_set() - # time_meassurement_channel_set_internal() + time_meassurement_channel_set_internal() set_all((0, 1, 1)) ########################################## From c4b398d6a6d48d9366b7fec47c631f1aacae127d Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 18:16:04 +0100 Subject: [PATCH 20/91] fix spelling --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 +- examples/tlc59711_multi_dev.py | 60 ++++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 4869ec0..ec33776 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -773,7 +773,7 @@ def __setitem__(self, key, value): # assert 0 <= value[1] <= 65535 # assert 0 <= value[2] <= 65535 - # optimized by inlining code : + # optimize: # check if we have float values if isinstance(value[0], float): # check if value is in range diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 30ba350..6a36a5e 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -88,8 +88,8 @@ def set_all(color): ########################################## -def time_meassurement_call(test_function, loop_count=1000): - """Meassure timming.""" +def time_measurement_call(test_function, loop_count=1000): + """Measure timing.""" duration = 0 start_time = time.monotonic() for _index in range(loop_count): @@ -113,66 +113,66 @@ def time_meassurement_call(test_function, loop_count=1000): ) -def time_meassurement_pixels_show(): - """Meassure timming.""" +def time_measurement_pixels_show(): + """Measure timing.""" print("pixels show:") loop_count = 1000 def _test(): pixels.show() print("'pixels.show()'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) -def time_meassurement_pixels_set(): - """Meassure timming pixels set.""" +def time_measurement_pixels_set(): + """Measure timing pixels set.""" print("pixels set:") loop_count = 1000 # def _test(): # pixels[3] = (0, 0, 1000) # print("'pixels[3] = (0, 0, 1000)'") - # time_meassurement_call(_test, loop_count) + # time_measurement_call(_test, loop_count) def _test(): pixels[3] = (500, 40500, 1000) print("'pixels[3] = (500, 40500, 1000)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) def _test(): pixels[12] = (0.5, 0.5, 0.5) print("'pixels[12] = (0.5, 0.5, 0.5)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) # def _test(): # for i in range(16): # pixels[i] = (0.5, 0.5, 0.5) # print("'pixels[for 0..16] = (0.5, 0.5, 0.5)'") - # time_meassurement_call(_test, 100) + # time_measurement_call(_test, 100) def _test(): for i in range(pixel_count): pixels[i] = (0.5, 0.5, 0.5) print("'pixels[for 0..{}] = (0.5, 0.5, 0.5)'".format(pixel_count)) - time_meassurement_call(_test, 10) + time_measurement_call(_test, 10) -def time_meassurement_channel_set(): - """Meassure timming channel set.""" +def time_measurement_channel_set(): + """Measure timing channel set.""" print("channel set:") loop_count = 1000 def _test(): pixels.set_channel(0, 10000) print("'set_channel(0, 10000)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) def _test(): pixels.set_channel(0, 10000) pixels.set_channel(1, 10000) pixels.set_channel(2, 10000) print("'set_channel(0..2, 10000)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) def _test(): for i in range(pixel_count * 3): @@ -181,25 +181,25 @@ def _test(): "'set_channel(for 0..{}, 10000)'" "".format(pixel_count * 3) ) - time_meassurement_call(_test, 10) + time_measurement_call(_test, 10) -def time_meassurement_channel_set_internal(): - """Meassure timming channel set internal.""" +def time_measurement_channel_set_internal(): + """Measure timing channel set internal.""" print("channel set internal:") loop_count = 1000 def _test(): pixels._set_channel_16bit_value(0, 10000) print("'_set_channel_16bit_value(0, 10000)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) def _test(): pixels._set_channel_16bit_value(0, 10000) pixels._set_channel_16bit_value(1, 10000) pixels._set_channel_16bit_value(2, 10000) print("'_set_channel_16bit_value(0..2, 10000)'") - time_meassurement_call(_test, loop_count) + time_measurement_call(_test, loop_count) def _test(): for i in range(pixel_count * 3): @@ -208,16 +208,16 @@ def _test(): "'_set_channel_16bit_value(for 0..{}, 10000)'" "".format(pixel_count * 3) ) - time_meassurement_call(_test, 10) + time_measurement_call(_test, 10) -def time_meassurement(): - """Meassure timming.""" - print("meassure timming:") - time_meassurement_pixels_show() - time_meassurement_pixels_set() - # time_meassurement_channel_set() - time_meassurement_channel_set_internal() +def time_measurement(): + """Measure timing.""" + print("meassure timing:") + time_measurement_pixels_show() + time_measurement_pixels_set() + # time_measurement_channel_set() + time_measurement_channel_set_internal() set_all((0, 1, 1)) ########################################## @@ -232,7 +232,7 @@ def test_main(): # time.sleep(0.5) # print(42 * '*') - time_meassurement() + time_measurement() time.sleep(0.5) print(42 * '*') From 5e3a6e58410c849bda31fe300c205d424aafbcdb Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 18:40:37 +0100 Subject: [PATCH 21/91] added set_pixel_16bit_XXXXX --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 51 ++++++++++++++++++++ examples/tlc59711_multi_dev.py | 10 ++++ 2 files changed, 61 insertions(+) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index ec33776..d559a38 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -692,6 +692,51 @@ def _set_channel_16bit_value(self, channel_index, value): self._buffer[buffer_start + 0] = (value >> 8) & 0xFF self._buffer[buffer_start + 1] = value & 0xFF + def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): + """ + Set the value for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + + :param int pixel_index: 0..(pixel_count) + :param int value_r: 0..65535 + :param int value_g: 0..65535 + :param int value_b: 0..65535 + """ + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF + + def set_pixel_16bit_color(self, pixel_index, value): + """ + Set color for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + its a little bit slower as `set_pixel_16bit_value` + + :param int pixel_index: 0..(pixel_count) + :param int 3-tuple of R, G, B; 0..65535 + """ + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[0] & 0xFF + # channel access def set_channel(self, channel_index, value): """ @@ -762,6 +807,12 @@ def __setitem__(self, key, value): # repr(value) # print("check length..") assert len(value) == 3 + # tested: + # splitting up into variables to not need the list.. + # this is about 0.25ms slower! + # value_r = value[0] + # value_g = value[1] + # value_b = value[2] # check if we have float values # value[0] = self._convert_if_float(value[0]) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 6a36a5e..0517628 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -139,6 +139,16 @@ def _test(): print("'pixels[3] = (500, 40500, 1000)'") time_measurement_call(_test, loop_count) + def _test(): + pixels.set_pixel_16bit_value(3, 500, 40500, 1000) + print("'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'") + time_measurement_call(_test, loop_count) + + def _test(): + pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) + print("'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'") + time_measurement_call(_test, loop_count) + def _test(): pixels[12] = (0.5, 0.5, 0.5) print("'pixels[12] = (0.5, 0.5, 0.5)'") From 4a90e3ce8fae8cbc3b56500d399dfc6d702e6900 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 18:43:42 +0100 Subject: [PATCH 22/91] added timing test --- examples/tlc59711_multi_dev.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 0517628..3a969ee 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -166,6 +166,15 @@ def _test(): print("'pixels[for 0..{}] = (0.5, 0.5, 0.5)'".format(pixel_count)) time_measurement_call(_test, 10) + def _test(): + for i in range(pixel_count): + pixels.set_pixel_16bit_value(i, 500, 40500, 1000) + print( + "'pixels.set_pixel_16bit_value(0..{}, 500, 40500, 1000)'" + "".format(pixel_count) + ) + time_measurement_call(_test, 10) + def time_measurement_channel_set(): """Measure timing channel set.""" From 1343d3f5515c5939a0b09e70be59b5d2c4dab906 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 19:15:53 +0100 Subject: [PATCH 23/91] added test for pixel get --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 60 ++++++++++++++---- examples/tlc59711_multi_dev.py | 67 ++++++++++++++++---- 2 files changed, 105 insertions(+), 22 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index d559a38..16337b8 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -682,6 +682,11 @@ def _convert_if_float(cls, value): value = cls._convert_01_float_to_16bit_integer(value) return value + def _get_channel_16bit_value(self, channel_index): + return self._get_16bit_value_from_buffer( + self._buffer_index_lookuptable[channel_index], + ) + def _set_channel_16bit_value(self, channel_index, value): # self._set_16bit_value_in_buffer( # self._buffer_index_lookuptable[channel_index], @@ -715,6 +720,32 @@ def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF self._buffer[buffer_start + 1] = value_r & 0xFF + def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): + """ + Set the value for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + + :param int pixel_index: 0..(pixel_count) + :param int value_r: 0..1 + :param int value_g: 0..1 + :param int value_b: 0..1 + """ + value_r = int(value_r * 65535) + value_g = int(value_g * 65535) + value_b = int(value_b * 65535) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF + def set_pixel_16bit_color(self, pixel_index, value): """ Set color for pixel. @@ -782,13 +813,17 @@ def __getitem__(self, key): Each value is a 16-bit number from 0-65535. """ if 0 <= key < self.pixel_count: + pixel_start = key * self.COLORS_PER_PIXEL return ( - self._get_16bit_value_from_buffer(key + 0), - self._get_16bit_value_from_buffer(key + 2), - self._get_16bit_value_from_buffer(key + 4) + self._get_channel_16bit_value(pixel_start + 0), + self._get_channel_16bit_value(pixel_start + 1), + self._get_channel_16bit_value(pixel_start + 2) ) else: - raise IndexError("index {} out of range".format(key)) + raise IndexError( + "index {} out of range [0..{}]" + "".format(key, self.pixel_count) + ) def __setitem__(self, key, value): """ @@ -855,14 +890,14 @@ def __setitem__(self, key, value): # we change channel order here: # buffer channel order is blue, green, red pixel_start = key * self.COLORS_PER_PIXEL - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 0], + # self._set_channel_16bit_value( + # pixel_start + 0, # value[2]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 1], + # self._set_channel_16bit_value( + # pixel_start + 1, # value[1]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 2], + # self._set_channel_16bit_value( + # pixel_start + 2, # value[0]) # optimize: # self._set_16bit_value_in_buffer( @@ -885,6 +920,9 @@ def __setitem__(self, key, value): self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF self._buffer[buffer_start + 1] = value[0] & 0xFF else: - raise IndexError("index {} out of range".format(key)) + raise IndexError( + "index {} out of range [0..{}]" + "".format(key, self.pixel_count) + ) ########################################## diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 3a969ee..dddc823 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -82,7 +82,6 @@ def set_all_black(): def set_all(color): """Set all Pixel to color.""" for i in range(pixel_count): - # pixels[i // 4][i % 4] = color pixels[i] = color @@ -139,16 +138,6 @@ def _test(): print("'pixels[3] = (500, 40500, 1000)'") time_measurement_call(_test, loop_count) - def _test(): - pixels.set_pixel_16bit_value(3, 500, 40500, 1000) - print("'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'") - time_measurement_call(_test, loop_count) - - def _test(): - pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) - print("'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'") - time_measurement_call(_test, loop_count) - def _test(): pixels[12] = (0.5, 0.5, 0.5) print("'pixels[12] = (0.5, 0.5, 0.5)'") @@ -166,6 +155,37 @@ def _test(): print("'pixels[for 0..{}] = (0.5, 0.5, 0.5)'".format(pixel_count)) time_measurement_call(_test, 10) + +def time_measurement_pixels_get(): + """Measure timing pixels get.""" + print("pixels get:") + + set_all((1, 11, 111)) + + def _test(): + print("[", end="") + for i in range(pixel_count): + print("{}:{}, ".format(i, pixels[i]), end="") + print("]", end="") + print("'print('{}:{}, '.format(i, pixels[i]), end='')'") + time_measurement_call(_test, 1) + + +def time_measurement_pixels_set2(): + """Measure timing pixels set.""" + print("pixels set2:") + loop_count = 1000 + + def _test(): + pixels.set_pixel_16bit_value(3, 500, 40500, 1000) + print("'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'") + time_measurement_call(_test, loop_count) + + def _test(): + pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) + print("'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'") + time_measurement_call(_test, loop_count) + def _test(): for i in range(pixel_count): pixels.set_pixel_16bit_value(i, 500, 40500, 1000) @@ -175,6 +195,29 @@ def _test(): ) time_measurement_call(_test, 10) + def _test(): + for i in range(pixel_count): + pixels.set_pixel_16bit_value( + i, + int(0.1 * 65535), + int(0.5 * 65535), + int(0.9 * 65535) + ) + print( + "'pixels.set_pixel_16bit_value(0..{}, f2i 0.1, f2i 0.5, f2i 0.9)'" + "".format(pixel_count) + ) + time_measurement_call(_test, 10) + + def _test(): + for i in range(pixel_count): + pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) + print( + "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" + "".format(pixel_count) + ) + time_measurement_call(_test, 10) + def time_measurement_channel_set(): """Measure timing channel set.""" @@ -235,8 +278,10 @@ def time_measurement(): print("meassure timing:") time_measurement_pixels_show() time_measurement_pixels_set() + time_measurement_pixels_set2() # time_measurement_channel_set() time_measurement_channel_set_internal() + time_measurement_pixels_get() set_all((0, 1, 1)) ########################################## From cb52b98a6450be47ee9465bd2f4d9985805484ca Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 20:55:21 +0100 Subject: [PATCH 24/91] more tests and cleanup --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 171 +++++++++++- examples/tlc59711_multi_dev.py | 273 +++++++++++++------ 2 files changed, 361 insertions(+), 83 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 16337b8..920dc1a 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -768,6 +768,159 @@ def set_pixel_16bit_color(self, pixel_index, value): self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF self._buffer[buffer_start + 1] = value[0] & 0xFF + def set_pixel_float_color(self, pixel_index, value): + """ + Set color for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + its a little bit slower as `set_pixel_16bit_value` + + :param int pixel_index: 0..(pixel_count) + :param tuple/float 3-tuple of R, G, B; 0..1 + """ + # convert tuple to list + # this way we can assign values. + # this seems faster than creating tree new variables + value = list(value) + # convert to 16bit int + value[0] = int(value[0] * 65535) + value[1] = int(value[1] * 65535) + value[2] = int(value[2] * 65535) + # calculate pixel_start + pixel_start = pixel_index * self.COLORS_PER_PIXEL + # set values + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[0] & 0xFF + + # value_r = int(value[0] * 65535) + # value_g = int(value[1] * 65535) + # value_b = int(value[2] * 65535) + # pixel_start = pixel_index * self.COLORS_PER_PIXEL + # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + # self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_b & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + # self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_g & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + # self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_r & 0xFF + + def set_pixel(self, pixel_index, value): + """ + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + + :param int pixel_index: 0..(pixel_count) + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + if 0 <= pixel_index < self.pixel_count: + # print("value", value) + # convert to list + value = list(value) + # print("value", value) + # print("rep:") + # repr(value) + # print("check length..") + if len(value) != self.COLORS_PER_PIXEL: + raise IndexError( + "length of value {} does not match COLORS_PER_PIXEL (= {})" + "".format(len(value), self.COLORS_PER_PIXEL) + ) + # tested: + # splitting up into variables to not need the list.. + # this is about 0.25ms slower! + # value_r = value[0] + # value_g = value[1] + # value_b = value[2] + + # check if we have float values + # value[0] = self._convert_if_float(value[0]) + # value[1] = self._convert_if_float(value[1]) + # value[2] = self._convert_if_float(value[2]) + + # check if values are in range + # assert 0 <= value[0] <= 65535 + # assert 0 <= value[1] <= 65535 + # assert 0 <= value[2] <= 65535 + + # optimize: + # check if we have float values + if isinstance(value[0], float): + # check if value is in range + assert 0 <= value[0] <= 1 + # convert to 16bit value + value[0] = int(value[0] * 65535) + else: + assert 0 <= value[0] <= 65535 + if isinstance(value[1], float): + # check if value is in range + assert 0 <= value[1] <= 1 + # convert to 16bit value + value[1] = int(value[1] * 65535) + else: + assert 0 <= value[1] <= 65535 + if isinstance(value[2], float): + # check if value is in range + assert 0 <= value[2] <= 1 + # convert to 16bit value + value[2] = int(value[2] * 65535) + else: + assert 0 <= value[2] <= 65535 + + # print("value", value) + + # update buffer + # print("pixel_index", pixel_index, "value", value) + # we change channel order here: + # buffer channel order is blue, green, red + pixel_start = pixel_index * self.COLORS_PER_PIXEL + # self._set_channel_16bit_value( + # pixel_start + 0, + # value[2]) + # self._set_channel_16bit_value( + # pixel_start + 1, + # value[1]) + # self._set_channel_16bit_value( + # pixel_start + 2, + # value[0]) + # optimize: + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 0], + # value[2]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 1], + # value[1]) + # self._set_16bit_value_in_buffer( + # self._buffer_index_lookuptable[pixel_start + 2], + # value[0]) + # optimize2 + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = value[0] & 0xFF + else: + raise IndexError( + "index {} out of range [0..{}]" + "".format(pixel_index, self.pixel_count) + ) + # channel access def set_channel(self, channel_index, value): """ @@ -827,11 +980,15 @@ def __getitem__(self, key): def __setitem__(self, key, value): """ - Set the R, G, B values for the provided channel. + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + this shortcut is identicall to `set_pixel` - Specify a 3-tuple of R, G, B values that are each - - 16-bit numbers (0-65535) - - or 0..1 floats + :param int key: 0..(pixel_count) + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 """ if 0 <= key < self.pixel_count: # print("value", value) @@ -841,7 +998,11 @@ def __setitem__(self, key, value): # print("rep:") # repr(value) # print("check length..") - assert len(value) == 3 + if len(value) != self.COLORS_PER_PIXEL: + raise IndexError( + "length of value {} does not match COLORS_PER_PIXEL (= {})" + "".format(len(value), self.COLORS_PER_PIXEL) + ) # tested: # splitting up into variables to not need the list.. # this is about 0.25ms slower! diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index dddc823..8563874 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -34,12 +34,14 @@ def channelcheck_update_pixel(): global offset #noqa # print("offset", offset) - pixels[offset] = (value_high, 0, 0) + # pixels[offset] = (value_high, 0, 0) + pixels.set_pixel_16bit_value(offset, value_high, 0, 0) # clear last pixel last = offset-1 if last < 0: last = pixel_count-1 - pixels[last] = (0, 0, 1) + # pixels[last] = (0, 0, 1) + pixels.set_pixel_16bit_value(last, 0, 0, 1) # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) pixels.show() @@ -83,11 +85,14 @@ def set_all(color): """Set all Pixel to color.""" for i in range(pixel_count): pixels[i] = color + pixels.set_pixel_float_value( + i, + value_high, 0, 0) ########################################## -def time_measurement_call(test_function, loop_count=1000): +def time_measurement_call(message, test_function, loop_count=1000): """Measure timing.""" duration = 0 start_time = time.monotonic() @@ -106,94 +111,178 @@ def time_measurement_call(test_function, loop_count=1000): # (duration/loop_count)*1000 # ) # ) + # print( + # "\t{:.2f}ms per call" + # "".format((duration / loop_count) * 1000) + # ) + # "{:>8.2f}ms".format(3.56) print( - "\t{:.2f}ms per call" - "".format((duration / loop_count) * 1000) + "{call_duration:>8.2f}ms\t{message}" + "".format( + call_duration=(duration / loop_count) * 1000, + message=message, + ) ) def time_measurement_pixels_show(): """Measure timing.""" - print("pixels show:") + print("*** pixels show:") loop_count = 1000 def _test(): pixels.show() - print("'pixels.show()'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'pixels.show()'", + _test, + loop_count + ) -def time_measurement_pixels_set(): +def time_measurement_pixels_set_single(): """Measure timing pixels set.""" - print("pixels set:") + print("*** pixels set single:") loop_count = 1000 - # def _test(): - # pixels[3] = (0, 0, 1000) - # print("'pixels[3] = (0, 0, 1000)'") - # time_measurement_call(_test, loop_count) - def _test(): pixels[3] = (500, 40500, 1000) - print("'pixels[3] = (500, 40500, 1000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'pixels[3] = (500, 40500, 1000)'", + _test, + loop_count + ) def _test(): - pixels[12] = (0.5, 0.5, 0.5) - print("'pixels[12] = (0.5, 0.5, 0.5)'") - time_measurement_call(_test, loop_count) + pixels[3] = (0.1, 0.5, 0.9) + time_measurement_call( + "'pixels[3] = (0.1, 0.5, 0.9)'", + _test, + loop_count + ) - # def _test(): - # for i in range(16): - # pixels[i] = (0.5, 0.5, 0.5) - # print("'pixels[for 0..16] = (0.5, 0.5, 0.5)'") - # time_measurement_call(_test, 100) + def _test(): + pixels.set_pixel(3, (500, 40500, 1000)) + time_measurement_call( + "'pixels.set_pixel(3, (500, 40500, 1000))'", + _test, + loop_count + ) def _test(): - for i in range(pixel_count): - pixels[i] = (0.5, 0.5, 0.5) - print("'pixels[for 0..{}] = (0.5, 0.5, 0.5)'".format(pixel_count)) - time_measurement_call(_test, 10) + pixels.set_pixel(3, (0.1, 0.5, 0.9)) + time_measurement_call( + "'pixels.set_pixel(3, (0.1, 0.5, 0.9))'", + _test, + loop_count + ) -def time_measurement_pixels_get(): - """Measure timing pixels get.""" - print("pixels get:") +def time_measurement_pixels_set_loop(): + """Measure timing pixels set.""" + print("*** pixels set loop:") + loop_count = 10 - set_all((1, 11, 111)) + def _test(): + for i in range(pixel_count): + pixels[i] = (500, 40500, 1000) + time_measurement_call( + "'pixels[for 0..{}] = (500, 40500, 1000)'".format(pixel_count), + _test, + loop_count + ) def _test(): - print("[", end="") for i in range(pixel_count): - print("{}:{}, ".format(i, pixels[i]), end="") - print("]", end="") - print("'print('{}:{}, '.format(i, pixels[i]), end='')'") - time_measurement_call(_test, 1) + pixels[i] = (0.1, 0.5, 0.9) + time_measurement_call( + "'pixels[for 0..{}] = (0.1, 0.5, 0.9)'".format(pixel_count), + _test, + loop_count + ) + + def _test(): + for i in range(pixel_count): + pixels.set_pixel(i, (500, 40500, 1000)) + time_measurement_call( + "'pixels.set_pixel(0..{}, (500, 40500, 1000))'".format(pixel_count), + _test, + loop_count + ) + + def _test(): + for i in range(pixel_count): + pixels.set_pixel(i, (0.1, 0.5, 0.9)) + time_measurement_call( + "'pixels.set_pixel(0..{}, (0.1, 0.5, 0.9))'".format(pixel_count), + _test, + loop_count + ) -def time_measurement_pixels_set2(): +def time_measurement_pixels_set_16bit(): """Measure timing pixels set.""" - print("pixels set2:") + print("*** pixels set 16bit:") loop_count = 1000 def _test(): pixels.set_pixel_16bit_value(3, 500, 40500, 1000) - print("'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'", + _test, + loop_count + ) def _test(): pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) - print("'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'", + _test, + loop_count + ) def _test(): for i in range(pixel_count): pixels.set_pixel_16bit_value(i, 500, 40500, 1000) - print( + time_measurement_call( "'pixels.set_pixel_16bit_value(0..{}, 500, 40500, 1000)'" - "".format(pixel_count) + "".format(pixel_count), + _test, + 10 + ) + + def _test(): + for i in range(pixel_count): + pixels.set_pixel_16bit_color(i, (500, 40500, 1000)) + time_measurement_call( + "'pixels.set_pixel_16bit_color(0..{}, (500, 40500, 1000))'" + "".format(pixel_count), + _test, + 10 + ) + + +def time_measurement_pixels_set_float(): + """Measure timing pixels set.""" + print("*** pixels set float:") + loop_count = 1000 + + def _test(): + pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9) + time_measurement_call( + "'pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9)'", + _test, + loop_count + ) + + def _test(): + for i in range(pixel_count): + pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) + time_measurement_call( + "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" + "".format(pixel_count), + _test, + 10 ) - time_measurement_call(_test, 10) def _test(): for i in range(pixel_count): @@ -203,83 +292,109 @@ def _test(): int(0.5 * 65535), int(0.9 * 65535) ) - print( + time_measurement_call( "'pixels.set_pixel_16bit_value(0..{}, f2i 0.1, f2i 0.5, f2i 0.9)'" - "".format(pixel_count) - ) - time_measurement_call(_test, 10) - - def _test(): - for i in range(pixel_count): - pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) - print( - "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" - "".format(pixel_count) + "".format(pixel_count), + _test, + 10 ) - time_measurement_call(_test, 10) def time_measurement_channel_set(): """Measure timing channel set.""" - print("channel set:") + print("*** channel set:") loop_count = 1000 def _test(): pixels.set_channel(0, 10000) - print("'set_channel(0, 10000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'set_channel(0, 10000)'", + _test, + loop_count + ) def _test(): pixels.set_channel(0, 10000) pixels.set_channel(1, 10000) pixels.set_channel(2, 10000) - print("'set_channel(0..2, 10000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'set_channel(0..2, 10000)'", + _test, + loop_count + ) def _test(): for i in range(pixel_count * 3): pixels.set_channel(i, 500) - print( + time_measurement_call( "'set_channel(for 0..{}, 10000)'" - "".format(pixel_count * 3) + "".format(pixel_count * 3), + _test, + 10 ) - time_measurement_call(_test, 10) def time_measurement_channel_set_internal(): """Measure timing channel set internal.""" - print("channel set internal:") + print("*** channel set internal:") loop_count = 1000 def _test(): pixels._set_channel_16bit_value(0, 10000) - print("'_set_channel_16bit_value(0, 10000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'_set_channel_16bit_value(0, 10000)'", + _test, + loop_count + ) def _test(): pixels._set_channel_16bit_value(0, 10000) pixels._set_channel_16bit_value(1, 10000) pixels._set_channel_16bit_value(2, 10000) - print("'_set_channel_16bit_value(0..2, 10000)'") - time_measurement_call(_test, loop_count) + time_measurement_call( + "'_set_channel_16bit_value(0..2, 10000)'", + _test, + loop_count + ) def _test(): for i in range(pixel_count * 3): pixels._set_channel_16bit_value(i, 500) - print( + time_measurement_call( "'_set_channel_16bit_value(for 0..{}, 10000)'" - "".format(pixel_count * 3) + "".format(pixel_count * 3), + _test, + 10 + ) + + +def time_measurement_pixels_get(): + """Measure timing pixels get.""" + print("*** pixels get:") + + set_all((1, 11, 111)) + + def _test(): + print("[", end="") + for i in range(pixel_count): + print("{}:{}, ".format(i, pixels[i]), end="") + print("]", end="") + time_measurement_call( + "'print('{}:{}, '.format(i, pixels[i]), end='')'", + _test, + 1 ) - time_measurement_call(_test, 10) def time_measurement(): """Measure timing.""" print("meassure timing:") time_measurement_pixels_show() - time_measurement_pixels_set() - time_measurement_pixels_set2() - # time_measurement_channel_set() + time_measurement_pixels_set_single() + time_measurement_pixels_set_loop() + time_measurement_pixels_set_16bit() + time_measurement_pixels_set_float() + time_measurement_channel_set() time_measurement_channel_set_internal() time_measurement_pixels_get() set_all((0, 1, 1)) @@ -299,6 +414,8 @@ def test_main(): time_measurement() time.sleep(0.5) print(42 * '*') + print() + print("loop:") while True: channelcheck_update() From 6a1363b0c0c878786bc8d500115a6eccb3559bf0 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 21:05:33 +0100 Subject: [PATCH 25/91] add set_pixels_all --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 11 ++++++ examples/tlc59711_multi_dev.py | 40 +++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 920dc1a..a3fb25e 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -682,6 +682,8 @@ def _convert_if_float(cls, value): value = cls._convert_01_float_to_16bit_integer(value) return value + ########################################## + def _get_channel_16bit_value(self, channel_index): return self._get_16bit_value_from_buffer( self._buffer_index_lookuptable[channel_index], @@ -921,6 +923,15 @@ def set_pixel(self, pixel_index, value): "".format(pixel_index, self.pixel_count) ) + def set_pixel_all(self, color): + """ + Set the R, G, B values for all pixels. + + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + for i in range(self.pixel_count): + self.set_pixel(i, color) + # channel access def set_channel(self, channel_index, value): """ diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 8563874..167d1b4 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -51,7 +51,7 @@ def channelcheck_update_pixel(): offset = 0 # print("clear") # set_all_black() - # set_all((0, 1, 0)) + # pixels.set_pixel_all((0, 1, 0)) # pixels.show() # print() # time.sleep(2) @@ -78,16 +78,7 @@ def channelcheck_update(): def set_all_black(): """Set all Pixel to Black.""" - set_all((0, 0, 0)) - - -def set_all(color): - """Set all Pixel to color.""" - for i in range(pixel_count): - pixels[i] = color - pixels.set_pixel_float_value( - i, - value_high, 0, 0) + pixels.set_pixel_all((0, 0, 0)) ########################################## @@ -219,6 +210,28 @@ def _test(): ) +def time_measurement_pixels_set_all(): + """Measure timing pixels set.""" + print("*** pixels set all:") + loop_count = 10 + + def _test(): + pixels.set_pixel_all((500, 40500, 1000)) + time_measurement_call( + "'pixels.set_pixel_all((500, 40500, 1000))'", + _test, + loop_count + ) + + def _test(): + pixels.set_pixel_all((0.1, 0.5, 0.9)) + time_measurement_call( + "'pixels.set_pixel_all((0.1, 0.5, 0.9))'", + _test, + loop_count + ) + + def time_measurement_pixels_set_16bit(): """Measure timing pixels set.""" print("*** pixels set 16bit:") @@ -372,7 +385,7 @@ def time_measurement_pixels_get(): """Measure timing pixels get.""" print("*** pixels get:") - set_all((1, 11, 111)) + pixels.set_pixel_all((1, 11, 111)) def _test(): print("[", end="") @@ -392,12 +405,13 @@ def time_measurement(): time_measurement_pixels_show() time_measurement_pixels_set_single() time_measurement_pixels_set_loop() + time_measurement_pixels_set_all() time_measurement_pixels_set_16bit() time_measurement_pixels_set_float() time_measurement_channel_set() time_measurement_channel_set_internal() time_measurement_pixels_get() - set_all((0, 1, 1)) + pixels.set_pixel_all((0, 1, 1)) ########################################## From 58300314bfe803ec18cced2c7e282a3ec0a10f6f Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 21:13:38 +0100 Subject: [PATCH 26/91] added set_pixel_all_16bit_value --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 18 +++++++++++++++ examples/tlc59711_multi_dev.py | 23 +++++++++++++++----- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index a3fb25e..ec27b6d 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -923,6 +923,19 @@ def set_pixel(self, pixel_index, value): "".format(pixel_index, self.pixel_count) ) + def set_pixel_all_16bit_value(self, value_r, value_g, value_b): + """ + Set the R, G, B values for all pixels. + + fast. without error checking. + + :param int value_r: 0..65535 + :param int value_g: 0..65535 + :param int value_b: 0..65535 + """ + for i in range(self.pixel_count): + self.set_pixel_16bit_value(i, value_r, value_g, value_b) + def set_pixel_all(self, color): """ Set the R, G, B values for all pixels. @@ -932,6 +945,11 @@ def set_pixel_all(self, color): for i in range(self.pixel_count): self.set_pixel(i, color) + def set_all_black(self): + """Set all pixels to black.""" + for i in range(self.pixel_count): + self.set_pixel_16bit_value(i, 0, 0, 0) + # channel access def set_channel(self, channel_index, value): """ diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 167d1b4..b91bd27 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -50,7 +50,7 @@ def channelcheck_update_pixel(): # time.sleep(0.5) offset = 0 # print("clear") - # set_all_black() + # pixels.set_all_black() # pixels.set_pixel_all((0, 1, 0)) # pixels.show() # print() @@ -76,11 +76,6 @@ def channelcheck_update(): offset = 0 -def set_all_black(): - """Set all Pixel to Black.""" - pixels.set_pixel_all((0, 0, 0)) - - ########################################## def time_measurement_call(message, test_function, loop_count=1000): @@ -231,6 +226,22 @@ def _test(): loop_count ) + def _test(): + pixels.set_pixel_all_16bit_value(500, 40500, 1000) + time_measurement_call( + "'pixels.set_pixel_all_16bit_value(500, 40500, 1000)'", + _test, + loop_count + ) + + def _test(): + pixels.set_all_black() + time_measurement_call( + "'pixels.set_all_black()'", + _test, + loop_count + ) + def time_measurement_pixels_set_16bit(): """Measure timing pixels set.""" From 1d265994f526d51f149a37a3337680ab5b776579 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 23:47:31 +0100 Subject: [PATCH 27/91] cleanup & change asserts to if with helpfull messages --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 190 ++++++++++--------- 1 file changed, 98 insertions(+), 92 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index ec27b6d..eb73a83 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -192,28 +192,6 @@ def set_bit(v, index, x): # Return the result, we're done. return v - class _GS_Value: - # Internal decorator to simplify exposing each 16-bit LED PWM channel. - # These will get/set the appropriate bytes in the shift register with - # the specified values. - - def __init__(self, byte_offset): - # Keep track of the byte within the shift register where this - # 16-bit value starts. Luckily these are all aligned on byte - # boundaries. Note the byte order is big endian (MSB first). - self._byte_offset = byte_offset - - def __get__(self, obj, obj_type): - # Grab the 16-bit value at the offset for this channel. - return (obj._buffer[self._byte_offset] << 8) | \ - obj._buffer[self._byte_offset + 1] - - def __set__(self, obj, val): - # Set the 16-bit value at the offset for this channel. - assert 0 <= val <= 65535 - obj._buffer[self._byte_offset] = (val >> 8) & 0xFF - obj._buffer[self._byte_offset + 1] = val & 0xFF - ########################################## # class _BC(): """ @@ -646,7 +624,11 @@ def _get_32bit_value_from_buffer(self, buffer_start): ) def _set_32bit_value_in_buffer(self, buffer_start, value): - assert 0 <= value <= 0xFFFFFFFF + if not 0 <= value <= 0xFFFFFFFF: + raise ValueError( + "value {} not in range: 0..0xFFFFFFFF" + "".format(value) + ) # print("buffer_start", buffer_start, "value", value) # self._debug_print_buffer() self._buffer[buffer_start + 0] = (value >> 24) & 0xFF @@ -661,7 +643,11 @@ def _get_16bit_value_from_buffer(self, buffer_start): ) def _set_16bit_value_in_buffer(self, buffer_start, value): - # assert 0 <= value <= 65535 + # if not 0 <= value <= 65535: + # raise ValueError( + # "value {} not in range: 0..65535" + # "".format(value) + # ) # print("buffer_start", buffer_start, "value", value) # self._debug_print_buffer() self._buffer[buffer_start + 0] = (value >> 8) & 0xFF @@ -671,7 +657,11 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): def _convert_01_float_to_16bit_integer(value): """Convert 0..1 Float Value to 16bit (0..65535) Range.""" # check if value is in range - assert 0 <= value <= 1 + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1" + "".format(value[0]) + ) # convert to 16bit value return int(value * 65535) @@ -851,35 +841,70 @@ def set_pixel(self, pixel_index, value): # value[0] = self._convert_if_float(value[0]) # value[1] = self._convert_if_float(value[1]) # value[2] = self._convert_if_float(value[2]) - - # check if values are in range - # assert 0 <= value[0] <= 65535 - # assert 0 <= value[1] <= 65535 - # assert 0 <= value[2] <= 65535 + # check range + # if not 0 <= value[0] <= 65535: + # raise ValueError( + # "value[0] {} not in range: 0..65535" + # "".format(value[0]) + # ) + # if not 0 <= value[1] <= 65535: + # raise ValueError( + # "value[1] {} not in range: 0..65535" + # "".format(value[1]) + # ) + # if not 0 <= value[2] <= 65535: + # raise ValueError( + # "value[2] {} not in range: 0..65535" + # "".format(value[2]) + # ) # optimize: # check if we have float values if isinstance(value[0], float): # check if value is in range - assert 0 <= value[0] <= 1 + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1" + "".format(value[0]) + ) # convert to 16bit value value[0] = int(value[0] * 65535) else: - assert 0 <= value[0] <= 65535 + if not 0 <= value[0] <= 65535: + raise ValueError( + "value[0] {} not in range: 0..65535" + "".format(value[0]) + ) if isinstance(value[1], float): # check if value is in range - assert 0 <= value[1] <= 1 + if not 0.0 <= value[1] <= 1.0: + raise ValueError( + "value[1] {} not in range: 0..1" + "".format(value[1]) + ) # convert to 16bit value value[1] = int(value[1] * 65535) else: - assert 0 <= value[1] <= 65535 + if not 0 <= value[1] <= 65535: + raise ValueError( + "value[1] {} not in range: 0..65535" + "".format(value[1]) + ) if isinstance(value[2], float): # check if value is in range - assert 0 <= value[2] <= 1 + if not 0.0 <= value[2] <= 1.0: + raise ValueError( + "value[2] {} not in range: 0..1" + "".format(value[2]) + ) # convert to 16bit value value[2] = int(value[2] * 65535) else: - assert 0 <= value[2] <= 65535 + if not 0 <= value[2] <= 65535: + raise ValueError( + "value[2] {} not in range: 0..65535" + "".format(value[2]) + ) # print("value", value) @@ -960,7 +985,10 @@ def set_channel(self, channel_index, value): """ if 0 <= channel_index < (self.channel_count): # check if values are in range - assert 0 <= value <= 65535 + if not 0 <= value <= 65535: + raise ValueError( + "value {} not in range: 0..65535" + ) # temp = channel_index # we change channel order here: # buffer channel order is blue, green, red @@ -1019,87 +1047,65 @@ def __setitem__(self, key, value): :param int key: 0..(pixel_count) :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 """ + # for a more detailed version with all the debugging code and + # comments look at set_pixel if 0 <= key < self.pixel_count: - # print("value", value) # convert to list value = list(value) - # print("value", value) - # print("rep:") - # repr(value) - # print("check length..") + if len(value) != self.COLORS_PER_PIXEL: raise IndexError( "length of value {} does not match COLORS_PER_PIXEL (= {})" "".format(len(value), self.COLORS_PER_PIXEL) ) - # tested: - # splitting up into variables to not need the list.. - # this is about 0.25ms slower! - # value_r = value[0] - # value_g = value[1] - # value_b = value[2] - # check if we have float values - # value[0] = self._convert_if_float(value[0]) - # value[1] = self._convert_if_float(value[1]) - # value[2] = self._convert_if_float(value[2]) - - # check if values are in range - # assert 0 <= value[0] <= 65535 - # assert 0 <= value[1] <= 65535 - # assert 0 <= value[2] <= 65535 - - # optimize: # check if we have float values if isinstance(value[0], float): # check if value is in range - assert 0 <= value[0] <= 1 + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1" + "".format(value[0]) + ) # convert to 16bit value value[0] = int(value[0] * 65535) else: - assert 0 <= value[0] <= 65535 + if not 0 <= value[0] <= 65535: + raise ValueError( + "value[0] {} not in range: 0..65535" + "".format(value[0]) + ) if isinstance(value[1], float): - # check if value is in range - assert 0 <= value[1] <= 1 - # convert to 16bit value + if not 0.0 <= value[1] <= 1.0: + raise ValueError( + "value[1] {} not in range: 0..1" + "".format(value[1]) + ) value[1] = int(value[1] * 65535) else: - assert 0 <= value[1] <= 65535 + if not 0 <= value[1] <= 65535: + raise ValueError( + "value[1] {} not in range: 0..65535" + "".format(value[1]) + ) if isinstance(value[2], float): - # check if value is in range - assert 0 <= value[2] <= 1 - # convert to 16bit value + if not 0.0 <= value[2] <= 1.0: + raise ValueError( + "value[2] {} not in range: 0..1" + "".format(value[2]) + ) value[2] = int(value[2] * 65535) else: - assert 0 <= value[2] <= 65535 - - # print("value", value) + if not 0 <= value[2] <= 65535: + raise ValueError( + "value[2] {} not in range: 0..65535" + "".format(value[2]) + ) # update buffer - # print("key", key, "value", value) # we change channel order here: # buffer channel order is blue, green, red pixel_start = key * self.COLORS_PER_PIXEL - # self._set_channel_16bit_value( - # pixel_start + 0, - # value[2]) - # self._set_channel_16bit_value( - # pixel_start + 1, - # value[1]) - # self._set_channel_16bit_value( - # pixel_start + 2, - # value[0]) - # optimize: - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 0], - # value[2]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 1], - # value[1]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 2], - # value[0]) - # optimize2 buffer_start = self._buffer_index_lookuptable[pixel_start + 0] self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF self._buffer[buffer_start + 1] = value[2] & 0xFF From 748eca76eb83375005b2893defc6ec0ed99b0a1d Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 23:48:00 +0100 Subject: [PATCH 28/91] update --- examples/tlc59711_multi_simpletest.py | 48 ++++++++++++++------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index ce57160..9df6f40 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -29,18 +29,17 @@ value_high = 1000 -def channelcheck_update(): - """ChannelCheck.""" +def channelcheck_update_pixel(): + """Channel check pixel.""" global offset #noqa - print("offset", offset) + # print("offset", offset) - pixels[offset] = (value_high, 0, 0) + pixels.set_pixel_16bit_value(offset, value_high, 0, 0) # clear last pixel last = offset-1 if last < 0: last = pixel_count-1 - pixels[last] = (0, 0, 1) - # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) + pixels.set_pixel_16bit_value(last, 0, 0, 1) pixels.show() offset += 1 @@ -48,37 +47,40 @@ def channelcheck_update(): time.sleep(0.5) offset = 0 print("clear") - # set_all_black() - set_all((0, 1, 0)) + pixels.set_all_black() + pixels.set_pixel_all((0, 1, 0)) pixels.show() print() - time.sleep(2) + time.sleep(1) -def set_all_black(): - """Set all Pixel to Black.""" - set_all((0, 0, 0)) +def channelcheck_update(): + """Channel check.""" + global offset #noqa + # print("offset", offset) + pixels.set_channel(offset, value_high) + # clear last set channel + last = offset-1 + if last < 0: + last = pixels.channel_count-1 + pixels.set_channel(last, 0) + pixels.show() -def set_all(color): - """Set all Pixel to color.""" - for i in range(pixel_count): - # pixels[i // 4][i % 4] = color - pixels[i] = color + offset += 1 + if offset >= pixels.channel_count: + offset = 0 def test_main(): """Test Main.""" - # print() print(42 * '*', end="") print(__doc__, end="") print(42 * '*') - # print() - # time.sleep(0.5) - # print(42 * '*') - + print("loop:") while True: - channelcheck_update() + channelcheck_update_pixel() + # channelcheck_update() time.sleep(0.5) From 91bc684751767958a7707a86cf2cd6188b5bedbb Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 23:52:57 +0100 Subject: [PATCH 29/91] simplified simpletest.py --- examples/tlc59711_multi_simpletest.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index 9df6f40..1d09332 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -26,7 +26,6 @@ # test function offset = 0 -value_high = 1000 def channelcheck_update_pixel(): @@ -34,7 +33,7 @@ def channelcheck_update_pixel(): global offset #noqa # print("offset", offset) - pixels.set_pixel_16bit_value(offset, value_high, 0, 0) + pixels.set_pixel_16bit_value(offset, 1000, 100, 0) # clear last pixel last = offset-1 if last < 0: @@ -44,14 +43,11 @@ def channelcheck_update_pixel(): offset += 1 if offset >= pixel_count: - time.sleep(0.5) + time.sleep(0.2) offset = 0 print("clear") - pixels.set_all_black() pixels.set_pixel_all((0, 1, 0)) pixels.show() - print() - time.sleep(1) def channelcheck_update(): @@ -59,7 +55,7 @@ def channelcheck_update(): global offset #noqa # print("offset", offset) - pixels.set_channel(offset, value_high) + pixels.set_channel(offset, 1000) # clear last set channel last = offset-1 if last < 0: @@ -80,8 +76,8 @@ def test_main(): print("loop:") while True: channelcheck_update_pixel() + time.sleep(0.2) # channelcheck_update() - time.sleep(0.5) ########################################## From 3697e4876dae746277a915136d44b3c7392626ca Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 5 Jan 2019 23:53:39 +0100 Subject: [PATCH 30/91] cleaned up *dev.py --- examples/tlc59711_multi_dev.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b91bd27..ec92380 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -47,14 +47,11 @@ def channelcheck_update_pixel(): offset += 1 if offset >= pixel_count: - # time.sleep(0.5) + time.sleep(0.2) offset = 0 - # print("clear") - # pixels.set_all_black() - # pixels.set_pixel_all((0, 1, 0)) - # pixels.show() - # print() - # time.sleep(2) + print("clear") + pixels.set_pixel_all((0, 1, 0)) + pixels.show() # From fd845dd75a50f3955f7c719ba31683e34057e7bb Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 00:00:16 +0100 Subject: [PATCH 31/91] fixed docu and more cleanup of *dev.py --- examples/tlc59711_multi_dev.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index ec92380..ee61549 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -1,8 +1,9 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -tlc59711_multi.py - TLC59711TLC59711Multi minimal example. +TLC59711Multi development helper. +this sketch contains a bunch of timing tests and other development helpers.. Enjoy the colors :-) """ @@ -11,7 +12,6 @@ import board import busio -# from adafruit_tlc59711.adafruit_tlc59711 import TLC59711 from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi @@ -52,7 +52,6 @@ def channelcheck_update_pixel(): print("clear") pixels.set_pixel_all((0, 1, 0)) pixels.show() - # def channelcheck_update(): @@ -433,6 +432,10 @@ def test_main(): # time.sleep(0.5) # print(42 * '*') + pixels.set_pixel_all_16bit_value(1, 10, 100) + pixels.show() + time.sleep(0.5) + time_measurement() time.sleep(0.5) print(42 * '*') From 4252b1fb0c6a7cc88baeccf154b229b680618d36 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 00:16:55 +0100 Subject: [PATCH 32/91] made pylint complexity checker happy.. this needs about 5ms more @128pixel --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 143 +++++++------------ 1 file changed, 54 insertions(+), 89 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index eb73a83..9e1c8dc 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -566,6 +566,8 @@ def _debug_print_tlc59711_ch(self): print("x{:02X}, ".format(self._buffer[index]), end="") print("]", end="") + ########################################## + # Define properties for global brightness control channels. # @property # def red_brightness(self): @@ -615,6 +617,8 @@ def _debug_print_tlc59711_ch(self): # if self.auto_show: # self._write() + ########################################## + def _get_32bit_value_from_buffer(self, buffer_start): return ( (self._buffer[buffer_start + 0] << 24) | @@ -672,6 +676,51 @@ def _convert_if_float(cls, value): value = cls._convert_01_float_to_16bit_integer(value) return value + @staticmethod + def _check_and_convert(value): + # check if we have float values + if isinstance(value[0], float): + # check if value is in range + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1" + "".format(value[0]) + ) + # convert to 16bit value + value[0] = int(value[0] * 65535) + else: + if not 0 <= value[0] <= 65535: + raise ValueError( + "value[0] {} not in range: 0..65535" + "".format(value[0]) + ) + if isinstance(value[1], float): + if not 0.0 <= value[1] <= 1.0: + raise ValueError( + "value[1] {} not in range: 0..1" + "".format(value[1]) + ) + value[1] = int(value[1] * 65535) + else: + if not 0 <= value[1] <= 65535: + raise ValueError( + "value[1] {} not in range: 0..65535" + "".format(value[1]) + ) + if isinstance(value[2], float): + if not 0.0 <= value[2] <= 1.0: + raise ValueError( + "value[2] {} not in range: 0..1" + "".format(value[2]) + ) + value[2] = int(value[2] * 65535) + else: + if not 0 <= value[2] <= 65535: + raise ValueError( + "value[2] {} not in range: 0..65535" + "".format(value[2]) + ) + ########################################## def _get_channel_16bit_value(self, channel_index): @@ -858,53 +907,9 @@ def set_pixel(self, pixel_index, value): # "".format(value[2]) # ) - # optimize: - # check if we have float values - if isinstance(value[0], float): - # check if value is in range - if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1" - "".format(value[0]) - ) - # convert to 16bit value - value[0] = int(value[0] * 65535) - else: - if not 0 <= value[0] <= 65535: - raise ValueError( - "value[0] {} not in range: 0..65535" - "".format(value[0]) - ) - if isinstance(value[1], float): - # check if value is in range - if not 0.0 <= value[1] <= 1.0: - raise ValueError( - "value[1] {} not in range: 0..1" - "".format(value[1]) - ) - # convert to 16bit value - value[1] = int(value[1] * 65535) - else: - if not 0 <= value[1] <= 65535: - raise ValueError( - "value[1] {} not in range: 0..65535" - "".format(value[1]) - ) - if isinstance(value[2], float): - # check if value is in range - if not 0.0 <= value[2] <= 1.0: - raise ValueError( - "value[2] {} not in range: 0..1" - "".format(value[2]) - ) - # convert to 16bit value - value[2] = int(value[2] * 65535) - else: - if not 0 <= value[2] <= 65535: - raise ValueError( - "value[2] {} not in range: 0..65535" - "".format(value[2]) - ) + # optimized: + # this modifies value in place.. + self._check_and_convert(value) # print("value", value) @@ -1059,48 +1064,8 @@ def __setitem__(self, key, value): "".format(len(value), self.COLORS_PER_PIXEL) ) - # check if we have float values - if isinstance(value[0], float): - # check if value is in range - if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1" - "".format(value[0]) - ) - # convert to 16bit value - value[0] = int(value[0] * 65535) - else: - if not 0 <= value[0] <= 65535: - raise ValueError( - "value[0] {} not in range: 0..65535" - "".format(value[0]) - ) - if isinstance(value[1], float): - if not 0.0 <= value[1] <= 1.0: - raise ValueError( - "value[1] {} not in range: 0..1" - "".format(value[1]) - ) - value[1] = int(value[1] * 65535) - else: - if not 0 <= value[1] <= 65535: - raise ValueError( - "value[1] {} not in range: 0..65535" - "".format(value[1]) - ) - if isinstance(value[2], float): - if not 0.0 <= value[2] <= 1.0: - raise ValueError( - "value[2] {} not in range: 0..1" - "".format(value[2]) - ) - value[2] = int(value[2] * 65535) - else: - if not 0 <= value[2] <= 65535: - raise ValueError( - "value[2] {} not in range: 0..65535" - "".format(value[2]) - ) + # this modifies value in place.. + self._check_and_convert(value) # update buffer # we change channel order here: From 1f7a36b4b0503c7ed84c718e29319b7cc8f14285 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 02:29:09 +0100 Subject: [PATCH 33/91] more test & clean up --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 304 +++++++++++-------- examples/tlc59711_multi_dev.py | 72 ++++- 2 files changed, 246 insertions(+), 130 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 9e1c8dc..0f0ca7c 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -205,7 +205,7 @@ def set_bit(v, index, x): _BC_BIT_COUNT = 3 * 7 # this holds the chip offset and _BC_FIELDS = { - "BCB": { + "BCR": { "offset": 0, "length": 7, "mask": 0b01111111, @@ -215,7 +215,7 @@ def set_bit(v, index, x): "length": 7, "mask": 0b01111111, }, - "BCR": { + "BCB": { "offset": 14, "length": 7, "mask": 0b01111111, @@ -354,16 +354,16 @@ def __init__(self, spi, pixel_count=1): # calculate how many chips are connected self.chip_count = self.pixel_count // 4 - # THe chips are just a big 28 byte long shift register without any + # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data self._buffer = bytearray(self.CHIP_BUFFER_LENGTH * self.chip_count) - # Initialize the brightness channel values to max (these are 7-bit - # values). - self._bcr = 127 - self._bcg = 127 - self._bcb = 127 + # Initialize the brightness channel values to max + # (these are 7-bit values). + self.bcr = 127 + self.bcg = 127 + self.bcb = 127 # Initialize external user-facing state for the function control # bits of the chip. These aren't commonly used but available and @@ -400,7 +400,7 @@ def _init_buffer(self): # self._debug_print_buffer() self.chip_set_BCData( - chip_index, bcr=self._bcr, bcg=self._bcg, bcb=self._bcb) + chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) # self._debug_print_buffer() self._chip_set_FunctionControl(chip_index) # self._debug_print_buffer() @@ -434,6 +434,17 @@ def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): field=self._BC_FIELDS["BCB"], value=bcb) + def update_BCData(self): + """ + Update BC-Data for all Chips in Buffer. + + need to be called after you changed on of the + BC-Data Parameters. (bcr, bcg, bcb) + """ + for chip_index in range(self.chip_count): + self.chip_set_BCData( + chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) + def _chip_set_FunctionControl(self, chip_index): """ Set Function Control Bits in Buffer. @@ -519,6 +530,147 @@ def show(self): """Write out the current LED PWM state to the chip.""" self._write() + ########################################## + + @staticmethod + def calculate_Ioclmax( + *, + Riref=2.48, + ): + """ + Calculate Maximum Constant Sink Current Value. + + see: + 8.4.1 Maximum Constant Sink Current Setting + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=18&zoom=160,0,524 + + Riref = (Viref / Ioclmax) * 41 + Ioclmax = (41 / Riref) * Viref + + :param float Riref: resistor value (kΩ) (default=20) + :return tuple: Ioclmax (mA) + """ + # Riref = (Viref / Ioclmax) * 41 | / 41 + # Riref / 41 = Viref / Ioclmax | switch + # 41 / Riref = Ioclmax / Viref | * Viref + # (41 / Riref) * Viref = Ioclmax + if not 0.8 <= Riref <= 24.8: + raise ValueError( + "Riref {} not in range: 0.8kΩ..25kΩ" + "".format(Riref) + ) + Viref = 1.21 + Ioclmax = (41 / Riref) * Viref + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError( + "Ioclmax {} not in range: 2mA..60mA" + "".format(Ioclmax) + ) + return Ioclmax + + @staticmethod + def calculate_Riref( + *, + Ioclmax=20, + ): + """ + Calculate Maximum Constant Sink Current Value. + + see: + 8.4.1 Maximum Constant Sink Current Setting + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 + + Riref = (Viref / Ioclmax) * 41 + + :param float Ioclmax: target max output current (mA) (default=20) + :return tuple: Riref (kΩ) + """ + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError( + "Ioclmax {} not in range: 2mA..60mA" + "".format(Ioclmax) + ) + Viref = 1.21 + Riref = (Viref / Ioclmax) * 41 + if not 0.8 <= Riref <= 24.8: + raise ValueError( + "Riref {} not in range: 0.8kΩ..25kΩ" + "".format(Riref) + ) + return Riref + + @staticmethod + def calculate_BCData( + *, + Ioclmax=20, + IoutR=9, + IoutG=15, + IoutB=17 + ): + """ + Calculate Global Brightness Control Values. + + see: + 8.5.1 Global Brightness Control (BC) Function (Sink Current Control) + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 + + Iout = Ioclmax * (BCX / 127) + BCX = Iout / Ioclmax * 127 + + :param float Ioclmax: max output current set by Riref (mA) (default=20) + :param float IoutR: max output current for red color group (mA) + (default=9) + :param float IoutG: max output current for green color (mA) + (default=15) + :param float IoutB: max output current for blue color (mA) + (default=17) + :return tuple: (bcr, bcg, bcb) + """ + # Iout = Ioclmax * (BCX / 127) | / Ioclmax + # Iout / Ioclmax = BCX / 127 | * 127 + # Iout / Ioclmax * 127 = BCX + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError( + "Ioclmax {} not in range: 2mA..60mA" + "".format(Ioclmax) + ) + if not 2.0 <= IoutR <= Ioclmax: + raise ValueError( + "IoutR {} not in range: 2mA..{}mA" + "".format(IoutR, Ioclmax) + ) + if not 2.0 <= IoutG <= Ioclmax: + raise ValueError( + "IoutG {} not in range: 2mA..{}mA" + "".format(IoutG, Ioclmax) + ) + if not 2.0 <= IoutB <= Ioclmax: + raise ValueError( + "IoutB {} not in range: 2mA..{}mA" + "".format(IoutB, Ioclmax) + ) + bcr = int((IoutR / Ioclmax) * 127) + bcg = int((IoutG / Ioclmax) * 127) + bcb = int((IoutB / Ioclmax) * 127) + if not 0 <= bcr <= 127: + raise ValueError( + "bcr {} not in range: 0..127" + "".format(bcr) + ) + if not 0 <= bcg <= 127: + raise ValueError( + "bcg {} not in range: 0..127" + "".format(bcg) + ) + if not 0 <= bcb <= 127: + raise ValueError( + "bcb {} not in range: 0..127" + "".format(bcb) + ) + return (bcr, bcg, bcb) + + ########################################## + def _debug_print_buffer(self): indent = " " if self.chip_count == 1: @@ -568,57 +720,6 @@ def _debug_print_tlc59711_ch(self): ########################################## - # Define properties for global brightness control channels. - # @property - # def red_brightness(self): - # """ - # Red brightness for all channels on all chips. - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcr - # - # @red_brightness.setter - # def red_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcr = val - # if self.auto_show: - # self._write() - # - # @property - # def green_brightness(self): - # """ - # Green brightness for all channels on all chips. - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcg - # - # @green_brightness.setter - # def green_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcg = val - # if self.auto_show: - # self._write() - # - # @property - # def blue_brightness(self): - # """ - # Blue brightness for all channels on all chips. - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcb - # - # @blue_brightness.setter - # def blue_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcb = val - # if self.auto_show: - # self._write() - - ########################################## - def _get_32bit_value_from_buffer(self, buffer_start): return ( (self._buffer[buffer_start + 0] << 24) | @@ -729,14 +830,10 @@ def _get_channel_16bit_value(self, channel_index): ) def _set_channel_16bit_value(self, channel_index, value): - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[channel_index], - # value - # ) - # optimized: - buffer_start = self._buffer_index_lookuptable[channel_index] - self._buffer[buffer_start + 0] = (value >> 8) & 0xFF - self._buffer[buffer_start + 1] = value & 0xFF + self._set_16bit_value_in_buffer( + self._buffer_index_lookuptable[channel_index], + value + ) def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): """ @@ -820,40 +917,22 @@ def set_pixel_float_color(self, pixel_index, value): :param int pixel_index: 0..(pixel_count) :param tuple/float 3-tuple of R, G, B; 0..1 """ - # convert tuple to list - # this way we can assign values. - # this seems faster than creating tree new variables - value = list(value) # convert to 16bit int - value[0] = int(value[0] * 65535) - value[1] = int(value[1] * 65535) - value[2] = int(value[2] * 65535) + value_r = int(value[0] * 65535) + value_g = int(value[1] * 65535) + value_b = int(value[2] * 65535) # calculate pixel_start pixel_start = pixel_index * self.COLORS_PER_PIXEL # set values buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[2] & 0xFF + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[1] & 0xFF + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[0] & 0xFF - - # value_r = int(value[0] * 65535) - # value_g = int(value[1] * 65535) - # value_b = int(value[2] * 65535) - # pixel_start = pixel_index * self.COLORS_PER_PIXEL - # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - # self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_b & 0xFF - # buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - # self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_g & 0xFF - # buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - # self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_r & 0xFF + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF def set_pixel(self, pixel_index, value): """ @@ -881,34 +960,13 @@ def set_pixel(self, pixel_index, value): ) # tested: # splitting up into variables to not need the list.. - # this is about 0.25ms slower! + # this is about 0.25ms slower.. # value_r = value[0] # value_g = value[1] # value_b = value[2] # check if we have float values - # value[0] = self._convert_if_float(value[0]) - # value[1] = self._convert_if_float(value[1]) - # value[2] = self._convert_if_float(value[2]) - # check range - # if not 0 <= value[0] <= 65535: - # raise ValueError( - # "value[0] {} not in range: 0..65535" - # "".format(value[0]) - # ) - # if not 0 <= value[1] <= 65535: - # raise ValueError( - # "value[1] {} not in range: 0..65535" - # "".format(value[1]) - # ) - # if not 0 <= value[2] <= 65535: - # raise ValueError( - # "value[2] {} not in range: 0..65535" - # "".format(value[2]) - # ) - - # optimized: - # this modifies value in place.. + # this modifies 'value' in place.. self._check_and_convert(value) # print("value", value) @@ -927,16 +985,6 @@ def set_pixel(self, pixel_index, value): # self._set_channel_16bit_value( # pixel_start + 2, # value[0]) - # optimize: - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 0], - # value[2]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 1], - # value[1]) - # self._set_16bit_value_in_buffer( - # self._buffer_index_lookuptable[pixel_start + 2], - # value[0]) # optimize2 buffer_start = self._buffer_index_lookuptable[pixel_start + 0] self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index ee61549..86899f4 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -294,6 +294,14 @@ def _test(): loop_count ) + def _test(): + pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9)) + time_measurement_call( + "'pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9))'", + _test, + loop_count + ) + def _test(): for i in range(pixel_count): pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) @@ -304,6 +312,16 @@ def _test(): 10 ) + def _test(): + for i in range(pixel_count): + pixels.set_pixel_float_color(i, (0.1, 0.5, 0.9)) + time_measurement_call( + "'pixels.set_pixel_float_color(0..{}, (0.1, 0.5, 0.9))'" + "".format(pixel_count), + _test, + 10 + ) + def _test(): for i in range(pixel_count): pixels.set_pixel_16bit_value( @@ -423,6 +441,53 @@ def time_measurement(): ########################################## +def test_BCData(): + """Test BC-Data setting.""" + print("test BC-Data setting:") + print("set pixel all to 100, 100, 100") + pixels.set_pixel_all((100, 100, 100)) + pixels.show() + time.sleep(2) + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + # calculate bc values + Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + print("Ioclmax = {}".format(Ioclmax)) + Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + print("Riref = {}".format(Riref)) + BCValues = TLC59711Multi.calculate_BCData(Ioclmax=Ioclmax) + # (62, 103, 117) + print("BCValues = {}".format(BCValues)) + + print("set bcX to {}".format(BCValues)) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + pixels.update_BCData() + pixels.show() + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + time.sleep(2) + +########################################## + + def test_main(): """Test Main.""" print(42 * '*', end="") @@ -436,12 +501,15 @@ def test_main(): pixels.show() time.sleep(0.5) + test_BCData() + time.sleep(0.5) + print(42 * '*') + time_measurement() time.sleep(0.5) print(42 * '*') - print() - print("loop:") + print("loop:") while True: channelcheck_update() time.sleep(0.5) From f3a9888111561e9f892a7e1a9280417277d1a761 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 02:29:40 +0100 Subject: [PATCH 34/91] add bcdata test sketch --- examples/tlc59711_multi_test_bcdata.py | 106 +++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 examples/tlc59711_multi_test_bcdata.py diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py new file mode 100644 index 0000000..127ce8b --- /dev/null +++ b/examples/tlc59711_multi_test_bcdata.py @@ -0,0 +1,106 @@ +"""TLC5971 / TLC59711 Multi.""" + +__doc__ = """ +TLC59711Multi development helper. + +this sketch contains a bunch of timing tests and other development helpers.. +Enjoy the colors :-) +""" + +import time + +import board +import busio +import supervisor + +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + + +########################################## +pixel_count = 16*8 + +spi = busio.SPI(board.SCK, MOSI=board.MOSI) +pixels = TLC59711Multi(spi, pixel_count=pixel_count) + +########################################## + + +def test_main(): + """Test Main.""" + print(42 * '*', end="") + print(__doc__, end="") + print(42 * '*') + # print() + # time.sleep(0.5) + # print(42 * '*') + + print("set pixel all to 100, 100, 100") + pixels.set_pixel_all((1000, 1000, 1000)) + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + pixels.show() + time.sleep(0.1) + + if supervisor.runtime.serial_connected: + print( + "you can change the global brightness control:\n" + "use format: 'Ioclmax; IoutR; IoutG; IoutB'\n" + "example: '18; 7; 15; 17'" + ) + while True: + if supervisor.runtime.serial_bytes_available: + new_value = input() + if "v" in new_value: + try: + value = int(new_value[1:]) + except ValueError as e: + print("Exception: ", e) + pixels.set_pixel_all_16bit_value(value, value, value) + else: + try: + Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') + Ioclmax = float(Ioclmax) + IoutR = float(IoutR) + IoutG = float(IoutG) + IoutB = float(IoutB) + except ValueError as e: + print("Exception: ", e) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=IoutR, + IoutG=IoutG, + IoutB=IoutB, + ) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + pixels.update_BCData() + pixels.show() + # prepare new input + print("\nenter new values:") + + +########################################## +# main loop + +if __name__ == '__main__': + + test_main() From 208e77a794956f6fcdc844ee948edf94acc28c18 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 02:45:28 +0100 Subject: [PATCH 35/91] update and refine BCData things --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 6 +- examples/tlc59711_multi_dev.py | 11 +- examples/tlc59711_multi_test_bcdata.py | 110 ++++++++++--------- 3 files changed, 72 insertions(+), 55 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 0f0ca7c..7d1d4b2 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -602,10 +602,10 @@ def calculate_Riref( @staticmethod def calculate_BCData( *, - Ioclmax=20, - IoutR=9, + Ioclmax=18, + IoutR=17, IoutG=15, - IoutB=17 + IoutB=9 ): """ Calculate Global Brightness Control Values. diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 86899f4..d1027e8 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -463,11 +463,16 @@ def test_BCData(): print("Ioclmax = {}".format(Ioclmax)) Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = TLC59711Multi.calculate_BCData(Ioclmax=Ioclmax) - # (62, 103, 117) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=18, + IoutG=11, + IoutB=13, + ) + # (127, 77, 91) print("BCValues = {}".format(BCValues)) - print("set bcX to {}".format(BCValues)) + print("set bcX") pixels.bcr = BCValues[0] pixels.bcg = BCValues[1] pixels.bcb = BCValues[2] diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index 127ce8b..92d3351 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -25,6 +25,49 @@ ########################################## +def main_loop(): + """Loop.""" + new_value = input() + if "v" in new_value: + try: + value = int(new_value[1:]) + except ValueError as e: + print("Exception: ", e) + pixels.set_pixel_all_16bit_value(value, value, value) + else: + try: + Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') + Ioclmax = float(Ioclmax) + IoutR = float(IoutR) + IoutG = float(IoutG) + IoutB = float(IoutB) + except ValueError as e: + print("Exception: ", e) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=IoutR, + IoutG=IoutG, + IoutB=IoutB, + ) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + pixels.update_BCData() + pixels.show() + # prepare new input + print("\nenter new values:") + + def test_main(): """Test Main.""" print(42 * '*', end="") @@ -35,17 +78,24 @@ def test_main(): # print(42 * '*') print("set pixel all to 100, 100, 100") - pixels.set_pixel_all((1000, 1000, 1000)) - print( - "bcr: {:>3}\n" - "bcg: {:>3}\n" - "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) + pixels.set_pixel_all((5000, 5000, 5000)) + # calculate bc values + Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + print("Ioclmax = {}".format(Ioclmax)) + Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + print("Riref = {}".format(Riref)) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=18, + IoutG=11, + IoutB=13, ) + # (127, 77, 91) + print("BCValues = {}".format(BCValues)) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + pixels.update_BCData() pixels.show() time.sleep(0.1) @@ -57,45 +107,7 @@ def test_main(): ) while True: if supervisor.runtime.serial_bytes_available: - new_value = input() - if "v" in new_value: - try: - value = int(new_value[1:]) - except ValueError as e: - print("Exception: ", e) - pixels.set_pixel_all_16bit_value(value, value, value) - else: - try: - Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') - Ioclmax = float(Ioclmax) - IoutR = float(IoutR) - IoutG = float(IoutG) - IoutB = float(IoutB) - except ValueError as e: - print("Exception: ", e) - BCValues = TLC59711Multi.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=IoutR, - IoutG=IoutG, - IoutB=IoutB, - ) - pixels.bcr = BCValues[0] - pixels.bcg = BCValues[1] - pixels.bcb = BCValues[2] - print( - "bcr: {:>3}\n" - "bcg: {:>3}\n" - "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) - ) - pixels.update_BCData() - pixels.show() - # prepare new input - print("\nenter new values:") + main_loop() ########################################## From c24ae1479eecc9717fe3e55e4a7b463389e42a78 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 02:59:19 +0100 Subject: [PATCH 36/91] some refines for BC-Data --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 6 +++--- examples/tlc59711_multi_simpletest.py | 14 ++++++++++++++ examples/tlc59711_multi_test_bcdata.py | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 7d1d4b2..cc4c213 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -634,17 +634,17 @@ def calculate_BCData( "Ioclmax {} not in range: 2mA..60mA" "".format(Ioclmax) ) - if not 2.0 <= IoutR <= Ioclmax: + if not 0.0 <= IoutR <= Ioclmax: raise ValueError( "IoutR {} not in range: 2mA..{}mA" "".format(IoutR, Ioclmax) ) - if not 2.0 <= IoutG <= Ioclmax: + if not 0.0 <= IoutG <= Ioclmax: raise ValueError( "IoutG {} not in range: 2mA..{}mA" "".format(IoutG, Ioclmax) ) - if not 2.0 <= IoutB <= Ioclmax: + if not 0.0 <= IoutB <= Ioclmax: raise ValueError( "IoutB {} not in range: 2mA..{}mA" "".format(IoutB, Ioclmax) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index 1d09332..1a4aac9 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -73,6 +73,20 @@ def test_main(): print(42 * '*', end="") print(__doc__, end="") print(42 * '*') + + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=18, + IoutR=18, + IoutG=11, + IoutB=13, + ) + print("BCValues = {}".format(BCValues)) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + pixels.update_BCData() + pixels.show() + print("loop:") while True: channelcheck_update_pixel() diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index 92d3351..affc484 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -35,6 +35,7 @@ def main_loop(): print("Exception: ", e) pixels.set_pixel_all_16bit_value(value, value, value) else: + Ioclmax, IoutR, IoutG, IoutB = (18, 18, 11, 13) try: Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') Ioclmax = float(Ioclmax) From 6bf3378c5aff0cab8c5564273389dcfbdfe123c9 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 6 Jan 2019 23:54:33 +0100 Subject: [PATCH 37/91] fix travis for subfolder. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e31dac4..ae0d206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ install: - pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme - pip install --force-reinstall pylint==1.9.2 script: -- pylint adafruit_tlc59711.py +- pylint adafruit_tlc59711/*.py - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-tlc59711 --library_location From ee46c9355fa1d85c022ab5571ba415e74c6016f9 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Jan 2019 00:04:05 +0100 Subject: [PATCH 38/91] make sphinx happy ;-) --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 33 ++++++++++---------- docs/api.rst | 5 ++- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index cc4c213..eeb5835 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -89,8 +89,8 @@ class TLC59711Multi: :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. The clock and MOSI/outout must be set, the MISO/input is unused. Maximal data clock frequence is: - - TLC59711: 10MHz - - TLC5971: 20MHz + - TLC59711: 10MHz + - TLC5971: 20MHz :param bool pixel_count: Number of RGB-LEDs (=Pixels) are connected. """ @@ -884,7 +884,7 @@ def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF self._buffer[buffer_start + 1] = value_r & 0xFF - def set_pixel_16bit_color(self, pixel_index, value): + def set_pixel_16bit_color(self, pixel_index, color): """ Set color for pixel. @@ -893,20 +893,20 @@ def set_pixel_16bit_color(self, pixel_index, value): its a little bit slower as `set_pixel_16bit_value` :param int pixel_index: 0..(pixel_count) - :param int 3-tuple of R, G, B; 0..65535 + :param int color: 3-tuple of R, G, B; 0..65535 """ pixel_start = pixel_index * self.COLORS_PER_PIXEL buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[2] & 0xFF + self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[2] & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[1] & 0xFF + self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[1] & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[0] & 0xFF + self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[0] & 0xFF - def set_pixel_float_color(self, pixel_index, value): + def set_pixel_float_color(self, pixel_index, color): """ Set color for pixel. @@ -915,12 +915,12 @@ def set_pixel_float_color(self, pixel_index, value): its a little bit slower as `set_pixel_16bit_value` :param int pixel_index: 0..(pixel_count) - :param tuple/float 3-tuple of R, G, B; 0..1 + :param tuple/float color: 3-tuple of R, G, B; 0..1 """ # convert to 16bit int - value_r = int(value[0] * 65535) - value_g = int(value[1] * 65535) - value_b = int(value[2] * 65535) + value_r = int(color[0] * 65535) + value_g = int(color[1] * 65535) + value_b = int(color[2] * 65535) # calculate pixel_start pixel_start = pixel_index * self.COLORS_PER_PIXEL # set values @@ -943,7 +943,8 @@ def set_pixel(self, pixel_index, value): but therefor gives clues to what is going wrong.. ;-) :param int pixel_index: 0..(pixel_count) - :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + :param tuple value: 3-tuple of R, G, B; + each int 0..65535 or float 0..1 """ if 0 <= pixel_index < self.pixel_count: # print("value", value) diff --git a/docs/api.rst b/docs/api.rst index 4991f11..88a67d7 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,5 +1,8 @@ .. If you created a package, create one automodule per module in the package. -.. automodule:: adafruit_tlc59711 +.. automodule:: adafruit_tlc59711.adafruit_tlc59711 + :members: + +.. automodule:: adafruit_tlc59711.adafruit_tlc59711_multi :members: From 4c93b91b98bee72c0492f46d48ec16ef69d0cab3 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Jan 2019 00:18:00 +0100 Subject: [PATCH 39/91] fix linting --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 +- examples/tlc59711_multi_dev.py | 72 ++++++++++---------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index eeb5835..5694315 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -304,7 +304,7 @@ def set_bit(v, index, x): def set_chipheader_bits_in_buffer( self, - *, # noqa + *, chip_index=0, part_bit_offset=0, field={"mask": 0, "length": 0, "offset": 0}, diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index d1027e8..30977e3 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -25,13 +25,11 @@ ########################################## # test function -offset = 0 value_high = 1000 -def channelcheck_update_pixel(): +def channelcheck_update_pixel(offset): """Channel check pixel.""" - global offset #noqa # print("offset", offset) # pixels[offset] = (value_high, 0, 0) @@ -52,11 +50,11 @@ def channelcheck_update_pixel(): print("clear") pixels.set_pixel_all((0, 1, 0)) pixels.show() + return offset -def channelcheck_update(): +def channelcheck_update(offset): """Channel check.""" - global offset #noqa # print("offset", offset) pixels.set_channel(offset, value_high) @@ -70,6 +68,7 @@ def channelcheck_update(): offset += 1 if offset >= pixels.channel_count: offset = 0 + return offset ########################################## @@ -375,35 +374,36 @@ def _test(): def time_measurement_channel_set_internal(): """Measure timing channel set internal.""" print("*** channel set internal:") - loop_count = 1000 - - def _test(): - pixels._set_channel_16bit_value(0, 10000) - time_measurement_call( - "'_set_channel_16bit_value(0, 10000)'", - _test, - loop_count - ) - - def _test(): - pixels._set_channel_16bit_value(0, 10000) - pixels._set_channel_16bit_value(1, 10000) - pixels._set_channel_16bit_value(2, 10000) - time_measurement_call( - "'_set_channel_16bit_value(0..2, 10000)'", - _test, - loop_count - ) - - def _test(): - for i in range(pixel_count * 3): - pixels._set_channel_16bit_value(i, 500) - time_measurement_call( - "'_set_channel_16bit_value(for 0..{}, 10000)'" - "".format(pixel_count * 3), - _test, - 10 - ) + # loop_count = 1000 + # + # def _test(): + # pixels._set_channel_16bit_value(0, 10000) + # time_measurement_call( + # "'_set_channel_16bit_value(0, 10000)'", + # _test, + # loop_count + # ) + # + # def _test(): + # pixels._set_channel_16bit_value(0, 10000) + # pixels._set_channel_16bit_value(1, 10000) + # pixels._set_channel_16bit_value(2, 10000) + # time_measurement_call( + # "'_set_channel_16bit_value(0..2, 10000)'", + # _test, + # loop_count + # ) + # + # def _test(): + # for i in range(pixel_count * 3): + # pixels._set_channel_16bit_value(i, 500) + # time_measurement_call( + # "'_set_channel_16bit_value(for 0..{}, 10000)'" + # "".format(pixel_count * 3), + # _test, + # 10 + # ) + print(" must be uncommented in code to work..") def time_measurement_pixels_get(): @@ -514,9 +514,11 @@ def test_main(): time.sleep(0.5) print(42 * '*') + offset = 0 + print("loop:") while True: - channelcheck_update() + offset = channelcheck_update(offset) time.sleep(0.5) From f729757c2ab194f4109a225cfb671f37a016130b Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Jan 2019 00:27:22 +0100 Subject: [PATCH 40/91] more linting fixes --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 126 +++++++++---------- examples/tlc59711_multi_simpletest.py | 16 +-- 2 files changed, 70 insertions(+), 72 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 5694315..d9603a4 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -94,63 +94,63 @@ class TLC59711Multi: :param bool pixel_count: Number of RGB-LEDs (=Pixels) are connected. """ - """ - TLC5971 data / register structure - - some detailed information on the protocol based on - http://www.ti.com/lit/ds/symlink/tlc5971.pdf - 8.5.4 Register and Data Latch Configuration (page 23ff) - 9.2.2.3 How to Control the TLC5971 (page27) - - How to send: - the first data we send are received by the last device in chain. - Device Nth (244Bit = 28Byte) - Write Command (6Bit) - WRCMD (fixed: 25h) - Function Control Data (5 x 1Bit = 5Bit) - OUTTMG 1bit - GS clock edge select - 1=rising edge, 0= falling edge - EXTGCK 1bit - GS reference clock select - 1=SCKI clock, 0=internal oscillator - TMGRST 1bit - display timing reset mode - 1=OUT forced of on latchpulse, 0=no forced reset - DSPRPT 1bit - display repeat mode - 1=auto repeate - 0=Out only turned on after Blank or internal latchpulse - BLANK 1bit; - 1=blank (outputs off) - 0=Out on - controlled by GS-Data - ic power on sets this to 1 - BC-Data (3 x 7Bits = 21Bit) - BCB 7bit; - BCG 7bit; - BCR 7bit; - GS-Data (12 x 16Bits = 192Bit) - GSB3 16bit; - GSG3 16bit; - GSR3 16bit; - GSB2 16bit; - GSG2 16bit; - GSR2 16bit; - GSB1 16bit; - GSG1 16bit; - GSR1 16bit; - GSB0 16bit; - GSG0 16bit; - GSR0 16bit; - Device Nth-1 (244Bit = 28Byte) - Device .. - Device 2 - Device 1 - short break of 8x period of clock (666ns .. 2.74ms) - to generate latchpulse - + 1.34uS - than next update. - """ + # """ + # TLC5971 data / register structure + # + # some detailed information on the protocol based on + # http://www.ti.com/lit/ds/symlink/tlc5971.pdf + # 8.5.4 Register and Data Latch Configuration (page 23ff) + # 9.2.2.3 How to Control the TLC5971 (page27) + # + # How to send: + # the first data we send are received by the last device in chain. + # Device Nth (244Bit = 28Byte) + # Write Command (6Bit) + # WRCMD (fixed: 25h) + # Function Control Data (5 x 1Bit = 5Bit) + # OUTTMG 1bit + # GS clock edge select + # 1=rising edge, 0= falling edge + # EXTGCK 1bit + # GS reference clock select + # 1=SCKI clock, 0=internal oscillator + # TMGRST 1bit + # display timing reset mode + # 1=OUT forced of on latchpulse, 0=no forced reset + # DSPRPT 1bit + # display repeat mode + # 1=auto repeate + # 0=Out only turned on after Blank or internal latchpulse + # BLANK 1bit; + # 1=blank (outputs off) + # 0=Out on - controlled by GS-Data + # ic power on sets this to 1 + # BC-Data (3 x 7Bits = 21Bit) + # BCB 7bit; + # BCG 7bit; + # BCR 7bit; + # GS-Data (12 x 16Bits = 192Bit) + # GSB3 16bit; + # GSG3 16bit; + # GSR3 16bit; + # GSB2 16bit; + # GSG2 16bit; + # GSR2 16bit; + # GSB1 16bit; + # GSG1 16bit; + # GSR1 16bit; + # GSB0 16bit; + # GSG0 16bit; + # GSR0 16bit; + # Device Nth-1 (244Bit = 28Byte) + # Device .. + # Device 2 + # Device 1 + # short break of 8x period of clock (666ns .. 2.74ms) + # to generate latchpulse + # + 1.34uS + # than next update. + # """ ########################################## # helper @@ -194,13 +194,11 @@ def set_bit(v, index, x): ########################################## # class _BC(): - """ - BC-Data (3 x 7Bits = 21Bit). - - BCB 7bit; - BCG 7bit; - BCR 7bit; - """ + # BC-Data (3 x 7Bits = 21Bit). + # + # BCB 7bit; + # BCG 7bit; + # BCR 7bit; _BC_CHIP_BUFFER_BIT_OFFSET = 0 _BC_BIT_COUNT = 3 * 7 # this holds the chip offset and diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_multi_simpletest.py index 1a4aac9..2edfe97 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_multi_simpletest.py @@ -25,12 +25,8 @@ ########################################## # test function -offset = 0 - - -def channelcheck_update_pixel(): +def channelcheck_update_pixel(offset): """Channel check pixel.""" - global offset #noqa # print("offset", offset) pixels.set_pixel_16bit_value(offset, 1000, 100, 0) @@ -48,11 +44,11 @@ def channelcheck_update_pixel(): print("clear") pixels.set_pixel_all((0, 1, 0)) pixels.show() + return offset -def channelcheck_update(): +def channelcheck_update(offset): """Channel check.""" - global offset #noqa # print("offset", offset) pixels.set_channel(offset, 1000) @@ -66,6 +62,7 @@ def channelcheck_update(): offset += 1 if offset >= pixels.channel_count: offset = 0 + return offset def test_main(): @@ -87,9 +84,12 @@ def test_main(): pixels.update_BCData() pixels.show() + offset = 0 + print("loop:") while True: - channelcheck_update_pixel() + offset = channelcheck_update_pixel(offset) + # offset = channelcheck_update(offset) time.sleep(0.2) # channelcheck_update() From 7e42ebceb999f3637e503cc93a044cf501bd2564 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Jan 2019 00:34:32 +0100 Subject: [PATCH 41/91] and more linting / cleaningup... --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 67 ++++++++------------ 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index d9603a4..ce13577 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -61,23 +61,6 @@ # refers to them as. # pylint: disable=invalid-name -# Globally disable too many instance attributes check. Again this is a case -# where pylint doesn't have the right context to make this call. The chip by -# design has many channels which must be exposed. -# pylint: disable=too-many-instance-attributes - -# Globally disable protected access. Once again pylint can't figure out the -# context for using internal decorate classes below. -# In these cases protectected access is by design for the internal class. -# pylint: disable=protected-access - -# Yet another pylint issue, it fails to recognize a decorator class by -# definition has no public methods. Disable the check. -# pylint: disable=too-few-public-methods - - -# this is not available in CircuitPython -# import uctypes as ctypes class TLC59711Multi: """Multi TLC59711 16-bit 12 channel LED PWM driver. @@ -222,30 +205,30 @@ def set_bit(v, index, x): ########################################## # class _FC(): - """ - Function Control Data (5 x 1Bit = 5Bit). - - OUTTMG 1bit - GS clock edge select - 1 = rising edge - 0 = falling edge - EXTGCK 1bit - GS reference clock select - 1 = SCKI clock - 0 = internal oscillator - TMGRST 1bit - display timing reset mode - 1 = OUT forced of on latchpulse - 0 = no forced reset - DSPRPT 1bit - display repeat mode - 1 = auto repeate - 0 = Out only turned on after Blank or internal latchpulse - BLANK 1bit; - ic power on sets this to 1 - 1 = blank (outputs off) - 0 = Out on - controlled by GS-Data - """ + # """ + # Function Control Data (5 x 1Bit = 5Bit). + # + # OUTTMG 1bit + # GS clock edge select + # 1 = rising edge + # 0 = falling edge + # EXTGCK 1bit + # GS reference clock select + # 1 = SCKI clock + # 0 = internal oscillator + # TMGRST 1bit + # display timing reset mode + # 1 = OUT forced of on latchpulse + # 0 = no forced reset + # DSPRPT 1bit + # display repeat mode + # 1 = auto repeate + # 0 = Out only turned on after Blank or internal latchpulse + # BLANK 1bit; + # ic power on sets this to 1 + # 1 = blank (outputs off) + # 0 = Out on - controlled by GS-Data + # """ _FC_CHIP_BUFFER_BIT_OFFSET = _BC_BIT_COUNT _FC_BIT_COUNT = 5 @@ -279,7 +262,7 @@ def set_bit(v, index, x): ########################################## # class _WRITE_COMMAND(): - """WRITE_COMMAND.""" + # """WRITE_COMMAND.""" _WC_CHIP_BUFFER_BIT_OFFSET = _FC_BIT_COUNT + _BC_BIT_COUNT _WC_BIT_COUNT = 6 From 4095964e1ec8ca9f30f599126359ba578c8602cb Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 25 Jan 2019 13:24:21 +0100 Subject: [PATCH 42/91] rename internals for better name compatibility to TLC5957 --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index ce13577..23e2cbc 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -139,11 +139,12 @@ class TLC59711Multi: # helper ########################################## - CHIP_BUFFER_LENGTH = 28 + CHIP_BUFFER_BYTE_COUNT = 28 COLORS_PER_PIXEL = 3 PIXEL_PER_CHIP = 4 CHANNEL_PER_CHIP = COLORS_PER_PIXEL * PIXEL_PER_CHIP + BUFFER_BYTES_PER_COLOR = 2 BUFFER_BYTES_PER_PIXEL = BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL @@ -310,7 +311,7 @@ def set_chipheader_bits_in_buffer( # move value to position value = value << offset # calculate header start - header_start = chip_index * self.CHIP_BUFFER_LENGTH + header_start = chip_index * self.CHIP_BUFFER_BYTE_COUNT # get chip header header = self._get_32bit_value_from_buffer(header_start) # print("{:032b}".format(header)) @@ -338,7 +339,7 @@ def __init__(self, spi, pixel_count=1): # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data - self._buffer = bytearray(self.CHIP_BUFFER_LENGTH * self.chip_count) + self._buffer = bytearray(self.CHIP_BUFFER_BYTE_COUNT * self.chip_count) # Initialize the brightness channel values to max # (these are 7-bit values). @@ -376,7 +377,7 @@ def __init__(self, spi, pixel_count=1): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - # buffer_start = chip_index * self.CHIP_BUFFER_LENGTH + # buffer_start = chip_index * self.CHIP_BUFFER_BYTE_COUNT # self._buffer[buffer_start] = 0x25 << 2 # self._debug_print_buffer() @@ -484,7 +485,7 @@ def _chip_set_WriteCommand(self, chip_index): def _init_lookuptable(self): for channel_index in range(self.channel_count): buffer_index = ( - (self.CHIP_BUFFER_LENGTH // self.BUFFER_BYTES_PER_COLOR) + (self.CHIP_BUFFER_BYTE_COUNT // self.BUFFER_BYTES_PER_COLOR) * (channel_index // self.CHANNEL_PER_CHIP) + channel_index % self.CHANNEL_PER_CHIP ) From 34b214f12199e5684ce95f2e10e807615cb105a2 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 8 Feb 2020 23:16:59 +0100 Subject: [PATCH 43/91] tweak --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 23e2cbc..aeef3b1 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -1016,7 +1016,7 @@ def set_channel(self, channel_index, value): """ Set the value for the provided channel. - :param int channel_index: 0..(channel_count) + :param int channel_index: 0..channel_count :param int value: 0..65535 """ if 0 <= channel_index < (self.channel_count): From f88c06d94cc06604c4b56fd688b247104d20f9d6 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 8 Feb 2020 23:20:24 +0100 Subject: [PATCH 44/91] add example --- examples/tlc59711_multi_powertest.py | 119 +++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 examples/tlc59711_multi_powertest.py diff --git a/examples/tlc59711_multi_powertest.py b/examples/tlc59711_multi_powertest.py new file mode 100644 index 0000000..1f37572 --- /dev/null +++ b/examples/tlc59711_multi_powertest.py @@ -0,0 +1,119 @@ +"""TLC5971 / TLC59711 Multi.""" + +__doc__ = """ +TLC59711Multi powertest. + +just check how much current your leds need... +Enjoy the colors :-) +""" + +import time + +import board +import busio +import supervisor + +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + + +########################################## +pixel_count = 16*2 + +spi = busio.SPI(board.SCK, MOSI=board.MOSI) +pixels = TLC59711Multi(spi, pixel_count=pixel_count) + +########################################## + + +def main_loop(): + """Loop.""" + new_value = input() + if "v" in new_value: + try: + value = int(new_value[1:]) + except ValueError as e: + print("Exception: ", e) + pixels.set_pixel_all_16bit_value(value, value, value) + else: + Ioclmax, IoutR, IoutG, IoutB = (18, 18, 11, 13) + try: + Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') + Ioclmax = float(Ioclmax) + IoutR = float(IoutR) + IoutG = float(IoutG) + IoutB = float(IoutB) + except ValueError as e: + print("Exception: ", e) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=IoutR, + IoutG=IoutG, + IoutB=IoutB, + ) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + print( + "bcr: {:>3}\n" + "bcg: {:>3}\n" + "bcb: {:>3}\n" + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) + ) + pixels.update_BCData() + pixels.show() + # prepare new input + print("\nenter new values:") + + +def test_main(): + """Test Main.""" + print(42 * '*', end="") + print(__doc__, end="") + print(42 * '*') + # print() + # time.sleep(0.5) + # print(42 * '*') + + print("set pixel all to 100, 100, 100") + pixels.set_pixel_all((5000, 5000, 5000)) + # calculate bc values + Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + print("Ioclmax = {}".format(Ioclmax)) + Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + print("Riref = {}".format(Riref)) + BCValues = TLC59711Multi.calculate_BCData( + Ioclmax=Ioclmax, + IoutR=18, + IoutG=11, + IoutB=13, + ) + # (127, 77, 91) + print("BCValues = {}".format(BCValues)) + pixels.bcr = BCValues[0] + pixels.bcg = BCValues[1] + pixels.bcb = BCValues[2] + pixels.update_BCData() + pixels.show() + time.sleep(0.1) + + if supervisor.runtime.serial_connected: + print( + "you can change the global brightness control:\n" + "use format: 'Ioclmax; IoutR; IoutG; IoutB'\n" + "example: '18; 7; 15; 17'" + ) + while True: + if supervisor.runtime.serial_bytes_available: + main_loop() + + +########################################## +# main loop + +if __name__ == '__main__': + + test_main() From ee2eedcbe042771560575dd64a8aa756ea1bec20 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 10 Feb 2020 13:58:24 +0100 Subject: [PATCH 45/91] change to const & internal const --- adafruit_tlc59711/adafruit_tlc59711.py | 2 +- adafruit_tlc59711/adafruit_tlc59711_multi.py | 54 ++++++++++---------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711.py b/adafruit_tlc59711/adafruit_tlc59711.py index 3ac74de..fc55f57 100644 --- a/adafruit_tlc59711/adafruit_tlc59711.py +++ b/adafruit_tlc59711/adafruit_tlc59711.py @@ -57,7 +57,7 @@ # Globally disable protected access. Once again pylint can't figure out the # context for using internal decorate classes below. -# In these cases protectected access is by design for the internal class. +# In these cases protected access is by design for the internal class. # pylint: disable=protected-access # Yet another pylint issue, it fails to recognize a decorator class by diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index aeef3b1..a3c8625 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -61,6 +61,8 @@ # refers to them as. # pylint: disable=invalid-name +from micropython import const + class TLC59711Multi: """Multi TLC59711 16-bit 12 channel LED PWM driver. @@ -139,14 +141,14 @@ class TLC59711Multi: # helper ########################################## - CHIP_BUFFER_BYTE_COUNT = 28 + _CHIP_BUFFER_BYTE_COUNT = const(28) - COLORS_PER_PIXEL = 3 - PIXEL_PER_CHIP = 4 - CHANNEL_PER_CHIP = COLORS_PER_PIXEL * PIXEL_PER_CHIP + COLORS_PER_PIXEL = const(3) + PIXEL_PER_CHIP = const(4) + CHANNEL_PER_CHIP = const(COLORS_PER_PIXEL * PIXEL_PER_CHIP) - BUFFER_BYTES_PER_COLOR = 2 - BUFFER_BYTES_PER_PIXEL = BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL + _BUFFER_BYTES_PER_COLOR = const(2) + _BUFFER_BYTES_PER_PIXEL = const(_BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL) @staticmethod def set_bit_with_mask(v, mask, x): @@ -183,8 +185,8 @@ def set_bit(v, index, x): # BCB 7bit; # BCG 7bit; # BCR 7bit; - _BC_CHIP_BUFFER_BIT_OFFSET = 0 - _BC_BIT_COUNT = 3 * 7 + _BC_CHIP_BUFFER_BIT_OFFSET = const(0) + _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { "BCR": { @@ -231,8 +233,8 @@ def set_bit(v, index, x): # 0 = Out on - controlled by GS-Data # """ - _FC_CHIP_BUFFER_BIT_OFFSET = _BC_BIT_COUNT - _FC_BIT_COUNT = 5 + _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) + _FC_BIT_COUNT = const(5) _FC_FIELDS = { "BLANK": { "offset": 0, @@ -265,8 +267,8 @@ def set_bit(v, index, x): # class _WRITE_COMMAND(): # """WRITE_COMMAND.""" - _WC_CHIP_BUFFER_BIT_OFFSET = _FC_BIT_COUNT + _BC_BIT_COUNT - _WC_BIT_COUNT = 6 + _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) + _WC_BIT_COUNT = const(6) _WC_FIELDS = { "WRITE_COMMAND": { "offset": 0, @@ -274,13 +276,13 @@ def set_bit(v, index, x): "mask": 0b111111, }, } - WRITE_COMMAND = 0b100101 + WRITE_COMMAND = const(0b100101) ########################################## ######## - CHIP_BUFFER_HEADER_BIT_COUNT = \ - _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT - CHIP_BUFFER_HEADER_BYTE_COUNT = CHIP_BUFFER_HEADER_BIT_COUNT // 8 + _CHIP_BUFFER_HEADER_BIT_COUNT = const( + _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT) + _CHIP_BUFFER_HEADER_BYTE_COUNT = const(_CHIP_BUFFER_HEADER_BIT_COUNT // 8) ########################################## @@ -311,7 +313,7 @@ def set_chipheader_bits_in_buffer( # move value to position value = value << offset # calculate header start - header_start = chip_index * self.CHIP_BUFFER_BYTE_COUNT + header_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT # get chip header header = self._get_32bit_value_from_buffer(header_start) # print("{:032b}".format(header)) @@ -339,7 +341,7 @@ def __init__(self, spi, pixel_count=1): # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data - self._buffer = bytearray(self.CHIP_BUFFER_BYTE_COUNT * self.chip_count) + self._buffer = bytearray(self._CHIP_BUFFER_BYTE_COUNT * self.chip_count) # Initialize the brightness channel values to max # (these are 7-bit values). @@ -377,7 +379,7 @@ def __init__(self, spi, pixel_count=1): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - # buffer_start = chip_index * self.CHIP_BUFFER_BYTE_COUNT + # buffer_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT # self._buffer[buffer_start] = 0x25 << 2 # self._debug_print_buffer() @@ -485,12 +487,12 @@ def _chip_set_WriteCommand(self, chip_index): def _init_lookuptable(self): for channel_index in range(self.channel_count): buffer_index = ( - (self.CHIP_BUFFER_BYTE_COUNT // self.BUFFER_BYTES_PER_COLOR) + (self._CHIP_BUFFER_BYTE_COUNT // self._BUFFER_BYTES_PER_COLOR) * (channel_index // self.CHANNEL_PER_CHIP) + channel_index % self.CHANNEL_PER_CHIP ) - buffer_index *= self.BUFFER_BYTES_PER_COLOR - buffer_index += self.CHIP_BUFFER_HEADER_BYTE_COUNT + buffer_index *= self._BUFFER_BYTES_PER_COLOR + buffer_index += self._CHIP_BUFFER_HEADER_BYTE_COUNT self._buffer_index_lookuptable.append(buffer_index) ########################################## @@ -685,17 +687,17 @@ def _debug_print_tlc59711(self): def _debug_print_tlc59711_header(self): # print( - # "self.CHIP_BUFFER_HEADER_BYTE_COUNT", - # self.CHIP_BUFFER_HEADER_BYTE_COUNT) + # "self._CHIP_BUFFER_HEADER_BYTE_COUNT", + # self._CHIP_BUFFER_HEADER_BYTE_COUNT) print("header: '", end="") - for index in range(self.CHIP_BUFFER_HEADER_BYTE_COUNT): + for index in range(self._CHIP_BUFFER_HEADER_BYTE_COUNT): print("{:08b} ".format(self._buffer[index]), end="") print("' ", end="") def _debug_print_tlc59711_ch(self): print("ch: [", end="") for index in range( - self.CHIP_BUFFER_HEADER_BYTE_COUNT, len(self._buffer) + self._CHIP_BUFFER_HEADER_BYTE_COUNT, len(self._buffer) ): print("x{:02X}, ".format(self._buffer[index]), end="") print("]", end="") From 36c0b50bc4551e4a38b87748e59045497fc801f2 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 10 Feb 2020 14:09:46 +0100 Subject: [PATCH 46/91] remove unused and _debug_print_* --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 138 ++++--------------- 1 file changed, 29 insertions(+), 109 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index a3c8625..827bd50 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -150,33 +150,33 @@ class TLC59711Multi: _BUFFER_BYTES_PER_COLOR = const(2) _BUFFER_BYTES_PER_PIXEL = const(_BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL) - @staticmethod - def set_bit_with_mask(v, mask, x): - """Set bit with help of mask.""" - # clear - v &= ~mask - if x: - # set - v |= mask - return v - - @staticmethod - def set_bit(v, index, x): - """Set bit - return new value. - - Set the index:th bit of v to 1 if x is truthy, - else to 0, and return the new value. - https://stackoverflow.com/a/12174051/574981 - """ - # Compute mask, an integer with just bit 'index' set. - mask = 1 << index - # Clear the bit indicated by the mask (if x is False) - v &= ~mask - if x: - # If x was True, set the bit indicated by the mask. - v |= mask - # Return the result, we're done. - return v + # @staticmethod + # def set_bit_with_mask(v, mask, x): + # """Set bit with help of mask.""" + # # clear + # v &= ~mask + # if x: + # # set + # v |= mask + # return v + # + # @staticmethod + # def set_bit(v, index, x): + # """Set bit - return new value. + # + # Set the index:th bit of v to 1 if x is truthy, + # else to 0, and return the new value. + # https://stackoverflow.com/a/12174051/574981 + # """ + # # Compute mask, an integer with just bit 'index' set. + # mask = 1 << index + # # Clear the bit indicated by the mask (if x is False) + # v &= ~mask + # if x: + # # If x was True, set the bit indicated by the mask. + # v |= mask + # # Return the result, we're done. + # return v ########################################## # class _BC(): @@ -295,18 +295,6 @@ def set_chipheader_bits_in_buffer( value=0 ): """Set chip header bits in buffer.""" - # print( - # "chip_index={} " - # "part_bit_offset={} " - # "field={} " - # "value={} " - # "".format( - # chip_index, - # part_bit_offset, - # field, - # value - # ) - # ) offset = part_bit_offset + field["offset"] # restrict value value &= field["mask"] @@ -316,7 +304,6 @@ def set_chipheader_bits_in_buffer( header_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT # get chip header header = self._get_32bit_value_from_buffer(header_start) - # print("{:032b}".format(header)) # 0xFFFFFFFF == 0b11111111111111111111111111111111 # create/move mask mask = field["mask"] << offset @@ -341,7 +328,8 @@ def __init__(self, spi, pixel_count=1): # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data - self._buffer = bytearray(self._CHIP_BUFFER_BYTE_COUNT * self.chip_count) + self._buffer = bytearray( + self._CHIP_BUFFER_BYTE_COUNT * self.chip_count) # Initialize the brightness channel values to max # (these are 7-bit values). @@ -367,10 +355,8 @@ def __init__(self, spi, pixel_count=1): # preparation done # now initialize buffer to default values - # self._debug_print_buffer() print("init buffer..") self._init_buffer() - # self._debug_print_buffer() print("-> done") self._buffer_index_lookuptable = [] @@ -382,14 +368,10 @@ def _init_buffer(self): # buffer_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT # self._buffer[buffer_start] = 0x25 << 2 - # self._debug_print_buffer() self.chip_set_BCData( chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) - # self._debug_print_buffer() self._chip_set_FunctionControl(chip_index) - # self._debug_print_buffer() self._chip_set_WriteCommand(chip_index) - # self._debug_print_buffer() # loop end def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): @@ -499,7 +481,6 @@ def _init_lookuptable(self): def _write(self): # Write out the current state to the shift register. - # self._debug_print_buffer() try: # Lock the SPI bus and configure it for the shift register. while not self._spi.try_lock(): @@ -655,55 +636,6 @@ def calculate_BCData( ########################################## - def _debug_print_buffer(self): - indent = " " - if self.chip_count == 1: - print("buffer: [", end="") - indent = "" - else: - print("buffer: [") - for index in range(self.chip_count): - print("{}{}: ".format(indent, index), end="") - # print() - # self._debug_print_tlc59711_bin() - # print() - # self._debug_print_tlc59711_hex() - self._debug_print_tlc59711() - if self.chip_count > 1: - print() - print("]") - - def _debug_print_tlc59711_bin(self): - for index in range(len(self._buffer)): - print("{:08b}".format(self._buffer[index]), end="") - - def _debug_print_tlc59711_hex(self): - for index in range(len(self._buffer)): - print("x{:02X}, ".format(self._buffer[index]), end="") - - def _debug_print_tlc59711(self): - self._debug_print_tlc59711_header() - self._debug_print_tlc59711_ch() - - def _debug_print_tlc59711_header(self): - # print( - # "self._CHIP_BUFFER_HEADER_BYTE_COUNT", - # self._CHIP_BUFFER_HEADER_BYTE_COUNT) - print("header: '", end="") - for index in range(self._CHIP_BUFFER_HEADER_BYTE_COUNT): - print("{:08b} ".format(self._buffer[index]), end="") - print("' ", end="") - - def _debug_print_tlc59711_ch(self): - print("ch: [", end="") - for index in range( - self._CHIP_BUFFER_HEADER_BYTE_COUNT, len(self._buffer) - ): - print("x{:02X}, ".format(self._buffer[index]), end="") - print("]", end="") - - ########################################## - def _get_32bit_value_from_buffer(self, buffer_start): return ( (self._buffer[buffer_start + 0] << 24) | @@ -718,8 +650,6 @@ def _set_32bit_value_in_buffer(self, buffer_start, value): "value {} not in range: 0..0xFFFFFFFF" "".format(value) ) - # print("buffer_start", buffer_start, "value", value) - # self._debug_print_buffer() self._buffer[buffer_start + 0] = (value >> 24) & 0xFF self._buffer[buffer_start + 1] = (value >> 16) & 0xFF self._buffer[buffer_start + 2] = (value >> 8) & 0xFF @@ -737,8 +667,6 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): # "value {} not in range: 0..65535" # "".format(value) # ) - # print("buffer_start", buffer_start, "value", value) - # self._debug_print_buffer() self._buffer[buffer_start + 0] = (value >> 8) & 0xFF self._buffer[buffer_start + 1] = value & 0xFF @@ -931,13 +859,9 @@ def set_pixel(self, pixel_index, value): each int 0..65535 or float 0..1 """ if 0 <= pixel_index < self.pixel_count: - # print("value", value) # convert to list value = list(value) - # print("value", value) - # print("rep:") # repr(value) - # print("check length..") if len(value) != self.COLORS_PER_PIXEL: raise IndexError( "length of value {} does not match COLORS_PER_PIXEL (= {})" @@ -954,10 +878,7 @@ def set_pixel(self, pixel_index, value): # this modifies 'value' in place.. self._check_and_convert(value) - # print("value", value) - # update buffer - # print("pixel_index", pixel_index, "value", value) # we change channel order here: # buffer channel order is blue, green, red pixel_start = pixel_index * self.COLORS_PER_PIXEL @@ -1035,7 +956,6 @@ def set_channel(self, channel_index, value): channel_index += 2 elif pixel_index_offset == 2: channel_index -= 2 - # print("{:>2} → {:>2}".format(temp, channel_index)) self._set_16bit_value_in_buffer( self._buffer_index_lookuptable[channel_index], value From cfcb2176708a9c052a005ca902591247782198c7 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 10 Feb 2020 14:14:30 +0100 Subject: [PATCH 47/91] fix code-style (linebreaks) --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 31 ++++++-------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 827bd50..ab470b4 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -498,10 +498,7 @@ def show(self): ########################################## @staticmethod - def calculate_Ioclmax( - *, - Riref=2.48, - ): + def calculate_Ioclmax(*, Riref=2.48): """ Calculate Maximum Constant Sink Current Value. @@ -534,10 +531,7 @@ def calculate_Ioclmax( return Ioclmax @staticmethod - def calculate_Riref( - *, - Ioclmax=20, - ): + def calculate_Riref(*, Ioclmax=20): """ Calculate Maximum Constant Sink Current Value. @@ -597,41 +591,34 @@ def calculate_BCData( if not 2.0 <= Ioclmax <= 60.0: raise ValueError( "Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax) - ) + "".format(Ioclmax)) if not 0.0 <= IoutR <= Ioclmax: raise ValueError( "IoutR {} not in range: 2mA..{}mA" - "".format(IoutR, Ioclmax) - ) + "".format(IoutR, Ioclmax)) if not 0.0 <= IoutG <= Ioclmax: raise ValueError( "IoutG {} not in range: 2mA..{}mA" - "".format(IoutG, Ioclmax) - ) + "".format(IoutG, Ioclmax)) if not 0.0 <= IoutB <= Ioclmax: raise ValueError( "IoutB {} not in range: 2mA..{}mA" - "".format(IoutB, Ioclmax) - ) + "".format(IoutB, Ioclmax)) bcr = int((IoutR / Ioclmax) * 127) bcg = int((IoutG / Ioclmax) * 127) bcb = int((IoutB / Ioclmax) * 127) if not 0 <= bcr <= 127: raise ValueError( "bcr {} not in range: 0..127" - "".format(bcr) - ) + "".format(bcr)) if not 0 <= bcg <= 127: raise ValueError( "bcg {} not in range: 0..127" - "".format(bcg) - ) + "".format(bcg)) if not 0 <= bcb <= 127: raise ValueError( "bcb {} not in range: 0..127" - "".format(bcb) - ) + "".format(bcb)) return (bcr, bcg, bcb) ########################################## From 8869b005268ddeaf2db0ecccc5f9b59f9a9189cf Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 13 Feb 2020 18:19:28 +0100 Subject: [PATCH 48/91] tweak set&get 16 and 32bit buffer values --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 36 +++++++++----------- examples/tlc59711_multi_dev.py | 2 +- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index ab470b4..1b19f70 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -62,6 +62,7 @@ # pylint: disable=invalid-name from micropython import const +import struct class TLC59711Multi: @@ -352,9 +353,11 @@ def __init__(self, spi, pixel_count=1): self.dsprpt = True self.blank = False + self._buffer_32bit_format = struct.Struct('I') + self._buffer_16bit_format = struct.Struct('H') + # preparation done # now initialize buffer to default values - print("init buffer..") self._init_buffer() print("-> done") @@ -589,9 +592,8 @@ def calculate_BCData( # Iout / Ioclmax = BCX / 127 | * 127 # Iout / Ioclmax * 127 = BCX if not 2.0 <= Ioclmax <= 60.0: - raise ValueError( - "Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax)) + raise ValueError("Ioclmax {} not in range: 2mA..60mA" + "".format(Ioclmax)) if not 0.0 <= IoutR <= Ioclmax: raise ValueError( "IoutR {} not in range: 2mA..{}mA" @@ -624,12 +626,7 @@ def calculate_BCData( ########################################## def _get_32bit_value_from_buffer(self, buffer_start): - return ( - (self._buffer[buffer_start + 0] << 24) | - (self._buffer[buffer_start + 1] << 16) | - (self._buffer[buffer_start + 2] << 8) | - self._buffer[buffer_start + 3] - ) + return self._buffer_32bit_format.unpack(buffer_start) def _set_32bit_value_in_buffer(self, buffer_start, value): if not 0 <= value <= 0xFFFFFFFF: @@ -637,16 +634,15 @@ def _set_32bit_value_in_buffer(self, buffer_start, value): "value {} not in range: 0..0xFFFFFFFF" "".format(value) ) - self._buffer[buffer_start + 0] = (value >> 24) & 0xFF - self._buffer[buffer_start + 1] = (value >> 16) & 0xFF - self._buffer[buffer_start + 2] = (value >> 8) & 0xFF - self._buffer[buffer_start + 3] = value & 0xFF + self._buffer_32bit_format.pack_into( + buffer_start, + (value >> 24) & 0xFF, + (value >> 16) & 0xFF, + (value >> 8) & 0xFF, + value & 0xFF) def _get_16bit_value_from_buffer(self, buffer_start): - return ( - (self._buffer[buffer_start + 0] << 8) | - self._buffer[buffer_start + 1] - ) + return self._buffer_16bit_format.unpack(buffer_start) def _set_16bit_value_in_buffer(self, buffer_start, value): # if not 0 <= value <= 65535: @@ -654,8 +650,8 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): # "value {} not in range: 0..65535" # "".format(value) # ) - self._buffer[buffer_start + 0] = (value >> 8) & 0xFF - self._buffer[buffer_start + 1] = value & 0xFF + self._buffer_16bit_format.pack_into( + buffer_start, (value >> 8) & 0xFF, value & 0xFF) @staticmethod def _convert_01_float_to_16bit_integer(value): diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 30977e3..cab8c21 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -16,7 +16,7 @@ ########################################## -pixel_count = 16*8 +pixel_count = 16*1 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = TLC59711Multi(spi, pixel_count=pixel_count) From 03b11168e0b5a1765561f12d8b85ff83e5c38122 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 24 Feb 2020 21:09:13 +0100 Subject: [PATCH 49/91] fix things.. --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 58 ++++++++++---------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 1b19f70..5c2873a 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -302,14 +302,14 @@ def set_chipheader_bits_in_buffer( # move value to position value = value << offset # calculate header start - header_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT + header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT # get chip header header = self._get_32bit_value_from_buffer(header_start) # 0xFFFFFFFF == 0b11111111111111111111111111111111 # create/move mask mask = field["mask"] << offset # clear - header &= ~mask + header &= (~mask) # set header |= value # write header back @@ -330,7 +330,7 @@ def __init__(self, spi, pixel_count=1): # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data self._buffer = bytearray( - self._CHIP_BUFFER_BYTE_COUNT * self.chip_count) + _CHIP_BUFFER_BYTE_COUNT * self.chip_count) # Initialize the brightness channel values to max # (these are 7-bit values). @@ -353,8 +353,8 @@ def __init__(self, spi, pixel_count=1): self.dsprpt = True self.blank = False - self._buffer_32bit_format = struct.Struct('I') - self._buffer_16bit_format = struct.Struct('H') + # self._buffer_32bit_format = struct.Struct('I') + # self._buffer_16bit_format = struct.Struct('H') # preparation done # now initialize buffer to default values @@ -368,7 +368,7 @@ def __init__(self, spi, pixel_count=1): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - # buffer_start = chip_index * self._CHIP_BUFFER_BYTE_COUNT + # buffer_start = chip_index * _CHIP_BUFFER_BYTE_COUNT # self._buffer[buffer_start] = 0x25 << 2 self.chip_set_BCData( @@ -389,17 +389,17 @@ def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): # set all bits self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCR"], value=bcr) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCG"], value=bcg) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._BC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCB"], value=bcb) @@ -425,27 +425,27 @@ def _chip_set_FunctionControl(self, chip_index): # set all bits self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["OUTTMG"], value=self.outtmg) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["EXTGCK"], value=self.extgck) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["TMGRST"], value=self.tmgrst) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["DSPRPT"], value=self.dsprpt) self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._FC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["BLANK"], value=self.blank) @@ -465,19 +465,19 @@ def _chip_set_WriteCommand(self, chip_index): # set all bits self.set_chipheader_bits_in_buffer( chip_index=chip_index, - part_bit_offset=self._WC_CHIP_BUFFER_BIT_OFFSET, + part_bit_offset=_WC_CHIP_BUFFER_BIT_OFFSET, field=self._WC_FIELDS["WRITE_COMMAND"], value=self.WRITE_COMMAND) def _init_lookuptable(self): for channel_index in range(self.channel_count): buffer_index = ( - (self._CHIP_BUFFER_BYTE_COUNT // self._BUFFER_BYTES_PER_COLOR) + (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) * (channel_index // self.CHANNEL_PER_CHIP) + channel_index % self.CHANNEL_PER_CHIP ) - buffer_index *= self._BUFFER_BYTES_PER_COLOR - buffer_index += self._CHIP_BUFFER_HEADER_BYTE_COUNT + buffer_index *= _BUFFER_BYTES_PER_COLOR + buffer_index += _CHIP_BUFFER_HEADER_BYTE_COUNT self._buffer_index_lookuptable.append(buffer_index) ########################################## @@ -626,7 +626,9 @@ def calculate_BCData( ########################################## def _get_32bit_value_from_buffer(self, buffer_start): - return self._buffer_32bit_format.unpack(buffer_start) + # return self._buffer_32bit_format.unpack_from( + # self._buffer, buffer_start) + return struct.unpack_from('I', self._buffer, buffer_start)[0] def _set_32bit_value_in_buffer(self, buffer_start, value): if not 0 <= value <= 0xFFFFFFFF: @@ -634,15 +636,13 @@ def _set_32bit_value_in_buffer(self, buffer_start, value): "value {} not in range: 0..0xFFFFFFFF" "".format(value) ) - self._buffer_32bit_format.pack_into( - buffer_start, - (value >> 24) & 0xFF, - (value >> 16) & 0xFF, - (value >> 8) & 0xFF, - value & 0xFF) + # self._buffer_32bit_format.pack_into( + struct.pack_into('I', self._buffer, buffer_start, value) def _get_16bit_value_from_buffer(self, buffer_start): - return self._buffer_16bit_format.unpack(buffer_start) + # return self._buffer_16bit_format.unpack_from( + # self._buffer, buffer_start)[0] + return struct.unpack_from('H', self._buffer, buffer_start)[0] def _set_16bit_value_in_buffer(self, buffer_start, value): # if not 0 <= value <= 65535: @@ -650,8 +650,10 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): # "value {} not in range: 0..65535" # "".format(value) # ) - self._buffer_16bit_format.pack_into( - buffer_start, (value >> 8) & 0xFF, value & 0xFF) + struct.pack_into('H', self._buffer, buffer_start, value) + # self._buffer_16bit_format.pack_into(self._buffer, buffer_start,value) + # self._buffer_16bit_format.pack_into( + # self._buffer, buffer_start, (value >> 8) & 0xFF, value & 0xFF) @staticmethod def _convert_01_float_to_16bit_integer(value): From 743e0c653a12f18549780ab1dcd79a21353292ff Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 24 Feb 2020 23:03:55 +0100 Subject: [PATCH 50/91] more struct experiments and fixes --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 34 ++++++++++++++------ examples/tlc59711_multi_dev.py | 4 +-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 5c2873a..8b2cf22 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -626,9 +626,15 @@ def calculate_BCData( ########################################## def _get_32bit_value_from_buffer(self, buffer_start): + # return ( + # (self._buffer[buffer_start + 0] << 24) | + # (self._buffer[buffer_start + 1] << 16) | + # (self._buffer[buffer_start + 2] << 8) | + # self._buffer[buffer_start + 3] + # ) # return self._buffer_32bit_format.unpack_from( # self._buffer, buffer_start) - return struct.unpack_from('I', self._buffer, buffer_start)[0] + return struct.unpack_from('>I', self._buffer, buffer_start)[0] def _set_32bit_value_in_buffer(self, buffer_start, value): if not 0 <= value <= 0xFFFFFFFF: @@ -636,24 +642,34 @@ def _set_32bit_value_in_buffer(self, buffer_start, value): "value {} not in range: 0..0xFFFFFFFF" "".format(value) ) + # self._buffer[buffer_start + 0] = (value >> 24) & 0xFF + # self._buffer[buffer_start + 1] = (value >> 16) & 0xFF + # self._buffer[buffer_start + 2] = (value >> 8) & 0xFF + # self._buffer[buffer_start + 3] = value & 0xFF # self._buffer_32bit_format.pack_into( - struct.pack_into('I', self._buffer, buffer_start, value) + struct.pack_into('>I', self._buffer, buffer_start, value) def _get_16bit_value_from_buffer(self, buffer_start): + # return ( + # (self._buffer[buffer_start + 0] << 8) | + # self._buffer[buffer_start + 1] + # ) # return self._buffer_16bit_format.unpack_from( # self._buffer, buffer_start)[0] - return struct.unpack_from('H', self._buffer, buffer_start)[0] + return struct.unpack_from('>H', self._buffer, buffer_start)[0] def _set_16bit_value_in_buffer(self, buffer_start, value): - # if not 0 <= value <= 65535: - # raise ValueError( - # "value {} not in range: 0..65535" - # "".format(value) - # ) - struct.pack_into('H', self._buffer, buffer_start, value) + if not 0 <= value <= 65535: + raise ValueError( + "value {} not in range: 0..65535" + "".format(value) + ) + # self._buffer[buffer_start + 0] = (value >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value & 0xFF # self._buffer_16bit_format.pack_into(self._buffer, buffer_start,value) # self._buffer_16bit_format.pack_into( # self._buffer, buffer_start, (value >> 8) & 0xFF, value & 0xFF) + struct.pack_into('>H', self._buffer, buffer_start, value) @staticmethod def _convert_01_float_to_16bit_integer(value): diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index cab8c21..aa58a62 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -55,7 +55,7 @@ def channelcheck_update_pixel(offset): def channelcheck_update(offset): """Channel check.""" - # print("offset", offset) + print("offset", offset) pixels.set_channel(offset, value_high) # clear last set channel @@ -416,7 +416,7 @@ def _test(): print("[", end="") for i in range(pixel_count): print("{}:{}, ".format(i, pixels[i]), end="") - print("]", end="") + print("]") time_measurement_call( "'print('{}:{}, '.format(i, pixels[i]), end='')'", _test, From 50553bd4a2800ce291596650ccce9076bb7692b7 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 13:57:58 +0100 Subject: [PATCH 51/91] linting and code cleanup --- .pylintrc | 4 +- adafruit_tlc59711/adafruit_tlc59711_multi.py | 195 +++++++------------ 2 files changed, 74 insertions(+), 125 deletions(-) diff --git a/.pylintrc b/.pylintrc index 039eaec..107d662 100644 --- a/.pylintrc +++ b/.pylintrc @@ -175,7 +175,9 @@ missing-member-max-choices=1 # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. -additional-builtins= +# this fixes the E0602: Undefined variable error for the micropython const defined values. +additional-builtins=_CHIP_BUFFER_BYTE_COUNT, _BC_CHIP_BUFFER_BIT_OFFSET, _FC_CHIP_BUFFER_BIT_OFFSET, _WC_CHIP_BUFFER_BIT_OFFSET, _BUFFER_BYTES_PER_COLOR, _CHIP_BUFFER_HEADER_BYTE_COUNT + # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 8b2cf22..0bd8014 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -61,15 +61,16 @@ # refers to them as. # pylint: disable=invalid-name -from micropython import const import struct +from micropython import const + class TLC59711Multi: """Multi TLC59711 16-bit 12 channel LED PWM driver. This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. - The class has an interface compatible with the FancyLED. + The class has an interface compatible with the FancyLED library. and with this is similar to the NeoPixel and DotStar Interfaces. :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. @@ -77,9 +78,12 @@ class TLC59711Multi: Maximal data clock frequence is: - TLC59711: 10MHz - TLC5971: 20MHz - :param bool pixel_count: Number of RGB-LEDs (=Pixels) are connected. + :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. """ + # pylint: disable=too-many-instance-attributes + # it just does make senes to have the chip params as attributes. + # """ # TLC5971 data / register structure # @@ -287,36 +291,6 @@ class TLC59711Multi: ########################################## - def set_chipheader_bits_in_buffer( - self, - *, - chip_index=0, - part_bit_offset=0, - field={"mask": 0, "length": 0, "offset": 0}, - value=0 - ): - """Set chip header bits in buffer.""" - offset = part_bit_offset + field["offset"] - # restrict value - value &= field["mask"] - # move value to position - value = value << offset - # calculate header start - header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT - # get chip header - header = self._get_32bit_value_from_buffer(header_start) - # 0xFFFFFFFF == 0b11111111111111111111111111111111 - # create/move mask - mask = field["mask"] << offset - # clear - header &= (~mask) - # set - header |= value - # write header back - self._set_32bit_value_in_buffer(header_start, header) - - ########################################## - def __init__(self, spi, pixel_count=1): """Init.""" self._spi = spi @@ -329,8 +303,7 @@ def __init__(self, spi, pixel_count=1): # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! # create raw output data - self._buffer = bytearray( - _CHIP_BUFFER_BYTE_COUNT * self.chip_count) + self._buffer = bytearray(_CHIP_BUFFER_BYTE_COUNT * self.chip_count) # Initialize the brightness channel values to max # (these are 7-bit values). @@ -353,14 +326,12 @@ def __init__(self, spi, pixel_count=1): self.dsprpt = True self.blank = False - # self._buffer_32bit_format = struct.Struct('I') - # self._buffer_16bit_format = struct.Struct('H') + # self._buf32_format = struct.Struct('>I') + # self._buf16_format = struct.Struct('>H') # preparation done # now initialize buffer to default values - print("init buffer..") self._init_buffer() - print("-> done") self._buffer_index_lookuptable = [] self._init_lookuptable() @@ -368,15 +339,42 @@ def __init__(self, spi, pixel_count=1): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - # buffer_start = chip_index * _CHIP_BUFFER_BYTE_COUNT - # self._buffer[buffer_start] = 0x25 << 2 - self.chip_set_BCData( chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) self._chip_set_FunctionControl(chip_index) self._chip_set_WriteCommand(chip_index) # loop end + def set_chipheader_bits_in_buffer( + self, + *, + chip_index=0, + part_bit_offset=0, + field={"mask": 0, "length": 0, "offset": 0}, + value=0 + ): + """Set chip header bits in buffer.""" + offset = part_bit_offset + field["offset"] + # restrict value + value &= field["mask"] + # move value to position + value = value << offset + # calculate header start + header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT + # get chip header + header = self._get_32bit_value_from_buffer(header_start) + # 0xFFFFFFFF == 0b11111111111111111111111111111111 + # create/move mask + mask = field["mask"] << offset + # clear + header &= (~mask) + # set + header |= value + # write header back + self._set_32bit_value_in_buffer(header_start, header) + + ########################################## + def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): """ Set BC-Data. @@ -474,8 +472,7 @@ def _init_lookuptable(self): buffer_index = ( (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) * (channel_index // self.CHANNEL_PER_CHIP) - + channel_index % self.CHANNEL_PER_CHIP - ) + + channel_index % self.CHANNEL_PER_CHIP) buffer_index *= _BUFFER_BYTES_PER_COLOR buffer_index += _CHIP_BUFFER_HEADER_BYTE_COUNT self._buffer_index_lookuptable.append(buffer_index) @@ -521,16 +518,12 @@ def calculate_Ioclmax(*, Riref=2.48): # (41 / Riref) * Viref = Ioclmax if not 0.8 <= Riref <= 24.8: raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ" - "".format(Riref) - ) + "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) Viref = 1.21 Ioclmax = (41 / Riref) * Viref if not 2.0 <= Ioclmax <= 60.0: raise ValueError( - "Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax) - ) + "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) return Ioclmax @staticmethod @@ -549,26 +542,16 @@ def calculate_Riref(*, Ioclmax=20): """ if not 2.0 <= Ioclmax <= 60.0: raise ValueError( - "Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax) - ) + "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) Viref = 1.21 Riref = (Viref / Ioclmax) * 41 if not 0.8 <= Riref <= 24.8: raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ" - "".format(Riref) - ) + "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) return Riref @staticmethod - def calculate_BCData( - *, - Ioclmax=18, - IoutR=17, - IoutG=15, - IoutB=9 - ): + def calculate_BCData(*, Ioclmax=18, IoutR=17, IoutG=15, IoutB=9): """ Calculate Global Brightness Control Values. @@ -596,31 +579,22 @@ def calculate_BCData( "".format(Ioclmax)) if not 0.0 <= IoutR <= Ioclmax: raise ValueError( - "IoutR {} not in range: 2mA..{}mA" - "".format(IoutR, Ioclmax)) + "IoutR {} not in range: 2mA..{}mA".format(IoutR, Ioclmax)) if not 0.0 <= IoutG <= Ioclmax: raise ValueError( - "IoutG {} not in range: 2mA..{}mA" - "".format(IoutG, Ioclmax)) + "IoutG {} not in range: 2mA..{}mA".format(IoutG, Ioclmax)) if not 0.0 <= IoutB <= Ioclmax: raise ValueError( - "IoutB {} not in range: 2mA..{}mA" - "".format(IoutB, Ioclmax)) + "IoutB {} not in range: 2mA..{}mA".format(IoutB, Ioclmax)) bcr = int((IoutR / Ioclmax) * 127) bcg = int((IoutG / Ioclmax) * 127) bcb = int((IoutB / Ioclmax) * 127) if not 0 <= bcr <= 127: - raise ValueError( - "bcr {} not in range: 0..127" - "".format(bcr)) + raise ValueError("bcr {} not in range: 0..127".format(bcr)) if not 0 <= bcg <= 127: - raise ValueError( - "bcg {} not in range: 0..127" - "".format(bcg)) + raise ValueError("bcg {} not in range: 0..127".format(bcg)) if not 0 <= bcb <= 127: - raise ValueError( - "bcb {} not in range: 0..127" - "".format(bcb)) + raise ValueError("bcb {} not in range: 0..127".format(bcb)) return (bcr, bcg, bcb) ########################################## @@ -632,21 +606,19 @@ def _get_32bit_value_from_buffer(self, buffer_start): # (self._buffer[buffer_start + 2] << 8) | # self._buffer[buffer_start + 3] # ) - # return self._buffer_32bit_format.unpack_from( + # return self._buf32_format.unpack_from( # self._buffer, buffer_start) return struct.unpack_from('>I', self._buffer, buffer_start)[0] def _set_32bit_value_in_buffer(self, buffer_start, value): if not 0 <= value <= 0xFFFFFFFF: raise ValueError( - "value {} not in range: 0..0xFFFFFFFF" - "".format(value) - ) + "value {} not in range: 0..0xFFFFFFFF".format(value)) # self._buffer[buffer_start + 0] = (value >> 24) & 0xFF # self._buffer[buffer_start + 1] = (value >> 16) & 0xFF # self._buffer[buffer_start + 2] = (value >> 8) & 0xFF # self._buffer[buffer_start + 3] = value & 0xFF - # self._buffer_32bit_format.pack_into( + # self._buf32_format.pack_into( struct.pack_into('>I', self._buffer, buffer_start, value) def _get_16bit_value_from_buffer(self, buffer_start): @@ -654,7 +626,7 @@ def _get_16bit_value_from_buffer(self, buffer_start): # (self._buffer[buffer_start + 0] << 8) | # self._buffer[buffer_start + 1] # ) - # return self._buffer_16bit_format.unpack_from( + # return self._buf16_format.unpack_from( # self._buffer, buffer_start)[0] return struct.unpack_from('>H', self._buffer, buffer_start)[0] @@ -666,9 +638,7 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): ) # self._buffer[buffer_start + 0] = (value >> 8) & 0xFF # self._buffer[buffer_start + 1] = value & 0xFF - # self._buffer_16bit_format.pack_into(self._buffer, buffer_start,value) - # self._buffer_16bit_format.pack_into( - # self._buffer, buffer_start, (value >> 8) & 0xFF, value & 0xFF) + # self._buf16_format.pack_into(self._buffer, buffer_start,value) struct.pack_into('>H', self._buffer, buffer_start, value) @staticmethod @@ -676,10 +646,7 @@ def _convert_01_float_to_16bit_integer(value): """Convert 0..1 Float Value to 16bit (0..65535) Range.""" # check if value is in range if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1" - "".format(value[0]) - ) + raise ValueError("value[0] {} not in range: 0..1".format(value[0])) # convert to 16bit value return int(value * 65535) @@ -697,43 +664,31 @@ def _check_and_convert(value): # check if value is in range if not 0.0 <= value[0] <= 1.0: raise ValueError( - "value[0] {} not in range: 0..1" - "".format(value[0]) - ) + "value[0] {} not in range: 0..1".format(value[0])) # convert to 16bit value value[0] = int(value[0] * 65535) else: if not 0 <= value[0] <= 65535: raise ValueError( - "value[0] {} not in range: 0..65535" - "".format(value[0]) - ) + "value[0] {} not in range: 0..65535".format(value[0])) if isinstance(value[1], float): if not 0.0 <= value[1] <= 1.0: raise ValueError( - "value[1] {} not in range: 0..1" - "".format(value[1]) - ) + "value[1] {} not in range: 0..1".format(value[1])) value[1] = int(value[1] * 65535) else: if not 0 <= value[1] <= 65535: raise ValueError( - "value[1] {} not in range: 0..65535" - "".format(value[1]) - ) + "value[1] {} not in range: 0..65535".format(value[1])) if isinstance(value[2], float): if not 0.0 <= value[2] <= 1.0: raise ValueError( - "value[2] {} not in range: 0..1" - "".format(value[2]) - ) + "value[2] {} not in range: 0..1".format(value[2])) value[2] = int(value[2] * 65535) else: if not 0 <= value[2] <= 65535: raise ValueError( - "value[2] {} not in range: 0..65535" - "".format(value[2]) - ) + "value[2] {} not in range: 0..65535".format(value[2])) ########################################## @@ -905,8 +860,7 @@ def set_pixel(self, pixel_index, value): else: raise IndexError( "index {} out of range [0..{}]" - "".format(pixel_index, self.pixel_count) - ) + "".format(pixel_index, self.pixel_count)) def set_pixel_all_16bit_value(self, value_r, value_g, value_b): """ @@ -946,9 +900,7 @@ def set_channel(self, channel_index, value): if 0 <= channel_index < (self.channel_count): # check if values are in range if not 0 <= value <= 65535: - raise ValueError( - "value {} not in range: 0..65535" - ) + raise ValueError("value {} not in range: 0..65535") # temp = channel_index # we change channel order here: # buffer channel order is blue, green, red @@ -963,11 +915,8 @@ def set_channel(self, channel_index, value): ) else: raise IndexError( - "channel_index {} out of range (0..{})".format( - channel_index, - self.channel_count - ) - ) + "channel_index {} out of range (0..{})" + .format(channel_index, self.channel_count)) # Define index and length properties to set and get each channel as # atomic RGB tuples. This provides a similar feel as using neopixels. @@ -988,11 +937,9 @@ def __getitem__(self, key): self._get_channel_16bit_value(pixel_start + 1), self._get_channel_16bit_value(pixel_start + 2) ) - else: - raise IndexError( - "index {} out of range [0..{}]" - "".format(key, self.pixel_count) - ) + # else: + raise IndexError( + "index {} out of range [0..{}]".format(key, self.pixel_count)) def __setitem__(self, key, value): """ From cc7b006a82f5638762c5ef98dc534634a3bcef63 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 14:33:58 +0100 Subject: [PATCH 52/91] more linting and cleanup --- .pylintrc | 3 ++- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 107d662..c9855fa 100644 --- a/.pylintrc +++ b/.pylintrc @@ -175,8 +175,9 @@ missing-member-max-choices=1 # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. -# this fixes the E0602: Undefined variable error for the micropython const defined values. additional-builtins=_CHIP_BUFFER_BYTE_COUNT, _BC_CHIP_BUFFER_BIT_OFFSET, _FC_CHIP_BUFFER_BIT_OFFSET, _WC_CHIP_BUFFER_BIT_OFFSET, _BUFFER_BYTES_PER_COLOR, _CHIP_BUFFER_HEADER_BYTE_COUNT +# ugly workaround for pylint not knowing of micropython const thing: +# this fixes the E0602: Undefined variable error. # Tells whether unused global variables should be treated as a violation. diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 0bd8014..bf0cb8a 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -146,6 +146,8 @@ class TLC59711Multi: # helper ########################################## + # pylama:ignore=E0602 + # ugly workaround for pylama not knowing of micropython const thing _CHIP_BUFFER_BYTE_COUNT = const(28) COLORS_PER_PIXEL = const(3) From 010fa27d0436e12273d1f1e37c837572f796abdc Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 15:59:14 +0100 Subject: [PATCH 53/91] more cleanup --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 99 +++++++++----------- examples/tlc59711_multi_dev.py | 9 +- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index bf0cb8a..b134d86 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -719,14 +719,17 @@ def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): """ pixel_start = pixel_index * self.COLORS_PER_PIXEL buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_b & 0xFF + # self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_b & 0xFF + struct.pack_into('>H', self._buffer, buffer_start, value_b) buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_g & 0xFF + # self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_g & 0xFF + struct.pack_into('>H', self._buffer, buffer_start, value_g) buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_r & 0xFF + # self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value_r & 0xFF + struct.pack_into('>H', self._buffer, buffer_start, value_r) def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): """ @@ -740,19 +743,12 @@ def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): :param int value_g: 0..1 :param int value_b: 0..1 """ - value_r = int(value_r * 65535) - value_g = int(value_g * 65535) - value_b = int(value_b * 65535) - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_b & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_g & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_r & 0xFF + self.set_pixel_16bit_value( + pixel_index, + int(value_r * 65535), + int(value_g * 65535), + int(value_b * 65535) + ) def set_pixel_16bit_color(self, pixel_index, color): """ @@ -765,16 +761,12 @@ def set_pixel_16bit_color(self, pixel_index, color): :param int pixel_index: 0..(pixel_count) :param int color: 3-tuple of R, G, B; 0..65535 """ - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[2] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[1] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[0] & 0xFF + self.set_pixel_16bit_value( + pixel_index, + color[0], + color[1], + color[2] + ) def set_pixel_float_color(self, pixel_index, color): """ @@ -787,22 +779,12 @@ def set_pixel_float_color(self, pixel_index, color): :param int pixel_index: 0..(pixel_count) :param tuple/float color: 3-tuple of R, G, B; 0..1 """ - # convert to 16bit int - value_r = int(color[0] * 65535) - value_g = int(color[1] * 65535) - value_b = int(color[2] * 65535) - # calculate pixel_start - pixel_start = pixel_index * self.COLORS_PER_PIXEL - # set values - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_b & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_g & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_r & 0xFF + self.set_pixel_16bit_value( + pixel_index, + int(color[0] * 65535), + int(color[1] * 65535), + int(color[2] * 65535) + ) def set_pixel(self, pixel_index, value): """ @@ -839,7 +821,7 @@ def set_pixel(self, pixel_index, value): # update buffer # we change channel order here: # buffer channel order is blue, green, red - pixel_start = pixel_index * self.COLORS_PER_PIXEL + # pixel_start = pixel_index * self.COLORS_PER_PIXEL # self._set_channel_16bit_value( # pixel_start + 0, # value[2]) @@ -850,15 +832,22 @@ def set_pixel(self, pixel_index, value): # pixel_start + 2, # value[0]) # optimize2 - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[2] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[1] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[0] & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + # self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[2] & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + # self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[1] & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + # self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[0] & 0xFF + # simpliefy code + self.set_pixel_16bit_value( + pixel_index, + value[0], + value[1], + value[2] + ) else: raise IndexError( "index {} out of range [0..{}]" diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index aa58a62..e89c678 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -16,7 +16,7 @@ ########################################## -pixel_count = 16*1 +pixel_count = 16*9 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = TLC59711Multi(spi, pixel_count=pixel_count) @@ -55,7 +55,7 @@ def channelcheck_update_pixel(offset): def channelcheck_update(offset): """Channel check.""" - print("offset", offset) + # print("offset", offset) pixels.set_channel(offset, value_high) # clear last set channel @@ -68,6 +68,7 @@ def channelcheck_update(offset): offset += 1 if offset >= pixels.channel_count: offset = 0 + print("offset overflow. start from 0") return offset @@ -167,7 +168,7 @@ def _test(): for i in range(pixel_count): pixels[i] = (500, 40500, 1000) time_measurement_call( - "'pixels[for 0..{}] = (500, 40500, 1000)'".format(pixel_count), + "'pixels[0..{}] = (500, 40500, 1000)'".format(pixel_count), _test, loop_count ) @@ -176,7 +177,7 @@ def _test(): for i in range(pixel_count): pixels[i] = (0.1, 0.5, 0.9) time_measurement_call( - "'pixels[for 0..{}] = (0.1, 0.5, 0.9)'".format(pixel_count), + "'pixels[0..{}] = (0.1, 0.5, 0.9)'".format(pixel_count), _test, loop_count ) From 0dee8f89ada7b25932a6fa70b7f9f8037fac255c Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 20:46:55 +0100 Subject: [PATCH 54/91] rewrite discreet steps as loop --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 44 ++++++-------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index b134d86..81c07f8 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -660,37 +660,19 @@ def _convert_if_float(cls, value): return value @staticmethod - def _check_and_convert(value): - # check if we have float values - if isinstance(value[0], float): - # check if value is in range - if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1".format(value[0])) - # convert to 16bit value - value[0] = int(value[0] * 65535) - else: - if not 0 <= value[0] <= 65535: - raise ValueError( - "value[0] {} not in range: 0..65535".format(value[0])) - if isinstance(value[1], float): - if not 0.0 <= value[1] <= 1.0: - raise ValueError( - "value[1] {} not in range: 0..1".format(value[1])) - value[1] = int(value[1] * 65535) - else: - if not 0 <= value[1] <= 65535: - raise ValueError( - "value[1] {} not in range: 0..65535".format(value[1])) - if isinstance(value[2], float): - if not 0.0 <= value[2] <= 1.0: - raise ValueError( - "value[2] {} not in range: 0..1".format(value[2])) - value[2] = int(value[2] * 65535) - else: - if not 0 <= value[2] <= 65535: - raise ValueError( - "value[2] {} not in range: 0..65535".format(value[2])) + def _check_and_convert(values): + error_message = "values[{}] {} not in range: 0..{}" + for i, value in enumerate(values): + # check if we have float values + if isinstance(value, float): + # check if value is in range + if not 0.0 <= value <= 1.0: + raise ValueError(error_message.format(i, value, '1')) + # convert to 16bit value + values[i] = int(value * 65535) + else: + if not 0 <= value[0] <= 65535: + raise ValueError(error_message.format(i, value, '65535')) ########################################## From efde043c4b4a5f02e6a3e4492dad1050530510fc Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 21:18:26 +0100 Subject: [PATCH 55/91] more cleanup & tests --- .gitignore | 1 + adafruit_tlc59711/adafruit_tlc59711_multi.py | 76 ++++++++++---------- examples/tlc59711_multi_dev.py | 2 +- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index 45fa8a3..4b8bb20 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ bundles .eggs dist **/*.egg-info +temp/ diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 81c07f8..ecd192f 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -638,10 +638,10 @@ def _set_16bit_value_in_buffer(self, buffer_start, value): "value {} not in range: 0..65535" "".format(value) ) - # self._buffer[buffer_start + 0] = (value >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value & 0xFF + self._buffer[buffer_start + 0] = (value >> 8) & 0xFF + self._buffer[buffer_start + 1] = value & 0xFF # self._buf16_format.pack_into(self._buffer, buffer_start,value) - struct.pack_into('>H', self._buffer, buffer_start, value) + # struct.pack_into('>H', self._buffer, buffer_start, value) @staticmethod def _convert_01_float_to_16bit_integer(value): @@ -660,19 +660,37 @@ def _convert_if_float(cls, value): return value @staticmethod - def _check_and_convert(values): - error_message = "values[{}] {} not in range: 0..{}" - for i, value in enumerate(values): - # check if we have float values - if isinstance(value, float): - # check if value is in range - if not 0.0 <= value <= 1.0: - raise ValueError(error_message.format(i, value, '1')) - # convert to 16bit value - values[i] = int(value * 65535) - else: - if not 0 <= value[0] <= 65535: - raise ValueError(error_message.format(i, value, '65535')) + def _check_and_convert(value): + # check if we have float values + if isinstance(value[0], float): + # check if value is in range + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1".format(value[0])) + # convert to 16bit value + value[0] = int(value[0] * 65535) + else: + if not 0 <= value[0] <= 65535: + raise ValueError( + "value[0] {} not in range: 0..65535".format(value[0])) + if isinstance(value[1], float): + if not 0.0 <= value[1] <= 1.0: + raise ValueError( + "value[1] {} not in range: 0..1".format(value[1])) + value[1] = int(value[1] * 65535) + else: + if not 0 <= value[1] <= 65535: + raise ValueError( + "value[1] {} not in range: 0..65535".format(value[1])) + if isinstance(value[2], float): + if not 0.0 <= value[2] <= 1.0: + raise ValueError( + "value[2] {} not in range: 0..1".format(value[2])) + value[2] = int(value[2] * 65535) + else: + if not 0 <= value[2] <= 65535: + raise ValueError( + "value[2] {} not in range: 0..65535".format(value[2])) ########################################## @@ -825,11 +843,7 @@ def set_pixel(self, pixel_index, value): # self._buffer[buffer_start + 1] = value[0] & 0xFF # simpliefy code self.set_pixel_16bit_value( - pixel_index, - value[0], - value[1], - value[2] - ) + pixel_index, value[0], value[1], value[2]) else: raise IndexError( "index {} out of range [0..{}]" @@ -929,31 +943,15 @@ def __setitem__(self, key, value): # for a more detailed version with all the debugging code and # comments look at set_pixel if 0 <= key < self.pixel_count: - # convert to list value = list(value) - if len(value) != self.COLORS_PER_PIXEL: raise IndexError( "length of value {} does not match COLORS_PER_PIXEL (= {})" "".format(len(value), self.COLORS_PER_PIXEL) ) - - # this modifies value in place.. + # _check_and_convert modifies value in place.. self._check_and_convert(value) - - # update buffer - # we change channel order here: - # buffer channel order is blue, green, red - pixel_start = key * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[2] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[1] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = value[0] & 0xFF + self.set_pixel_16bit_value(key, value[0], value[1], value[2]) else: raise IndexError( "index {} out of range [0..{}]" diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index e89c678..5f6979f 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -99,7 +99,7 @@ def time_measurement_call(message, test_function, loop_count=1000): # ) # "{:>8.2f}ms".format(3.56) print( - "{call_duration:>8.2f}ms\t{message}" + "{call_duration:>10.4f}ms\t{message}" "".format( call_duration=(duration / loop_count) * 1000, message=message, From 33bd8334f12f6545ebc21de8e275ee43d84e3b82 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 21:38:06 +0100 Subject: [PATCH 56/91] cleanup set_channel --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 38 +++----------------- examples/tlc59711_multi_dev.py | 6 ++-- 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index ecd192f..7ce6607 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -623,26 +623,6 @@ def _set_32bit_value_in_buffer(self, buffer_start, value): # self._buf32_format.pack_into( struct.pack_into('>I', self._buffer, buffer_start, value) - def _get_16bit_value_from_buffer(self, buffer_start): - # return ( - # (self._buffer[buffer_start + 0] << 8) | - # self._buffer[buffer_start + 1] - # ) - # return self._buf16_format.unpack_from( - # self._buffer, buffer_start)[0] - return struct.unpack_from('>H', self._buffer, buffer_start)[0] - - def _set_16bit_value_in_buffer(self, buffer_start, value): - if not 0 <= value <= 65535: - raise ValueError( - "value {} not in range: 0..65535" - "".format(value) - ) - self._buffer[buffer_start + 0] = (value >> 8) & 0xFF - self._buffer[buffer_start + 1] = value & 0xFF - # self._buf16_format.pack_into(self._buffer, buffer_start,value) - # struct.pack_into('>H', self._buffer, buffer_start, value) - @staticmethod def _convert_01_float_to_16bit_integer(value): """Convert 0..1 Float Value to 16bit (0..65535) Range.""" @@ -695,15 +675,8 @@ def _check_and_convert(value): ########################################## def _get_channel_16bit_value(self, channel_index): - return self._get_16bit_value_from_buffer( - self._buffer_index_lookuptable[channel_index], - ) - - def _set_channel_16bit_value(self, channel_index, value): - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[channel_index], - value - ) + buffer_start = self._buffer_index_lookuptable[channel_index] + return struct.unpack_from('>H', self._buffer, buffer_start)[0] def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): """ @@ -896,10 +869,9 @@ def set_channel(self, channel_index, value): channel_index += 2 elif pixel_index_offset == 2: channel_index -= 2 - self._set_16bit_value_in_buffer( - self._buffer_index_lookuptable[channel_index], - value - ) + # set value in buffer + buffer_start = self._buffer_index_lookuptable[channel_index] + struct.pack_into('>H', self._buffer, buffer_start, value) else: raise IndexError( "channel_index {} out of range (0..{})" diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 5f6979f..6a2d432 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -361,12 +361,14 @@ def _test(): loop_count ) + channel_count = pixel_count * 3 + def _test(): - for i in range(pixel_count * 3): + for i in range(channel_count): pixels.set_channel(i, 500) time_measurement_call( "'set_channel(for 0..{}, 10000)'" - "".format(pixel_count * 3), + "".format(channel_count), _test, 10 ) From b40ddd035c1de305727cab9a0c330b4f86efe5ef Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 21:44:05 +0100 Subject: [PATCH 57/91] cleanup unneeded helper functions --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 40 ++++++++------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index 7ce6607..a4dc5e7 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -364,7 +364,7 @@ def set_chipheader_bits_in_buffer( # calculate header start header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT # get chip header - header = self._get_32bit_value_from_buffer(header_start) + header = struct.unpack_from('>I', self._buffer, header_start)[0] # 0xFFFFFFFF == 0b11111111111111111111111111111111 # create/move mask mask = field["mask"] << offset @@ -373,7 +373,7 @@ def set_chipheader_bits_in_buffer( # set header |= value # write header back - self._set_32bit_value_in_buffer(header_start, header) + struct.pack_into('>I', self._buffer, header_start, value) ########################################## @@ -601,28 +601,6 @@ def calculate_BCData(*, Ioclmax=18, IoutR=17, IoutG=15, IoutB=9): ########################################## - def _get_32bit_value_from_buffer(self, buffer_start): - # return ( - # (self._buffer[buffer_start + 0] << 24) | - # (self._buffer[buffer_start + 1] << 16) | - # (self._buffer[buffer_start + 2] << 8) | - # self._buffer[buffer_start + 3] - # ) - # return self._buf32_format.unpack_from( - # self._buffer, buffer_start) - return struct.unpack_from('>I', self._buffer, buffer_start)[0] - - def _set_32bit_value_in_buffer(self, buffer_start, value): - if not 0 <= value <= 0xFFFFFFFF: - raise ValueError( - "value {} not in range: 0..0xFFFFFFFF".format(value)) - # self._buffer[buffer_start + 0] = (value >> 24) & 0xFF - # self._buffer[buffer_start + 1] = (value >> 16) & 0xFF - # self._buffer[buffer_start + 2] = (value >> 8) & 0xFF - # self._buffer[buffer_start + 3] = value & 0xFF - # self._buf32_format.pack_into( - struct.pack_into('>I', self._buffer, buffer_start, value) - @staticmethod def _convert_01_float_to_16bit_integer(value): """Convert 0..1 Float Value to 16bit (0..65535) Range.""" @@ -641,6 +619,20 @@ def _convert_if_float(cls, value): @staticmethod def _check_and_convert(value): + # loop + # error_message = "values[{}] {} not in range: 0..{}" + # for i, value in enumerate(values): + # # check if we have float values + # if isinstance(value, float): + # # check if value is in range + # if not 0.0 <= value <= 1.0: + # raise ValueError(error_message.format(i, value, '1')) + # # convert to 16bit value + # values[i] = int(value * 65535) + # else: + # if not 0 <= value <= 65535: + # raise ValueError(error_message.format(i, value, '65535')) + # discreet # check if we have float values if isinstance(value[0], float): # check if value is in range From a07c083d91e5203c44db3d7f7b97926cc9818efe Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 23:16:03 +0100 Subject: [PATCH 58/91] speed-optimize --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 138 ++++++++++++------- 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index a4dc5e7..f4b85ad 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -620,19 +620,22 @@ def _convert_if_float(cls, value): @staticmethod def _check_and_convert(value): # loop - # error_message = "values[{}] {} not in range: 0..{}" - # for i, value in enumerate(values): + # mega slow + # for i, val in enumerate(value): # # check if we have float values - # if isinstance(value, float): - # # check if value is in range - # if not 0.0 <= value <= 1.0: - # raise ValueError(error_message.format(i, value, '1')) - # # convert to 16bit value - # values[i] = int(value * 65535) + # if isinstance(val, float): + # # check if val is in range + # if not 0.0 <= val <= 1.0: + # raise ValueError( + # "value[{}] {} not in range: 0..1".format(i, val)) + # # convert to 16bit val + # value[i] = int(val * 65535) # else: - # if not 0 <= value <= 65535: - # raise ValueError(error_message.format(i, value, '65535')) - # discreet + # if not 0 <= val <= 65535: + # raise ValueError( + # "value[{}] {} not in range: 0..65535".format(i, val)) + # discreet is way faster + # (compared with tlc59711_multi_dev.py: pixels.set_all_black()) # check if we have float values if isinstance(value[0], float): # check if value is in range @@ -682,19 +685,25 @@ def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): :param int value_g: 0..65535 :param int value_b: 0..65535 """ + # optimized for speed. + # the struct version leads to very slow runtime behaivor if you set + # lots of pixels. that is the reason the discreet version is used. + # you can check with the tlc59711_multi_dev.py file. + # most prominent this is visible at the set_pixel_all_16bit_value func: + # struct 157ms to 16ms (@144pixel on ItsyBitsy M4) pixel_start = pixel_index * self.COLORS_PER_PIXEL buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - # self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_b & 0xFF - struct.pack_into('>H', self._buffer, buffer_start, value_b) + # struct.pack_into('>H', self._buffer, buffer_start, value_b) + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - # self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_g & 0xFF - struct.pack_into('>H', self._buffer, buffer_start, value_g) + # struct.pack_into('>H', self._buffer, buffer_start, value_g) + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - # self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value_r & 0xFF - struct.pack_into('>H', self._buffer, buffer_start, value_r) + # struct.pack_into('>H', self._buffer, buffer_start, value_r) + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): """ @@ -708,12 +717,27 @@ def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): :param int value_g: 0..1 :param int value_b: 0..1 """ - self.set_pixel_16bit_value( - pixel_index, - int(value_r * 65535), - int(value_g * 65535), - int(value_b * 65535) - ) + # self.set_pixel_16bit_value( + # pixel_index, + # int(value_r * 65535), + # int(value_g * 65535), + # int(value_b * 65535) + # ) + # this is again a speed optimized version: + # this cuts down from 228ms to 22ms (@144pixel on ItsyBitsy M4) + value_r = int(value_r * 65535) + value_g = int(value_g * 65535) + value_b = int(value_b * 65535) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF def set_pixel_16bit_color(self, pixel_index, color): """ @@ -726,12 +750,25 @@ def set_pixel_16bit_color(self, pixel_index, color): :param int pixel_index: 0..(pixel_count) :param int color: 3-tuple of R, G, B; 0..65535 """ - self.set_pixel_16bit_value( - pixel_index, - color[0], - color[1], - color[2] - ) + # self.set_pixel_16bit_value( + # pixel_index, + # color[0], + # color[1], + # color[2] + # ) + # speed optimization: 140ms to 24ms (@144pixel on ItsyBitsy M4) + # the `color = list(color)` is the key here! (don't ask me why..) + color = list(color) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[0] & 0xFF def set_pixel_float_color(self, pixel_index, color): """ @@ -744,12 +781,27 @@ def set_pixel_float_color(self, pixel_index, color): :param int pixel_index: 0..(pixel_count) :param tuple/float color: 3-tuple of R, G, B; 0..1 """ - self.set_pixel_16bit_value( - pixel_index, - int(color[0] * 65535), - int(color[1] * 65535), - int(color[2] * 65535) - ) + # self.set_pixel_16bit_value( + # pixel_index, + # int(color[0] * 65535), + # int(color[1] * 65535), + # int(color[2] * 65535) + # ) + # speed optimization: 140ms to 30ms (@144pixel on ItsyBitsy M4) + color = list(color) + color[0] = int(color[0] * 65535) + color[1] = int(color[1] * 65535) + color[2] = int(color[2] * 65535) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[0] & 0xFF def set_pixel(self, pixel_index, value): """ @@ -787,16 +839,6 @@ def set_pixel(self, pixel_index, value): # we change channel order here: # buffer channel order is blue, green, red # pixel_start = pixel_index * self.COLORS_PER_PIXEL - # self._set_channel_16bit_value( - # pixel_start + 0, - # value[2]) - # self._set_channel_16bit_value( - # pixel_start + 1, - # value[1]) - # self._set_channel_16bit_value( - # pixel_start + 2, - # value[0]) - # optimize2 # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] # self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF # self._buffer[buffer_start + 1] = value[2] & 0xFF From ebed4178f3ad8820e7f5c2b18e9a9e6929f330df Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 23:30:30 +0100 Subject: [PATCH 59/91] rename example --- ...ulti_simpletest.py => tlc59711_fastset.py} | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) rename examples/{tlc59711_multi_simpletest.py => tlc59711_fastset.py} (64%) diff --git a/examples/tlc59711_multi_simpletest.py b/examples/tlc59711_fastset.py similarity index 64% rename from examples/tlc59711_multi_simpletest.py rename to examples/tlc59711_fastset.py index 2edfe97..1ab6b72 100644 --- a/examples/tlc59711_multi_simpletest.py +++ b/examples/tlc59711_fastset.py @@ -1,7 +1,11 @@ -"""TLC5971 / TLC59711 Multi.""" +"""TLC5971 / TLC59711.""" __doc__ = """ -tlc59711_multi.py - TLC59711TLC59711Multi minimal example. +tlc59711_fastset.py - TLC59711 fast set example. + +showcases the usage of set_pixel_16bit_value for fastests setting of values. +for speed comparision of all the available set calls +look at the tlc59711_multi_dev.py file. Enjoy the colors :-) """ @@ -42,45 +46,27 @@ def channelcheck_update_pixel(offset): time.sleep(0.2) offset = 0 print("clear") - pixels.set_pixel_all((0, 1, 0)) + pixels.set_pixel_all_16bit_value(0, 1, 0) pixels.show() return offset -def channelcheck_update(offset): - """Channel check.""" - # print("offset", offset) - - pixels.set_channel(offset, 1000) - # clear last set channel - last = offset-1 - if last < 0: - last = pixels.channel_count-1 - pixels.set_channel(last, 0) - pixels.show() - - offset += 1 - if offset >= pixels.channel_count: - offset = 0 - return offset - - def test_main(): """Test Main.""" print(42 * '*', end="") print(__doc__, end="") print(42 * '*') - BCValues = TLC59711Multi.calculate_BCData( + bcvalues = TLC59711Multi.calculate_BCData( Ioclmax=18, IoutR=18, IoutG=11, IoutB=13, ) - print("BCValues = {}".format(BCValues)) - pixels.bcr = BCValues[0] - pixels.bcg = BCValues[1] - pixels.bcb = BCValues[2] + print("bcvalues = {}".format(bcvalues)) + pixels.bcr = bcvalues[0] + pixels.bcg = bcvalues[1] + pixels.bcb = bcvalues[2] pixels.update_BCData() pixels.show() @@ -89,9 +75,7 @@ def test_main(): print("loop:") while True: offset = channelcheck_update_pixel(offset) - # offset = channelcheck_update(offset) time.sleep(0.2) - # channelcheck_update() ########################################## From 5a9bede10be1cf8ffa2bd0f45fb7d3589dc9ca71 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 25 Feb 2020 23:39:25 +0100 Subject: [PATCH 60/91] fix bug --- adafruit_tlc59711/adafruit_tlc59711_multi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711/adafruit_tlc59711_multi.py index f4b85ad..b5ba7ed 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711/adafruit_tlc59711_multi.py @@ -373,7 +373,7 @@ def set_chipheader_bits_in_buffer( # set header |= value # write header back - struct.pack_into('>I', self._buffer, header_start, value) + struct.pack_into('>I', self._buffer, header_start, header) ########################################## From d676db90e4060ede31729032cf6fc2fd416f7f7f Mon Sep 17 00:00:00 2001 From: s-light Date: Wed, 26 Feb 2020 00:01:14 +0100 Subject: [PATCH 61/91] add example --- examples/tlc59711_minimal.py | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/tlc59711_minimal.py diff --git a/examples/tlc59711_minimal.py b/examples/tlc59711_minimal.py new file mode 100644 index 0000000..2e94808 --- /dev/null +++ b/examples/tlc59711_minimal.py @@ -0,0 +1,40 @@ +"""TLC5971 / TLC59711.""" + +__doc__ = """ +tlc59711_minimal.py - TLC59711 minimal usage example. + +simple demo of the TLC59711 16-bit 12 channel LED PWM driver. +Shows the minimal usage - how to set pixel values. + +Enjoy the colors :-) +""" + +import board +import busio + +# import adafruit_tlc59711 +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + +# Define SPI bus connected to chip. +# You only need the clock and MOSI (output) line to use this chip. +spi = busio.SPI(board.SCK, MOSI=board.MOSI) + +# Define the TLC59711 instance. +pixels = TLC59711Multi(spi, pixel_count=16) + + +print("tlc59711_minimal.py") + +# Ways to set the values: +# just a list or tuple with 3 integer values: R G B +# each 0 - 65535 or 0.0 - 1.0 +# every chip has 4 RGB-LEDs (=12 Channel) +pixels[0] = (100, 100, 100) +pixels[1] = (0, 0, 100) +pixels[2] = (0.01, 0.0, 0.01) +pixels[3] = (0.1, 0.01, 0.0) +# if you are ready to show your values you have to call +pixels.show() + +# there are a bunch of other advanced ways to set pixel. +# have a look at the other examples. From dcbc36a769b032a32c84483991ed1478ae3f53ad Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Sep 2020 07:50:55 +0200 Subject: [PATCH 62/91] dev: change debug output --- examples/tlc59711_multi_dev.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index 6a2d432..b00d39a 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -16,7 +16,7 @@ ########################################## -pixel_count = 16*9 +pixel_count = 16*1 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = TLC59711Multi(spi, pixel_count=pixel_count) @@ -523,6 +523,7 @@ def test_main(): while True: offset = channelcheck_update(offset) time.sleep(0.5) + print(offset) ########################################## From cb08af971930d130bea2db99fa12d042c1376c84 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Sep 2020 08:31:26 +0200 Subject: [PATCH 63/91] moved modules outside of subfolder --- ...afruit_tlc59711.py => adafruit_tlc59711.py | 8 +++- ...711_multi.py => adafruit_tlc59711_multi.py | 4 +- examples/tlc59711_onechip.py | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) rename adafruit_tlc59711/adafruit_tlc59711.py => adafruit_tlc59711.py (99%) rename adafruit_tlc59711/adafruit_tlc59711_multi.py => adafruit_tlc59711_multi.py (99%) create mode 100644 examples/tlc59711_onechip.py diff --git a/adafruit_tlc59711/adafruit_tlc59711.py b/adafruit_tlc59711.py similarity index 99% rename from adafruit_tlc59711/adafruit_tlc59711.py rename to adafruit_tlc59711.py index fc55f57..ceb4b09 100644 --- a/adafruit_tlc59711/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -1,3 +1,4 @@ + # The MIT License (MIT) # # Copyright (c) 2017 Tony DiCola for Adafruit Industries @@ -19,12 +20,15 @@ # 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. + + """ `adafruit_tlc59711` ==================================================== -CircuitPython module for the TLC59711 16-bit 12 channel LED PWM driver. See -examples/simpletest.py for a demo of the usage. +CircuitPython module for the +TLC59711 16-bit 12 channel LED PWM driver. +See examples/simpletest.py for a demo of the usage. * Author(s): Tony DiCola diff --git a/adafruit_tlc59711/adafruit_tlc59711_multi.py b/adafruit_tlc59711_multi.py similarity index 99% rename from adafruit_tlc59711/adafruit_tlc59711_multi.py rename to adafruit_tlc59711_multi.py index b5ba7ed..b545429 100644 --- a/adafruit_tlc59711/adafruit_tlc59711_multi.py +++ b/adafruit_tlc59711_multi.py @@ -293,7 +293,7 @@ class TLC59711Multi: ########################################## - def __init__(self, spi, pixel_count=1): + def __init__(self, spi, pixel_count=4): """Init.""" self._spi = spi # how many pixels are there? @@ -911,7 +911,7 @@ def set_channel(self, channel_index, value): "channel_index {} out of range (0..{})" .format(channel_index, self.channel_count)) - # Define index and length properties to set and get each channel as + # Define index and length properties to set and get each pixel as # atomic RGB tuples. This provides a similar feel as using neopixels. def __len__(self): """Retrieve TLC5975 the total number of Pixels available.""" diff --git a/examples/tlc59711_onechip.py b/examples/tlc59711_onechip.py new file mode 100644 index 0000000..4fdd360 --- /dev/null +++ b/examples/tlc59711_onechip.py @@ -0,0 +1,40 @@ +"""TLC5971 / TLC59711.""" + +__doc__ = """ +tlc59711_onechip.py - TLC59711 minimal usage example. + +simple demo of the TLC59711 16-bit 12 channel LED PWM driver. +Shows the minimal usage - how to set pixel values. + +Enjoy the colors :-) +""" + +import board +import busio + +# import adafruit_tlc59711 +from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi + +# Define SPI bus connected to chip. +# You only need the clock and MOSI (output) line to use this chip. +spi = busio.SPI(board.SCK, MOSI=board.MOSI) + +# Define the TLC59711 instance with one TLC chip connected. +pixels = TLC59711Multi(spi) + + +print("tlc59711_onechip.py") + +# Ways to set the values: +# just a list or tuple with 3 integer values: R G B +# each 0 - 65535 or 0.0 - 1.0 +# every chip has 4 RGB-LEDs (=12 Channel) +pixels[0] = (100, 100, 10111) +pixels[1] = (0, 0, 100) +pixels[2] = (0.01, 0.0, 0.01) +pixels[3] = (0.1, 0.01, 0.0) +# if you are ready to show your values you have to call +pixels.show() + +# there are a bunch of other advanced ways to set pixel. +# have a look at the other examples. From f285c013d0502fe5e169aa4cc91b50296b6228a6 Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 7 Sep 2020 08:33:07 +0200 Subject: [PATCH 64/91] changed module names to remove multiple versions --- adafruit_tlc59711.py | 1096 +++++++++++++++++++++++++------- adafruit_tlc59711__original.py | 325 ++++++++++ adafruit_tlc59711_multi.py | 967 ---------------------------- 3 files changed, 1194 insertions(+), 1194 deletions(-) create mode 100644 adafruit_tlc59711__original.py delete mode 100644 adafruit_tlc59711_multi.py diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index ceb4b09..f01b1db 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -1,7 +1,8 @@ -# The MIT License (MIT) +# The MIT License (MIT). # # Copyright (c) 2017 Tony DiCola for Adafruit Industries +# Copyright (c) 2018 Stefan Krüger s-light.eu # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -21,16 +22,16 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. - """ -`adafruit_tlc59711` +`adafruit_tlc59711_multi`. + ==================================================== CircuitPython module for the -TLC59711 16-bit 12 channel LED PWM driver. -See examples/simpletest.py for a demo of the usage. +TLC59711 or TLC5971 16-bit 12 channel LED PWM driver. +See examples/simpletest_multi.py for a demo of the usage. -* Author(s): Tony DiCola +* Author(s): Tony DiCola, Stefan Kruger Implementation Notes -------------------- @@ -39,10 +40,16 @@ * Adafruit `12-Channel 16-bit PWM LED Driver - SPI Interface - TLC59711 `_ (Product ID: 1455) + or TLC5971 **Software and Dependencies:** -* Adafruit CircuitPython firmware for the ESP8622 and M0-based boards: +* this is a variant with multi-chip support. + The API is mostly compatible to the DotStar / NeoPixel Libraries + and is therefore also compatible with FancyLED. + for this see examples/fancy_multi.py + +* Adafruit CircuitPython firmware for the ESP8622, M0 or M4-based boards: https://github.com/adafruit/circuitpython/releases """ __version__ = "0.0.0-auto.0" @@ -54,125 +61,425 @@ # refers to them as. # pylint: disable=invalid-name -# Globally disable too many instance attributes check. Again this is a case -# where pylint doesn't have the right context to make this call. The chip by -# design has many channels which must be exposed. -# pylint: disable=too-many-instance-attributes - -# Globally disable protected access. Once again pylint can't figure out the -# context for using internal decorate classes below. -# In these cases protected access is by design for the internal class. -# pylint: disable=protected-access - -# Yet another pylint issue, it fails to recognize a decorator class by -# definition has no public methods. Disable the check. -# pylint: disable=too-few-public-methods +import struct +from micropython import const -def _shift_in(target_byte, val): - # Shift in a new bit value to the provided target byte. The byte will be - # shift one position left and a new bit inserted that's a 1 if val is true, - # of a 0 if false. - target_byte <<= 1 - if val: - target_byte |= 0x01 - return target_byte +class TLC59711Multi: + """Multi TLC59711 16-bit 12 channel LED PWM driver. - -class TLC59711: - """TLC59711 16-bit 12 channel LED PWM driver. This chip is designed to - drive 4 RGB LEDs with 16-bit PWM control of each LED. The class has an - interface much like that of NeoPixels with attribute access to the 4 - RGB channels (note they are 16-bit values). Or you can access each - independent channel by name (r0, g0, b0, r1, b1, etc.) as properties for - fine-grained control. + This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. + The class has an interface compatible with the FancyLED library. + and with this is similar to the NeoPixel and DotStar Interfaces. :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. The clock and MOSI/outout must be set, the MISO/input is unused. - :param bool auto_show: This is a boolean that defaults to True and - indicates any change to a channel value will instantly be written - to the chip. You might wish to set this to false if you desire - to perform your own atomic operations of channel values. In that case - call the show function after making updates to channel state. + Maximal data clock frequence is: + - TLC59711: 10MHz + - TLC5971: 20MHz + :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. """ - class _GS_Value: - # Internal decorator to simplify exposing each 16-bit LED PWM channel. - # These will get/set the appropriate bytes in the shift register with - # the specified values. - - def __init__(self, byte_offset): - # Keep track of the byte within the shift register where this - # 16-bit value starts. Luckily these are all aligned on byte - # boundaries. Note the byte order is big endian (MSB first). - self._byte_offset = byte_offset - - def __get__(self, obj, obj_type): - # Grab the 16-bit value at the offset for this channel. - return (obj._shift_reg[self._byte_offset] << 8) | \ - obj._shift_reg[self._byte_offset + 1] - - def __set__(self, obj, val): - # Set the 16-bit value at the offset for this channel. - assert 0 <= val <= 65535 - obj._shift_reg[self._byte_offset] = (val >> 8) & 0xFF - obj._shift_reg[self._byte_offset + 1] = val & 0xFF - # Write out the new values if auto_show is enabled. - if obj.auto_show: - obj._write() - - # Define explicit GS channels (each LED PWM channel) for users to control. - # See also the __len__ and iterable dunder methods that provide a - # neopixel-like interface to the GS channel values too. Each has a - # trade-off in usage so users can decide how they choose to use the class - # (must change all 3 values at a time with neopixel-like interface vs. - # direct single channel control with these properties below). - b3 = _GS_Value(4) - g3 = _GS_Value(6) - r3 = _GS_Value(8) - - b2 = _GS_Value(10) - g2 = _GS_Value(12) - r2 = _GS_Value(14) - - b1 = _GS_Value(16) - g1 = _GS_Value(18) - r1 = _GS_Value(20) - - b0 = _GS_Value(22) - g0 = _GS_Value(24) - r0 = _GS_Value(26) - - - def __init__(self, spi, *, auto_show=True): # noqa + # pylint: disable=too-many-instance-attributes + # it just does make senes to have the chip params as attributes. + + # """ + # TLC5971 data / register structure + # + # some detailed information on the protocol based on + # http://www.ti.com/lit/ds/symlink/tlc5971.pdf + # 8.5.4 Register and Data Latch Configuration (page 23ff) + # 9.2.2.3 How to Control the TLC5971 (page27) + # + # How to send: + # the first data we send are received by the last device in chain. + # Device Nth (244Bit = 28Byte) + # Write Command (6Bit) + # WRCMD (fixed: 25h) + # Function Control Data (5 x 1Bit = 5Bit) + # OUTTMG 1bit + # GS clock edge select + # 1=rising edge, 0= falling edge + # EXTGCK 1bit + # GS reference clock select + # 1=SCKI clock, 0=internal oscillator + # TMGRST 1bit + # display timing reset mode + # 1=OUT forced of on latchpulse, 0=no forced reset + # DSPRPT 1bit + # display repeat mode + # 1=auto repeate + # 0=Out only turned on after Blank or internal latchpulse + # BLANK 1bit; + # 1=blank (outputs off) + # 0=Out on - controlled by GS-Data + # ic power on sets this to 1 + # BC-Data (3 x 7Bits = 21Bit) + # BCB 7bit; + # BCG 7bit; + # BCR 7bit; + # GS-Data (12 x 16Bits = 192Bit) + # GSB3 16bit; + # GSG3 16bit; + # GSR3 16bit; + # GSB2 16bit; + # GSG2 16bit; + # GSR2 16bit; + # GSB1 16bit; + # GSG1 16bit; + # GSR1 16bit; + # GSB0 16bit; + # GSG0 16bit; + # GSR0 16bit; + # Device Nth-1 (244Bit = 28Byte) + # Device .. + # Device 2 + # Device 1 + # short break of 8x period of clock (666ns .. 2.74ms) + # to generate latchpulse + # + 1.34uS + # than next update. + # """ + + ########################################## + # helper + ########################################## + + # pylama:ignore=E0602 + # ugly workaround for pylama not knowing of micropython const thing + _CHIP_BUFFER_BYTE_COUNT = const(28) + + COLORS_PER_PIXEL = const(3) + PIXEL_PER_CHIP = const(4) + CHANNEL_PER_CHIP = const(COLORS_PER_PIXEL * PIXEL_PER_CHIP) + + _BUFFER_BYTES_PER_COLOR = const(2) + _BUFFER_BYTES_PER_PIXEL = const(_BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL) + + # @staticmethod + # def set_bit_with_mask(v, mask, x): + # """Set bit with help of mask.""" + # # clear + # v &= ~mask + # if x: + # # set + # v |= mask + # return v + # + # @staticmethod + # def set_bit(v, index, x): + # """Set bit - return new value. + # + # Set the index:th bit of v to 1 if x is truthy, + # else to 0, and return the new value. + # https://stackoverflow.com/a/12174051/574981 + # """ + # # Compute mask, an integer with just bit 'index' set. + # mask = 1 << index + # # Clear the bit indicated by the mask (if x is False) + # v &= ~mask + # if x: + # # If x was True, set the bit indicated by the mask. + # v |= mask + # # Return the result, we're done. + # return v + + ########################################## + # class _BC(): + # BC-Data (3 x 7Bits = 21Bit). + # + # BCB 7bit; + # BCG 7bit; + # BCR 7bit; + _BC_CHIP_BUFFER_BIT_OFFSET = const(0) + _BC_BIT_COUNT = const(3 * 7) + # this holds the chip offset and + _BC_FIELDS = { + "BCR": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCB": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, + } + + ########################################## + # class _FC(): + # """ + # Function Control Data (5 x 1Bit = 5Bit). + # + # OUTTMG 1bit + # GS clock edge select + # 1 = rising edge + # 0 = falling edge + # EXTGCK 1bit + # GS reference clock select + # 1 = SCKI clock + # 0 = internal oscillator + # TMGRST 1bit + # display timing reset mode + # 1 = OUT forced of on latchpulse + # 0 = no forced reset + # DSPRPT 1bit + # display repeat mode + # 1 = auto repeate + # 0 = Out only turned on after Blank or internal latchpulse + # BLANK 1bit; + # ic power on sets this to 1 + # 1 = blank (outputs off) + # 0 = Out on - controlled by GS-Data + # """ + + _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) + _FC_BIT_COUNT = const(5) + _FC_FIELDS = { + "BLANK": { + "offset": 0, + "length": 1, + "mask": 0b1, + }, + "DSPRPT": { + "offset": 1, + "length": 1, + "mask": 0b1, + }, + "TMGRST": { + "offset": 2, + "length": 1, + "mask": 0b1, + }, + "EXTGCK": { + "offset": 3, + "length": 1, + "mask": 0b1, + }, + "OUTTMG": { + "offset": 4, + "length": 1, + "mask": 0b1, + }, + } + + ########################################## + # class _WRITE_COMMAND(): + # """WRITE_COMMAND.""" + + _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) + _WC_BIT_COUNT = const(6) + _WC_FIELDS = { + "WRITE_COMMAND": { + "offset": 0, + "length": 6, + "mask": 0b111111, + }, + } + WRITE_COMMAND = const(0b100101) + ########################################## + + ######## + _CHIP_BUFFER_HEADER_BIT_COUNT = const( + _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT) + _CHIP_BUFFER_HEADER_BYTE_COUNT = const(_CHIP_BUFFER_HEADER_BIT_COUNT // 8) + + ########################################## + + def __init__(self, spi, pixel_count=4): + """Init.""" self._spi = spi - # This device is just a big 28 byte long shift register without any + # how many pixels are there? + self.pixel_count = pixel_count + self.channel_count = self.pixel_count * self.COLORS_PER_PIXEL + # calculate how many chips are connected + self.chip_count = self.pixel_count // 4 + + # The chips are just a big 28 byte long shift register without any # fancy update protocol. Blast out all the bits to update, that's it! - self._shift_reg = bytearray(28) - # Keep track of automatically writing out the state of the PWM channels - # on any change (auto_show = True). If set to false the user must - # explicitly call the show method to write out the PWM state to the - # chip--this is useful for performing atomic updates to LEDs (i.e. - # changing all the R, G, B channels at once). - self.auto_show = auto_show - # Initialize the brightness channel values to max (these are 7-bit - # values). - self._bcr = 127 - self._bcg = 127 - self._bcb = 127 + # create raw output data + self._buffer = bytearray(_CHIP_BUFFER_BYTE_COUNT * self.chip_count) + + # Initialize the brightness channel values to max + # (these are 7-bit values). + self.bcr = 127 + self.bcg = 127 + self.bcb = 127 + # Initialize external user-facing state for the function control # bits of the chip. These aren't commonly used but available and - # match the nomenclature from the datasheet. Note they won't honor - # the auto_show property and instead you must manually call show - # after changing them (reduces the need to make frivolous - # memory-hogging properties). - # Set OUTTMG, TMGRST, and DSPRPT to on like the Arduino library. + # match the nomenclature from the datasheet. + # you must manually call update_fc() after changing them + # (reduces the need to make frivolous memory-hogging properties). + # Default set + # OUTTMG, TMGRST, and DSPRPT to on + # like in Arduino library. + # these are set for all chips self.outtmg = True - self.extgclk = False + self.extgck = False self.tmgrst = True self.dsprpt = True self.blank = False + # self._buf32_format = struct.Struct('>I') + # self._buf16_format = struct.Struct('>H') + + # preparation done + # now initialize buffer to default values + self._init_buffer() + + self._buffer_index_lookuptable = [] + self._init_lookuptable() + + def _init_buffer(self): + for chip_index in range(self.chip_count): + # set Write Command (6Bit) WRCMD (fixed: 25h) + self.chip_set_BCData( + chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) + self._chip_set_FunctionControl(chip_index) + self._chip_set_WriteCommand(chip_index) + # loop end + + def set_chipheader_bits_in_buffer( + self, + *, + chip_index=0, + part_bit_offset=0, + field={"mask": 0, "length": 0, "offset": 0}, + value=0 + ): + """Set chip header bits in buffer.""" + offset = part_bit_offset + field["offset"] + # restrict value + value &= field["mask"] + # move value to position + value = value << offset + # calculate header start + header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT + # get chip header + header = struct.unpack_from('>I', self._buffer, header_start)[0] + # 0xFFFFFFFF == 0b11111111111111111111111111111111 + # create/move mask + mask = field["mask"] << offset + # clear + header &= (~mask) + # set + header |= value + # write header back + struct.pack_into('>I', self._buffer, header_start, header) + + ########################################## + + def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): + """ + Set BC-Data. + + :param int chip_index: Index of Chip to set. + :param int bcr: 7-bit value from 0-127 (default=127) + :param int bcg: 7-bit value from 0-127 (default=127) + :param int bcb: 7-bit value from 0-127 (default=127) + """ + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCR"], + value=bcr) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCG"], + value=bcg) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, + field=self._BC_FIELDS["BCB"], + value=bcb) + + def update_BCData(self): + """ + Update BC-Data for all Chips in Buffer. + + need to be called after you changed on of the + BC-Data Parameters. (bcr, bcg, bcb) + """ + for chip_index in range(self.chip_count): + self.chip_set_BCData( + chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) + + def _chip_set_FunctionControl(self, chip_index): + """ + Set Function Control Bits in Buffer. + + values from object global parameters are used. + + :param int chip_index: Index of Chip to set. + """ + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["OUTTMG"], + value=self.outtmg) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["EXTGCK"], + value=self.extgck) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["TMGRST"], + value=self.tmgrst) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["DSPRPT"], + value=self.dsprpt) + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, + field=self._FC_FIELDS["BLANK"], + value=self.blank) + + def update_fc(self): + """ + Update Function Control Bits for all Chips in Buffer. + + need to be called after you changed on of the + Function Control Bit Parameters. + (outtmg, extgck, tmgrst, dsprpt, blank) + """ + for chip_index in range(self.chip_count): + self._chip_set_FunctionControl(chip_index) + + def _chip_set_WriteCommand(self, chip_index): + """Set WRITE_COMMAND.""" + # set all bits + self.set_chipheader_bits_in_buffer( + chip_index=chip_index, + part_bit_offset=_WC_CHIP_BUFFER_BIT_OFFSET, + field=self._WC_FIELDS["WRITE_COMMAND"], + value=self.WRITE_COMMAND) + + def _init_lookuptable(self): + for channel_index in range(self.channel_count): + buffer_index = ( + (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) + * (channel_index // self.CHANNEL_PER_CHIP) + + channel_index % self.CHANNEL_PER_CHIP) + buffer_index *= _BUFFER_BYTES_PER_COLOR + buffer_index += _CHIP_BUFFER_HEADER_BYTE_COUNT + self._buffer_index_lookuptable.append(buffer_index) + + ########################################## + def _write(self): # Write out the current state to the shift register. try: @@ -180,145 +487,480 @@ def _write(self): while not self._spi.try_lock(): pass self._spi.configure(baudrate=10000000, polarity=0, phase=0) - # Update the preamble of chip state in the first 4 bytes (32-bits) - # with the write command, function control bits, and brightness - # control register values. - self._shift_reg[0] = 0x25 # 0x25 in top 6 bits initiates write. - # Lower two bits control OUTTMG and EXTGCLK bits, set them - # as appropriate. - self._shift_reg[0] = _shift_in(self._shift_reg[0], self.outtmg) - self._shift_reg[0] = _shift_in(self._shift_reg[0], self.extgclk) - # Next byte contains remaining function control state and start of - # brightness control bits. - self._shift_reg[1] = 0x00 - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.tmgrst) - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.dsprpt) - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.blank) - # Top 5 bits from BC blue channel. - self._shift_reg[1] <<= 5 - self._shift_reg[1] |= (self._bcb >> 2) & 0b11111 - # Next byte contains lower 2 bits from BC blue channel and upper 6 - # from BC green channel. - self._shift_reg[2] = (self._bcb) & 0b11 - self._shift_reg[2] <<= 6 - self._shift_reg[2] |= (self._bcg >> 1) & 0b111111 - # Final byte contains lower 1 bit from BC green and 7 bits from BC - # red channel. - self._shift_reg[3] = self._bcg & 0b1 - self._shift_reg[3] <<= 7 - self._shift_reg[3] |= self._bcr & 0b1111111 - # The remaining bytes in the shift register are the channel PWM - # values that have already been set by the user. Now write out the - # the entire set of bytes. Note there is no latch or other - # explicit line to tell the chip when finished, it expects 28 bytes. - self._spi.write(self._shift_reg) + self._spi.write(self._buffer) finally: # Ensure the SPI bus is unlocked. self._spi.unlock() def show(self): - """Write out the current LED PWM state to the chip. This is only necessary if - auto_show was set to false in the initializer. - """ + """Write out the current LED PWM state to the chip.""" self._write() - # Define properties for global brightness control channels. - @property - def red_brightness(self): - """The red brightness for all channels (i.e. R0, R1, R2, and R3). + ########################################## - This is a 7-bit value from 0-127. + @staticmethod + def calculate_Ioclmax(*, Riref=2.48): """ - return self._bcr + Calculate Maximum Constant Sink Current Value. - @red_brightness.setter - def red_brightness(self, val): - assert 0 <= val <= 127 - self._bcr = val - if self.auto_show: - self._write() + see: + 8.4.1 Maximum Constant Sink Current Setting + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=18&zoom=160,0,524 - @property - def green_brightness(self): - """The green brightness for all channels (i.e. G0, G1, G2, and G3). + Riref = (Viref / Ioclmax) * 41 + Ioclmax = (41 / Riref) * Viref - This is a 7-bit value from 0-127. + :param float Riref: resistor value (kΩ) (default=20) + :return tuple: Ioclmax (mA) """ - return self._bcg + # Riref = (Viref / Ioclmax) * 41 | / 41 + # Riref / 41 = Viref / Ioclmax | switch + # 41 / Riref = Ioclmax / Viref | * Viref + # (41 / Riref) * Viref = Ioclmax + if not 0.8 <= Riref <= 24.8: + raise ValueError( + "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) + Viref = 1.21 + Ioclmax = (41 / Riref) * Viref + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError( + "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) + return Ioclmax + + @staticmethod + def calculate_Riref(*, Ioclmax=20): + """ + Calculate Maximum Constant Sink Current Value. - @green_brightness.setter - def green_brightness(self, val): - assert 0 <= val <= 127 - self._bcg = val - if self.auto_show: - self._write() + see: + 8.4.1 Maximum Constant Sink Current Setting + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 - @property - def blue_brightness(self): - """The blue brightness for all channels (i.e. B0, B1, B2, and B3). + Riref = (Viref / Ioclmax) * 41 - This is a 7-bit value from 0-127. + :param float Ioclmax: target max output current (mA) (default=20) + :return tuple: Riref (kΩ) + """ + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError( + "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) + Viref = 1.21 + Riref = (Viref / Ioclmax) * 41 + if not 0.8 <= Riref <= 24.8: + raise ValueError( + "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) + return Riref + + @staticmethod + def calculate_BCData(*, Ioclmax=18, IoutR=17, IoutG=15, IoutB=9): + """ + Calculate Global Brightness Control Values. + + see: + 8.5.1 Global Brightness Control (BC) Function (Sink Current Control) + http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 + + Iout = Ioclmax * (BCX / 127) + BCX = Iout / Ioclmax * 127 + + :param float Ioclmax: max output current set by Riref (mA) (default=20) + :param float IoutR: max output current for red color group (mA) + (default=9) + :param float IoutG: max output current for green color (mA) + (default=15) + :param float IoutB: max output current for blue color (mA) + (default=17) + :return tuple: (bcr, bcg, bcb) + """ + # Iout = Ioclmax * (BCX / 127) | / Ioclmax + # Iout / Ioclmax = BCX / 127 | * 127 + # Iout / Ioclmax * 127 = BCX + if not 2.0 <= Ioclmax <= 60.0: + raise ValueError("Ioclmax {} not in range: 2mA..60mA" + "".format(Ioclmax)) + if not 0.0 <= IoutR <= Ioclmax: + raise ValueError( + "IoutR {} not in range: 2mA..{}mA".format(IoutR, Ioclmax)) + if not 0.0 <= IoutG <= Ioclmax: + raise ValueError( + "IoutG {} not in range: 2mA..{}mA".format(IoutG, Ioclmax)) + if not 0.0 <= IoutB <= Ioclmax: + raise ValueError( + "IoutB {} not in range: 2mA..{}mA".format(IoutB, Ioclmax)) + bcr = int((IoutR / Ioclmax) * 127) + bcg = int((IoutG / Ioclmax) * 127) + bcb = int((IoutB / Ioclmax) * 127) + if not 0 <= bcr <= 127: + raise ValueError("bcr {} not in range: 0..127".format(bcr)) + if not 0 <= bcg <= 127: + raise ValueError("bcg {} not in range: 0..127".format(bcg)) + if not 0 <= bcb <= 127: + raise ValueError("bcb {} not in range: 0..127".format(bcb)) + return (bcr, bcg, bcb) + + ########################################## + + @staticmethod + def _convert_01_float_to_16bit_integer(value): + """Convert 0..1 Float Value to 16bit (0..65535) Range.""" + # check if value is in range + if not 0.0 <= value[0] <= 1.0: + raise ValueError("value[0] {} not in range: 0..1".format(value[0])) + # convert to 16bit value + return int(value * 65535) + + @classmethod + def _convert_if_float(cls, value): + """Convert if value is Float.""" + if isinstance(value, float): + value = cls._convert_01_float_to_16bit_integer(value) + return value + + @staticmethod + def _check_and_convert(value): + # loop + # mega slow + # for i, val in enumerate(value): + # # check if we have float values + # if isinstance(val, float): + # # check if val is in range + # if not 0.0 <= val <= 1.0: + # raise ValueError( + # "value[{}] {} not in range: 0..1".format(i, val)) + # # convert to 16bit val + # value[i] = int(val * 65535) + # else: + # if not 0 <= val <= 65535: + # raise ValueError( + # "value[{}] {} not in range: 0..65535".format(i, val)) + # discreet is way faster + # (compared with tlc59711_multi_dev.py: pixels.set_all_black()) + # check if we have float values + if isinstance(value[0], float): + # check if value is in range + if not 0.0 <= value[0] <= 1.0: + raise ValueError( + "value[0] {} not in range: 0..1".format(value[0])) + # convert to 16bit value + value[0] = int(value[0] * 65535) + else: + if not 0 <= value[0] <= 65535: + raise ValueError( + "value[0] {} not in range: 0..65535".format(value[0])) + if isinstance(value[1], float): + if not 0.0 <= value[1] <= 1.0: + raise ValueError( + "value[1] {} not in range: 0..1".format(value[1])) + value[1] = int(value[1] * 65535) + else: + if not 0 <= value[1] <= 65535: + raise ValueError( + "value[1] {} not in range: 0..65535".format(value[1])) + if isinstance(value[2], float): + if not 0.0 <= value[2] <= 1.0: + raise ValueError( + "value[2] {} not in range: 0..1".format(value[2])) + value[2] = int(value[2] * 65535) + else: + if not 0 <= value[2] <= 65535: + raise ValueError( + "value[2] {} not in range: 0..65535".format(value[2])) + + ########################################## + + def _get_channel_16bit_value(self, channel_index): + buffer_start = self._buffer_index_lookuptable[channel_index] + return struct.unpack_from('>H', self._buffer, buffer_start)[0] + + def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): + """ + Set the value for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + + :param int pixel_index: 0..(pixel_count) + :param int value_r: 0..65535 + :param int value_g: 0..65535 + :param int value_b: 0..65535 + """ + # optimized for speed. + # the struct version leads to very slow runtime behaivor if you set + # lots of pixels. that is the reason the discreet version is used. + # you can check with the tlc59711_multi_dev.py file. + # most prominent this is visible at the set_pixel_all_16bit_value func: + # struct 157ms to 16ms (@144pixel on ItsyBitsy M4) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + # struct.pack_into('>H', self._buffer, buffer_start, value_b) + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + # struct.pack_into('>H', self._buffer, buffer_start, value_g) + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + # struct.pack_into('>H', self._buffer, buffer_start, value_r) + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF + + def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): """ - return self._bcb + Set the value for pixel. - @blue_brightness.setter - def blue_brightness(self, val): - assert 0 <= val <= 127 - self._bcb = val - if self.auto_show: - self._write() + This is a Fast UNPROTECTED function: + no error / range checking is done. - # Define index and length properties to set and get each channel as + :param int pixel_index: 0..(pixel_count) + :param int value_r: 0..1 + :param int value_g: 0..1 + :param int value_b: 0..1 + """ + # self.set_pixel_16bit_value( + # pixel_index, + # int(value_r * 65535), + # int(value_g * 65535), + # int(value_b * 65535) + # ) + # this is again a speed optimized version: + # this cuts down from 228ms to 22ms (@144pixel on ItsyBitsy M4) + value_r = int(value_r * 65535) + value_g = int(value_g * 65535) + value_b = int(value_b * 65535) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_b & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_g & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF + self._buffer[buffer_start + 1] = value_r & 0xFF + + def set_pixel_16bit_color(self, pixel_index, color): + """ + Set color for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + its a little bit slower as `set_pixel_16bit_value` + + :param int pixel_index: 0..(pixel_count) + :param int color: 3-tuple of R, G, B; 0..65535 + """ + # self.set_pixel_16bit_value( + # pixel_index, + # color[0], + # color[1], + # color[2] + # ) + # speed optimization: 140ms to 24ms (@144pixel on ItsyBitsy M4) + # the `color = list(color)` is the key here! (don't ask me why..) + color = list(color) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[0] & 0xFF + + def set_pixel_float_color(self, pixel_index, color): + """ + Set color for pixel. + + This is a Fast UNPROTECTED function: + no error / range checking is done. + its a little bit slower as `set_pixel_16bit_value` + + :param int pixel_index: 0..(pixel_count) + :param tuple/float color: 3-tuple of R, G, B; 0..1 + """ + # self.set_pixel_16bit_value( + # pixel_index, + # int(color[0] * 65535), + # int(color[1] * 65535), + # int(color[2] * 65535) + # ) + # speed optimization: 140ms to 30ms (@144pixel on ItsyBitsy M4) + color = list(color) + color[0] = int(color[0] * 65535) + color[1] = int(color[1] * 65535) + color[2] = int(color[2] * 65535) + pixel_start = pixel_index * self.COLORS_PER_PIXEL + buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[2] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[1] & 0xFF + buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF + self._buffer[buffer_start + 1] = color[0] & 0xFF + + def set_pixel(self, pixel_index, value): + """ + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + + :param int pixel_index: 0..(pixel_count) + :param tuple value: 3-tuple of R, G, B; + each int 0..65535 or float 0..1 + """ + if 0 <= pixel_index < self.pixel_count: + # convert to list + value = list(value) + # repr(value) + if len(value) != self.COLORS_PER_PIXEL: + raise IndexError( + "length of value {} does not match COLORS_PER_PIXEL (= {})" + "".format(len(value), self.COLORS_PER_PIXEL) + ) + # tested: + # splitting up into variables to not need the list.. + # this is about 0.25ms slower.. + # value_r = value[0] + # value_g = value[1] + # value_b = value[2] + + # check if we have float values + # this modifies 'value' in place.. + self._check_and_convert(value) + + # update buffer + # we change channel order here: + # buffer channel order is blue, green, red + # pixel_start = pixel_index * self.COLORS_PER_PIXEL + # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] + # self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[2] & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 1] + # self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[1] & 0xFF + # buffer_start = self._buffer_index_lookuptable[pixel_start + 2] + # self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF + # self._buffer[buffer_start + 1] = value[0] & 0xFF + # simpliefy code + self.set_pixel_16bit_value( + pixel_index, value[0], value[1], value[2]) + else: + raise IndexError( + "index {} out of range [0..{}]" + "".format(pixel_index, self.pixel_count)) + + def set_pixel_all_16bit_value(self, value_r, value_g, value_b): + """ + Set the R, G, B values for all pixels. + + fast. without error checking. + + :param int value_r: 0..65535 + :param int value_g: 0..65535 + :param int value_b: 0..65535 + """ + for i in range(self.pixel_count): + self.set_pixel_16bit_value(i, value_r, value_g, value_b) + + def set_pixel_all(self, color): + """ + Set the R, G, B values for all pixels. + + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + for i in range(self.pixel_count): + self.set_pixel(i, color) + + def set_all_black(self): + """Set all pixels to black.""" + for i in range(self.pixel_count): + self.set_pixel_16bit_value(i, 0, 0, 0) + + # channel access + def set_channel(self, channel_index, value): + """ + Set the value for the provided channel. + + :param int channel_index: 0..channel_count + :param int value: 0..65535 + """ + if 0 <= channel_index < (self.channel_count): + # check if values are in range + if not 0 <= value <= 65535: + raise ValueError("value {} not in range: 0..65535") + # temp = channel_index + # we change channel order here: + # buffer channel order is blue, green, red + pixel_index_offset = channel_index % self.COLORS_PER_PIXEL + if pixel_index_offset == 0: + channel_index += 2 + elif pixel_index_offset == 2: + channel_index -= 2 + # set value in buffer + buffer_start = self._buffer_index_lookuptable[channel_index] + struct.pack_into('>H', self._buffer, buffer_start, value) + else: + raise IndexError( + "channel_index {} out of range (0..{})" + .format(channel_index, self.channel_count)) + + # Define index and length properties to set and get each pixel as # atomic RGB tuples. This provides a similar feel as using neopixels. def __len__(self): - """Retrieve the total number of LED channels available.""" - return 4 # Always 4 RGB channels on the chip. + """Retrieve TLC5975 the total number of Pixels available.""" + return self.pixel_count def __getitem__(self, key): - # pylint: disable=no-else-return - # Disable should be removed when refactor can be tested - """Retrieve the R, G, B values for the provided channel as a - 3-tuple. Each value is a 16-bit number from 0-65535. - """ - if key == 0: - return (self.r0, self.g0, self.b0) - elif key == 1: - return (self.r1, self.g1, self.b1) - elif key == 2: - return (self.r2, self.g2, self.b2) - elif key == 3: - return (self.r3, self.g3, self.b3) + """ + Retrieve the R, G, B values for the provided channel as a 3-tuple. + + Each value is a 16-bit number from 0-65535. + """ + if 0 <= key < self.pixel_count: + pixel_start = key * self.COLORS_PER_PIXEL + return ( + self._get_channel_16bit_value(pixel_start + 0), + self._get_channel_16bit_value(pixel_start + 1), + self._get_channel_16bit_value(pixel_start + 2) + ) + # else: + raise IndexError( + "index {} out of range [0..{}]".format(key, self.pixel_count)) + + def __setitem__(self, key, value): + """ + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + this shortcut is identicall to `set_pixel` + + :param int key: 0..(pixel_count) + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + # for a more detailed version with all the debugging code and + # comments look at set_pixel + if 0 <= key < self.pixel_count: + value = list(value) + if len(value) != self.COLORS_PER_PIXEL: + raise IndexError( + "length of value {} does not match COLORS_PER_PIXEL (= {})" + "".format(len(value), self.COLORS_PER_PIXEL) + ) + # _check_and_convert modifies value in place.. + self._check_and_convert(value) + self.set_pixel_16bit_value(key, value[0], value[1], value[2]) else: - raise IndexError - - def __setitem__(self, key, val): - """Set the R, G, B values for the provided channel. Specify a - 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). - """ - # Do this check here instead of later to - # prevent accidentally keeping auto_show - # turned off when a bad key is provided. - assert 0 <= key <= 3 - - assert len(val) == 3 - assert 0 <= val[0] <= 65535 - assert 0 <= val[1] <= 65535 - assert 0 <= val[2] <= 65535 - # Temporarily halt auto write to perform an atomic update of all - # the channel values. - old_auto_show = self.auto_show - self.auto_show = False - # Update appropriate channel values. - if key == 0: - self.r0, self.g0, self.b0 = val - elif key == 1: - self.r1, self.g1, self.b1 = val - elif key == 2: - self.r2, self.g2, self.b2 = val - elif key == 3: - self.r3, self.g3, self.b3 = val - # Restore auto_show state. - self.auto_show = old_auto_show - # Write out new values if in auto_show state. - if self.auto_show: - self._write() + raise IndexError( + "index {} out of range [0..{}]" + "".format(key, self.pixel_count) + ) + +########################################## diff --git a/adafruit_tlc59711__original.py b/adafruit_tlc59711__original.py new file mode 100644 index 0000000..e25f32f --- /dev/null +++ b/adafruit_tlc59711__original.py @@ -0,0 +1,325 @@ + +# The MIT License (MIT) +# +# Copyright (c) 2017 Tony DiCola for Adafruit Industries +# +# 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. + + +""" +`adafruit_tlc59711` +==================================================== + +CircuitPython module for the +TLC59711 16-bit 12 channel LED PWM driver. +See examples/simpletest.py for a demo of the usage. + +* Author(s): Tony DiCola + +Implementation Notes +-------------------- + +**Hardware:** + +* Adafruit `12-Channel 16-bit PWM LED Driver - SPI Interface - TLC59711 + `_ (Product ID: 1455) + + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the ESP8622 and M0-based boards: + https://github.com/adafruit/circuitpython/releases +""" +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" + + +# Globally disable invalid-name check as this chip by design has short channel +# and register names. It is confusing to rename these from what the datasheet +# refers to them as. +# pylint: disable=invalid-name + +# Globally disable too many instance attributes check. Again this is a case +# where pylint doesn't have the right context to make this call. The chip by +# design has many channels which must be exposed. +# pylint: disable=too-many-instance-attributes + +# Globally disable protected access. Once again pylint can't figure out the +# context for using internal decorate classes below. +# In these cases protected access is by design for the internal class. +# pylint: disable=protected-access + +# Yet another pylint issue, it fails to recognize a decorator class by +# definition has no public methods. Disable the check. +# pylint: disable=too-few-public-methods + + +def _shift_in(target_byte, val): + # Shift in a new bit value to the provided target byte. The byte will be + # shift one position left and a new bit inserted that's a 1 if val is true, + # of a 0 if false. + target_byte <<= 1 + if val: + target_byte |= 0x01 + return target_byte + + +class TLC59711: + """TLC59711 16-bit 12 channel LED PWM driver. This chip is designed to + drive 4 RGB LEDs with 16-bit PWM control of each LED. The class has an + interface much like that of NeoPixels with attribute access to the 4 + RGB channels (note they are 16-bit values). Or you can access each + independent channel by name (r0, g0, b0, r1, b1, etc.) as properties for + fine-grained control. + + :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. + The clock and MOSI/outout must be set, the MISO/input is unused. + :param bool auto_show: This is a boolean that defaults to True and + indicates any change to a channel value will instantly be written + to the chip. You might wish to set this to false if you desire + to perform your own atomic operations of channel values. In that case + call the show function after making updates to channel state. + """ + + class _GS_Value: + # Internal decorator to simplify exposing each 16-bit LED PWM channel. + # These will get/set the appropriate bytes in the shift register with + # the specified values. + + def __init__(self, byte_offset): + # Keep track of the byte within the shift register where this + # 16-bit value starts. Luckily these are all aligned on byte + # boundaries. Note the byte order is big endian (MSB first). + self._byte_offset = byte_offset + + def __get__(self, obj, obj_type): + # Grab the 16-bit value at the offset for this channel. + return (obj._shift_reg[self._byte_offset] << 8) | \ + obj._shift_reg[self._byte_offset + 1] + + def __set__(self, obj, val): + # Set the 16-bit value at the offset for this channel. + assert 0 <= val <= 65535 + obj._shift_reg[self._byte_offset] = (val >> 8) & 0xFF + obj._shift_reg[self._byte_offset + 1] = val & 0xFF + # Write out the new values if auto_show is enabled. + if obj.auto_show: + obj._write() + + # Define explicit GS channels (each LED PWM channel) for users to control. + # See also the __len__ and iterable dunder methods that provide a + # neopixel-like interface to the GS channel values too. Each has a + # trade-off in usage so users can decide how they choose to use the class + # (must change all 3 values at a time with neopixel-like interface vs. + # direct single channel control with these properties below). + b3 = _GS_Value(4) + g3 = _GS_Value(6) + r3 = _GS_Value(8) + + b2 = _GS_Value(10) + g2 = _GS_Value(12) + r2 = _GS_Value(14) + + b1 = _GS_Value(16) + g1 = _GS_Value(18) + r1 = _GS_Value(20) + + b0 = _GS_Value(22) + g0 = _GS_Value(24) + r0 = _GS_Value(26) + + + def __init__(self, spi, *, auto_show=True): # noqa + self._spi = spi + # This device is just a big 28 byte long shift register without any + # fancy update protocol. Blast out all the bits to update, that's it! + self._shift_reg = bytearray(28) + # Keep track of automatically writing out the state of the PWM channels + # on any change (auto_show = True). If set to false the user must + # explicitly call the show method to write out the PWM state to the + # chip--this is useful for performing atomic updates to LEDs (i.e. + # changing all the R, G, B channels at once). + self.auto_show = auto_show + # Initialize the brightness channel values to max (these are 7-bit + # values). + self._bcr = 127 + self._bcg = 127 + self._bcb = 127 + # Initialize external user-facing state for the function control + # bits of the chip. These aren't commonly used but available and + # match the nomenclature from the datasheet. Note they won't honor + # the auto_show property and instead you must manually call show + # after changing them (reduces the need to make frivolous + # memory-hogging properties). + # Set OUTTMG, TMGRST, and DSPRPT to on like the Arduino library. + self.outtmg = True + self.extgclk = False + self.tmgrst = True + self.dsprpt = True + self.blank = False + + def _write(self): + # Write out the current state to the shift register. + try: + # Lock the SPI bus and configure it for the shift register. + while not self._spi.try_lock(): + pass + self._spi.configure(baudrate=10000000, polarity=0, phase=0) + # Update the preamble of chip state in the first 4 bytes (32-bits) + # with the write command, function control bits, and brightness + # control register values. + self._shift_reg[0] = 0x25 # 0x25 in top 6 bits initiates write. + # Lower two bits control OUTTMG and EXTGCLK bits, set them + # as appropriate. + self._shift_reg[0] = _shift_in(self._shift_reg[0], self.outtmg) + self._shift_reg[0] = _shift_in(self._shift_reg[0], self.extgclk) + # Next byte contains remaining function control state and start of + # brightness control bits. + self._shift_reg[1] = 0x00 + self._shift_reg[1] = _shift_in(self._shift_reg[1], self.tmgrst) + self._shift_reg[1] = _shift_in(self._shift_reg[1], self.dsprpt) + self._shift_reg[1] = _shift_in(self._shift_reg[1], self.blank) + # Top 5 bits from BC blue channel. + self._shift_reg[1] <<= 5 + self._shift_reg[1] |= (self._bcb >> 2) & 0b11111 + # Next byte contains lower 2 bits from BC blue channel and upper 6 + # from BC green channel. + self._shift_reg[2] = (self._bcb) & 0b11 + self._shift_reg[2] <<= 6 + self._shift_reg[2] |= (self._bcg >> 1) & 0b111111 + # Final byte contains lower 1 bit from BC green and 7 bits from BC + # red channel. + self._shift_reg[3] = self._bcg & 0b1 + self._shift_reg[3] <<= 7 + self._shift_reg[3] |= self._bcr & 0b1111111 + # The remaining bytes in the shift register are the channel PWM + # values that have already been set by the user. Now write out the + # the entire set of bytes. Note there is no latch or other + # explicit line to tell the chip when finished, it expects 28 bytes. + self._spi.write(self._shift_reg) + finally: + # Ensure the SPI bus is unlocked. + self._spi.unlock() + + def show(self): + """Write out the current LED PWM state to the chip. This is only necessary if + auto_show was set to false in the initializer. + """ + self._write() + + # Define properties for global brightness control channels. + @property + def red_brightness(self): + """The red brightness for all channels (i.e. R0, R1, R2, and R3). + + This is a 7-bit value from 0-127. + """ + return self._bcr + + @red_brightness.setter + def red_brightness(self, val): + assert 0 <= val <= 127 + self._bcr = val + if self.auto_show: + self._write() + + @property + def green_brightness(self): + """The green brightness for all channels (i.e. G0, G1, G2, and G3). + + This is a 7-bit value from 0-127. + """ + return self._bcg + + @green_brightness.setter + def green_brightness(self, val): + assert 0 <= val <= 127 + self._bcg = val + if self.auto_show: + self._write() + + @property + def blue_brightness(self): + """The blue brightness for all channels (i.e. B0, B1, B2, and B3). + + This is a 7-bit value from 0-127. + """ + return self._bcb + + @blue_brightness.setter + def blue_brightness(self, val): + assert 0 <= val <= 127 + self._bcb = val + if self.auto_show: + self._write() + + # Define index and length properties to set and get each channel as + # atomic RGB tuples. This provides a similar feel as using neopixels. + def __len__(self): + """Retrieve the total number of LED channels available.""" + return 4 # Always 4 RGB channels on the chip. + + def __getitem__(self, key): + # pylint: disable=no-else-return + # Disable should be removed when refactor can be tested + """Retrieve the R, G, B values for the provided channel as a + 3-tuple. Each value is a 16-bit number from 0-65535. + """ + if key == 0: + return (self.r0, self.g0, self.b0) + elif key == 1: + return (self.r1, self.g1, self.b1) + elif key == 2: + return (self.r2, self.g2, self.b2) + elif key == 3: + return (self.r3, self.g3, self.b3) + else: + raise IndexError + + def __setitem__(self, key, val): + """Set the R, G, B values for the provided channel. Specify a + 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). + """ + # Do this check here instead of later to + # prevent accidentally keeping auto_show + # turned off when a bad key is provided. + assert 0 <= key <= 3 + + assert len(val) == 3 + assert 0 <= val[0] <= 65535 + assert 0 <= val[1] <= 65535 + assert 0 <= val[2] <= 65535 + # Temporarily halt auto write to perform an atomic update of all + # the channel values. + old_auto_show = self.auto_show + self.auto_show = False + # Update appropriate channel values. + if key == 0: + self.r0, self.g0, self.b0 = val + elif key == 1: + self.r1, self.g1, self.b1 = val + elif key == 2: + self.r2, self.g2, self.b2 = val + elif key == 3: + self.r3, self.g3, self.b3 = val + # Restore auto_show state. + self.auto_show = old_auto_show + # Write out new values if in auto_show state. + if self.auto_show: + self._write() diff --git a/adafruit_tlc59711_multi.py b/adafruit_tlc59711_multi.py deleted file mode 100644 index b545429..0000000 --- a/adafruit_tlc59711_multi.py +++ /dev/null @@ -1,967 +0,0 @@ - -# The MIT License (MIT). -# -# Copyright (c) 2017 Tony DiCola for Adafruit Industries -# Copyright (c) 2018 Stefan Krüger s-light.eu -# -# 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. - -""" -`adafruit_tlc59711_multi`. - -==================================================== - -CircuitPython module for the -TLC59711 or TLC5971 16-bit 12 channel LED PWM driver. -See examples/simpletest_multi.py for a demo of the usage. - -* Author(s): Tony DiCola, Stefan Kruger - -Implementation Notes --------------------- - -**Hardware:** - -* Adafruit `12-Channel 16-bit PWM LED Driver - SPI Interface - TLC59711 - `_ (Product ID: 1455) - or TLC5971 - -**Software and Dependencies:** - -* this is a variant with multi-chip support. - The API is mostly compatible to the DotStar / NeoPixel Libraries - and is therefore also compatible with FancyLED. - for this see examples/fancy_multi.py - -* Adafruit CircuitPython firmware for the ESP8622, M0 or M4-based boards: - https://github.com/adafruit/circuitpython/releases -""" -__version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" - - -# Globally disable invalid-name check as this chip by design has short channel -# and register names. It is confusing to rename these from what the datasheet -# refers to them as. -# pylint: disable=invalid-name - -import struct - -from micropython import const - - -class TLC59711Multi: - """Multi TLC59711 16-bit 12 channel LED PWM driver. - - This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. - The class has an interface compatible with the FancyLED library. - and with this is similar to the NeoPixel and DotStar Interfaces. - - :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. - The clock and MOSI/outout must be set, the MISO/input is unused. - Maximal data clock frequence is: - - TLC59711: 10MHz - - TLC5971: 20MHz - :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. - """ - - # pylint: disable=too-many-instance-attributes - # it just does make senes to have the chip params as attributes. - - # """ - # TLC5971 data / register structure - # - # some detailed information on the protocol based on - # http://www.ti.com/lit/ds/symlink/tlc5971.pdf - # 8.5.4 Register and Data Latch Configuration (page 23ff) - # 9.2.2.3 How to Control the TLC5971 (page27) - # - # How to send: - # the first data we send are received by the last device in chain. - # Device Nth (244Bit = 28Byte) - # Write Command (6Bit) - # WRCMD (fixed: 25h) - # Function Control Data (5 x 1Bit = 5Bit) - # OUTTMG 1bit - # GS clock edge select - # 1=rising edge, 0= falling edge - # EXTGCK 1bit - # GS reference clock select - # 1=SCKI clock, 0=internal oscillator - # TMGRST 1bit - # display timing reset mode - # 1=OUT forced of on latchpulse, 0=no forced reset - # DSPRPT 1bit - # display repeat mode - # 1=auto repeate - # 0=Out only turned on after Blank or internal latchpulse - # BLANK 1bit; - # 1=blank (outputs off) - # 0=Out on - controlled by GS-Data - # ic power on sets this to 1 - # BC-Data (3 x 7Bits = 21Bit) - # BCB 7bit; - # BCG 7bit; - # BCR 7bit; - # GS-Data (12 x 16Bits = 192Bit) - # GSB3 16bit; - # GSG3 16bit; - # GSR3 16bit; - # GSB2 16bit; - # GSG2 16bit; - # GSR2 16bit; - # GSB1 16bit; - # GSG1 16bit; - # GSR1 16bit; - # GSB0 16bit; - # GSG0 16bit; - # GSR0 16bit; - # Device Nth-1 (244Bit = 28Byte) - # Device .. - # Device 2 - # Device 1 - # short break of 8x period of clock (666ns .. 2.74ms) - # to generate latchpulse - # + 1.34uS - # than next update. - # """ - - ########################################## - # helper - ########################################## - - # pylama:ignore=E0602 - # ugly workaround for pylama not knowing of micropython const thing - _CHIP_BUFFER_BYTE_COUNT = const(28) - - COLORS_PER_PIXEL = const(3) - PIXEL_PER_CHIP = const(4) - CHANNEL_PER_CHIP = const(COLORS_PER_PIXEL * PIXEL_PER_CHIP) - - _BUFFER_BYTES_PER_COLOR = const(2) - _BUFFER_BYTES_PER_PIXEL = const(_BUFFER_BYTES_PER_COLOR * COLORS_PER_PIXEL) - - # @staticmethod - # def set_bit_with_mask(v, mask, x): - # """Set bit with help of mask.""" - # # clear - # v &= ~mask - # if x: - # # set - # v |= mask - # return v - # - # @staticmethod - # def set_bit(v, index, x): - # """Set bit - return new value. - # - # Set the index:th bit of v to 1 if x is truthy, - # else to 0, and return the new value. - # https://stackoverflow.com/a/12174051/574981 - # """ - # # Compute mask, an integer with just bit 'index' set. - # mask = 1 << index - # # Clear the bit indicated by the mask (if x is False) - # v &= ~mask - # if x: - # # If x was True, set the bit indicated by the mask. - # v |= mask - # # Return the result, we're done. - # return v - - ########################################## - # class _BC(): - # BC-Data (3 x 7Bits = 21Bit). - # - # BCB 7bit; - # BCG 7bit; - # BCR 7bit; - _BC_CHIP_BUFFER_BIT_OFFSET = const(0) - _BC_BIT_COUNT = const(3 * 7) - # this holds the chip offset and - _BC_FIELDS = { - "BCR": { - "offset": 0, - "length": 7, - "mask": 0b01111111, - }, - "BCG": { - "offset": 7, - "length": 7, - "mask": 0b01111111, - }, - "BCB": { - "offset": 14, - "length": 7, - "mask": 0b01111111, - }, - } - - ########################################## - # class _FC(): - # """ - # Function Control Data (5 x 1Bit = 5Bit). - # - # OUTTMG 1bit - # GS clock edge select - # 1 = rising edge - # 0 = falling edge - # EXTGCK 1bit - # GS reference clock select - # 1 = SCKI clock - # 0 = internal oscillator - # TMGRST 1bit - # display timing reset mode - # 1 = OUT forced of on latchpulse - # 0 = no forced reset - # DSPRPT 1bit - # display repeat mode - # 1 = auto repeate - # 0 = Out only turned on after Blank or internal latchpulse - # BLANK 1bit; - # ic power on sets this to 1 - # 1 = blank (outputs off) - # 0 = Out on - controlled by GS-Data - # """ - - _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) - _FC_BIT_COUNT = const(5) - _FC_FIELDS = { - "BLANK": { - "offset": 0, - "length": 1, - "mask": 0b1, - }, - "DSPRPT": { - "offset": 1, - "length": 1, - "mask": 0b1, - }, - "TMGRST": { - "offset": 2, - "length": 1, - "mask": 0b1, - }, - "EXTGCK": { - "offset": 3, - "length": 1, - "mask": 0b1, - }, - "OUTTMG": { - "offset": 4, - "length": 1, - "mask": 0b1, - }, - } - - ########################################## - # class _WRITE_COMMAND(): - # """WRITE_COMMAND.""" - - _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) - _WC_BIT_COUNT = const(6) - _WC_FIELDS = { - "WRITE_COMMAND": { - "offset": 0, - "length": 6, - "mask": 0b111111, - }, - } - WRITE_COMMAND = const(0b100101) - ########################################## - - ######## - _CHIP_BUFFER_HEADER_BIT_COUNT = const( - _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT) - _CHIP_BUFFER_HEADER_BYTE_COUNT = const(_CHIP_BUFFER_HEADER_BIT_COUNT // 8) - - ########################################## - - def __init__(self, spi, pixel_count=4): - """Init.""" - self._spi = spi - # how many pixels are there? - self.pixel_count = pixel_count - self.channel_count = self.pixel_count * self.COLORS_PER_PIXEL - # calculate how many chips are connected - self.chip_count = self.pixel_count // 4 - - # The chips are just a big 28 byte long shift register without any - # fancy update protocol. Blast out all the bits to update, that's it! - # create raw output data - self._buffer = bytearray(_CHIP_BUFFER_BYTE_COUNT * self.chip_count) - - # Initialize the brightness channel values to max - # (these are 7-bit values). - self.bcr = 127 - self.bcg = 127 - self.bcb = 127 - - # Initialize external user-facing state for the function control - # bits of the chip. These aren't commonly used but available and - # match the nomenclature from the datasheet. - # you must manually call update_fc() after changing them - # (reduces the need to make frivolous memory-hogging properties). - # Default set - # OUTTMG, TMGRST, and DSPRPT to on - # like in Arduino library. - # these are set for all chips - self.outtmg = True - self.extgck = False - self.tmgrst = True - self.dsprpt = True - self.blank = False - - # self._buf32_format = struct.Struct('>I') - # self._buf16_format = struct.Struct('>H') - - # preparation done - # now initialize buffer to default values - self._init_buffer() - - self._buffer_index_lookuptable = [] - self._init_lookuptable() - - def _init_buffer(self): - for chip_index in range(self.chip_count): - # set Write Command (6Bit) WRCMD (fixed: 25h) - self.chip_set_BCData( - chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) - self._chip_set_FunctionControl(chip_index) - self._chip_set_WriteCommand(chip_index) - # loop end - - def set_chipheader_bits_in_buffer( - self, - *, - chip_index=0, - part_bit_offset=0, - field={"mask": 0, "length": 0, "offset": 0}, - value=0 - ): - """Set chip header bits in buffer.""" - offset = part_bit_offset + field["offset"] - # restrict value - value &= field["mask"] - # move value to position - value = value << offset - # calculate header start - header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT - # get chip header - header = struct.unpack_from('>I', self._buffer, header_start)[0] - # 0xFFFFFFFF == 0b11111111111111111111111111111111 - # create/move mask - mask = field["mask"] << offset - # clear - header &= (~mask) - # set - header |= value - # write header back - struct.pack_into('>I', self._buffer, header_start, header) - - ########################################## - - def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): - """ - Set BC-Data. - - :param int chip_index: Index of Chip to set. - :param int bcr: 7-bit value from 0-127 (default=127) - :param int bcg: 7-bit value from 0-127 (default=127) - :param int bcb: 7-bit value from 0-127 (default=127) - """ - # set all bits - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCR"], - value=bcr) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCG"], - value=bcg) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, - field=self._BC_FIELDS["BCB"], - value=bcb) - - def update_BCData(self): - """ - Update BC-Data for all Chips in Buffer. - - need to be called after you changed on of the - BC-Data Parameters. (bcr, bcg, bcb) - """ - for chip_index in range(self.chip_count): - self.chip_set_BCData( - chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) - - def _chip_set_FunctionControl(self, chip_index): - """ - Set Function Control Bits in Buffer. - - values from object global parameters are used. - - :param int chip_index: Index of Chip to set. - """ - # set all bits - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, - field=self._FC_FIELDS["OUTTMG"], - value=self.outtmg) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, - field=self._FC_FIELDS["EXTGCK"], - value=self.extgck) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, - field=self._FC_FIELDS["TMGRST"], - value=self.tmgrst) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, - field=self._FC_FIELDS["DSPRPT"], - value=self.dsprpt) - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, - field=self._FC_FIELDS["BLANK"], - value=self.blank) - - def update_fc(self): - """ - Update Function Control Bits for all Chips in Buffer. - - need to be called after you changed on of the - Function Control Bit Parameters. - (outtmg, extgck, tmgrst, dsprpt, blank) - """ - for chip_index in range(self.chip_count): - self._chip_set_FunctionControl(chip_index) - - def _chip_set_WriteCommand(self, chip_index): - """Set WRITE_COMMAND.""" - # set all bits - self.set_chipheader_bits_in_buffer( - chip_index=chip_index, - part_bit_offset=_WC_CHIP_BUFFER_BIT_OFFSET, - field=self._WC_FIELDS["WRITE_COMMAND"], - value=self.WRITE_COMMAND) - - def _init_lookuptable(self): - for channel_index in range(self.channel_count): - buffer_index = ( - (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) - * (channel_index // self.CHANNEL_PER_CHIP) - + channel_index % self.CHANNEL_PER_CHIP) - buffer_index *= _BUFFER_BYTES_PER_COLOR - buffer_index += _CHIP_BUFFER_HEADER_BYTE_COUNT - self._buffer_index_lookuptable.append(buffer_index) - - ########################################## - - def _write(self): - # Write out the current state to the shift register. - try: - # Lock the SPI bus and configure it for the shift register. - while not self._spi.try_lock(): - pass - self._spi.configure(baudrate=10000000, polarity=0, phase=0) - self._spi.write(self._buffer) - finally: - # Ensure the SPI bus is unlocked. - self._spi.unlock() - - def show(self): - """Write out the current LED PWM state to the chip.""" - self._write() - - ########################################## - - @staticmethod - def calculate_Ioclmax(*, Riref=2.48): - """ - Calculate Maximum Constant Sink Current Value. - - see: - 8.4.1 Maximum Constant Sink Current Setting - http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=18&zoom=160,0,524 - - Riref = (Viref / Ioclmax) * 41 - Ioclmax = (41 / Riref) * Viref - - :param float Riref: resistor value (kΩ) (default=20) - :return tuple: Ioclmax (mA) - """ - # Riref = (Viref / Ioclmax) * 41 | / 41 - # Riref / 41 = Viref / Ioclmax | switch - # 41 / Riref = Ioclmax / Viref | * Viref - # (41 / Riref) * Viref = Ioclmax - if not 0.8 <= Riref <= 24.8: - raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) - Viref = 1.21 - Ioclmax = (41 / Riref) * Viref - if not 2.0 <= Ioclmax <= 60.0: - raise ValueError( - "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) - return Ioclmax - - @staticmethod - def calculate_Riref(*, Ioclmax=20): - """ - Calculate Maximum Constant Sink Current Value. - - see: - 8.4.1 Maximum Constant Sink Current Setting - http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 - - Riref = (Viref / Ioclmax) * 41 - - :param float Ioclmax: target max output current (mA) (default=20) - :return tuple: Riref (kΩ) - """ - if not 2.0 <= Ioclmax <= 60.0: - raise ValueError( - "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) - Viref = 1.21 - Riref = (Viref / Ioclmax) * 41 - if not 0.8 <= Riref <= 24.8: - raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) - return Riref - - @staticmethod - def calculate_BCData(*, Ioclmax=18, IoutR=17, IoutG=15, IoutB=9): - """ - Calculate Global Brightness Control Values. - - see: - 8.5.1 Global Brightness Control (BC) Function (Sink Current Control) - http://www.ti.com/lit/ds/symlink/tlc5971.pdf#page=19&zoom=200,0,697 - - Iout = Ioclmax * (BCX / 127) - BCX = Iout / Ioclmax * 127 - - :param float Ioclmax: max output current set by Riref (mA) (default=20) - :param float IoutR: max output current for red color group (mA) - (default=9) - :param float IoutG: max output current for green color (mA) - (default=15) - :param float IoutB: max output current for blue color (mA) - (default=17) - :return tuple: (bcr, bcg, bcb) - """ - # Iout = Ioclmax * (BCX / 127) | / Ioclmax - # Iout / Ioclmax = BCX / 127 | * 127 - # Iout / Ioclmax * 127 = BCX - if not 2.0 <= Ioclmax <= 60.0: - raise ValueError("Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax)) - if not 0.0 <= IoutR <= Ioclmax: - raise ValueError( - "IoutR {} not in range: 2mA..{}mA".format(IoutR, Ioclmax)) - if not 0.0 <= IoutG <= Ioclmax: - raise ValueError( - "IoutG {} not in range: 2mA..{}mA".format(IoutG, Ioclmax)) - if not 0.0 <= IoutB <= Ioclmax: - raise ValueError( - "IoutB {} not in range: 2mA..{}mA".format(IoutB, Ioclmax)) - bcr = int((IoutR / Ioclmax) * 127) - bcg = int((IoutG / Ioclmax) * 127) - bcb = int((IoutB / Ioclmax) * 127) - if not 0 <= bcr <= 127: - raise ValueError("bcr {} not in range: 0..127".format(bcr)) - if not 0 <= bcg <= 127: - raise ValueError("bcg {} not in range: 0..127".format(bcg)) - if not 0 <= bcb <= 127: - raise ValueError("bcb {} not in range: 0..127".format(bcb)) - return (bcr, bcg, bcb) - - ########################################## - - @staticmethod - def _convert_01_float_to_16bit_integer(value): - """Convert 0..1 Float Value to 16bit (0..65535) Range.""" - # check if value is in range - if not 0.0 <= value[0] <= 1.0: - raise ValueError("value[0] {} not in range: 0..1".format(value[0])) - # convert to 16bit value - return int(value * 65535) - - @classmethod - def _convert_if_float(cls, value): - """Convert if value is Float.""" - if isinstance(value, float): - value = cls._convert_01_float_to_16bit_integer(value) - return value - - @staticmethod - def _check_and_convert(value): - # loop - # mega slow - # for i, val in enumerate(value): - # # check if we have float values - # if isinstance(val, float): - # # check if val is in range - # if not 0.0 <= val <= 1.0: - # raise ValueError( - # "value[{}] {} not in range: 0..1".format(i, val)) - # # convert to 16bit val - # value[i] = int(val * 65535) - # else: - # if not 0 <= val <= 65535: - # raise ValueError( - # "value[{}] {} not in range: 0..65535".format(i, val)) - # discreet is way faster - # (compared with tlc59711_multi_dev.py: pixels.set_all_black()) - # check if we have float values - if isinstance(value[0], float): - # check if value is in range - if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1".format(value[0])) - # convert to 16bit value - value[0] = int(value[0] * 65535) - else: - if not 0 <= value[0] <= 65535: - raise ValueError( - "value[0] {} not in range: 0..65535".format(value[0])) - if isinstance(value[1], float): - if not 0.0 <= value[1] <= 1.0: - raise ValueError( - "value[1] {} not in range: 0..1".format(value[1])) - value[1] = int(value[1] * 65535) - else: - if not 0 <= value[1] <= 65535: - raise ValueError( - "value[1] {} not in range: 0..65535".format(value[1])) - if isinstance(value[2], float): - if not 0.0 <= value[2] <= 1.0: - raise ValueError( - "value[2] {} not in range: 0..1".format(value[2])) - value[2] = int(value[2] * 65535) - else: - if not 0 <= value[2] <= 65535: - raise ValueError( - "value[2] {} not in range: 0..65535".format(value[2])) - - ########################################## - - def _get_channel_16bit_value(self, channel_index): - buffer_start = self._buffer_index_lookuptable[channel_index] - return struct.unpack_from('>H', self._buffer, buffer_start)[0] - - def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): - """ - Set the value for pixel. - - This is a Fast UNPROTECTED function: - no error / range checking is done. - - :param int pixel_index: 0..(pixel_count) - :param int value_r: 0..65535 - :param int value_g: 0..65535 - :param int value_b: 0..65535 - """ - # optimized for speed. - # the struct version leads to very slow runtime behaivor if you set - # lots of pixels. that is the reason the discreet version is used. - # you can check with the tlc59711_multi_dev.py file. - # most prominent this is visible at the set_pixel_all_16bit_value func: - # struct 157ms to 16ms (@144pixel on ItsyBitsy M4) - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - # struct.pack_into('>H', self._buffer, buffer_start, value_b) - self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_b & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - # struct.pack_into('>H', self._buffer, buffer_start, value_g) - self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_g & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - # struct.pack_into('>H', self._buffer, buffer_start, value_r) - self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_r & 0xFF - - def set_pixel_float_value(self, pixel_index, value_r, value_g, value_b): - """ - Set the value for pixel. - - This is a Fast UNPROTECTED function: - no error / range checking is done. - - :param int pixel_index: 0..(pixel_count) - :param int value_r: 0..1 - :param int value_g: 0..1 - :param int value_b: 0..1 - """ - # self.set_pixel_16bit_value( - # pixel_index, - # int(value_r * 65535), - # int(value_g * 65535), - # int(value_b * 65535) - # ) - # this is again a speed optimized version: - # this cuts down from 228ms to 22ms (@144pixel on ItsyBitsy M4) - value_r = int(value_r * 65535) - value_g = int(value_g * 65535) - value_b = int(value_b * 65535) - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (value_b >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_b & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (value_g >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_g & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (value_r >> 8) & 0xFF - self._buffer[buffer_start + 1] = value_r & 0xFF - - def set_pixel_16bit_color(self, pixel_index, color): - """ - Set color for pixel. - - This is a Fast UNPROTECTED function: - no error / range checking is done. - its a little bit slower as `set_pixel_16bit_value` - - :param int pixel_index: 0..(pixel_count) - :param int color: 3-tuple of R, G, B; 0..65535 - """ - # self.set_pixel_16bit_value( - # pixel_index, - # color[0], - # color[1], - # color[2] - # ) - # speed optimization: 140ms to 24ms (@144pixel on ItsyBitsy M4) - # the `color = list(color)` is the key here! (don't ask me why..) - color = list(color) - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[2] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[1] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[0] & 0xFF - - def set_pixel_float_color(self, pixel_index, color): - """ - Set color for pixel. - - This is a Fast UNPROTECTED function: - no error / range checking is done. - its a little bit slower as `set_pixel_16bit_value` - - :param int pixel_index: 0..(pixel_count) - :param tuple/float color: 3-tuple of R, G, B; 0..1 - """ - # self.set_pixel_16bit_value( - # pixel_index, - # int(color[0] * 65535), - # int(color[1] * 65535), - # int(color[2] * 65535) - # ) - # speed optimization: 140ms to 30ms (@144pixel on ItsyBitsy M4) - color = list(color) - color[0] = int(color[0] * 65535) - color[1] = int(color[1] * 65535) - color[2] = int(color[2] * 65535) - pixel_start = pixel_index * self.COLORS_PER_PIXEL - buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - self._buffer[buffer_start + 0] = (color[2] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[2] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - self._buffer[buffer_start + 0] = (color[1] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[1] & 0xFF - buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - self._buffer[buffer_start + 0] = (color[0] >> 8) & 0xFF - self._buffer[buffer_start + 1] = color[0] & 0xFF - - def set_pixel(self, pixel_index, value): - """ - Set the R, G, B values for the pixel. - - this funciton hase some advanced error checking. - it is much slower than the other provided 'bare' variants.. - but therefor gives clues to what is going wrong.. ;-) - - :param int pixel_index: 0..(pixel_count) - :param tuple value: 3-tuple of R, G, B; - each int 0..65535 or float 0..1 - """ - if 0 <= pixel_index < self.pixel_count: - # convert to list - value = list(value) - # repr(value) - if len(value) != self.COLORS_PER_PIXEL: - raise IndexError( - "length of value {} does not match COLORS_PER_PIXEL (= {})" - "".format(len(value), self.COLORS_PER_PIXEL) - ) - # tested: - # splitting up into variables to not need the list.. - # this is about 0.25ms slower.. - # value_r = value[0] - # value_g = value[1] - # value_b = value[2] - - # check if we have float values - # this modifies 'value' in place.. - self._check_and_convert(value) - - # update buffer - # we change channel order here: - # buffer channel order is blue, green, red - # pixel_start = pixel_index * self.COLORS_PER_PIXEL - # buffer_start = self._buffer_index_lookuptable[pixel_start + 0] - # self._buffer[buffer_start + 0] = (value[2] >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value[2] & 0xFF - # buffer_start = self._buffer_index_lookuptable[pixel_start + 1] - # self._buffer[buffer_start + 0] = (value[1] >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value[1] & 0xFF - # buffer_start = self._buffer_index_lookuptable[pixel_start + 2] - # self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF - # self._buffer[buffer_start + 1] = value[0] & 0xFF - # simpliefy code - self.set_pixel_16bit_value( - pixel_index, value[0], value[1], value[2]) - else: - raise IndexError( - "index {} out of range [0..{}]" - "".format(pixel_index, self.pixel_count)) - - def set_pixel_all_16bit_value(self, value_r, value_g, value_b): - """ - Set the R, G, B values for all pixels. - - fast. without error checking. - - :param int value_r: 0..65535 - :param int value_g: 0..65535 - :param int value_b: 0..65535 - """ - for i in range(self.pixel_count): - self.set_pixel_16bit_value(i, value_r, value_g, value_b) - - def set_pixel_all(self, color): - """ - Set the R, G, B values for all pixels. - - :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 - """ - for i in range(self.pixel_count): - self.set_pixel(i, color) - - def set_all_black(self): - """Set all pixels to black.""" - for i in range(self.pixel_count): - self.set_pixel_16bit_value(i, 0, 0, 0) - - # channel access - def set_channel(self, channel_index, value): - """ - Set the value for the provided channel. - - :param int channel_index: 0..channel_count - :param int value: 0..65535 - """ - if 0 <= channel_index < (self.channel_count): - # check if values are in range - if not 0 <= value <= 65535: - raise ValueError("value {} not in range: 0..65535") - # temp = channel_index - # we change channel order here: - # buffer channel order is blue, green, red - pixel_index_offset = channel_index % self.COLORS_PER_PIXEL - if pixel_index_offset == 0: - channel_index += 2 - elif pixel_index_offset == 2: - channel_index -= 2 - # set value in buffer - buffer_start = self._buffer_index_lookuptable[channel_index] - struct.pack_into('>H', self._buffer, buffer_start, value) - else: - raise IndexError( - "channel_index {} out of range (0..{})" - .format(channel_index, self.channel_count)) - - # Define index and length properties to set and get each pixel as - # atomic RGB tuples. This provides a similar feel as using neopixels. - def __len__(self): - """Retrieve TLC5975 the total number of Pixels available.""" - return self.pixel_count - - def __getitem__(self, key): - """ - Retrieve the R, G, B values for the provided channel as a 3-tuple. - - Each value is a 16-bit number from 0-65535. - """ - if 0 <= key < self.pixel_count: - pixel_start = key * self.COLORS_PER_PIXEL - return ( - self._get_channel_16bit_value(pixel_start + 0), - self._get_channel_16bit_value(pixel_start + 1), - self._get_channel_16bit_value(pixel_start + 2) - ) - # else: - raise IndexError( - "index {} out of range [0..{}]".format(key, self.pixel_count)) - - def __setitem__(self, key, value): - """ - Set the R, G, B values for the pixel. - - this funciton hase some advanced error checking. - it is much slower than the other provided 'bare' variants.. - but therefor gives clues to what is going wrong.. ;-) - this shortcut is identicall to `set_pixel` - - :param int key: 0..(pixel_count) - :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 - """ - # for a more detailed version with all the debugging code and - # comments look at set_pixel - if 0 <= key < self.pixel_count: - value = list(value) - if len(value) != self.COLORS_PER_PIXEL: - raise IndexError( - "length of value {} does not match COLORS_PER_PIXEL (= {})" - "".format(len(value), self.COLORS_PER_PIXEL) - ) - # _check_and_convert modifies value in place.. - self._check_and_convert(value) - self.set_pixel_16bit_value(key, value[0], value[1], value[2]) - else: - raise IndexError( - "index {} out of range [0..{}]" - "".format(key, self.pixel_count) - ) - -########################################## From 8c8069844f9e189784e7848676e1310b033491cf Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 11 Sep 2020 22:27:57 +0200 Subject: [PATCH 65/91] add backwards compatibility class --- adafruit_tlc59711.py | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index f01b1db..ed26bc4 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -65,6 +65,7 @@ from micropython import const + class TLC59711Multi: """Multi TLC59711 16-bit 12 channel LED PWM driver. @@ -964,3 +965,110 @@ def __setitem__(self, key, value): ) ########################################## + + +class TLC59711(TLC59711Multi): + """Multi TLC59711 16-bit 12 channel LED PWM driver. + + This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. + The class has an interface compatible with the FancyLED library. + and with this is similar to the NeoPixel and DotStar Interfaces. + + this TLC59711 is a subclass of TLC59711Multi. + just for compatiblility. + here maybee some of the original API will get implemented + + :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. + The clock and MOSI/outout must be set, the MISO/input is unused. + Maximal data clock frequence is: + - TLC59711: 10MHz + - TLC5971: 20MHz + :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. + """ + + class _ChannelDirekt: + # Internal decorator to simplify mapping. + + def __init__(self, channel): + self._channel = channel + + def __get__(self, obj, obj_type): + # Grab the 16-bit value at the offset for this channel. + return obj._get_channel_16bit_value(self._channel) + + def __set__(self, obj, value): + # Set the 16-bit value at the offset for this channel. + assert 0 <= value <= 65535 + obj._set_channel_16bit_value(self._channel, value) + # Write out the new values if auto_show is enabled. + # if obj.auto_show: + # obj._write() + + # Define explicit channels for first IC. + # this is only for api backwards compliance. + b0 = _ChannelDirekt(0) + g0 = _ChannelDirekt(1) + r0 = _ChannelDirekt(2) + + b1 = _ChannelDirekt(3) + g1 = _ChannelDirekt(4) + r1 = _ChannelDirekt(5) + + b2 = _ChannelDirekt(6) + g2 = _ChannelDirekt(7) + r2 = _ChannelDirekt(8) + + b3 = _ChannelDirekt(9) + g3 = _ChannelDirekt(10) + r3 = _ChannelDirekt(11) + + def __init__(self, spi, pixel_count=4): + """Init.""" + super(TLC59711, self).__init__(spi, pixel_count=pixel_count) + + # old stuff... + # i think it is good to leave this out. + # @property + # def red_brightness(self): + # """The red brightness for all channels (i.e. R0, R1, R2, and R3). + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcr + # + # @red_brightness.setter + # def red_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcr = val + # if self.auto_show: + # self._write() + # + # @property + # def green_brightness(self): + # """The green brightness for all channels (i.e. G0, G1, G2, and G3). + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcg + # + # @green_brightness.setter + # def green_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcg = val + # if self.auto_show: + # self._write() + # + # @property + # def blue_brightness(self): + # """The blue brightness for all channels (i.e. B0, B1, B2, and B3). + # + # This is a 7-bit value from 0-127. + # """ + # return self._bcb + # + # @blue_brightness.setter + # def blue_brightness(self, val): + # assert 0 <= val <= 127 + # self._bcb = val + # if self.auto_show: + # self._write() From a55043726b3e80f7e2167d250350e160e8181d7f Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 11 Sep 2020 22:34:54 +0200 Subject: [PATCH 66/91] change example import syntax (not tested yet) --- examples/tlc59711_fastset.py | 7 +++---- examples/tlc59711_minimal.py | 5 ++--- examples/tlc59711_multi_dev.py | 12 ++++++------ examples/tlc59711_multi_powertest.py | 12 ++++++------ examples/tlc59711_multi_test_bcdata.py | 12 ++++++------ examples/tlc59711_simpletest.py | 2 ++ .../{tlc59711_onechip.py => tlc59711_singlechip.py} | 5 ++--- 7 files changed, 27 insertions(+), 28 deletions(-) rename examples/{tlc59711_onechip.py => tlc59711_singlechip.py} (88%) diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 1ab6b72..72bda65 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -15,15 +15,14 @@ import board import busio -# from adafruit_tlc59711.adafruit_tlc59711 import TLC59711 -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 ########################################## pixel_count = 16 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) ########################################## @@ -57,7 +56,7 @@ def test_main(): print(__doc__, end="") print(42 * '*') - bcvalues = TLC59711Multi.calculate_BCData( + bcvalues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=18, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_minimal.py b/examples/tlc59711_minimal.py index 2e94808..2de2b37 100644 --- a/examples/tlc59711_minimal.py +++ b/examples/tlc59711_minimal.py @@ -12,15 +12,14 @@ import board import busio -# import adafruit_tlc59711 -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) # Define the TLC59711 instance. -pixels = TLC59711Multi(spi, pixel_count=16) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=16) print("tlc59711_minimal.py") diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b00d39a..b09f67c 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -1,7 +1,7 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -TLC59711Multi development helper. +adafruit_tlc59711.TLC59711Multi development helper. this sketch contains a bunch of timing tests and other development helpers.. Enjoy the colors :-) @@ -12,14 +12,14 @@ import board import busio -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 ########################################## pixel_count = 16*1 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) ########################################## @@ -462,11 +462,11 @@ def test_BCData(): ) ) # calculate bc values - Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) print("Ioclmax = {}".format(Ioclmax)) - Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=Ioclmax, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_multi_powertest.py b/examples/tlc59711_multi_powertest.py index 1f37572..98072e4 100644 --- a/examples/tlc59711_multi_powertest.py +++ b/examples/tlc59711_multi_powertest.py @@ -13,14 +13,14 @@ import busio import supervisor -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 ########################################## pixel_count = 16*2 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) ########################################## @@ -44,7 +44,7 @@ def main_loop(): IoutB = float(IoutB) except ValueError as e: print("Exception: ", e) - BCValues = TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=Ioclmax, IoutR=IoutR, IoutG=IoutG, @@ -81,11 +81,11 @@ def test_main(): print("set pixel all to 100, 100, 100") pixels.set_pixel_all((5000, 5000, 5000)) # calculate bc values - Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) print("Ioclmax = {}".format(Ioclmax)) - Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=Ioclmax, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index affc484..c3c7258 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -13,14 +13,14 @@ import busio import supervisor -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 ########################################## pixel_count = 16*8 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) ########################################## @@ -44,7 +44,7 @@ def main_loop(): IoutB = float(IoutB) except ValueError as e: print("Exception: ", e) - BCValues = TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=Ioclmax, IoutR=IoutR, IoutG=IoutG, @@ -81,11 +81,11 @@ def test_main(): print("set pixel all to 100, 100, 100") pixels.set_pixel_all((5000, 5000, 5000)) # calculate bc values - Ioclmax = TLC59711Multi.calculate_Ioclmax(Riref=2.7) + Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) print("Ioclmax = {}".format(Ioclmax)) - Riref = TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=Ioclmax, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_simpletest.py b/examples/tlc59711_simpletest.py index 0c9157a..e6916b0 100644 --- a/examples/tlc59711_simpletest.py +++ b/examples/tlc59711_simpletest.py @@ -7,6 +7,8 @@ import adafruit_tlc59711 +# TODO: s-light fix removed things + # Define SPI bus connected to chip. You only need the clock and MOSI (output) # line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) diff --git a/examples/tlc59711_onechip.py b/examples/tlc59711_singlechip.py similarity index 88% rename from examples/tlc59711_onechip.py rename to examples/tlc59711_singlechip.py index 4fdd360..b7a293c 100644 --- a/examples/tlc59711_onechip.py +++ b/examples/tlc59711_singlechip.py @@ -12,15 +12,14 @@ import board import busio -# import adafruit_tlc59711 -from adafruit_tlc59711.adafruit_tlc59711_multi import TLC59711Multi +import adafruit_tlc59711 # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) # Define the TLC59711 instance with one TLC chip connected. -pixels = TLC59711Multi(spi) +pixels = adafruit_tlc59711.TLC59711Multi(spi) print("tlc59711_onechip.py") From bc69ef25b34cda85c7d1632999808e3329b693ad Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 11 Sep 2020 23:26:40 +0200 Subject: [PATCH 67/91] formating and linting --- adafruit_tlc59711.py | 132 +++++++-------- examples/tlc59711_fastset.py | 11 +- examples/tlc59711_multi_dev.py | 217 +++++++++++-------------- examples/tlc59711_multi_powertest.py | 10 +- examples/tlc59711_multi_test_bcdata.py | 10 +- examples/tlc59711_simpletest.py | 19 ++- examples/tlc59711_singlechip.py | 2 +- pylama.ini | 5 + 8 files changed, 191 insertions(+), 215 deletions(-) create mode 100644 pylama.ini diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 6b4fad3..b32ebe7 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -1,4 +1,3 @@ - # The MIT License (MIT). # # Copyright (c) 2017 Tony DiCola for Adafruit Industries @@ -302,8 +301,7 @@ class TLC59711Multi: ########################################## ######## - _CHIP_BUFFER_HEADER_BIT_COUNT = const( - _WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT) + _CHIP_BUFFER_HEADER_BIT_COUNT = const(_WC_BIT_COUNT + _FC_BIT_COUNT + _BC_BIT_COUNT) _CHIP_BUFFER_HEADER_BYTE_COUNT = const(_CHIP_BUFFER_HEADER_BIT_COUNT // 8) ########################################## @@ -356,21 +354,22 @@ def __init__(self, spi, *, pixel_count=4): def _init_buffer(self): for chip_index in range(self.chip_count): # set Write Command (6Bit) WRCMD (fixed: 25h) - self.chip_set_BCData( - chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) + self.chip_set_BCData(chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) self._chip_set_FunctionControl(chip_index) self._chip_set_WriteCommand(chip_index) # loop end def set_chipheader_bits_in_buffer( - self, - *, - chip_index=0, - part_bit_offset=0, - field={"mask": 0, "length": 0, "offset": 0}, - value=0 + self, + *, + chip_index=0, + part_bit_offset=0, + field=None, + value=0 ): """Set chip header bits in buffer.""" + if field is None: + field = {"mask": 0, "length": 0, "offset": 0} offset = part_bit_offset + field["offset"] # restrict value value &= field["mask"] @@ -379,16 +378,16 @@ def set_chipheader_bits_in_buffer( # calculate header start header_start = chip_index * _CHIP_BUFFER_BYTE_COUNT # get chip header - header = struct.unpack_from('>I', self._buffer, header_start)[0] + header = struct.unpack_from(">I", self._buffer, header_start)[0] # 0xFFFFFFFF == 0b11111111111111111111111111111111 # create/move mask mask = field["mask"] << offset # clear - header &= (~mask) + header &= ~mask # set header |= value # write header back - struct.pack_into('>I', self._buffer, header_start, header) + struct.pack_into(">I", self._buffer, header_start, header) ########################################## @@ -406,17 +405,20 @@ def chip_set_BCData(self, chip_index, bcr=127, bcg=127, bcb=127): chip_index=chip_index, part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCR"], - value=bcr) + value=bcr, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCG"], - value=bcg) + value=bcg, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_BC_CHIP_BUFFER_BIT_OFFSET, field=self._BC_FIELDS["BCB"], - value=bcb) + value=bcb, + ) def update_BCData(self): """ @@ -426,8 +428,7 @@ def update_BCData(self): BC-Data Parameters. (bcr, bcg, bcb) """ for chip_index in range(self.chip_count): - self.chip_set_BCData( - chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) + self.chip_set_BCData(chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) def _chip_set_FunctionControl(self, chip_index): """ @@ -442,27 +443,32 @@ def _chip_set_FunctionControl(self, chip_index): chip_index=chip_index, part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["OUTTMG"], - value=self.outtmg) + value=self.outtmg, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["EXTGCK"], - value=self.extgck) + value=self.extgck, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["TMGRST"], - value=self.tmgrst) + value=self.tmgrst, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["DSPRPT"], - value=self.dsprpt) + value=self.dsprpt, + ) self.set_chipheader_bits_in_buffer( chip_index=chip_index, part_bit_offset=_FC_CHIP_BUFFER_BIT_OFFSET, field=self._FC_FIELDS["BLANK"], - value=self.blank) + value=self.blank, + ) def update_fc(self): """ @@ -482,14 +488,14 @@ def _chip_set_WriteCommand(self, chip_index): chip_index=chip_index, part_bit_offset=_WC_CHIP_BUFFER_BIT_OFFSET, field=self._WC_FIELDS["WRITE_COMMAND"], - value=self.WRITE_COMMAND) + value=self.WRITE_COMMAND, + ) def _init_lookuptable(self): for channel_index in range(self.channel_count): - buffer_index = ( - (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) - * (channel_index // self.CHANNEL_PER_CHIP) - + channel_index % self.CHANNEL_PER_CHIP) + buffer_index = (_CHIP_BUFFER_BYTE_COUNT // _BUFFER_BYTES_PER_COLOR) * ( + channel_index // self.CHANNEL_PER_CHIP + ) + channel_index % self.CHANNEL_PER_CHIP buffer_index *= _BUFFER_BYTES_PER_COLOR buffer_index += _CHIP_BUFFER_HEADER_BYTE_COUNT self._buffer_index_lookuptable.append(buffer_index) @@ -534,13 +540,11 @@ def calculate_Ioclmax(*, Riref=2.48): # 41 / Riref = Ioclmax / Viref | * Viref # (41 / Riref) * Viref = Ioclmax if not 0.8 <= Riref <= 24.8: - raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) + raise ValueError("Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) Viref = 1.21 Ioclmax = (41 / Riref) * Viref if not 2.0 <= Ioclmax <= 60.0: - raise ValueError( - "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) + raise ValueError("Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) return Ioclmax @staticmethod @@ -558,13 +562,11 @@ def calculate_Riref(*, Ioclmax=20): :return tuple: Riref (kΩ) """ if not 2.0 <= Ioclmax <= 60.0: - raise ValueError( - "Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) + raise ValueError("Ioclmax {} not in range: 2mA..60mA".format(Ioclmax)) Viref = 1.21 Riref = (Viref / Ioclmax) * 41 if not 0.8 <= Riref <= 24.8: - raise ValueError( - "Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) + raise ValueError("Riref {} not in range: 0.8kΩ..25kΩ".format(Riref)) return Riref @staticmethod @@ -592,17 +594,13 @@ def calculate_BCData(*, Ioclmax=18, IoutR=17, IoutG=15, IoutB=9): # Iout / Ioclmax = BCX / 127 | * 127 # Iout / Ioclmax * 127 = BCX if not 2.0 <= Ioclmax <= 60.0: - raise ValueError("Ioclmax {} not in range: 2mA..60mA" - "".format(Ioclmax)) + raise ValueError("Ioclmax {} not in range: 2mA..60mA" "".format(Ioclmax)) if not 0.0 <= IoutR <= Ioclmax: - raise ValueError( - "IoutR {} not in range: 2mA..{}mA".format(IoutR, Ioclmax)) + raise ValueError("IoutR {} not in range: 2mA..{}mA".format(IoutR, Ioclmax)) if not 0.0 <= IoutG <= Ioclmax: - raise ValueError( - "IoutG {} not in range: 2mA..{}mA".format(IoutG, Ioclmax)) + raise ValueError("IoutG {} not in range: 2mA..{}mA".format(IoutG, Ioclmax)) if not 0.0 <= IoutB <= Ioclmax: - raise ValueError( - "IoutB {} not in range: 2mA..{}mA".format(IoutB, Ioclmax)) + raise ValueError("IoutB {} not in range: 2mA..{}mA".format(IoutB, Ioclmax)) bcr = int((IoutR / Ioclmax) * 127) bcg = int((IoutG / Ioclmax) * 127) bcb = int((IoutB / Ioclmax) * 127) @@ -655,38 +653,32 @@ def _check_and_convert(value): if isinstance(value[0], float): # check if value is in range if not 0.0 <= value[0] <= 1.0: - raise ValueError( - "value[0] {} not in range: 0..1".format(value[0])) + raise ValueError("value[0] {} not in range: 0..1".format(value[0])) # convert to 16bit value value[0] = int(value[0] * 65535) else: if not 0 <= value[0] <= 65535: - raise ValueError( - "value[0] {} not in range: 0..65535".format(value[0])) + raise ValueError("value[0] {} not in range: 0..65535".format(value[0])) if isinstance(value[1], float): if not 0.0 <= value[1] <= 1.0: - raise ValueError( - "value[1] {} not in range: 0..1".format(value[1])) + raise ValueError("value[1] {} not in range: 0..1".format(value[1])) value[1] = int(value[1] * 65535) else: if not 0 <= value[1] <= 65535: - raise ValueError( - "value[1] {} not in range: 0..65535".format(value[1])) + raise ValueError("value[1] {} not in range: 0..65535".format(value[1])) if isinstance(value[2], float): if not 0.0 <= value[2] <= 1.0: - raise ValueError( - "value[2] {} not in range: 0..1".format(value[2])) + raise ValueError("value[2] {} not in range: 0..1".format(value[2])) value[2] = int(value[2] * 65535) else: if not 0 <= value[2] <= 65535: - raise ValueError( - "value[2] {} not in range: 0..65535".format(value[2])) + raise ValueError("value[2] {} not in range: 0..65535".format(value[2])) ########################################## def _get_channel_16bit_value(self, channel_index): buffer_start = self._buffer_index_lookuptable[channel_index] - return struct.unpack_from('>H', self._buffer, buffer_start)[0] + return struct.unpack_from(">H", self._buffer, buffer_start)[0] def set_pixel_16bit_value(self, pixel_index, value_r, value_g, value_b): """ @@ -864,12 +856,11 @@ def set_pixel(self, pixel_index, value): # self._buffer[buffer_start + 0] = (value[0] >> 8) & 0xFF # self._buffer[buffer_start + 1] = value[0] & 0xFF # simpliefy code - self.set_pixel_16bit_value( - pixel_index, value[0], value[1], value[2]) + self.set_pixel_16bit_value(pixel_index, value[0], value[1], value[2]) else: raise IndexError( - "index {} out of range [0..{}]" - "".format(pixel_index, self.pixel_count)) + "index {} out of range [0..{}]" "".format(pixel_index, self.pixel_count) + ) def set_pixel_all_16bit_value(self, value_r, value_g, value_b): """ @@ -920,11 +911,13 @@ def set_channel(self, channel_index, value): channel_index -= 2 # set value in buffer buffer_start = self._buffer_index_lookuptable[channel_index] - struct.pack_into('>H', self._buffer, buffer_start, value) + struct.pack_into(">H", self._buffer, buffer_start, value) else: raise IndexError( - "channel_index {} out of range (0..{})" - .format(channel_index, self.channel_count)) + "channel_index {} out of range (0..{})".format( + channel_index, self.channel_count + ) + ) # Define index and length properties to set and get each pixel as # atomic RGB tuples. This provides a similar feel as using neopixels. @@ -943,11 +936,10 @@ def __getitem__(self, key): return ( self._get_channel_16bit_value(pixel_start + 0), self._get_channel_16bit_value(pixel_start + 1), - self._get_channel_16bit_value(pixel_start + 2) + self._get_channel_16bit_value(pixel_start + 2), ) # else: - raise IndexError( - "index {} out of range [0..{}]".format(key, self.pixel_count)) + raise IndexError("index {} out of range [0..{}]".format(key, self.pixel_count)) def __setitem__(self, key, value): """ @@ -975,10 +967,10 @@ def __setitem__(self, key, value): self.set_pixel_16bit_value(key, value[0], value[1], value[2]) else: raise IndexError( - "index {} out of range [0..{}]" - "".format(key, self.pixel_count) + "index {} out of range [0..{}]" "".format(key, self.pixel_count) ) + ########################################## diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 72bda65..86f31d7 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -28,15 +28,16 @@ ########################################## # test function + def channelcheck_update_pixel(offset): """Channel check pixel.""" # print("offset", offset) pixels.set_pixel_16bit_value(offset, 1000, 100, 0) # clear last pixel - last = offset-1 + last = offset - 1 if last < 0: - last = pixel_count-1 + last = pixel_count - 1 pixels.set_pixel_16bit_value(last, 0, 0, 1) pixels.show() @@ -52,9 +53,9 @@ def channelcheck_update_pixel(offset): def test_main(): """Test Main.""" - print(42 * '*', end="") + print(42 * "*", end="") print(__doc__, end="") - print(42 * '*') + print(42 * "*") bcvalues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( Ioclmax=18, @@ -80,6 +81,6 @@ def test_main(): ########################################## # main loop -if __name__ == '__main__': +if __name__ == "__main__": test_main() diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b09f67c..b6fd9c3 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -16,35 +16,35 @@ ########################################## -pixel_count = 16*1 +PIXEL_COUNT = 16 * 1 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) ########################################## # test function -value_high = 1000 +VALUE_HIGH = 1000 def channelcheck_update_pixel(offset): """Channel check pixel.""" # print("offset", offset) - # pixels[offset] = (value_high, 0, 0) - pixels.set_pixel_16bit_value(offset, value_high, 0, 0) + # pixels[offset] = (VALUE_HIGH, 0, 0) + pixels.set_pixel_16bit_value(offset, VALUE_HIGH, 0, 0) # clear last pixel - last = offset-1 + last = offset - 1 if last < 0: - last = pixel_count-1 + last = PIXEL_COUNT - 1 # pixels[last] = (0, 0, 1) pixels.set_pixel_16bit_value(last, 0, 0, 1) # pixels[offset] = (0xAAAA, 0xBBBB, 0xCCCC) pixels.show() offset += 1 - if offset >= pixel_count: + if offset >= PIXEL_COUNT: time.sleep(0.2) offset = 0 print("clear") @@ -57,11 +57,11 @@ def channelcheck_update(offset): """Channel check.""" # print("offset", offset) - pixels.set_channel(offset, value_high) + pixels.set_channel(offset, VALUE_HIGH) # clear last set channel - last = offset-1 + last = offset - 1 if last < 0: - last = pixels.channel_count-1 + last = pixels.channel_count - 1 pixels.set_channel(last, 0) pixels.show() @@ -74,6 +74,7 @@ def channelcheck_update(offset): ########################################## + def time_measurement_call(message, test_function, loop_count=1000): """Measure timing.""" duration = 0 @@ -114,11 +115,8 @@ def time_measurement_pixels_show(): def _test(): pixels.show() - time_measurement_call( - "'pixels.show()'", - _test, - loop_count - ) + + time_measurement_call("'pixels.show()'", _test, loop_count) def time_measurement_pixels_set_single(): @@ -128,35 +126,25 @@ def time_measurement_pixels_set_single(): def _test(): pixels[3] = (500, 40500, 1000) - time_measurement_call( - "'pixels[3] = (500, 40500, 1000)'", - _test, - loop_count - ) + + time_measurement_call("'pixels[3] = (500, 40500, 1000)'", _test, loop_count) def _test(): pixels[3] = (0.1, 0.5, 0.9) - time_measurement_call( - "'pixels[3] = (0.1, 0.5, 0.9)'", - _test, - loop_count - ) + + time_measurement_call("'pixels[3] = (0.1, 0.5, 0.9)'", _test, loop_count) def _test(): pixels.set_pixel(3, (500, 40500, 1000)) + time_measurement_call( - "'pixels.set_pixel(3, (500, 40500, 1000))'", - _test, - loop_count + "'pixels.set_pixel(3, (500, 40500, 1000))'", _test, loop_count ) def _test(): pixels.set_pixel(3, (0.1, 0.5, 0.9)) - time_measurement_call( - "'pixels.set_pixel(3, (0.1, 0.5, 0.9))'", - _test, - loop_count - ) + + time_measurement_call("'pixels.set_pixel(3, (0.1, 0.5, 0.9))'", _test, loop_count) def time_measurement_pixels_set_loop(): @@ -165,39 +153,39 @@ def time_measurement_pixels_set_loop(): loop_count = 10 def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels[i] = (500, 40500, 1000) + time_measurement_call( - "'pixels[0..{}] = (500, 40500, 1000)'".format(pixel_count), - _test, - loop_count + "'pixels[0..{}] = (500, 40500, 1000)'".format(PIXEL_COUNT), _test, loop_count ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels[i] = (0.1, 0.5, 0.9) + time_measurement_call( - "'pixels[0..{}] = (0.1, 0.5, 0.9)'".format(pixel_count), - _test, - loop_count + "'pixels[0..{}] = (0.1, 0.5, 0.9)'".format(PIXEL_COUNT), _test, loop_count ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel(i, (500, 40500, 1000)) + time_measurement_call( - "'pixels.set_pixel(0..{}, (500, 40500, 1000))'".format(pixel_count), + "'pixels.set_pixel(0..{}, (500, 40500, 1000))'".format(PIXEL_COUNT), _test, - loop_count + loop_count, ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel(i, (0.1, 0.5, 0.9)) + time_measurement_call( - "'pixels.set_pixel(0..{}, (0.1, 0.5, 0.9))'".format(pixel_count), + "'pixels.set_pixel(0..{}, (0.1, 0.5, 0.9))'".format(PIXEL_COUNT), _test, - loop_count + loop_count, ) @@ -208,35 +196,27 @@ def time_measurement_pixels_set_all(): def _test(): pixels.set_pixel_all((500, 40500, 1000)) + time_measurement_call( - "'pixels.set_pixel_all((500, 40500, 1000))'", - _test, - loop_count + "'pixels.set_pixel_all((500, 40500, 1000))'", _test, loop_count ) def _test(): pixels.set_pixel_all((0.1, 0.5, 0.9)) - time_measurement_call( - "'pixels.set_pixel_all((0.1, 0.5, 0.9))'", - _test, - loop_count - ) + + time_measurement_call("'pixels.set_pixel_all((0.1, 0.5, 0.9))'", _test, loop_count) def _test(): pixels.set_pixel_all_16bit_value(500, 40500, 1000) + time_measurement_call( - "'pixels.set_pixel_all_16bit_value(500, 40500, 1000)'", - _test, - loop_count + "'pixels.set_pixel_all_16bit_value(500, 40500, 1000)'", _test, loop_count ) def _test(): pixels.set_all_black() - time_measurement_call( - "'pixels.set_all_black()'", - _test, - loop_count - ) + + time_measurement_call("'pixels.set_all_black()'", _test, loop_count) def time_measurement_pixels_set_16bit(): @@ -246,38 +226,38 @@ def time_measurement_pixels_set_16bit(): def _test(): pixels.set_pixel_16bit_value(3, 500, 40500, 1000) + time_measurement_call( - "'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'", - _test, - loop_count + "'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'", _test, loop_count ) def _test(): pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) + time_measurement_call( - "'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'", - _test, - loop_count + "'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'", _test, loop_count ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel_16bit_value(i, 500, 40500, 1000) + time_measurement_call( "'pixels.set_pixel_16bit_value(0..{}, 500, 40500, 1000)'" - "".format(pixel_count), + "".format(PIXEL_COUNT), _test, - 10 + 10, ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel_16bit_color(i, (500, 40500, 1000)) + time_measurement_call( "'pixels.set_pixel_16bit_color(0..{}, (500, 40500, 1000))'" - "".format(pixel_count), + "".format(PIXEL_COUNT), _test, - 10 + 10, ) @@ -288,53 +268,49 @@ def time_measurement_pixels_set_float(): def _test(): pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9) + time_measurement_call( - "'pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9)'", - _test, - loop_count + "'pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9)'", _test, loop_count ) def _test(): pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9)) + time_measurement_call( - "'pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9))'", - _test, - loop_count + "'pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9))'", _test, loop_count ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) + time_measurement_call( - "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" - "".format(pixel_count), + "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" "".format(PIXEL_COUNT), _test, - 10 + 10, ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel_float_color(i, (0.1, 0.5, 0.9)) + time_measurement_call( - "'pixels.set_pixel_float_color(0..{}, (0.1, 0.5, 0.9))'" - "".format(pixel_count), + "'pixels.set_pixel_float_color(0..{}, (0.1, 0.5, 0.9))'" "".format(PIXEL_COUNT), _test, - 10 + 10, ) def _test(): - for i in range(pixel_count): + for i in range(PIXEL_COUNT): pixels.set_pixel_16bit_value( - i, - int(0.1 * 65535), - int(0.5 * 65535), - int(0.9 * 65535) + i, int(0.1 * 65535), int(0.5 * 65535), int(0.9 * 65535) ) + time_measurement_call( "'pixels.set_pixel_16bit_value(0..{}, f2i 0.1, f2i 0.5, f2i 0.9)'" - "".format(pixel_count), + "".format(PIXEL_COUNT), _test, - 10 + 10, ) @@ -345,32 +321,24 @@ def time_measurement_channel_set(): def _test(): pixels.set_channel(0, 10000) - time_measurement_call( - "'set_channel(0, 10000)'", - _test, - loop_count - ) + + time_measurement_call("'set_channel(0, 10000)'", _test, loop_count) def _test(): pixels.set_channel(0, 10000) pixels.set_channel(1, 10000) pixels.set_channel(2, 10000) - time_measurement_call( - "'set_channel(0..2, 10000)'", - _test, - loop_count - ) - channel_count = pixel_count * 3 + time_measurement_call("'set_channel(0..2, 10000)'", _test, loop_count) + + channel_count = PIXEL_COUNT * 3 def _test(): for i in range(channel_count): pixels.set_channel(i, 500) + time_measurement_call( - "'set_channel(for 0..{}, 10000)'" - "".format(channel_count), - _test, - 10 + "'set_channel(for 0..{}, 10000)'" "".format(channel_count), _test, 10 ) @@ -398,11 +366,11 @@ def time_measurement_channel_set_internal(): # ) # # def _test(): - # for i in range(pixel_count * 3): + # for i in range(PIXEL_COUNT * 3): # pixels._set_channel_16bit_value(i, 500) # time_measurement_call( # "'_set_channel_16bit_value(for 0..{}, 10000)'" - # "".format(pixel_count * 3), + # "".format(PIXEL_COUNT * 3), # _test, # 10 # ) @@ -417,14 +385,11 @@ def time_measurement_pixels_get(): def _test(): print("[", end="") - for i in range(pixel_count): + for i in range(PIXEL_COUNT): print("{}:{}, ".format(i, pixels[i]), end="") print("]") - time_measurement_call( - "'print('{}:{}, '.format(i, pixels[i]), end='')'", - _test, - 1 - ) + + time_measurement_call("'print('{}:{}, '.format(i, pixels[i]), end='')'", _test, 1) def time_measurement(): @@ -441,6 +406,7 @@ def time_measurement(): time_measurement_pixels_get() pixels.set_pixel_all((0, 1, 1)) + ########################################## @@ -493,14 +459,15 @@ def test_BCData(): ) time.sleep(2) + ########################################## def test_main(): """Test Main.""" - print(42 * '*', end="") + print(42 * "*", end="") print(__doc__, end="") - print(42 * '*') + print(42 * "*") # print() # time.sleep(0.5) # print(42 * '*') @@ -511,11 +478,11 @@ def test_main(): test_BCData() time.sleep(0.5) - print(42 * '*') + print(42 * "*") time_measurement() time.sleep(0.5) - print(42 * '*') + print(42 * "*") offset = 0 @@ -529,6 +496,6 @@ def test_main(): ########################################## # main loop -if __name__ == '__main__': +if __name__ == "__main__": test_main() diff --git a/examples/tlc59711_multi_powertest.py b/examples/tlc59711_multi_powertest.py index 98072e4..28f41f9 100644 --- a/examples/tlc59711_multi_powertest.py +++ b/examples/tlc59711_multi_powertest.py @@ -17,7 +17,7 @@ ########################################## -pixel_count = 16*2 +pixel_count = 16 * 2 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) @@ -37,7 +37,7 @@ def main_loop(): else: Ioclmax, IoutR, IoutG, IoutB = (18, 18, 11, 13) try: - Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') + Ioclmax, IoutR, IoutG, IoutB = new_value.split(";") Ioclmax = float(Ioclmax) IoutR = float(IoutR) IoutG = float(IoutG) @@ -71,9 +71,9 @@ def main_loop(): def test_main(): """Test Main.""" - print(42 * '*', end="") + print(42 * "*", end="") print(__doc__, end="") - print(42 * '*') + print(42 * "*") # print() # time.sleep(0.5) # print(42 * '*') @@ -114,6 +114,6 @@ def test_main(): ########################################## # main loop -if __name__ == '__main__': +if __name__ == "__main__": test_main() diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index c3c7258..c9a70c0 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -17,7 +17,7 @@ ########################################## -pixel_count = 16*8 +pixel_count = 16 * 8 spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) @@ -37,7 +37,7 @@ def main_loop(): else: Ioclmax, IoutR, IoutG, IoutB = (18, 18, 11, 13) try: - Ioclmax, IoutR, IoutG, IoutB = new_value.split(';') + Ioclmax, IoutR, IoutG, IoutB = new_value.split(";") Ioclmax = float(Ioclmax) IoutR = float(IoutR) IoutG = float(IoutG) @@ -71,9 +71,9 @@ def main_loop(): def test_main(): """Test Main.""" - print(42 * '*', end="") + print(42 * "*", end="") print(__doc__, end="") - print(42 * '*') + print(42 * "*") # print() # time.sleep(0.5) # print(42 * '*') @@ -114,6 +114,6 @@ def test_main(): ########################################## # main loop -if __name__ == '__main__': +if __name__ == "__main__": test_main() diff --git a/examples/tlc59711_simpletest.py b/examples/tlc59711_simpletest.py index fb706b4..f5a7a57 100644 --- a/examples/tlc59711_simpletest.py +++ b/examples/tlc59711_simpletest.py @@ -1,13 +1,24 @@ -# Simple demo of the TLC59711 16-bit 12 channel LED PWM driver. -# Shows setting channel values in a few ways. -# Author: Tony DiCola +"""TLC5971 / TLC59711.""" + +__doc__ = """ +tlc59711_fastset.py - TLC59711 fast set example. + +showcases the usage of set_pixel_16bit_value for fastests setting of values. +for speed comparision of all the available set calls +look at the tlc59711_multi_dev.py file. + +Simple demo of the TLC59711 16-bit 12 channel LED PWM driver. +Shows setting channel values in a few ways. +Author: Tony DiCola, Stefan Krüger +""" + import board import busio import adafruit_tlc59711 -# TODO: s-light fix removed things +# TODO: s-light fix removed params # Define SPI bus connected to chip. You only need the clock and MOSI (output) # line to use this chip. diff --git a/examples/tlc59711_singlechip.py b/examples/tlc59711_singlechip.py index b7a293c..e9662ab 100644 --- a/examples/tlc59711_singlechip.py +++ b/examples/tlc59711_singlechip.py @@ -1,7 +1,7 @@ """TLC5971 / TLC59711.""" __doc__ = """ -tlc59711_onechip.py - TLC59711 minimal usage example. +tlc59711_singlechip.py - TLC59711 minimal usage example. simple demo of the TLC59711 16-bit 12 channel LED PWM driver. Shows the minimal usage - how to set pixel values. diff --git a/pylama.ini b/pylama.ini new file mode 100644 index 0000000..401048b --- /dev/null +++ b/pylama.ini @@ -0,0 +1,5 @@ +[pylama:pycodestyle] +max_line_length = 100 + +[pylama:pylint] +max_line_length = 100 From 21a27d84b497011a8bb4745c88cffaa8448b1790 Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 11 Sep 2020 23:49:32 +0200 Subject: [PATCH 68/91] run black & linting --- adafruit_tlc59711.py | 124 ++++--------------------- adafruit_tlc59711__original.py | 13 ++- examples/tlc59711_fastset.py | 8 +- examples/tlc59711_multi_powertest.py | 4 +- examples/tlc59711_multi_test_bcdata.py | 4 +- examples/tlc59711_simpletest.py | 12 --- 6 files changed, 31 insertions(+), 134 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index b32ebe7..f72d46b 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -43,8 +43,7 @@ **Software and Dependencies:** -* this is a variant with multi-chip support. - The API is mostly compatible to the DotStar / NeoPixel Libraries +* The API is mostly compatible to the DotStar / NeoPixel Libraries and is therefore also compatible with FancyLED. for this see examples/fancy_multi.py @@ -55,26 +54,11 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" -# Globally disable invalid-name check as this chip by design has short channel -# and register names. It is confusing to rename these from what the datasheet -# refers to them as. +# Globally disable pylint things +# invalid-name: this chip by design has short channel and register names. +# It is confusing to rename these from what the datasheet refers to them as. # pylint: disable=invalid-name -# Globally disable too many instance attributes check. Again this is a case -# where pylint doesn't have the right context to make this call. The chip by -# design has many channels which must be exposed. -# pylint: disable=too-many-instance-attributes - -# Globally disable protected access. Once again pylint can't figure out the -# context for using internal decorate classes below. In these cases protectected -# access is by design for the internal class. -# pylint: disable=protected-access - -# Yet another pylint issue, it fails to recognize a decorator class by -# definition has no public methods. Disable the check. -# pylint: disable=too-few-public-methods - - import struct from micropython import const @@ -309,45 +293,34 @@ class TLC59711Multi: def __init__(self, spi, *, pixel_count=4): """Init.""" self._spi = spi - # how many pixels are there? self.pixel_count = pixel_count self.channel_count = self.pixel_count * self.COLORS_PER_PIXEL # calculate how many chips are connected self.chip_count = self.pixel_count // 4 - # The chips are just a big 28 byte long shift register without any - # fancy update protocol. Blast out all the bits to update, that's it! - # create raw output data + # The chips are just a big 28 byte long shift register without any fancy update protocol. + # Blast out all the bits to update, that's it! → create raw output data self._buffer = bytearray(_CHIP_BUFFER_BYTE_COUNT * self.chip_count) - # Initialize the brightness channel values to max - # (these are 7-bit values). + # Initialize the brightness channel values to max (these are 7-bit values). self.bcr = 127 self.bcg = 127 self.bcb = 127 - # Initialize external user-facing state for the function control - # bits of the chip. These aren't commonly used but available and - # match the nomenclature from the datasheet. + # Initialize external user-facing state for the function control bits of the chip. + # These aren't commonly used but available and match the nomenclature from the datasheet. # you must manually call update_fc() after changing them # (reduces the need to make frivolous memory-hogging properties). - # Default set - # OUTTMG, TMGRST, and DSPRPT to on - # like in Arduino library. - # these are set for all chips + # Default set: OUTTMG, TMGRST, and DSPRPT to on; like in Arduino library. + # these are set for all chips the same self.outtmg = True self.extgck = False self.tmgrst = True self.dsprpt = True self.blank = False - # self._buf32_format = struct.Struct('>I') - # self._buf16_format = struct.Struct('>H') - - # preparation done - # now initialize buffer to default values + # preparation done → now initialize buffer to default values self._init_buffer() - self._buffer_index_lookuptable = [] self._init_lookuptable() @@ -357,15 +330,9 @@ def _init_buffer(self): self.chip_set_BCData(chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) self._chip_set_FunctionControl(chip_index) self._chip_set_WriteCommand(chip_index) - # loop end def set_chipheader_bits_in_buffer( - self, - *, - chip_index=0, - part_bit_offset=0, - field=None, - value=0 + self, *, chip_index=0, part_bit_offset=0, field=None, value=0 ): """Set chip header bits in buffer.""" if field is None: @@ -424,8 +391,7 @@ def update_BCData(self): """ Update BC-Data for all Chips in Buffer. - need to be called after you changed on of the - BC-Data Parameters. (bcr, bcg, bcb) + need to be called after you changed on of the BC-Data Parameters. (bcr, bcg, bcb) """ for chip_index in range(self.chip_count): self.chip_set_BCData(chip_index, bcr=self.bcr, bcg=self.bcg, bcb=self.bcb) @@ -474,8 +440,7 @@ def update_fc(self): """ Update Function Control Bits for all Chips in Buffer. - need to be called after you changed on of the - Function Control Bit Parameters. + need to be called after you changed on of the Function Control Bit Parameters. (outtmg, extgck, tmgrst, dsprpt, blank) """ for chip_index in range(self.chip_count): @@ -981,8 +946,7 @@ class TLC59711(TLC59711Multi): The class has an interface compatible with the FancyLED library. and with this is similar to the NeoPixel and DotStar Interfaces. - this TLC59711 is a subclass of TLC59711Multi. - just for compatiblility. + this TLC59711 is a subclass of TLC59711Multi just for compatiblility. here maybee some of the original API will get implemented :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. @@ -993,8 +957,6 @@ class TLC59711(TLC59711Multi): :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. """ - # :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. The clock and - # MOSI/outout must be set, the MISO/input is unused. # :param bool auto_show: This is a boolean that defaults to True and indicates any # change to a channel value will instantly be written to the chip. You might wish to # set this to false if you desire to perform your own atomic operations of channel @@ -1014,24 +976,19 @@ def __set__(self, obj, value): # Set the 16-bit value at the offset for this channel. assert 0 <= value <= 65535 obj._set_channel_16bit_value(self._channel, value) - # Write out the new values if auto_show is enabled. # if obj.auto_show: # obj._write() - # Define explicit channels for first IC. - # this is only for api backwards compliance. + # Define explicit channels for first IC. → this is only for api backwards compliance. b0 = _ChannelDirekt(0) g0 = _ChannelDirekt(1) r0 = _ChannelDirekt(2) - b1 = _ChannelDirekt(3) g1 = _ChannelDirekt(4) r1 = _ChannelDirekt(5) - b2 = _ChannelDirekt(6) g2 = _ChannelDirekt(7) r2 = _ChannelDirekt(8) - b3 = _ChannelDirekt(9) g3 = _ChannelDirekt(10) r3 = _ChannelDirekt(11) @@ -1039,50 +996,3 @@ def __set__(self, obj, value): def __init__(self, spi, pixel_count=4): """Init.""" super(TLC59711, self).__init__(spi, pixel_count=pixel_count) - - # old stuff... - # i think it is good to leave this out. - # @property - # def red_brightness(self): - # """The red brightness for all channels (i.e. R0, R1, R2, and R3). - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcr - # - # @red_brightness.setter - # def red_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcr = val - # if self.auto_show: - # self._write() - # - # @property - # def green_brightness(self): - # """The green brightness for all channels (i.e. G0, G1, G2, and G3). - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcg - # - # @green_brightness.setter - # def green_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcg = val - # if self.auto_show: - # self._write() - # - # @property - # def blue_brightness(self): - # """The blue brightness for all channels (i.e. B0, B1, B2, and B3). - # - # This is a 7-bit value from 0-127. - # """ - # return self._bcb - # - # @blue_brightness.setter - # def blue_brightness(self, val): - # assert 0 <= val <= 127 - # self._bcb = val - # if self.auto_show: - # self._write() diff --git a/adafruit_tlc59711__original.py b/adafruit_tlc59711__original.py index e25f32f..1bb6a10 100644 --- a/adafruit_tlc59711__original.py +++ b/adafruit_tlc59711__original.py @@ -1,4 +1,3 @@ - # The MIT License (MIT) # # Copyright (c) 2017 Tony DiCola for Adafruit Industries @@ -110,8 +109,9 @@ def __init__(self, byte_offset): def __get__(self, obj, obj_type): # Grab the 16-bit value at the offset for this channel. - return (obj._shift_reg[self._byte_offset] << 8) | \ - obj._shift_reg[self._byte_offset + 1] + return (obj._shift_reg[self._byte_offset] << 8) | obj._shift_reg[ + self._byte_offset + 1 + ] def __set__(self, obj, val): # Set the 16-bit value at the offset for this channel. @@ -144,7 +144,6 @@ def __set__(self, obj, val): g0 = _GS_Value(24) r0 = _GS_Value(26) - def __init__(self, spi, *, auto_show=True): # noqa self._spi = spi # This device is just a big 28 byte long shift register without any @@ -219,7 +218,7 @@ def _write(self): def show(self): """Write out the current LED PWM state to the chip. This is only necessary if - auto_show was set to false in the initializer. + auto_show was set to false in the initializer. """ self._write() @@ -279,7 +278,7 @@ def __getitem__(self, key): # pylint: disable=no-else-return # Disable should be removed when refactor can be tested """Retrieve the R, G, B values for the provided channel as a - 3-tuple. Each value is a 16-bit number from 0-65535. + 3-tuple. Each value is a 16-bit number from 0-65535. """ if key == 0: return (self.r0, self.g0, self.b0) @@ -294,7 +293,7 @@ def __getitem__(self, key): def __setitem__(self, key, val): """Set the R, G, B values for the provided channel. Specify a - 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). + 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). """ # Do this check here instead of later to # prevent accidentally keeping auto_show diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 86f31d7..161bb82 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -19,10 +19,10 @@ ########################################## -pixel_count = 16 +PIXEL_COUNT = 16 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) ########################################## @@ -37,12 +37,12 @@ def channelcheck_update_pixel(offset): # clear last pixel last = offset - 1 if last < 0: - last = pixel_count - 1 + last = PIXEL_COUNT - 1 pixels.set_pixel_16bit_value(last, 0, 0, 1) pixels.show() offset += 1 - if offset >= pixel_count: + if offset >= PIXEL_COUNT: time.sleep(0.2) offset = 0 print("clear") diff --git a/examples/tlc59711_multi_powertest.py b/examples/tlc59711_multi_powertest.py index 28f41f9..66dd51d 100644 --- a/examples/tlc59711_multi_powertest.py +++ b/examples/tlc59711_multi_powertest.py @@ -17,10 +17,10 @@ ########################################## -pixel_count = 16 * 2 +PIXEL_COUNT = 16 * 2 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) ########################################## diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index c9a70c0..19ec483 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -17,10 +17,10 @@ ########################################## -pixel_count = 16 * 8 +PIXEL_COUNT = 16 * 8 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=pixel_count) +pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) ########################################## diff --git a/examples/tlc59711_simpletest.py b/examples/tlc59711_simpletest.py index f5a7a57..b09fe40 100644 --- a/examples/tlc59711_simpletest.py +++ b/examples/tlc59711_simpletest.py @@ -18,8 +18,6 @@ import adafruit_tlc59711 -# TODO: s-light fix removed params - # Define SPI bus connected to chip. You only need the clock and MOSI (output) # line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) @@ -51,13 +49,3 @@ leds.g2 = 65535 # Again don't forget to call show if you disabled auto_show above. # leds.show() - -# The chip also supports global brightness channels to change the red, green, -# blue colors of all 4 channels at once. These are 7-bit values that range -# from 0-127. Get and set them with the red_brightness, green_brightness, -# and blue_brightness properties and again be sure to call show if you -# disabled auto_show. -# For example set the red channel to half brightness globally. -leds.red_brightness = 63 -# Don't forget to call show if you disabled auto_show above. -# leds.show() From 88b0c98a8e644e61924d2992b43b2ee898434e4b Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 12 Sep 2020 15:15:07 +0200 Subject: [PATCH 69/91] cleanup.. (test examples, cleanup doublets, fix small bugs) --- .pylintrc | 10 ++- adafruit_tlc59711.py | 7 +- examples/tlc59711_fastset.py | 2 +- examples/tlc59711_minimal.py | 7 +- examples/tlc59711_multi_dev.py | 114 +++++++++++------------ examples/tlc59711_multi_powertest.py | 119 ------------------------- examples/tlc59711_multi_test_bcdata.py | 14 +-- examples/tlc59711_simpletest.py | 51 ----------- examples/tlc59711_singlechip.py | 11 ++- 9 files changed, 82 insertions(+), 253 deletions(-) delete mode 100644 examples/tlc59711_multi_powertest.py delete mode 100644 examples/tlc59711_simpletest.py diff --git a/.pylintrc b/.pylintrc index fc5a76c..0d907b9 100644 --- a/.pylintrc +++ b/.pylintrc @@ -173,8 +173,8 @@ missing-member-max-choices=1 [VARIABLES] -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. +# List of additional names supposed to be defined in builtins. +# Remember that you should avoid to define new builtins when possible. additional-builtins=_CHIP_BUFFER_BYTE_COUNT, _BC_CHIP_BUFFER_BIT_OFFSET, _FC_CHIP_BUFFER_BIT_OFFSET, _WC_CHIP_BUFFER_BIT_OFFSET, _BUFFER_BYTES_PER_COLOR, _CHIP_BUFFER_HEADER_BYTE_COUNT # ugly workaround for pylint not knowing of micropython const thing: # this fixes the E0602: Undefined variable error. @@ -304,7 +304,11 @@ function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Good variable names which should always be accepted, separated by a comma # good-names=i,j,k,ex,Run,_ -good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ +# good-names=r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_ +# these variable names represent the datasheet nameing - so they are allowed! +# good-names=Ioclmax, IoutR, IoutG, IoutB, BCValues,calculate_Ioclmax +# combined: +good-names=r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_,Riref,Viref,Ioclmax,IoutR,IoutG,IoutB,BCValues,calculate_Ioclmax,calculate_Riref,calculate_BCData,chip_set_BCData,update_BCData,_chip_set_FunctionControl,_chip_set_WriteCommand,b0,g0,r0,b1,g1,r1,b2,g2,r2,b3,g3,r3 # Include a hint for the correct naming format with invalid-name include-naming-hint=no diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index f72d46b..bc8d841 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -54,11 +54,6 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" -# Globally disable pylint things -# invalid-name: this chip by design has short channel and register names. -# It is confusing to rename these from what the datasheet refers to them as. -# pylint: disable=invalid-name - import struct from micropython import const @@ -975,7 +970,7 @@ def __get__(self, obj, obj_type): def __set__(self, obj, value): # Set the 16-bit value at the offset for this channel. assert 0 <= value <= 65535 - obj._set_channel_16bit_value(self._channel, value) + obj.set_channel(self._channel, value) # if obj.auto_show: # obj._write() diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 161bb82..9482520 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -3,7 +3,7 @@ __doc__ = """ tlc59711_fastset.py - TLC59711 fast set example. -showcases the usage of set_pixel_16bit_value for fastests setting of values. +showcases the usage of set_pixel_16bit_value for fastest setting of values. for speed comparision of all the available set calls look at the tlc59711_multi_dev.py file. diff --git a/examples/tlc59711_minimal.py b/examples/tlc59711_minimal.py index 2de2b37..f00e468 100644 --- a/examples/tlc59711_minimal.py +++ b/examples/tlc59711_minimal.py @@ -14,16 +14,13 @@ import adafruit_tlc59711 +print("tlc59711_minimal.py") + # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) - -# Define the TLC59711 instance. pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=16) - -print("tlc59711_minimal.py") - # Ways to set the values: # just a list or tuple with 3 integer values: R G B # each 0 - 65535 or 0.0 - 1.0 diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_multi_dev.py index b6fd9c3..bb2217f 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_multi_dev.py @@ -1,9 +1,9 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -adafruit_tlc59711.TLC59711Multi development helper. +TLC59711Multi development helper. -this sketch contains a bunch of timing tests and other development helpers.. +this sketch contains a bunch of timing tests and other development things.. Enjoy the colors :-) """ @@ -75,7 +75,7 @@ def channelcheck_update(offset): ########################################## -def time_measurement_call(message, test_function, loop_count=1000): +def timeit_call(message, test_function, loop_count=1000): """Measure timing.""" duration = 0 start_time = time.monotonic() @@ -108,7 +108,7 @@ def time_measurement_call(message, test_function, loop_count=1000): ) -def time_measurement_pixels_show(): +def timeit_pixels_show(): """Measure timing.""" print("*** pixels show:") loop_count = 1000 @@ -116,10 +116,10 @@ def time_measurement_pixels_show(): def _test(): pixels.show() - time_measurement_call("'pixels.show()'", _test, loop_count) + timeit_call("'pixels.show()'", _test, loop_count) -def time_measurement_pixels_set_single(): +def timeit_pixels_set_single(): """Measure timing pixels set.""" print("*** pixels set single:") loop_count = 1000 @@ -127,27 +127,25 @@ def time_measurement_pixels_set_single(): def _test(): pixels[3] = (500, 40500, 1000) - time_measurement_call("'pixels[3] = (500, 40500, 1000)'", _test, loop_count) + timeit_call("'pixels[3] = (500, 40500, 1000)'", _test, loop_count) def _test(): pixels[3] = (0.1, 0.5, 0.9) - time_measurement_call("'pixels[3] = (0.1, 0.5, 0.9)'", _test, loop_count) + timeit_call("'pixels[3] = (0.1, 0.5, 0.9)'", _test, loop_count) def _test(): pixels.set_pixel(3, (500, 40500, 1000)) - time_measurement_call( - "'pixels.set_pixel(3, (500, 40500, 1000))'", _test, loop_count - ) + timeit_call("'pixels.set_pixel(3, (500, 40500, 1000))'", _test, loop_count) def _test(): pixels.set_pixel(3, (0.1, 0.5, 0.9)) - time_measurement_call("'pixels.set_pixel(3, (0.1, 0.5, 0.9))'", _test, loop_count) + timeit_call("'pixels.set_pixel(3, (0.1, 0.5, 0.9))'", _test, loop_count) -def time_measurement_pixels_set_loop(): +def timeit_pixels_set_loop(): """Measure timing pixels set.""" print("*** pixels set loop:") loop_count = 10 @@ -156,7 +154,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels[i] = (500, 40500, 1000) - time_measurement_call( + timeit_call( "'pixels[0..{}] = (500, 40500, 1000)'".format(PIXEL_COUNT), _test, loop_count ) @@ -164,7 +162,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels[i] = (0.1, 0.5, 0.9) - time_measurement_call( + timeit_call( "'pixels[0..{}] = (0.1, 0.5, 0.9)'".format(PIXEL_COUNT), _test, loop_count ) @@ -172,7 +170,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel(i, (500, 40500, 1000)) - time_measurement_call( + timeit_call( "'pixels.set_pixel(0..{}, (500, 40500, 1000))'".format(PIXEL_COUNT), _test, loop_count, @@ -182,14 +180,14 @@ def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel(i, (0.1, 0.5, 0.9)) - time_measurement_call( + timeit_call( "'pixels.set_pixel(0..{}, (0.1, 0.5, 0.9))'".format(PIXEL_COUNT), _test, loop_count, ) -def time_measurement_pixels_set_all(): +def timeit_pixels_set_all(): """Measure timing pixels set.""" print("*** pixels set all:") loop_count = 10 @@ -197,29 +195,27 @@ def time_measurement_pixels_set_all(): def _test(): pixels.set_pixel_all((500, 40500, 1000)) - time_measurement_call( - "'pixels.set_pixel_all((500, 40500, 1000))'", _test, loop_count - ) + timeit_call("'pixels.set_pixel_all((500, 40500, 1000))'", _test, loop_count) def _test(): pixels.set_pixel_all((0.1, 0.5, 0.9)) - time_measurement_call("'pixels.set_pixel_all((0.1, 0.5, 0.9))'", _test, loop_count) + timeit_call("'pixels.set_pixel_all((0.1, 0.5, 0.9))'", _test, loop_count) def _test(): pixels.set_pixel_all_16bit_value(500, 40500, 1000) - time_measurement_call( + timeit_call( "'pixels.set_pixel_all_16bit_value(500, 40500, 1000)'", _test, loop_count ) def _test(): pixels.set_all_black() - time_measurement_call("'pixels.set_all_black()'", _test, loop_count) + timeit_call("'pixels.set_all_black()'", _test, loop_count) -def time_measurement_pixels_set_16bit(): +def timeit_pixels_set_16bit(): """Measure timing pixels set.""" print("*** pixels set 16bit:") loop_count = 1000 @@ -227,14 +223,14 @@ def time_measurement_pixels_set_16bit(): def _test(): pixels.set_pixel_16bit_value(3, 500, 40500, 1000) - time_measurement_call( + timeit_call( "'pixels.set_pixel_16bit_value(3, 500, 40500, 1000)'", _test, loop_count ) def _test(): pixels.set_pixel_16bit_color(3, (500, 40500, 1000)) - time_measurement_call( + timeit_call( "'pixels.set_pixel_16bit_color(3, (500, 40500, 1000))'", _test, loop_count ) @@ -242,7 +238,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel_16bit_value(i, 500, 40500, 1000) - time_measurement_call( + timeit_call( "'pixels.set_pixel_16bit_value(0..{}, 500, 40500, 1000)'" "".format(PIXEL_COUNT), _test, @@ -253,7 +249,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel_16bit_color(i, (500, 40500, 1000)) - time_measurement_call( + timeit_call( "'pixels.set_pixel_16bit_color(0..{}, (500, 40500, 1000))'" "".format(PIXEL_COUNT), _test, @@ -261,7 +257,7 @@ def _test(): ) -def time_measurement_pixels_set_float(): +def timeit_pixels_set_float(): """Measure timing pixels set.""" print("*** pixels set float:") loop_count = 1000 @@ -269,22 +265,18 @@ def time_measurement_pixels_set_float(): def _test(): pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9) - time_measurement_call( - "'pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9)'", _test, loop_count - ) + timeit_call("'pixels.set_pixel_float_value(3, 0.1, 0.5, 0.9)'", _test, loop_count) def _test(): pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9)) - time_measurement_call( - "'pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9))'", _test, loop_count - ) + timeit_call("'pixels.set_pixel_float_color(3, (0.1, 0.5, 0.9))'", _test, loop_count) def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel_float_value(i, 0.1, 0.5, 0.9) - time_measurement_call( + timeit_call( "'pixels.set_pixel_float_value(0..{}, 0.1, 0.5, 0.9)'" "".format(PIXEL_COUNT), _test, 10, @@ -294,7 +286,7 @@ def _test(): for i in range(PIXEL_COUNT): pixels.set_pixel_float_color(i, (0.1, 0.5, 0.9)) - time_measurement_call( + timeit_call( "'pixels.set_pixel_float_color(0..{}, (0.1, 0.5, 0.9))'" "".format(PIXEL_COUNT), _test, 10, @@ -306,7 +298,7 @@ def _test(): i, int(0.1 * 65535), int(0.5 * 65535), int(0.9 * 65535) ) - time_measurement_call( + timeit_call( "'pixels.set_pixel_16bit_value(0..{}, f2i 0.1, f2i 0.5, f2i 0.9)'" "".format(PIXEL_COUNT), _test, @@ -314,7 +306,7 @@ def _test(): ) -def time_measurement_channel_set(): +def timeit_channel_set(): """Measure timing channel set.""" print("*** channel set:") loop_count = 1000 @@ -322,14 +314,14 @@ def time_measurement_channel_set(): def _test(): pixels.set_channel(0, 10000) - time_measurement_call("'set_channel(0, 10000)'", _test, loop_count) + timeit_call("'set_channel(0, 10000)'", _test, loop_count) def _test(): pixels.set_channel(0, 10000) pixels.set_channel(1, 10000) pixels.set_channel(2, 10000) - time_measurement_call("'set_channel(0..2, 10000)'", _test, loop_count) + timeit_call("'set_channel(0..2, 10000)'", _test, loop_count) channel_count = PIXEL_COUNT * 3 @@ -337,19 +329,17 @@ def _test(): for i in range(channel_count): pixels.set_channel(i, 500) - time_measurement_call( - "'set_channel(for 0..{}, 10000)'" "".format(channel_count), _test, 10 - ) + timeit_call("'set_channel(for 0..{}, 10000)'" "".format(channel_count), _test, 10) -def time_measurement_channel_set_internal(): +def timeit_channel_set_internal(): """Measure timing channel set internal.""" print("*** channel set internal:") # loop_count = 1000 # # def _test(): # pixels._set_channel_16bit_value(0, 10000) - # time_measurement_call( + # timeit_call( # "'_set_channel_16bit_value(0, 10000)'", # _test, # loop_count @@ -359,7 +349,7 @@ def time_measurement_channel_set_internal(): # pixels._set_channel_16bit_value(0, 10000) # pixels._set_channel_16bit_value(1, 10000) # pixels._set_channel_16bit_value(2, 10000) - # time_measurement_call( + # timeit_call( # "'_set_channel_16bit_value(0..2, 10000)'", # _test, # loop_count @@ -368,7 +358,7 @@ def time_measurement_channel_set_internal(): # def _test(): # for i in range(PIXEL_COUNT * 3): # pixels._set_channel_16bit_value(i, 500) - # time_measurement_call( + # timeit_call( # "'_set_channel_16bit_value(for 0..{}, 10000)'" # "".format(PIXEL_COUNT * 3), # _test, @@ -377,7 +367,7 @@ def time_measurement_channel_set_internal(): print(" must be uncommented in code to work..") -def time_measurement_pixels_get(): +def timeit_pixels_get(): """Measure timing pixels get.""" print("*** pixels get:") @@ -389,28 +379,28 @@ def _test(): print("{}:{}, ".format(i, pixels[i]), end="") print("]") - time_measurement_call("'print('{}:{}, '.format(i, pixels[i]), end='')'", _test, 1) + timeit_call("'print('{}:{}, '.format(i, pixels[i]), end='')'", _test, 1) def time_measurement(): """Measure timing.""" print("meassure timing:") - time_measurement_pixels_show() - time_measurement_pixels_set_single() - time_measurement_pixels_set_loop() - time_measurement_pixels_set_all() - time_measurement_pixels_set_16bit() - time_measurement_pixels_set_float() - time_measurement_channel_set() - time_measurement_channel_set_internal() - time_measurement_pixels_get() + timeit_pixels_show() + timeit_pixels_set_single() + timeit_pixels_set_loop() + timeit_pixels_set_all() + timeit_pixels_set_16bit() + timeit_pixels_set_float() + timeit_channel_set() + timeit_channel_set_internal() + timeit_pixels_get() pixels.set_pixel_all((0, 1, 1)) ########################################## -def test_BCData(): +def test_bcdata(): """Test BC-Data setting.""" print("test BC-Data setting:") print("set pixel all to 100, 100, 100") @@ -476,7 +466,7 @@ def test_main(): pixels.show() time.sleep(0.5) - test_BCData() + test_bcdata() time.sleep(0.5) print(42 * "*") diff --git a/examples/tlc59711_multi_powertest.py b/examples/tlc59711_multi_powertest.py deleted file mode 100644 index 66dd51d..0000000 --- a/examples/tlc59711_multi_powertest.py +++ /dev/null @@ -1,119 +0,0 @@ -"""TLC5971 / TLC59711 Multi.""" - -__doc__ = """ -TLC59711Multi powertest. - -just check how much current your leds need... -Enjoy the colors :-) -""" - -import time - -import board -import busio -import supervisor - -import adafruit_tlc59711 - - -########################################## -PIXEL_COUNT = 16 * 2 - -spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) - -########################################## - - -def main_loop(): - """Loop.""" - new_value = input() - if "v" in new_value: - try: - value = int(new_value[1:]) - except ValueError as e: - print("Exception: ", e) - pixels.set_pixel_all_16bit_value(value, value, value) - else: - Ioclmax, IoutR, IoutG, IoutB = (18, 18, 11, 13) - try: - Ioclmax, IoutR, IoutG, IoutB = new_value.split(";") - Ioclmax = float(Ioclmax) - IoutR = float(IoutR) - IoutG = float(IoutG) - IoutB = float(IoutB) - except ValueError as e: - print("Exception: ", e) - BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=IoutR, - IoutG=IoutG, - IoutB=IoutB, - ) - pixels.bcr = BCValues[0] - pixels.bcg = BCValues[1] - pixels.bcb = BCValues[2] - print( - "bcr: {:>3}\n" - "bcg: {:>3}\n" - "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) - ) - pixels.update_BCData() - pixels.show() - # prepare new input - print("\nenter new values:") - - -def test_main(): - """Test Main.""" - print(42 * "*", end="") - print(__doc__, end="") - print(42 * "*") - # print() - # time.sleep(0.5) - # print(42 * '*') - - print("set pixel all to 100, 100, 100") - pixels.set_pixel_all((5000, 5000, 5000)) - # calculate bc values - Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) - print("Ioclmax = {}".format(Ioclmax)) - Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) - print("Riref = {}".format(Riref)) - BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=18, - IoutG=11, - IoutB=13, - ) - # (127, 77, 91) - print("BCValues = {}".format(BCValues)) - pixels.bcr = BCValues[0] - pixels.bcg = BCValues[1] - pixels.bcb = BCValues[2] - pixels.update_BCData() - pixels.show() - time.sleep(0.1) - - if supervisor.runtime.serial_connected: - print( - "you can change the global brightness control:\n" - "use format: 'Ioclmax; IoutR; IoutG; IoutB'\n" - "example: '18; 7; 15; 17'" - ) - while True: - if supervisor.runtime.serial_bytes_available: - main_loop() - - -########################################## -# main loop - -if __name__ == "__main__": - - test_main() diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_multi_test_bcdata.py index 19ec483..272ddf3 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_multi_test_bcdata.py @@ -1,10 +1,9 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -TLC59711Multi development helper. +tlc59711_multi_test_bcdata.py . -this sketch contains a bunch of timing tests and other development helpers.. -Enjoy the colors :-) +test brightness correction data (BC) """ import time @@ -15,7 +14,6 @@ import adafruit_tlc59711 - ########################################## PIXEL_COUNT = 16 * 8 @@ -102,9 +100,15 @@ def test_main(): if supervisor.runtime.serial_connected: print( - "you can change the global brightness control:\n" + "\n" + "this script offers two things to be changed:\n" + "- value for all channels\n" + "example: 'v10'\n" + "example: 'v65535'\n" + "- (global) brightness control:\n" "use format: 'Ioclmax; IoutR; IoutG; IoutB'\n" "example: '18; 7; 15; 17'" + "\n" ) while True: if supervisor.runtime.serial_bytes_available: diff --git a/examples/tlc59711_simpletest.py b/examples/tlc59711_simpletest.py deleted file mode 100644 index b09fe40..0000000 --- a/examples/tlc59711_simpletest.py +++ /dev/null @@ -1,51 +0,0 @@ -"""TLC5971 / TLC59711.""" - -__doc__ = """ -tlc59711_fastset.py - TLC59711 fast set example. - -showcases the usage of set_pixel_16bit_value for fastests setting of values. -for speed comparision of all the available set calls -look at the tlc59711_multi_dev.py file. - -Simple demo of the TLC59711 16-bit 12 channel LED PWM driver. -Shows setting channel values in a few ways. -Author: Tony DiCola, Stefan Krüger -""" - -import board -import busio - -import adafruit_tlc59711 - - -# Define SPI bus connected to chip. You only need the clock and MOSI (output) -# line to use this chip. -spi = busio.SPI(board.SCK, MOSI=board.MOSI) - -# Define the TLC59711 instance. -leds = adafruit_tlc59711.TLC59711(spi) -# Optionally you can disable the auto_show behavior that updates the chip -# as soon as any channel value is written. The default is True/on but you can -# disable and explicitly call show to control when updates happen for better -# animation or atomic RGB LED updates. -# leds = adafruit_tlc59711.TLC59711(spi, auto_show=False) - -# There are a couple ways to control the channels of the chip. -# The first is using an interface like a strip of NeoPixels. Index into the -# class for the channel and set or get its R, G, B tuple value. Note the -# component values are 16-bit numbers that range from 0-65535 (off to full -# brightness). Remember there are only 4 channels available too (0 to 3). -# For example set channel 0 (R0, G0, B0) to half brightness: -leds[0] = (32767, 32767, 32767) -# Dont forget to call show if you disabled auto_show above. -# leds.show() - -# Or to set channel 1 to full red only (green and blue off). -leds[1] = (65535, 0, 0) - -# You can also explicitly control each R0, G0, B0, R1, B1, etc. channel -# by getting and setting its 16-bit value directly with properties. -# For example set channel 2 to full green (i.e. G2 to maximum): -leds.g2 = 65535 -# Again don't forget to call show if you disabled auto_show above. -# leds.show() diff --git a/examples/tlc59711_singlechip.py b/examples/tlc59711_singlechip.py index e9662ab..2d065db 100644 --- a/examples/tlc59711_singlechip.py +++ b/examples/tlc59711_singlechip.py @@ -6,6 +6,8 @@ simple demo of the TLC59711 16-bit 12 channel LED PWM driver. Shows the minimal usage - how to set pixel values. +Author: Tony DiCola, Stefan Krueger + Enjoy the colors :-) """ @@ -14,12 +16,14 @@ import adafruit_tlc59711 +print(__doc__) + # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) # Define the TLC59711 instance with one TLC chip connected. -pixels = adafruit_tlc59711.TLC59711Multi(spi) +pixels = adafruit_tlc59711.TLC59711(spi) print("tlc59711_onechip.py") @@ -35,5 +39,10 @@ # if you are ready to show your values you have to call pixels.show() +# You can also explicitly control each R0, G0, B0, R1, B1, etc. channel of the first ic +# by getting and setting its 16-bit value directly with properties. +# For example set channel 2 to 1/4 green (i.e. G2): +pixels.g2 = 65535 // 4 + # there are a bunch of other advanced ways to set pixel. # have a look at the other examples. From 1179a299548840aec283b5545f8f9e3ba9d8f15f Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 12 Sep 2020 15:47:01 +0200 Subject: [PATCH 70/91] more cleanup merged TLC59711 into TLC59711Multi & renamed later to first. if we need a auto_show functionality i think it is necessary to create a special subclass for this (for performance reasons) --- adafruit_tlc59711.py | 49 +++++-------------- ...{tlc59711_multi_dev.py => tlc59711_dev.py} | 10 ++-- ...test_bcdata.py => tlc59711_test_bcdata.py} | 2 +- 3 files changed, 18 insertions(+), 43 deletions(-) rename examples/{tlc59711_multi_dev.py => tlc59711_dev.py} (97%) rename examples/{tlc59711_multi_test_bcdata.py => tlc59711_test_bcdata.py} (98%) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index bc8d841..4ff496e 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -59,19 +59,20 @@ from micropython import const -class TLC59711Multi: - """Multi TLC59711 16-bit 12 channel LED PWM driver. +class TLC59711: + """TLC5971 & TLC59711 16-bit 12 channel LED PWM driver. - This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. - The class has an interface compatible with the FancyLED library. - and with this is similar to the NeoPixel and DotStar Interfaces. + The TLC59711 & TLC5971 chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. + This Library can control 1..many chips. + The class has an interface compatible with the FancyLED library - + and the API is similar to the NeoPixel and DotStar Interfaces. :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. The clock and MOSI/outout must be set, the MISO/input is unused. Maximal data clock frequence is: - TLC59711: 10MHz - TLC5971: 20MHz - :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. + :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. (default=4) """ # pylint: disable=too-many-instance-attributes @@ -930,33 +931,6 @@ def __setitem__(self, key, value): "index {} out of range [0..{}]" "".format(key, self.pixel_count) ) - -########################################## - - -class TLC59711(TLC59711Multi): - """Multi TLC59711 16-bit 12 channel LED PWM driver. - - This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. - The class has an interface compatible with the FancyLED library. - and with this is similar to the NeoPixel and DotStar Interfaces. - - this TLC59711 is a subclass of TLC59711Multi just for compatiblility. - here maybee some of the original API will get implemented - - :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. - The clock and MOSI/outout must be set, the MISO/input is unused. - Maximal data clock frequence is: - - TLC59711: 10MHz - - TLC5971: 20MHz - :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. - """ - - # :param bool auto_show: This is a boolean that defaults to True and indicates any - # change to a channel value will instantly be written to the chip. You might wish to - # set this to false if you desire to perform your own atomic operations of channel - # values. In that case call the show function after making updates to channel state. - class _ChannelDirekt: # Internal decorator to simplify mapping. @@ -974,7 +948,9 @@ def __set__(self, obj, value): # if obj.auto_show: # obj._write() - # Define explicit channels for first IC. → this is only for api backwards compliance. + # Define explicit channels for first IC. + # → this is only for api backwards compliance. + # not recommended for new use - use *set_channel* b0 = _ChannelDirekt(0) g0 = _ChannelDirekt(1) r0 = _ChannelDirekt(2) @@ -988,6 +964,5 @@ def __set__(self, obj, value): g3 = _ChannelDirekt(10) r3 = _ChannelDirekt(11) - def __init__(self, spi, pixel_count=4): - """Init.""" - super(TLC59711, self).__init__(spi, pixel_count=pixel_count) + +########################################## diff --git a/examples/tlc59711_multi_dev.py b/examples/tlc59711_dev.py similarity index 97% rename from examples/tlc59711_multi_dev.py rename to examples/tlc59711_dev.py index bb2217f..a7ec71c 100644 --- a/examples/tlc59711_multi_dev.py +++ b/examples/tlc59711_dev.py @@ -1,7 +1,7 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -TLC59711Multi development helper. +TLC59711 development helper. this sketch contains a bunch of timing tests and other development things.. Enjoy the colors :-) @@ -19,7 +19,7 @@ PIXEL_COUNT = 16 * 1 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) +pixels = adafruit_tlc59711.TLC59711(spi, pixel_count=PIXEL_COUNT) ########################################## @@ -418,11 +418,11 @@ def test_bcdata(): ) ) # calculate bc values - Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) + Ioclmax = adafruit_tlc59711.TLC59711.calculate_Ioclmax(Riref=2.7) print("Ioclmax = {}".format(Ioclmax)) - Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( Ioclmax=Ioclmax, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_multi_test_bcdata.py b/examples/tlc59711_test_bcdata.py similarity index 98% rename from examples/tlc59711_multi_test_bcdata.py rename to examples/tlc59711_test_bcdata.py index 272ddf3..e5ad972 100644 --- a/examples/tlc59711_multi_test_bcdata.py +++ b/examples/tlc59711_test_bcdata.py @@ -1,7 +1,7 @@ """TLC5971 / TLC59711 Multi.""" __doc__ = """ -tlc59711_multi_test_bcdata.py . +tlc59711_test_bcdata.py. test brightness correction data (BC) """ From ee70d97034f5fc8e6a1163a168d70cf5db4f3ce0 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 12 Sep 2020 15:56:22 +0200 Subject: [PATCH 71/91] added minimal first AutoShow class --- adafruit_tlc59711.py | 113 ++++++++++++++++++ ...hip.py => tlc59711_singlechip_autoshow.py} | 13 +- 2 files changed, 117 insertions(+), 9 deletions(-) rename examples/{tlc59711_singlechip.py => tlc59711_singlechip_autoshow.py} (77%) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 4ff496e..3201b24 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -966,3 +966,116 @@ def __set__(self, obj, value): ########################################## + +class TLC59711AutoShow(TLC59711): + """TLC59711 16-bit 12 channel LED PWM driver with Auto-Show. + + This chip is designed to drive 4 RGB LEDs with 16-bit PWM per Color. + The class has an interface compatible with the FancyLED library. + and with this is similar to the NeoPixel and DotStar Interfaces. + + this TLC59711AutoShow is a subclass of TLC59711 that adds automatically + sending changed data to the chips. + this creates very slows responses on big changes. + It is mainly usefull if you only have a very small number of pixels. + + :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. + The clock and MOSI/outout must be set, the MISO/input is unused. + Maximal data clock frequence is: + - TLC59711: 10MHz + - TLC5971: 20MHz + :param bool pixel_count: Number of RGB-LEDs (=Pixels) that are connected. + """ + + def __init__(self, spi, pixel_count=4): + """Init.""" + super(TLC59711AutoShow, self).__init__(spi, pixel_count=pixel_count) + + ########################################## + + def set_pixel(self, pixel_index, value): + """ + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + + :param int pixel_index: 0..(pixel_count) + :param tuple value: 3-tuple of R, G, B; + each int 0..65535 or float 0..1 + """ + super(TLC59711AutoShow, self).set_pixel(pixel_index, value) + self._write() + + def set_pixel_all(self, color): + """ + Set the R, G, B values for all pixels. + + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + super(TLC59711AutoShow, self).set_pixel_all(color) + self._write() + + def set_all_black(self): + """Set all pixels to black.""" + super(TLC59711AutoShow, self).set_all_black() + self._write() + + # channel access + def set_channel(self, channel_index, value): + """ + Set the value for the provided channel. + + :param int channel_index: 0..channel_count + :param int value: 0..65535 + """ + super(TLC59711AutoShow, self).set_channel(channel_index, value) + self._write() + + def __setitem__(self, key, value): + """ + Set the R, G, B values for the pixel. + + this funciton hase some advanced error checking. + it is much slower than the other provided 'bare' variants.. + but therefor gives clues to what is going wrong.. ;-) + this shortcut is identicall to `set_pixel` + + :param int key: 0..(pixel_count) + :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 + """ + super(TLC59711AutoShow, self).__setitem__(key, value) + self._write() + + class _ChannelDirektAutoShow: + # Internal decorator to simplify mapping. + + def __init__(self, channel): + self._channel = channel + + def __get__(self, obj, obj_type): + # Grab the 16-bit value at the offset for this channel. + return obj._get_channel_16bit_value(self._channel) + + def __set__(self, obj, value): + # Set the 16-bit value at the offset for this channel. + assert 0 <= value <= 65535 + obj.set_channel(self._channel, value) + obj._write() + + # Define explicit channels for first IC. + # → this is only for api backwards compliance. + # not recommended for new use - use *set_channel* + b0 = _ChannelDirektAutoShow(0) + g0 = _ChannelDirektAutoShow(1) + r0 = _ChannelDirektAutoShow(2) + b1 = _ChannelDirektAutoShow(3) + g1 = _ChannelDirektAutoShow(4) + r1 = _ChannelDirektAutoShow(5) + b2 = _ChannelDirektAutoShow(6) + g2 = _ChannelDirektAutoShow(7) + r2 = _ChannelDirektAutoShow(8) + b3 = _ChannelDirektAutoShow(9) + g3 = _ChannelDirektAutoShow(10) + r3 = _ChannelDirektAutoShow(11) diff --git a/examples/tlc59711_singlechip.py b/examples/tlc59711_singlechip_autoshow.py similarity index 77% rename from examples/tlc59711_singlechip.py rename to examples/tlc59711_singlechip_autoshow.py index 2d065db..1154f80 100644 --- a/examples/tlc59711_singlechip.py +++ b/examples/tlc59711_singlechip_autoshow.py @@ -1,10 +1,12 @@ """TLC5971 / TLC59711.""" __doc__ = """ -tlc59711_singlechip.py - TLC59711 minimal usage example. +tlc59711_singlechip_autoshow.py - TLC59711AutoShow minimal usage example. simple demo of the TLC59711 16-bit 12 channel LED PWM driver. Shows the minimal usage - how to set pixel values. +the TLC59711AutoShow class automatically writes the pixel values on each change. +this makes it very slow on lots of pixel changs but is convenient for only a handfull of pixels.. Author: Tony DiCola, Stefan Krueger @@ -21,12 +23,7 @@ # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) - -# Define the TLC59711 instance with one TLC chip connected. -pixels = adafruit_tlc59711.TLC59711(spi) - - -print("tlc59711_onechip.py") +pixels = adafruit_tlc59711.TLC59711AutoShow(spi) # Ways to set the values: # just a list or tuple with 3 integer values: R G B @@ -36,8 +33,6 @@ pixels[1] = (0, 0, 100) pixels[2] = (0.01, 0.0, 0.01) pixels[3] = (0.1, 0.01, 0.0) -# if you are ready to show your values you have to call -pixels.show() # You can also explicitly control each R0, G0, B0, R1, B1, etc. channel of the first ic # by getting and setting its 16-bit value directly with properties. From 17fbcee9c666839a23b89c1d347fa29dad0823a1 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 12 Sep 2020 15:59:38 +0200 Subject: [PATCH 72/91] fix examples --- examples/tlc59711_fastset.py | 6 +++--- examples/tlc59711_minimal.py | 2 +- examples/tlc59711_test_bcdata.py | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 9482520..9f42109 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -5,7 +5,7 @@ showcases the usage of set_pixel_16bit_value for fastest setting of values. for speed comparision of all the available set calls -look at the tlc59711_multi_dev.py file. +look at the tlc59711_dev.py file. Enjoy the colors :-) """ @@ -22,7 +22,7 @@ PIXEL_COUNT = 16 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) +pixels = adafruit_tlc59711.TLC59711(spi, pixel_count=PIXEL_COUNT) ########################################## @@ -57,7 +57,7 @@ def test_main(): print(__doc__, end="") print(42 * "*") - bcvalues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( + bcvalues = adafruit_tlc59711.TLC59711.calculate_BCData( Ioclmax=18, IoutR=18, IoutG=11, diff --git a/examples/tlc59711_minimal.py b/examples/tlc59711_minimal.py index f00e468..eeaac3c 100644 --- a/examples/tlc59711_minimal.py +++ b/examples/tlc59711_minimal.py @@ -19,7 +19,7 @@ # Define SPI bus connected to chip. # You only need the clock and MOSI (output) line to use this chip. spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=16) +pixels = adafruit_tlc59711.TLC59711(spi, pixel_count=16) # Ways to set the values: # just a list or tuple with 3 integer values: R G B diff --git a/examples/tlc59711_test_bcdata.py b/examples/tlc59711_test_bcdata.py index e5ad972..80244bf 100644 --- a/examples/tlc59711_test_bcdata.py +++ b/examples/tlc59711_test_bcdata.py @@ -18,7 +18,7 @@ PIXEL_COUNT = 16 * 8 spi = busio.SPI(board.SCK, MOSI=board.MOSI) -pixels = adafruit_tlc59711.TLC59711Multi(spi, pixel_count=PIXEL_COUNT) +pixels = adafruit_tlc59711.TLC59711(spi, pixel_count=PIXEL_COUNT) ########################################## @@ -42,7 +42,7 @@ def main_loop(): IoutB = float(IoutB) except ValueError as e: print("Exception: ", e) - BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( Ioclmax=Ioclmax, IoutR=IoutR, IoutG=IoutG, @@ -79,11 +79,11 @@ def test_main(): print("set pixel all to 100, 100, 100") pixels.set_pixel_all((5000, 5000, 5000)) # calculate bc values - Ioclmax = adafruit_tlc59711.TLC59711Multi.calculate_Ioclmax(Riref=2.7) + Ioclmax = adafruit_tlc59711.TLC59711.calculate_Ioclmax(Riref=2.7) print("Ioclmax = {}".format(Ioclmax)) - Riref = adafruit_tlc59711.TLC59711Multi.calculate_Riref(Ioclmax=Ioclmax) + Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) - BCValues = adafruit_tlc59711.TLC59711Multi.calculate_BCData( + BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( Ioclmax=Ioclmax, IoutR=18, IoutG=11, From 9e16d6e9185442f060ccbd56b09b2d01ff26478e Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 12 Sep 2020 16:05:43 +0200 Subject: [PATCH 73/91] linting.. --- .pylintrc | 28 +++++++++++++++++++++++++--- adafruit_tlc59711.py | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/.pylintrc b/.pylintrc index 0d907b9..e509798 100644 --- a/.pylintrc +++ b/.pylintrc @@ -175,7 +175,13 @@ missing-member-max-choices=1 # List of additional names supposed to be defined in builtins. # Remember that you should avoid to define new builtins when possible. -additional-builtins=_CHIP_BUFFER_BYTE_COUNT, _BC_CHIP_BUFFER_BIT_OFFSET, _FC_CHIP_BUFFER_BIT_OFFSET, _WC_CHIP_BUFFER_BIT_OFFSET, _BUFFER_BYTES_PER_COLOR, _CHIP_BUFFER_HEADER_BYTE_COUNT +additional-builtins= + _CHIP_BUFFER_BYTE_COUNT, + _BC_CHIP_BUFFER_BIT_OFFSET, + _FC_CHIP_BUFFER_BIT_OFFSET, + _WC_CHIP_BUFFER_BIT_OFFSET, + _BUFFER_BYTES_PER_COLOR, + _CHIP_BUFFER_HEADER_BYTE_COUNT # ugly workaround for pylint not knowing of micropython const thing: # this fixes the E0602: Undefined variable error. @@ -223,7 +229,7 @@ indent-string=' ' max-line-length=100 # Maximum number of lines in a module -max-module-lines=1000 +max-module-lines=1100 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. @@ -308,7 +314,23 @@ function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # these variable names represent the datasheet nameing - so they are allowed! # good-names=Ioclmax, IoutR, IoutG, IoutB, BCValues,calculate_Ioclmax # combined: -good-names=r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_,Riref,Viref,Ioclmax,IoutR,IoutG,IoutB,BCValues,calculate_Ioclmax,calculate_Riref,calculate_BCData,chip_set_BCData,update_BCData,_chip_set_FunctionControl,_chip_set_WriteCommand,b0,g0,r0,b1,g1,r1,b2,g2,r2,b3,g3,r3 +good-names= + r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_, + Riref, + Viref, + Ioclmax, + IoutR, + IoutG, + IoutB, + BCValues, + calculate_Ioclmax, + calculate_Riref, + calculate_BCData, + chip_set_BCData, + update_BCData, + _chip_set_FunctionControl, + _chip_set_WriteCommand, + b0,g0,r0,b1,g1,r1,b2,g2,r2,b3,g3,r3 # Include a hint for the correct naming format with invalid-name include-naming-hint=no diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 3201b24..af57c08 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -967,6 +967,7 @@ def __set__(self, obj, value): ########################################## + class TLC59711AutoShow(TLC59711): """TLC59711 16-bit 12 channel LED PWM driver with Auto-Show. From 334701220506a4352422c5173c1e56628df92851 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Sat, 12 Sep 2020 17:41:14 -0500 Subject: [PATCH 74/91] black format --- adafruit_tlc59711.py | 54 ++++++-------------------------- examples/tlc59711_dev.py | 22 +++---------- examples/tlc59711_fastset.py | 5 +-- examples/tlc59711_test_bcdata.py | 16 ++-------- 4 files changed, 17 insertions(+), 80 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index af57c08..7f76ec7 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -190,21 +190,9 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": { - "offset": 0, - "length": 7, - "mask": 0b01111111, - }, - "BCG": { - "offset": 7, - "length": 7, - "mask": 0b01111111, - }, - "BCB": { - "offset": 14, - "length": 7, - "mask": 0b01111111, - }, + "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, + "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, + "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, } ########################################## @@ -237,31 +225,11 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": { - "offset": 0, - "length": 1, - "mask": 0b1, - }, - "DSPRPT": { - "offset": 1, - "length": 1, - "mask": 0b1, - }, - "TMGRST": { - "offset": 2, - "length": 1, - "mask": 0b1, - }, - "EXTGCK": { - "offset": 3, - "length": 1, - "mask": 0b1, - }, - "OUTTMG": { - "offset": 4, - "length": 1, - "mask": 0b1, - }, + "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, + "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, + "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, + "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, + "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, } ########################################## @@ -271,11 +239,7 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": { - "offset": 0, - "length": 6, - "mask": 0b111111, - }, + "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, } WRITE_COMMAND = const(0b100101) ########################################## diff --git a/examples/tlc59711_dev.py b/examples/tlc59711_dev.py index a7ec71c..5f5ba07 100644 --- a/examples/tlc59711_dev.py +++ b/examples/tlc59711_dev.py @@ -101,10 +101,7 @@ def timeit_call(message, test_function, loop_count=1000): # "{:>8.2f}ms".format(3.56) print( "{call_duration:>10.4f}ms\t{message}" - "".format( - call_duration=(duration / loop_count) * 1000, - message=message, - ) + "".format(call_duration=(duration / loop_count) * 1000, message=message,) ) @@ -411,11 +408,7 @@ def test_bcdata(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) + "".format(pixels.bcr, pixels.bcg, pixels.bcb,) ) # calculate bc values Ioclmax = adafruit_tlc59711.TLC59711.calculate_Ioclmax(Riref=2.7) @@ -423,10 +416,7 @@ def test_bcdata(): Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=18, - IoutG=11, - IoutB=13, + Ioclmax=Ioclmax, IoutR=18, IoutG=11, IoutB=13, ) # (127, 77, 91) print("BCValues = {}".format(BCValues)) @@ -441,11 +431,7 @@ def test_bcdata(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) + "".format(pixels.bcr, pixels.bcg, pixels.bcb,) ) time.sleep(2) diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 9f42109..5ee8bf4 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -58,10 +58,7 @@ def test_main(): print(42 * "*") bcvalues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=18, - IoutR=18, - IoutG=11, - IoutB=13, + Ioclmax=18, IoutR=18, IoutG=11, IoutB=13, ) print("bcvalues = {}".format(bcvalues)) pixels.bcr = bcvalues[0] diff --git a/examples/tlc59711_test_bcdata.py b/examples/tlc59711_test_bcdata.py index 80244bf..b84b079 100644 --- a/examples/tlc59711_test_bcdata.py +++ b/examples/tlc59711_test_bcdata.py @@ -43,10 +43,7 @@ def main_loop(): except ValueError as e: print("Exception: ", e) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=IoutR, - IoutG=IoutG, - IoutB=IoutB, + Ioclmax=Ioclmax, IoutR=IoutR, IoutG=IoutG, IoutB=IoutB, ) pixels.bcr = BCValues[0] pixels.bcg = BCValues[1] @@ -55,11 +52,7 @@ def main_loop(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format( - pixels.bcr, - pixels.bcg, - pixels.bcb, - ) + "".format(pixels.bcr, pixels.bcg, pixels.bcb,) ) pixels.update_BCData() pixels.show() @@ -84,10 +77,7 @@ def test_main(): Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, - IoutR=18, - IoutG=11, - IoutB=13, + Ioclmax=Ioclmax, IoutR=18, IoutG=11, IoutB=13, ) # (127, 77, 91) print("BCValues = {}".format(BCValues)) From e56306a3a115469841ed44ebd3686e57edc5b782 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Sat, 12 Sep 2020 17:48:19 -0500 Subject: [PATCH 75/91] fix pylint issues for super call --- adafruit_tlc59711.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 7f76ec7..d3c3247 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -954,7 +954,7 @@ class TLC59711AutoShow(TLC59711): def __init__(self, spi, pixel_count=4): """Init.""" - super(TLC59711AutoShow, self).__init__(spi, pixel_count=pixel_count) + super().__init__(spi, pixel_count=pixel_count) ########################################## @@ -970,7 +970,7 @@ def set_pixel(self, pixel_index, value): :param tuple value: 3-tuple of R, G, B; each int 0..65535 or float 0..1 """ - super(TLC59711AutoShow, self).set_pixel(pixel_index, value) + super().set_pixel(pixel_index, value) self._write() def set_pixel_all(self, color): @@ -979,12 +979,12 @@ def set_pixel_all(self, color): :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 """ - super(TLC59711AutoShow, self).set_pixel_all(color) + super().set_pixel_all(color) self._write() def set_all_black(self): """Set all pixels to black.""" - super(TLC59711AutoShow, self).set_all_black() + super().set_all_black() self._write() # channel access @@ -995,7 +995,7 @@ def set_channel(self, channel_index, value): :param int channel_index: 0..channel_count :param int value: 0..65535 """ - super(TLC59711AutoShow, self).set_channel(channel_index, value) + super().set_channel(channel_index, value) self._write() def __setitem__(self, key, value): @@ -1010,7 +1010,7 @@ def __setitem__(self, key, value): :param int key: 0..(pixel_count) :param tuple 3-tuple of R, G, B; each int 0..65535 or float 0..1 """ - super(TLC59711AutoShow, self).__setitem__(key, value) + super().__setitem__(key, value) self._write() class _ChannelDirektAutoShow: From 56ff1c64ed12e4f2ab1425be02e4a516d33a51e4 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 13 Sep 2020 18:58:26 +0200 Subject: [PATCH 76/91] rename minimal to simpletest --- examples/{tlc59711_minimal.py => tlc59711_simpletest.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{tlc59711_minimal.py => tlc59711_simpletest.py} (100%) diff --git a/examples/tlc59711_minimal.py b/examples/tlc59711_simpletest.py similarity index 100% rename from examples/tlc59711_minimal.py rename to examples/tlc59711_simpletest.py From 913b596ce0850f6c80eed4e6151eb82c4337a265 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 13 Sep 2020 19:05:01 +0200 Subject: [PATCH 77/91] fix doc --- docs/api.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 88a67d7..d84b817 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -3,6 +3,3 @@ .. automodule:: adafruit_tlc59711.adafruit_tlc59711 :members: - -.. automodule:: adafruit_tlc59711.adafruit_tlc59711_multi - :members: From 3ce7ab51fdfa46e54ce37cbde6d1a015a301e4e5 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 13 Sep 2020 19:20:25 +0200 Subject: [PATCH 78/91] fixed doc (removed package sub path) --- docs/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index d84b817..4991f11 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,5 +1,5 @@ .. If you created a package, create one automodule per module in the package. -.. automodule:: adafruit_tlc59711.adafruit_tlc59711 +.. automodule:: adafruit_tlc59711 :members: From 951317155d84d783c7f6ccacfe07c5e086fb70a3 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 13 Sep 2020 19:31:42 +0200 Subject: [PATCH 79/91] another fix --- adafruit_tlc59711.py | 56 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index d3c3247..9932b27 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -22,7 +22,7 @@ # THE SOFTWARE. """ -`adafruit_tlc59711_multi`. +`adafruit_tlc59711`. ==================================================== @@ -190,9 +190,21 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, - "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, - "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, + "BCR": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCB": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, } ########################################## @@ -225,11 +237,31 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, - "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, - "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, - "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, - "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, + "BLANK": { + "offset": 0, + "length": 1, + "mask": 0b1, + }, + "DSPRPT": { + "offset": 1, + "length": 1, + "mask": 0b1, + }, + "TMGRST": { + "offset": 2, + "length": 1, + "mask": 0b1, + }, + "EXTGCK": { + "offset": 3, + "length": 1, + "mask": 0b1, + }, + "OUTTMG": { + "offset": 4, + "length": 1, + "mask": 0b1, + }, } ########################################## @@ -239,7 +271,11 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, + "WRITE_COMMAND": { + "offset": 0, + "length": 6, + "mask": 0b111111, + }, } WRITE_COMMAND = const(0b100101) ########################################## From b09f17af2fb52f89f08bbe1693ec3bc4a078db44 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Sun, 13 Sep 2020 14:50:21 -0500 Subject: [PATCH 80/91] black format --- adafruit_tlc59711.py | 54 ++++++++------------------------------------ 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 9932b27..1e33ff2 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -190,21 +190,9 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": { - "offset": 0, - "length": 7, - "mask": 0b01111111, - }, - "BCG": { - "offset": 7, - "length": 7, - "mask": 0b01111111, - }, - "BCB": { - "offset": 14, - "length": 7, - "mask": 0b01111111, - }, + "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, + "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, + "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, } ########################################## @@ -237,31 +225,11 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": { - "offset": 0, - "length": 1, - "mask": 0b1, - }, - "DSPRPT": { - "offset": 1, - "length": 1, - "mask": 0b1, - }, - "TMGRST": { - "offset": 2, - "length": 1, - "mask": 0b1, - }, - "EXTGCK": { - "offset": 3, - "length": 1, - "mask": 0b1, - }, - "OUTTMG": { - "offset": 4, - "length": 1, - "mask": 0b1, - }, + "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, + "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, + "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, + "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, + "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, } ########################################## @@ -271,11 +239,7 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": { - "offset": 0, - "length": 6, - "mask": 0b111111, - }, + "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, } WRITE_COMMAND = const(0b100101) ########################################## From 8d921215046911b7e2953a55193987ceb3efce52 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 13 Sep 2020 22:56:05 +0200 Subject: [PATCH 81/91] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ae0d206..e31dac4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ install: - pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme - pip install --force-reinstall pylint==1.9.2 script: -- pylint adafruit_tlc59711/*.py +- pylint adafruit_tlc59711.py - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-tlc59711 --library_location From d97e601c3fa2f7b5e5ec9f6f00c46deb877ae532 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Mon, 28 Sep 2020 10:50:29 -0500 Subject: [PATCH 82/91] remove travis --- .travis.yml | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ae0d206..0000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -dist: trusty -sudo: false -language: python -python: -- '3.6' -cache: - pip: true -deploy: -- provider: releases - api_key: "$GITHUB_TOKEN" - file_glob: true - file: "$TRAVIS_BUILD_DIR/bundles/*" - skip_cleanup: true - overwrite: true - on: - tags: true -- provider: pypi - user: adafruit-travis - on: - tags: true - password: - secure: Bb5O7KFF8KzwlRBmKuBD4MXOZfycKyHvsghpaGabp9ckZWy+wqS1kKlYbosXbRuAlF4xeGNMFRDBXDx6nEQFa70ozFqgqfA6CpCDtgQgtGhIQxthurR9Mrob4o9kCzwdG8rk1+XC35Ab290bnwLF27tGUm/qeOKhrK/WPOq1VBe4tKjF1HuPhvFljJFa10w1kST+EeSDOnJr+y5o4Cw8Vdoo++e86h184b0vXFT01nefpRDXtHDnzGT+MT24jnfdkAivKuTODHRih7OgpkiyzZKZgyf7oFkKdPqjA0XODTCmnKH9gzFZJ+aeqQUQt2bHk0+yxezy6BV6HRITpPkYW3hH/TCYSUDNexGx1rfGVWrMs0F9wN2lMWyGEzWH6wnBcXQWiCpnRbQOHEeUA4502TO3Ybk3Brr9Y8uFWAIJiIR3fzk0SmhPOT8GN/stmz7U5KiIaXTxeTJaEmZcokE/9NJtqORNXboM9sDqVcXkN59muibkFKN0Zsg+YPEiieitGQv4bPedmg1lW1Bl4G36Vf/xkX2P8XlDq2f8ADLPdQhcjLuQmxHfUHiWrKonqmEfr49E1DQ+fDqwkOCEG0MykQlN0q1MFiZNs6OPSwW5yjsGLMUsfWHqQXYc5ZXtAp5twRHHqPtdqAaKLSbN1v/a9cNO/8oqn+I4A5L9ImYtFS4= -install: -- pip install -r requirements.txt -- pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme -- pip install --force-reinstall pylint==1.9.2 -script: -- pylint adafruit_tlc59711/*.py -- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace - examples/*.py) -- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-tlc59711 --library_location - . -- cd docs && sphinx-build -E -W -b html . _build/html && cd .. From ab0dccc1e12dc95dcdfd647347ccc57a62c7bcd8 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Mon, 28 Sep 2020 10:51:26 -0500 Subject: [PATCH 83/91] remove travis --- .travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e69de29..0000000 From cbb8a2fa96d65961e3f2384677071cefd2e26b19 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 19 Dec 2020 11:18:02 +0100 Subject: [PATCH 84/91] cleanup --- adafruit_tlc59711__original.py | 324 --------------------------------- 1 file changed, 324 deletions(-) delete mode 100644 adafruit_tlc59711__original.py diff --git a/adafruit_tlc59711__original.py b/adafruit_tlc59711__original.py deleted file mode 100644 index 1bb6a10..0000000 --- a/adafruit_tlc59711__original.py +++ /dev/null @@ -1,324 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2017 Tony DiCola for Adafruit Industries -# -# 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. - - -""" -`adafruit_tlc59711` -==================================================== - -CircuitPython module for the -TLC59711 16-bit 12 channel LED PWM driver. -See examples/simpletest.py for a demo of the usage. - -* Author(s): Tony DiCola - -Implementation Notes --------------------- - -**Hardware:** - -* Adafruit `12-Channel 16-bit PWM LED Driver - SPI Interface - TLC59711 - `_ (Product ID: 1455) - - -**Software and Dependencies:** - -* Adafruit CircuitPython firmware for the ESP8622 and M0-based boards: - https://github.com/adafruit/circuitpython/releases -""" -__version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" - - -# Globally disable invalid-name check as this chip by design has short channel -# and register names. It is confusing to rename these from what the datasheet -# refers to them as. -# pylint: disable=invalid-name - -# Globally disable too many instance attributes check. Again this is a case -# where pylint doesn't have the right context to make this call. The chip by -# design has many channels which must be exposed. -# pylint: disable=too-many-instance-attributes - -# Globally disable protected access. Once again pylint can't figure out the -# context for using internal decorate classes below. -# In these cases protected access is by design for the internal class. -# pylint: disable=protected-access - -# Yet another pylint issue, it fails to recognize a decorator class by -# definition has no public methods. Disable the check. -# pylint: disable=too-few-public-methods - - -def _shift_in(target_byte, val): - # Shift in a new bit value to the provided target byte. The byte will be - # shift one position left and a new bit inserted that's a 1 if val is true, - # of a 0 if false. - target_byte <<= 1 - if val: - target_byte |= 0x01 - return target_byte - - -class TLC59711: - """TLC59711 16-bit 12 channel LED PWM driver. This chip is designed to - drive 4 RGB LEDs with 16-bit PWM control of each LED. The class has an - interface much like that of NeoPixels with attribute access to the 4 - RGB channels (note they are 16-bit values). Or you can access each - independent channel by name (r0, g0, b0, r1, b1, etc.) as properties for - fine-grained control. - - :param ~busio.SPI spi: An instance of the SPI bus connected to the chip. - The clock and MOSI/outout must be set, the MISO/input is unused. - :param bool auto_show: This is a boolean that defaults to True and - indicates any change to a channel value will instantly be written - to the chip. You might wish to set this to false if you desire - to perform your own atomic operations of channel values. In that case - call the show function after making updates to channel state. - """ - - class _GS_Value: - # Internal decorator to simplify exposing each 16-bit LED PWM channel. - # These will get/set the appropriate bytes in the shift register with - # the specified values. - - def __init__(self, byte_offset): - # Keep track of the byte within the shift register where this - # 16-bit value starts. Luckily these are all aligned on byte - # boundaries. Note the byte order is big endian (MSB first). - self._byte_offset = byte_offset - - def __get__(self, obj, obj_type): - # Grab the 16-bit value at the offset for this channel. - return (obj._shift_reg[self._byte_offset] << 8) | obj._shift_reg[ - self._byte_offset + 1 - ] - - def __set__(self, obj, val): - # Set the 16-bit value at the offset for this channel. - assert 0 <= val <= 65535 - obj._shift_reg[self._byte_offset] = (val >> 8) & 0xFF - obj._shift_reg[self._byte_offset + 1] = val & 0xFF - # Write out the new values if auto_show is enabled. - if obj.auto_show: - obj._write() - - # Define explicit GS channels (each LED PWM channel) for users to control. - # See also the __len__ and iterable dunder methods that provide a - # neopixel-like interface to the GS channel values too. Each has a - # trade-off in usage so users can decide how they choose to use the class - # (must change all 3 values at a time with neopixel-like interface vs. - # direct single channel control with these properties below). - b3 = _GS_Value(4) - g3 = _GS_Value(6) - r3 = _GS_Value(8) - - b2 = _GS_Value(10) - g2 = _GS_Value(12) - r2 = _GS_Value(14) - - b1 = _GS_Value(16) - g1 = _GS_Value(18) - r1 = _GS_Value(20) - - b0 = _GS_Value(22) - g0 = _GS_Value(24) - r0 = _GS_Value(26) - - def __init__(self, spi, *, auto_show=True): # noqa - self._spi = spi - # This device is just a big 28 byte long shift register without any - # fancy update protocol. Blast out all the bits to update, that's it! - self._shift_reg = bytearray(28) - # Keep track of automatically writing out the state of the PWM channels - # on any change (auto_show = True). If set to false the user must - # explicitly call the show method to write out the PWM state to the - # chip--this is useful for performing atomic updates to LEDs (i.e. - # changing all the R, G, B channels at once). - self.auto_show = auto_show - # Initialize the brightness channel values to max (these are 7-bit - # values). - self._bcr = 127 - self._bcg = 127 - self._bcb = 127 - # Initialize external user-facing state for the function control - # bits of the chip. These aren't commonly used but available and - # match the nomenclature from the datasheet. Note they won't honor - # the auto_show property and instead you must manually call show - # after changing them (reduces the need to make frivolous - # memory-hogging properties). - # Set OUTTMG, TMGRST, and DSPRPT to on like the Arduino library. - self.outtmg = True - self.extgclk = False - self.tmgrst = True - self.dsprpt = True - self.blank = False - - def _write(self): - # Write out the current state to the shift register. - try: - # Lock the SPI bus and configure it for the shift register. - while not self._spi.try_lock(): - pass - self._spi.configure(baudrate=10000000, polarity=0, phase=0) - # Update the preamble of chip state in the first 4 bytes (32-bits) - # with the write command, function control bits, and brightness - # control register values. - self._shift_reg[0] = 0x25 # 0x25 in top 6 bits initiates write. - # Lower two bits control OUTTMG and EXTGCLK bits, set them - # as appropriate. - self._shift_reg[0] = _shift_in(self._shift_reg[0], self.outtmg) - self._shift_reg[0] = _shift_in(self._shift_reg[0], self.extgclk) - # Next byte contains remaining function control state and start of - # brightness control bits. - self._shift_reg[1] = 0x00 - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.tmgrst) - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.dsprpt) - self._shift_reg[1] = _shift_in(self._shift_reg[1], self.blank) - # Top 5 bits from BC blue channel. - self._shift_reg[1] <<= 5 - self._shift_reg[1] |= (self._bcb >> 2) & 0b11111 - # Next byte contains lower 2 bits from BC blue channel and upper 6 - # from BC green channel. - self._shift_reg[2] = (self._bcb) & 0b11 - self._shift_reg[2] <<= 6 - self._shift_reg[2] |= (self._bcg >> 1) & 0b111111 - # Final byte contains lower 1 bit from BC green and 7 bits from BC - # red channel. - self._shift_reg[3] = self._bcg & 0b1 - self._shift_reg[3] <<= 7 - self._shift_reg[3] |= self._bcr & 0b1111111 - # The remaining bytes in the shift register are the channel PWM - # values that have already been set by the user. Now write out the - # the entire set of bytes. Note there is no latch or other - # explicit line to tell the chip when finished, it expects 28 bytes. - self._spi.write(self._shift_reg) - finally: - # Ensure the SPI bus is unlocked. - self._spi.unlock() - - def show(self): - """Write out the current LED PWM state to the chip. This is only necessary if - auto_show was set to false in the initializer. - """ - self._write() - - # Define properties for global brightness control channels. - @property - def red_brightness(self): - """The red brightness for all channels (i.e. R0, R1, R2, and R3). - - This is a 7-bit value from 0-127. - """ - return self._bcr - - @red_brightness.setter - def red_brightness(self, val): - assert 0 <= val <= 127 - self._bcr = val - if self.auto_show: - self._write() - - @property - def green_brightness(self): - """The green brightness for all channels (i.e. G0, G1, G2, and G3). - - This is a 7-bit value from 0-127. - """ - return self._bcg - - @green_brightness.setter - def green_brightness(self, val): - assert 0 <= val <= 127 - self._bcg = val - if self.auto_show: - self._write() - - @property - def blue_brightness(self): - """The blue brightness for all channels (i.e. B0, B1, B2, and B3). - - This is a 7-bit value from 0-127. - """ - return self._bcb - - @blue_brightness.setter - def blue_brightness(self, val): - assert 0 <= val <= 127 - self._bcb = val - if self.auto_show: - self._write() - - # Define index and length properties to set and get each channel as - # atomic RGB tuples. This provides a similar feel as using neopixels. - def __len__(self): - """Retrieve the total number of LED channels available.""" - return 4 # Always 4 RGB channels on the chip. - - def __getitem__(self, key): - # pylint: disable=no-else-return - # Disable should be removed when refactor can be tested - """Retrieve the R, G, B values for the provided channel as a - 3-tuple. Each value is a 16-bit number from 0-65535. - """ - if key == 0: - return (self.r0, self.g0, self.b0) - elif key == 1: - return (self.r1, self.g1, self.b1) - elif key == 2: - return (self.r2, self.g2, self.b2) - elif key == 3: - return (self.r3, self.g3, self.b3) - else: - raise IndexError - - def __setitem__(self, key, val): - """Set the R, G, B values for the provided channel. Specify a - 3-tuple of R, G, B values that are each 16-bit numbers (0-65535). - """ - # Do this check here instead of later to - # prevent accidentally keeping auto_show - # turned off when a bad key is provided. - assert 0 <= key <= 3 - - assert len(val) == 3 - assert 0 <= val[0] <= 65535 - assert 0 <= val[1] <= 65535 - assert 0 <= val[2] <= 65535 - # Temporarily halt auto write to perform an atomic update of all - # the channel values. - old_auto_show = self.auto_show - self.auto_show = False - # Update appropriate channel values. - if key == 0: - self.r0, self.g0, self.b0 = val - elif key == 1: - self.r1, self.g1, self.b1 = val - elif key == 2: - self.r2, self.g2, self.b2 = val - elif key == 3: - self.r3, self.g3, self.b3 = val - # Restore auto_show state. - self.auto_show = old_auto_show - # Write out new values if in auto_show state. - if self.auto_show: - self._write() From 309b4823e5bbdaf481a919ad3f71a111578fc8f0 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 19 Dec 2020 11:39:19 +0100 Subject: [PATCH 85/91] add detailed explanation --- examples/tlc59711_simpletest.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/tlc59711_simpletest.py b/examples/tlc59711_simpletest.py index eeaac3c..0749e8a 100644 --- a/examples/tlc59711_simpletest.py +++ b/examples/tlc59711_simpletest.py @@ -21,10 +21,18 @@ spi = busio.SPI(board.SCK, MOSI=board.MOSI) pixels = adafruit_tlc59711.TLC59711(spi, pixel_count=16) -# Ways to set the values: -# just a list or tuple with 3 integer values: R G B -# each 0 - 65535 or 0.0 - 1.0 -# every chip has 4 RGB-LEDs (=12 Channel) +# examples how to set the pixels: +# range: +# 0 - 65535 +# or +# 0.0 - 1.0 +# every pixel needs a color - +# give it just a list or tuple with 3 integer values: R G B + +# set all pixels to a very low level +pixels.set_pixel_all((10, 10, 10)) + +# every chip has 4 Pixels (=RGB-LEDs = 12 Channel) pixels[0] = (100, 100, 100) pixels[1] = (0, 0, 100) pixels[2] = (0.01, 0.0, 0.01) @@ -32,5 +40,5 @@ # if you are ready to show your values you have to call pixels.show() -# there are a bunch of other advanced ways to set pixel. +# there are a bunch of other ways to set pixel. # have a look at the other examples. From af124975ea89fc5aca347163b8af2af07afd4db4 Mon Sep 17 00:00:00 2001 From: s-light Date: Sat, 19 Dec 2020 17:09:18 +0100 Subject: [PATCH 86/91] revert changes to .pylintrc and add file global disables. (inline disable would not make sens to fix the undefined-variable and invalid-name multiple times in my opinion.) --- .pylintrc | 37 +++--------------------- adafruit_tlc59711.py | 68 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 43 deletions(-) diff --git a/.pylintrc b/.pylintrc index e509798..d8f0ee8 100644 --- a/.pylintrc +++ b/.pylintrc @@ -173,18 +173,9 @@ missing-member-max-choices=1 [VARIABLES] -# List of additional names supposed to be defined in builtins. -# Remember that you should avoid to define new builtins when possible. +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. additional-builtins= - _CHIP_BUFFER_BYTE_COUNT, - _BC_CHIP_BUFFER_BIT_OFFSET, - _FC_CHIP_BUFFER_BIT_OFFSET, - _WC_CHIP_BUFFER_BIT_OFFSET, - _BUFFER_BYTES_PER_COLOR, - _CHIP_BUFFER_HEADER_BYTE_COUNT -# ugly workaround for pylint not knowing of micropython const thing: -# this fixes the E0602: Undefined variable error. - # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes @@ -229,7 +220,7 @@ indent-string=' ' max-line-length=100 # Maximum number of lines in a module -max-module-lines=1100 +max-module-lines=1000 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. @@ -310,27 +301,7 @@ function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Good variable names which should always be accepted, separated by a comma # good-names=i,j,k,ex,Run,_ -# good-names=r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_ -# these variable names represent the datasheet nameing - so they are allowed! -# good-names=Ioclmax, IoutR, IoutG, IoutB, BCValues,calculate_Ioclmax -# combined: -good-names= - r,g,b,w,i,j,k,n,x,y,z,e,ex,ok,Run,_, - Riref, - Viref, - Ioclmax, - IoutR, - IoutG, - IoutB, - BCValues, - calculate_Ioclmax, - calculate_Riref, - calculate_BCData, - chip_set_BCData, - update_BCData, - _chip_set_FunctionControl, - _chip_set_WriteCommand, - b0,g0,r0,b1,g1,r1,b2,g2,r2,b3,g3,r3 +good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ # Include a hint for the correct naming format with invalid-name include-naming-hint=no diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index 1e33ff2..cff5f3e 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -45,7 +45,6 @@ * The API is mostly compatible to the DotStar / NeoPixel Libraries and is therefore also compatible with FancyLED. - for this see examples/fancy_multi.py * Adafruit CircuitPython firmware for the ESP8622, M0 or M4-based boards: https://github.com/adafruit/circuitpython/releases @@ -54,6 +53,19 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TLC59711.git" +# pylint - globally disable +# 'invalid-name' check to allow for datasheet conform short channel and register names. +# pylint: disable=invalid-name +# 'undefined-variable' to allow for micropython const definitions +# pylint: disable=undefined-variable +# 'too-many-lines' with the extra class and the api backwards compatibel things i have ~1100 lines.. +# and as it was wished to not alter the .pylint file to limit to 1100 i disable it here.. +# and yes - this code is very detailed commented. but i think that this is a good thing - +# as hopefully this way it is easier to understand desicions & +# what is going on and learn the backgrounds.. +# pylint: disable=too-many-lines + + import struct from micropython import const @@ -190,9 +202,21 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, - "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, - "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, + "BCR": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCB": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, } ########################################## @@ -225,11 +249,31 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, - "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, - "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, - "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, - "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, + "BLANK": { + "offset": 0, + "length": 1, + "mask": 0b1, + }, + "DSPRPT": { + "offset": 1, + "length": 1, + "mask": 0b1, + }, + "TMGRST": { + "offset": 2, + "length": 1, + "mask": 0b1, + }, + "EXTGCK": { + "offset": 3, + "length": 1, + "mask": 0b1, + }, + "OUTTMG": { + "offset": 4, + "length": 1, + "mask": 0b1, + }, } ########################################## @@ -239,7 +283,11 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, + "WRITE_COMMAND": { + "offset": 0, + "length": 6, + "mask": 0b111111, + }, } WRITE_COMMAND = const(0b100101) ########################################## From ea3fff7caf6aeca6e049b27a6a25ccef03534025 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 22 Dec 2020 20:55:52 +0100 Subject: [PATCH 87/91] add simple fancyled rainbow example --- examples/tlc59711_fancyled.pdf | Bin 0 -> 1690 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/tlc59711_fancyled.pdf diff --git a/examples/tlc59711_fancyled.pdf b/examples/tlc59711_fancyled.pdf new file mode 100644 index 0000000000000000000000000000000000000000..29aaa0f9cb50516ed4466968a30acf1123feac08 GIT binary patch literal 1690 zcmb7E+iu%141L#Ea5k_yY2qf^x^@M!hov1BtZfP;-O~U=wv||&Eg7=BG=D!zzV-ri z5pt2pLml!^lKbwYEYwNJ#R(ICA>ZpnijTyF@o)^0jJeoeK&dz5b7MjKoU5qh`pyCg zaU5rTJwN?&Hl4zI_)bN%zrMQk(M(7X#4-v3n1NZo1|vi#ya4=A0ql`xdCFiT6*6a- z5|V>X7}(I$Ge~);sM^Dh>!jl%SK>kLEijU)R0Uj&2PQE>c$Q10A(T|b-Ks3OY*#d< z8-)c0I*n`@O;GFDn4(e^`!6g&3uwHAxc@y!uDH;i^IJG@4Bn>?Fa&4l3~*7~8tGcY zYaoLi9K`EF#oRJtL+e~nZOv)Q3kEUYa*b07ITu(V_G5LoKq?oCoCi@Vqd(Zx7Uo}8 z0SmD#wP(flSM#4w@P5n{i!_(wS!8YXm-p+t`*lr`$$~$_*_8SWH_O$cp)mLZ8F(Sz zWLT`0Ed%1;WLVsq5?W2Go*fO3dX06A&Jda-=vShmq?kx+>GT_cDREZmSyg-Z8S6UT z>vMCVu%);6HvwMQ6{ax#OmhCn(gNr0QEzUA-&|jh01ixghToB0*r*_qrO>lxzY)Qc zSyT4>&Ir$x;qZILK?95uo>%*HxX#vtQ6X6R64^5&`ypbvkWnrml`^lBc_ExaKqz+> zgTf^x3*=@~FpY9e$S&ddbgfm%F03Y@;@d#Q?^irhl^AB@p2O&6OlH(aBw=Nvrec^c3j7Zj C*z%kJ literal 0 HcmV?d00001 From 91103cb0492a36f5d425bd82ee52669fe4a768ad Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 5 Jan 2021 16:10:08 +0100 Subject: [PATCH 88/91] run black==19.10b0 --- adafruit_tlc59711.py | 54 ++++++++------------------------------------ 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index cff5f3e..df4ebf8 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -202,21 +202,9 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": { - "offset": 0, - "length": 7, - "mask": 0b01111111, - }, - "BCG": { - "offset": 7, - "length": 7, - "mask": 0b01111111, - }, - "BCB": { - "offset": 14, - "length": 7, - "mask": 0b01111111, - }, + "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, + "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, + "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, } ########################################## @@ -249,31 +237,11 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": { - "offset": 0, - "length": 1, - "mask": 0b1, - }, - "DSPRPT": { - "offset": 1, - "length": 1, - "mask": 0b1, - }, - "TMGRST": { - "offset": 2, - "length": 1, - "mask": 0b1, - }, - "EXTGCK": { - "offset": 3, - "length": 1, - "mask": 0b1, - }, - "OUTTMG": { - "offset": 4, - "length": 1, - "mask": 0b1, - }, + "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, + "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, + "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, + "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, + "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, } ########################################## @@ -283,11 +251,7 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": { - "offset": 0, - "length": 6, - "mask": 0b111111, - }, + "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, } WRITE_COMMAND = const(0b100101) ########################################## From 81b9c30221c8f53bc1c81afb9f22a5a4e6024715 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 7 Jan 2021 11:53:50 +0100 Subject: [PATCH 89/91] fix pdf to py --- ...9711_fancyled.pdf => tlc59711_fancyled.py} | Bin 1690 -> 1680 bytes 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{tlc59711_fancyled.pdf => tlc59711_fancyled.py} (95%) diff --git a/examples/tlc59711_fancyled.pdf b/examples/tlc59711_fancyled.py similarity index 95% rename from examples/tlc59711_fancyled.pdf rename to examples/tlc59711_fancyled.py index 29aaa0f9cb50516ed4466968a30acf1123feac08..17520d0a88da9a3573c070fe9750c1153ecd7574 100644 GIT binary patch delta 43 xcmbQmJArqD5sO@LL8dJb>nIdtR;1>{C+C;umDu`)`o{aXx&-TNj$(0O0suuO4o3h0 delta 53 zcmbQhJBxRN5sLKpIl>JqHOwK;&rfe8SY C{SQR| From a3e4f27ca7c236f06bb4327c0e2d97aaf8b2052c Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 7 Jan 2021 18:52:54 +0100 Subject: [PATCH 90/91] fix pylint import order --- examples/tlc59711_fancyled.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tlc59711_fancyled.py b/examples/tlc59711_fancyled.py index 17520d0..2baa37c 100644 --- a/examples/tlc59711_fancyled.py +++ b/examples/tlc59711_fancyled.py @@ -15,8 +15,8 @@ import busio -import adafruit_tlc59711 import adafruit_fancyled.adafruit_fancyled as fancyled +import adafruit_tlc59711 ########################################## print("\n" + (42 * "*") + "\n" + __doc__ + "\n" + (42 * "*") + "\n" + "\n") From 13c36364a12ad4288ac55447ef5fb66f8614844d Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 27 Apr 2021 13:26:27 +0200 Subject: [PATCH 91/91] merge things cleanup.... --- adafruit_tlc59711.py | 113 +++++++++++------------ examples/tlc59711_dev.py | 32 ++++++- examples/tlc59711_fancyled.py | 9 +- examples/tlc59711_fastset.py | 16 +++- examples/tlc59711_singlechip_autoshow.py | 10 +- examples/tlc59711_test_bcdata.py | 26 +++++- pylama.ini | 3 + 7 files changed, 135 insertions(+), 74 deletions(-) diff --git a/adafruit_tlc59711.py b/adafruit_tlc59711.py index cf4c512..d99d2ad 100644 --- a/adafruit_tlc59711.py +++ b/adafruit_tlc59711.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-FileCopyrightText: 2018 Stefan Krüger s-light.eu # # SPDX-License-Identifier: MIT @@ -9,7 +10,7 @@ CircuitPython module for the TLC59711 or TLC5971 16-bit 12 channel LED PWM driver. -See examples/simpletest_multi.py for a demo of the usage. +See examples/tlc59711_simpletest.py for a demo of the usage. * Author(s): Tony DiCola, Stefan Kruger @@ -183,9 +184,21 @@ class TLC59711: _BC_BIT_COUNT = const(3 * 7) # this holds the chip offset and _BC_FIELDS = { - "BCR": {"offset": 0, "length": 7, "mask": 0b01111111,}, - "BCG": {"offset": 7, "length": 7, "mask": 0b01111111,}, - "BCB": {"offset": 14, "length": 7, "mask": 0b01111111,}, + "BCR": { + "offset": 0, + "length": 7, + "mask": 0b01111111, + }, + "BCG": { + "offset": 7, + "length": 7, + "mask": 0b01111111, + }, + "BCB": { + "offset": 14, + "length": 7, + "mask": 0b01111111, + }, } ########################################## @@ -218,11 +231,31 @@ class TLC59711: _FC_CHIP_BUFFER_BIT_OFFSET = const(_BC_BIT_COUNT) _FC_BIT_COUNT = const(5) _FC_FIELDS = { - "BLANK": {"offset": 0, "length": 1, "mask": 0b1,}, - "DSPRPT": {"offset": 1, "length": 1, "mask": 0b1,}, - "TMGRST": {"offset": 2, "length": 1, "mask": 0b1,}, - "EXTGCK": {"offset": 3, "length": 1, "mask": 0b1,}, - "OUTTMG": {"offset": 4, "length": 1, "mask": 0b1,}, + "BLANK": { + "offset": 0, + "length": 1, + "mask": 0b1, + }, + "DSPRPT": { + "offset": 1, + "length": 1, + "mask": 0b1, + }, + "TMGRST": { + "offset": 2, + "length": 1, + "mask": 0b1, + }, + "EXTGCK": { + "offset": 3, + "length": 1, + "mask": 0b1, + }, + "OUTTMG": { + "offset": 4, + "length": 1, + "mask": 0b1, + }, } ########################################## @@ -232,7 +265,11 @@ class TLC59711: _WC_CHIP_BUFFER_BIT_OFFSET = const(_FC_BIT_COUNT + _BC_BIT_COUNT) _WC_BIT_COUNT = const(6) _WC_FIELDS = { - "WRITE_COMMAND": {"offset": 0, "length": 6, "mask": 0b111111,}, + "WRITE_COMMAND": { + "offset": 0, + "length": 6, + "mask": 0b111111, + }, } WRITE_COMMAND = const(0b100101) ########################################## @@ -433,7 +470,6 @@ def _write(self): self._spi.unlock() def show(self): - """Write out the current LED PWM state to the chip.""" self._write() @@ -839,57 +875,12 @@ def set_channel(self, channel_index, value): ) # Define index and length properties to set and get each pixel as -======= - """Write out the current LED PWM state to the chip. This is only necessary if - auto_show was set to false in the initializer. - """ - self._write() - - # Define properties for global brightness control channels. - @property - def red_brightness(self): - """The red brightness for all channels (i.e. R0, R1, R2, and R3). This is a 7-bit - value from 0-127. - """ - return self._bcr - - @red_brightness.setter - def red_brightness(self, val): - assert 0 <= val <= 127 - self._bcr = val - if self.auto_show: - self._write() - - @property - def green_brightness(self): - """The green brightness for all channels (i.e. G0, G1, G2, and G3). This is a - 7-bit value from 0-127. - """ - return self._bcg - - @green_brightness.setter - def green_brightness(self, val): - assert 0 <= val <= 127 - self._bcg = val - if self.auto_show: - self._write() - - @property - def blue_brightness(self): - """The blue brightness for all channels (i.e. B0, B1, B2, and B3). This is a 7-bit - value from 0-127. - """ - return self._bcb - - @blue_brightness.setter - def blue_brightness(self, val): - assert 0 <= val <= 127 - self._bcb = val - if self.auto_show: - self._write() - - # Define index and length properties to set and get each channel as + # atomic RGB tuples. This provides a similar feel as using neopixels. + def __len__(self): + """Retrieve TLC5975 the total number of Pixels available.""" + return self.pixel_count + def __getitem__(self, key): """ Retrieve the R, G, B values for the provided channel as a 3-tuple. diff --git a/examples/tlc59711_dev.py b/examples/tlc59711_dev.py index 5f5ba07..d8cdae5 100644 --- a/examples/tlc59711_dev.py +++ b/examples/tlc59711_dev.py @@ -1,4 +1,12 @@ -"""TLC5971 / TLC59711 Multi.""" +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# CircuitPython + +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: MIT +# Author Stefan Krüger (s-light) + +"""TLC5971 / TLC59711 Multi Development.""" __doc__ = """ TLC59711 development helper. @@ -101,7 +109,10 @@ def timeit_call(message, test_function, loop_count=1000): # "{:>8.2f}ms".format(3.56) print( "{call_duration:>10.4f}ms\t{message}" - "".format(call_duration=(duration / loop_count) * 1000, message=message,) + "".format( + call_duration=(duration / loop_count) * 1000, + message=message, + ) ) @@ -408,7 +419,11 @@ def test_bcdata(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format(pixels.bcr, pixels.bcg, pixels.bcb,) + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) ) # calculate bc values Ioclmax = adafruit_tlc59711.TLC59711.calculate_Ioclmax(Riref=2.7) @@ -416,7 +431,10 @@ def test_bcdata(): Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, IoutR=18, IoutG=11, IoutB=13, + Ioclmax=Ioclmax, + IoutR=18, + IoutG=11, + IoutB=13, ) # (127, 77, 91) print("BCValues = {}".format(BCValues)) @@ -431,7 +449,11 @@ def test_bcdata(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format(pixels.bcr, pixels.bcg, pixels.bcb,) + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) ) time.sleep(2) diff --git a/examples/tlc59711_fancyled.py b/examples/tlc59711_fancyled.py index 2baa37c..7338cf9 100644 --- a/examples/tlc59711_fancyled.py +++ b/examples/tlc59711_fancyled.py @@ -2,6 +2,10 @@ # -*- coding: utf-8 -*- # CircuitPython +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: MIT +# Author Stefan Krüger (s-light) + """TLC59711 & FancyLED.""" __doc__ = """ @@ -38,7 +42,10 @@ print(42 * "*") print("init TLC5957") NUM_LEDS = 16 -pixels = adafruit_tlc59711.TLC59711(spi=spi, pixel_count=NUM_LEDS,) +pixels = adafruit_tlc59711.TLC59711( + spi=spi, + pixel_count=NUM_LEDS, +) print("pixel_count", pixels.pixel_count) print("chip_count", pixels.chip_count) diff --git a/examples/tlc59711_fastset.py b/examples/tlc59711_fastset.py index 5ee8bf4..85c7f1a 100644 --- a/examples/tlc59711_fastset.py +++ b/examples/tlc59711_fastset.py @@ -1,4 +1,12 @@ -"""TLC5971 / TLC59711.""" +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# CircuitPython + +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: MIT +# Author Stefan Krüger (s-light) + +"""TLC5971 / TLC59711 Example.""" __doc__ = """ tlc59711_fastset.py - TLC59711 fast set example. @@ -10,6 +18,7 @@ Enjoy the colors :-) """ + import time import board @@ -58,7 +67,10 @@ def test_main(): print(42 * "*") bcvalues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=18, IoutR=18, IoutG=11, IoutB=13, + Ioclmax=18, + IoutR=18, + IoutG=11, + IoutB=13, ) print("bcvalues = {}".format(bcvalues)) pixels.bcr = bcvalues[0] diff --git a/examples/tlc59711_singlechip_autoshow.py b/examples/tlc59711_singlechip_autoshow.py index 1154f80..f4a4dce 100644 --- a/examples/tlc59711_singlechip_autoshow.py +++ b/examples/tlc59711_singlechip_autoshow.py @@ -1,4 +1,12 @@ -"""TLC5971 / TLC59711.""" +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# CircuitPython + +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: MIT +# Author Stefan Krüger (s-light) + +"""TLC5971 / TLC59711 Example.""" __doc__ = """ tlc59711_singlechip_autoshow.py - TLC59711AutoShow minimal usage example. diff --git a/examples/tlc59711_test_bcdata.py b/examples/tlc59711_test_bcdata.py index b84b079..2e42824 100644 --- a/examples/tlc59711_test_bcdata.py +++ b/examples/tlc59711_test_bcdata.py @@ -1,4 +1,12 @@ -"""TLC5971 / TLC59711 Multi.""" +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# CircuitPython + +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: MIT +# Author Stefan Krüger (s-light) + +"""TLC5971 / TLC59711 Test BCData.""" __doc__ = """ tlc59711_test_bcdata.py. @@ -43,7 +51,10 @@ def main_loop(): except ValueError as e: print("Exception: ", e) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, IoutR=IoutR, IoutG=IoutG, IoutB=IoutB, + Ioclmax=Ioclmax, + IoutR=IoutR, + IoutG=IoutG, + IoutB=IoutB, ) pixels.bcr = BCValues[0] pixels.bcg = BCValues[1] @@ -52,7 +63,11 @@ def main_loop(): "bcr: {:>3}\n" "bcg: {:>3}\n" "bcb: {:>3}\n" - "".format(pixels.bcr, pixels.bcg, pixels.bcb,) + "".format( + pixels.bcr, + pixels.bcg, + pixels.bcb, + ) ) pixels.update_BCData() pixels.show() @@ -77,7 +92,10 @@ def test_main(): Riref = adafruit_tlc59711.TLC59711.calculate_Riref(Ioclmax=Ioclmax) print("Riref = {}".format(Riref)) BCValues = adafruit_tlc59711.TLC59711.calculate_BCData( - Ioclmax=Ioclmax, IoutR=18, IoutG=11, IoutB=13, + Ioclmax=Ioclmax, + IoutR=18, + IoutG=11, + IoutB=13, ) # (127, 77, 91) print("BCValues = {}".format(BCValues)) diff --git a/pylama.ini b/pylama.ini index 401048b..ffd3559 100644 --- a/pylama.ini +++ b/pylama.ini @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2021 s-light +# SPDX-License-Identifier: Unlicense + [pylama:pycodestyle] max_line_length = 100