|
30 | 30 |
|
31 | 31 | import math
|
32 | 32 |
|
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 NotImplementedError: |
| 38 | + # silently accept this, can still use NeoPixel SPI class |
| 39 | + pass |
35 | 40 |
|
36 | 41 | __version__ = "0.0.0-auto.0"
|
37 | 42 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git"
|
@@ -230,3 +235,85 @@ def show(self):
|
230 | 235 | neopixel_write(self.pin, self.buf)
|
231 | 236 | else:
|
232 | 237 | 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, super-init-not-called |
| 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 spibus: |
| 271 | + try: |
| 272 | + # get actual SPI frequency |
| 273 | + freq = spibus.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 | + self.spibuf = bytearray(8*len(self.buf)) |
| 287 | + # Set auto_write to False temporarily so brightness setter does _not_ |
| 288 | + # call show() while in __init__. |
| 289 | + self.auto_write = False |
| 290 | + self.brightness = brightness |
| 291 | + self.auto_write = auto_write |
| 292 | + |
| 293 | + def deinit(self): |
| 294 | + """Blank out the NeoPixels.""" |
| 295 | + for i in range(len(self.buf)): |
| 296 | + self.buf[i] = 0 |
| 297 | + self.show() |
| 298 | + |
| 299 | + def show(self): |
| 300 | + """Shows the new colors on the pixels themselves if they haven't already |
| 301 | + been autowritten.""" |
| 302 | + self._transmogrify() |
| 303 | + with self._spi as spi: |
| 304 | + # write out special byte sequence surrounded by RESET |
| 305 | + # leading RESET needed for cases where MOSI rests HI |
| 306 | + spi.write(self.RESET + self.spibuf + self.RESET) |
| 307 | + |
| 308 | + def _transmogrify(self): |
| 309 | + """Turn every BIT of buf into a special BYTE pattern.""" |
| 310 | + k = 0 |
| 311 | + for byte in self.buf: |
| 312 | + byte = int(byte * self.brightness) |
| 313 | + # MSB first |
| 314 | + for i in range(7, -1, -1): |
| 315 | + if byte >> i & 0x01: |
| 316 | + self.spibuf[k] = 0b11110000 # A NeoPixel 1 bit |
| 317 | + else: |
| 318 | + self.spibuf[k] = 0b11000000 # A NeoPixel 0 bit |
| 319 | + k += 1 |
0 commit comments