Skip to content

Commit 7f38b38

Browse files
authored
Merge pull request #48 from adafruit/pb-cm
A couple of speedups
2 parents af91d66 + 1f3bf4f commit 7f38b38

File tree

2 files changed

+62
-18
lines changed

2 files changed

+62
-18
lines changed

adafruit_is31fl3731/__init__.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ class IS31FL3731:
9292
width = 16
9393
height = 9
9494

95-
def __init__(self, i2c, address=0x74):
95+
def __init__(self, i2c, address=0x74, frames=None):
9696
self.i2c = i2c
9797
self.address = address
9898
self._frame = None
99-
self._init()
99+
self._init(frames=frames)
100100

101101
def _i2c_read_reg(self, reg, result):
102102
# Read a buffer of data from the specified 8-bit I2C register address.
@@ -111,19 +111,21 @@ def _i2c_read_reg(self, reg, result):
111111
self.i2c.unlock()
112112
return None
113113

114-
def _i2c_write_reg(self, reg, data):
115-
# Write a buffer of data (byte array) to the specified I2C register
116-
# address.
114+
def _i2c_write_block(self, data):
115+
# Writes a contiguous block of data (bytearray) where the first byte
116+
# is the starting I2C register address (register is not an argument).
117117
while not self.i2c.try_lock():
118118
pass
119119
try:
120-
buf = bytearray(1)
121-
buf[0] = reg
122-
buf.extend(data)
123-
self.i2c.writeto(self.address, buf)
120+
self.i2c.writeto(self.address, data)
124121
finally:
125122
self.i2c.unlock()
126123

124+
def _i2c_write_reg(self, reg, data):
125+
# Write a contiguous block of data (bytearray) starting at the
126+
# specified I2C register address (register passed as argument).
127+
self._i2c_write_block(bytes([reg]) + data)
128+
127129
def _bank(self, bank=None):
128130
if bank is None:
129131
result = bytearray(1)
@@ -142,16 +144,21 @@ def _register(self, bank, register, value=None):
142144
def _mode(self, mode=None):
143145
return self._register(_CONFIG_BANK, _MODE_REGISTER, mode)
144146

145-
def _init(self):
147+
def _init(self, frames=None):
146148
self.sleep(True)
147-
time.sleep(0.01) # 10 MS pause to reset.
148-
self._mode(_PICTURE_MODE)
149-
self.frame(0)
150-
for frame in range(8):
151-
self.fill(0, False, frame=frame)
152-
for col in range(18):
153-
self._register(frame, _ENABLE_OFFSET + col, 0xFF)
154-
self.audio_sync(False)
149+
# Clear config; sets to Picture Mode, no audio sync, maintains sleep
150+
self._bank(_CONFIG_BANK)
151+
self._i2c_write_block(bytes([0] * 14))
152+
enable_data = bytes([_ENABLE_OFFSET] + [255] * 18)
153+
fill_data = bytearray([0] * 25)
154+
# Initialize requested frames, or all 8 if unspecified
155+
for frame in frames if frames else range(8):
156+
self._bank(frame)
157+
self._i2c_write_block(enable_data) # Set all enable bits
158+
for row in range(6): # Barebones quick fill() w/0
159+
fill_data[0] = _COLOR_OFFSET + row * 24
160+
self._i2c_write_block(fill_data)
161+
self._frame = 0 # To match config bytes above
155162
self.sleep(False)
156163

157164
def reset(self):

adafruit_is31fl3731/matrix.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,40 @@ class Matrix(IS31FL3731):
4040
def pixel_addr(x, y):
4141
"""Calulate the offset into the device array for x,y pixel"""
4242
return x + y * 16
43+
44+
# This takes precedence over image() in __init__ and is tuned for the
45+
# Matrix class. Some shortcuts can be taken because matrix layout is
46+
# very straightforward, and a few large write operations are used
47+
# rather than pixel-by-pixel writes, yielding significant speed gains
48+
# for animation. Buffering the full matrix for a quick write is not a
49+
# memory concern here, as by definition this method is used with PIL
50+
# images; we're not running on a RAM-constrained microcontroller.
51+
def image(self, img, blink=None, frame=None):
52+
"""Set buffer to value of Python Imaging Library image.
53+
The image should be in 8-bit mode (L) and a size equal to the
54+
display size.
55+
56+
:param img: Python Imaging Library image
57+
:param blink: True to blink
58+
:param frame: the frame to set the image
59+
"""
60+
if img.mode != "L":
61+
raise ValueError("Image must be in mode L.")
62+
if img.size[0] != self.width or img.size[1] != self.height:
63+
raise ValueError(
64+
"Image must be same dimensions as display ({0}x{1}).".format(
65+
self.width, self.height
66+
)
67+
)
68+
69+
# Frame-select and then write pixel data in one big operation
70+
if frame is not None:
71+
self._bank(frame)
72+
# We can safely reduce the image to a "flat" byte sequence because
73+
# the matrix layout is known linear; no need to go through a 2D
74+
# pixel array or invoke pixel_addr().
75+
self._i2c_write_block(bytes([0x24]) + img.tobytes())
76+
# Set or clear blink state if requested, for all pixels at once
77+
if blink is not None:
78+
# 0x12 is _BLINK_OFFSET in __init__.py
79+
self._i2c_write_block(bytes([0x12] + [1 if blink else 0] * 18))

0 commit comments

Comments
 (0)