Skip to content

Commit 1d4f729

Browse files
committed
add NeoPixel_SPI class
1 parent c0bdd8b commit 1d4f729

File tree

1 file changed

+86
-2
lines changed

1 file changed

+86
-2
lines changed

neopixel.py

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@
3030

3131
import math
3232

33-
import digitalio
34-
from neopixel_write import neopixel_write
33+
try:
34+
# imports needed for main NeoPixel class
35+
import digitalio
36+
from neopixel_write import neopixel_write
37+
except:
38+
# silently accept this, can still use NeoPixel SPI class
39+
pass
3540

3641
__version__ = "0.0.0-auto.0"
3742
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git"
@@ -230,3 +235,82 @@ def show(self):
230235
neopixel_write(self.pin, self.buf)
231236
else:
232237
neopixel_write(self.pin, bytearray([int(i * self.brightness) for i in self.buf]))
238+
239+
class NeoPixel_SPI(NeoPixel):
240+
"""
241+
A sequence of neopixels.
242+
243+
:param ~busio.SPI spi: The SPI bus to output neopixel data on.
244+
:param int n: The number of neopixels in the chain
245+
:param int bpp: Bytes per pixel. 3 for RGB and 4 for RGBW pixels.
246+
:param float brightness: Brightness of the pixels between 0.0 and 1.0 where 1.0 is full
247+
brightness
248+
:param bool auto_write: True if the neopixels should immediately change when set. If False,
249+
`show` must be called explicitly.
250+
:param tuple pixel_order: Set the pixel color channel order. GRBW is set by default.
251+
252+
Example:
253+
254+
.. code-block:: python
255+
256+
import board
257+
import neopixel
258+
259+
pixels = neopixel.NeoPixel_SPI(board.SPI(), 10)
260+
pixels.fill(0xff0000)
261+
"""
262+
#pylint: disable=invalid-name
263+
264+
FREQ = 6400000 # 800kHz * 8, actual may be different
265+
TRST = 80e-6 # Reset code low level time
266+
267+
def __init__(self, spi, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None):
268+
from adafruit_bus_device.spi_device import SPIDevice
269+
self._spi = SPIDevice(spi, baudrate=self.FREQ)
270+
with self._spi as spi:
271+
try:
272+
# get actual SPI frequency
273+
freq = spi.frequency
274+
except AttributeError:
275+
# use nominal
276+
freq = self.FREQ
277+
self.RESET = bytes([0]*round(freq*self.TRST))
278+
self.n = n
279+
if pixel_order is None:
280+
self.order = GRBW
281+
self.bpp = bpp
282+
else:
283+
self.order = pixel_order
284+
self.bpp = len(self.order)
285+
self.buf = bytearray(self.n * self.bpp)
286+
# Set auto_write to False temporarily so brightness setter does _not_
287+
# call show() while in __init__.
288+
self.auto_write = False
289+
self.brightness = brightness
290+
self.auto_write = auto_write
291+
292+
def deinit(self):
293+
"""Blank out the NeoPixels."""
294+
for i in range(len(self.buf)):
295+
self.buf[i] = 0
296+
self.show()
297+
298+
def show(self):
299+
"""Shows the new colors on the pixels themselves if they haven't already
300+
been autowritten."""
301+
with self._spi as spi:
302+
# write out special byte sequence surrounded by RESET
303+
# leading RESET needed for cases where MOSI rests HI
304+
spi.write(self.RESET + self._transmogrify(self.buf) + self.RESET)
305+
306+
def _transmogrify(self, buf):
307+
"""Turn every BIT of buf into a special BYTE pattern."""
308+
out_buf = bytearray()
309+
for byte in self.buf:
310+
# MSB first
311+
for i in range(7, -1, -1):
312+
if byte >> i & 0x01:
313+
out_buf.append(0b11110000) # A NeoPixel 1 bit
314+
else:
315+
out_buf.append(0b11000000) # A NeoPixel 0 bit
316+
return out_buf

0 commit comments

Comments
 (0)