Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support any number of strands from 1 to 8; make demo more like arduino demo #4

Merged
merged 6 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions adafruit_neopxl8.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
bitloop:
pull ifempty [1] ; don't start outputting HIGH unless data is available (always-low part)
mov pins, ~ null [3] ; always-high part
out pins, 8 [4] ; variable part
{} ; variable part
mov pins, null ; always-low part (last cycle is the 'pull ifempty' after wrap)

jmp y--, bitloop ; always-low part
Expand All @@ -46,7 +46,6 @@
jmp top
"""

_ASSEMBLED = adafruit_pioasm.assemble(_PROGRAM)

# Pixel color order constants
RGB = "RGB"
Expand Down Expand Up @@ -110,7 +109,7 @@ def __init__(
brightness=1.0,
auto_write=True,
pixel_order=None,
):
): # pylint: disable=too-many-locals
if n % num_strands:
raise ValueError("Length must be a multiple of num_strands")
if not pixel_order:
Expand All @@ -124,25 +123,48 @@ def __init__(
n, brightness=brightness, byteorder=pixel_order, auto_write=auto_write
)

data_len = bpp * n * 8 // num_strands
if num_strands == 1:
data_len = bpp * n
pack = ">L"
osr = False
loop_count = 8 * data_len
else:
data_len = bpp * n * 8 // num_strands
pack = "<L"
osr = True
loop_count = data_len
padding_count = -data_len % 4

self._num_strands = num_strands
self._data = bytearray(8 + data_len + padding_count)
self._data32 = memoryview(self._data).cast("L")
self._transposed = memoryview(self._data)[4 : 4 + data_len]
self._data[:4] = struct.pack("<L", data_len - 1)
self._data[-4:] = struct.pack("<L", 3840 * 2)
self._pixels = memoryview(self._data)[4 : 4 + data_len]
self._data[:4] = struct.pack(pack, loop_count - 1)
self._data[-4:] = struct.pack(pack, 3840)

self._num_strands = num_strands

if num_strands == 8:
variable_part = "out pins, 8 [4] ; variable part"
elif num_strands == 1:
variable_part = "out pins, 1 [4] ; variable part"
else:
variable_part = f"""
out pins, {num_strands} [3] ; variable part
out x, {8-num_strands} ; variable part
"""

program = _PROGRAM.format(variable_part)
assembled = adafruit_pioasm.assemble(program)

self._sm = rp2pio.StateMachine(
_ASSEMBLED,
assembled,
frequency=800_000 * 16,
first_out_pin=data0,
out_pin_count=8,
out_pin_count=num_strands,
first_set_pin=data0,
auto_pull=False,
out_shift_right=True,
out_shift_right=osr,
)

def deinit(self):
Expand Down Expand Up @@ -177,5 +199,9 @@ def num_strands(self):
def _transmit(self, buffer):
while self._sm.pending:
pass
bitops.bit_transpose(buffer, self._transposed, self._num_strands)
self._sm.background_write(self._data32)
if self.num_strands == 1:
self._pixels[:] = buffer
self._sm.background_write(self._data32, swap=True)
else:
bitops.bit_transpose(buffer, self._pixels, self._num_strands)
self._sm.background_write(self._data32)
48 changes: 28 additions & 20 deletions examples/neopxl8_animations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@
#
# SPDX-License-Identifier: Unlicense

# Set up a separate animation on each of 8 strips with NeoPxl8

import board
from adafruit_led_animation.animation.rainbow import Rainbow
import rainbowio
import adafruit_ticks
from adafruit_led_animation.animation.comet import Comet
from adafruit_led_animation.animation.rainbowcomet import RainbowComet
from adafruit_led_animation.animation.rainbowchase import RainbowChase
from adafruit_led_animation.animation.chase import Chase
from adafruit_led_animation.group import AnimationGroup
from adafruit_led_animation.helper import PixelMap
from adafruit_led_animation import color
from adafruit_neopxl8 import NeoPxl8

# Customize for your strands here
Expand All @@ -28,30 +23,43 @@
num_pixels,
num_strands=num_strands,
auto_write=False,
brightness=0.07,
brightness=0.50,
)


def strand(i):
def strand(n):
return PixelMap(
pixels,
range(i * strand_length, (i + 1) * strand_length),
range(n * strand_length, (n + 1) * strand_length),
individual_pixels=True,
)


# Create the 8 virtual strands
strands = [strand(i) for i in range(num_strands)]

animations = AnimationGroup(
Comet(strands[0], 0.5, color.CYAN),
Comet(strands[1], 0.4, color.AMBER),
RainbowComet(strands[2], 0.3),
RainbowComet(strands[3], 0.7),
Chase(strands[4], 0.05, size=2, spacing=3, color=color.PURPLE),
RainbowChase(strands[5], 0.05, size=2, spacing=3),
Rainbow(strands[6], 0.6),
Rainbow(strands[7], 0.23, step=21),
)
# For each strand, create a comet animation of a different color
animations = [
Comet(strand, 0.02, rainbowio.colorwheel(3 * 32 * i), ring=True)
for i, strand in enumerate(strands)
]

# Advance the animations by varying amounts so that they become staggered
for i, animation in enumerate(animations):
animation._tail_start = 30 * 5 * i // 8 # pylint: disable=protected-access

# Group them so we can run them all at once
animations = AnimationGroup(*animations)

# Run the animations and report on the speed in frame per secodn
t0 = adafruit_ticks.ticks_ms()
frame_count = 0
while True:
animations.animate()
frame_count += 1
t1 = adafruit_ticks.ticks_ms()
dt = adafruit_ticks.ticks_diff(t1, t0)
if dt > 1000:
print(f"{frame_count * 1000/dt:.1f}fps")
t0 = t1
frame_count = 0