Add neopixel background example
This commit is contained in:
parent
3a9a0288b7
commit
387abbbc4c
1 changed files with 125 additions and 0 deletions
125
examples/pioasm_neopixel_bg.py
Normal file
125
examples/pioasm_neopixel_bg.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jeff Epler, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""Demonstrate background writing with NeoPixels
|
||||
|
||||
The NeoPixelBackground class defined here is largely compatible with the
|
||||
standard NeoPixel class, except that the ``show()`` method returns immediately,
|
||||
writing data to the LEDs in the background.
|
||||
|
||||
Writing the LED data in the background will allow more time for your
|
||||
Python code to run, so it may be possible to slightly increase the refresh
|
||||
rate of your LEDs or do more complicated processing.
|
||||
|
||||
The demonstration code, under ``if __name__ == '__main__':`` is intended
|
||||
for the Adafruit MacroPad, with 12 NeoPixel LEDs. It shows a cycling rainbow
|
||||
pattern across all the LEDs.
|
||||
"""
|
||||
|
||||
import struct
|
||||
import adafruit_pixelbuf
|
||||
from ulab import numpy as np
|
||||
from rp2pio import StateMachine
|
||||
from adafruit_pioasm import Program
|
||||
|
||||
# Pixel color order constants
|
||||
RGB = "RGB"
|
||||
"""Red Green Blue"""
|
||||
GRB = "GRB"
|
||||
"""Green Red Blue"""
|
||||
RGBW = "RGBW"
|
||||
"""Red Green Blue White"""
|
||||
GRBW = "GRBW"
|
||||
"""Green Red Blue White"""
|
||||
|
||||
# NeoPixels are 800khz bit streams. We are choosing zeros as <312ns hi, 936 lo> and ones
|
||||
# and ones as <700 ns hi, 556 ns lo>.
|
||||
# cycle. The first two instructions always run while only one of the two final
|
||||
# instructions run per bit. We start with the low period because it can be
|
||||
# longer while waiting for more data.
|
||||
_program = Program(
|
||||
"""
|
||||
.side_set 1 opt
|
||||
.wrap_target
|
||||
pull block side 0
|
||||
out y, 16 side 0 ; get count of NeoPixel bits
|
||||
|
||||
bitloop:
|
||||
pull ifempty side 0 ; drive low
|
||||
out x 1 side 0 [5]
|
||||
jmp !x do_zero side 1 [3] ; drive high and branch depending on bit val
|
||||
jmp y--, bitloop side 1 [4] ; drive high for a one (long pulse)
|
||||
jmp end_sequence side 0 ; sequence is over
|
||||
|
||||
do_zero:
|
||||
jmp y--, bitloop side 0 [4] ; drive low for a zero (short pulse)
|
||||
|
||||
end_sequence:
|
||||
pull block side 0 ; get fresh 16 bit delay value
|
||||
out y, 16 side 0 ; get delay count
|
||||
wait_reset:
|
||||
jmp y--, wait_reset side 0 ; wait until delay elapses
|
||||
.wrap
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
class NeoPixelBackground( # pylint: disable=too-few-public-methods
|
||||
adafruit_pixelbuf.PixelBuf
|
||||
):
|
||||
def __init__(
|
||||
self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None
|
||||
):
|
||||
if not pixel_order:
|
||||
pixel_order = GRB if bpp == 3 else GRBW
|
||||
elif isinstance(pixel_order, tuple):
|
||||
order_list = [RGBW[order] for order in pixel_order]
|
||||
pixel_order = "".join(order_list)
|
||||
|
||||
byte_count = bpp * n
|
||||
bit_count = byte_count * 8
|
||||
padding_count = byte_count % 2
|
||||
|
||||
if bit_count > 65536:
|
||||
raise ValueError("Too many pixels")
|
||||
|
||||
# backwards, so that ulab byteswap corrects it!
|
||||
header = struct.pack(">H", (bit_count - 1) & 0xFFFF)
|
||||
trailer = b"\0" * padding_count + struct.pack(">H", 3840)
|
||||
|
||||
self._sm = StateMachine(
|
||||
_program.assembled,
|
||||
auto_pull=False,
|
||||
first_sideset_pin=pin,
|
||||
out_shift_right=False,
|
||||
pull_threshold=16,
|
||||
frequency=12_800_000,
|
||||
**_program.pio_kwargs,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
n,
|
||||
brightness=brightness,
|
||||
byteorder=pixel_order,
|
||||
auto_write=auto_write,
|
||||
header=header,
|
||||
trailer=trailer,
|
||||
)
|
||||
|
||||
def _transmit(self, buf):
|
||||
self._sm.background_write(np.frombuffer(buf, dtype=np.uint16).byteswap())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import board
|
||||
import rainbowio
|
||||
import time
|
||||
|
||||
NEOPIXEL = board.NEOPIXEL
|
||||
NUM_PIXELS = 12
|
||||
pixels = NeoPixelBackground(NEOPIXEL, NUM_PIXELS)
|
||||
i = 0
|
||||
while True:
|
||||
pixels.fill(rainbowio.colorwheel(i := (i + 1) % 256))
|
||||
time.sleep(0.01)
|
||||
Loading…
Reference in a new issue