3030
3131import 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