Skip to content

Commit 56b4872

Browse files
authored
Merge pull request #46 from jepler/neopixel-match-core
match the latest core code
2 parents 89e2dfa + 079fe9e commit 56b4872

File tree

2 files changed

+134
-9
lines changed

2 files changed

+134
-9
lines changed

examples/pioasm_neopixel.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88
import microcontroller
99
import adafruit_pioasm
1010

11-
# NeoPixels are 800khz bit streams. Zeroes are 1/3 duty cycle (~416ns) and ones
12-
# are 2/3 duty cycle (~833ns).
11+
# NeoPixels are 800khz bit streams. We are choosing zeros as <312ns hi, 936 lo>
12+
# and ones as <700 ns hi, 556 ns lo>.
13+
# The first two instructions always run while only one of the two final
14+
# instructions run per bit. We start with the low period because it can be
15+
# longer while waiting for more data.
1316
program = """
1417
.program ws2812
1518
.side_set 1
1619
.wrap_target
1720
bitloop:
18-
out x 1 side 0 [1]; Side-set still takes place when instruction stalls
19-
jmp !x do_zero side 1 [1]; Branch on the bit we shifted out. Positive pulse
20-
do_one:
21-
jmp bitloop side 1 [1]; Continue driving high, for a long pulse
22-
do_zero:
23-
nop side 0 [1]; Or drive low, for a short pulse
21+
out x 1 side 0 [6]; Drive low. Side-set still takes place before instruction stalls.
22+
jmp !x do_zero side 1 [3]; Branch on the bit we shifted out previous delay. Drive high.
23+
do_one:
24+
jmp bitloop side 1 [4]; Continue driving high, for a one (long pulse)
25+
do_zero:
26+
nop side 0 [4]; Or drive low, for a zero (short pulse)
2427
.wrap
2528
"""
2629

@@ -35,7 +38,7 @@
3538

3639
sm = rp2pio.StateMachine(
3740
assembled,
38-
frequency=800000 * 6, # 800khz * 6 clocks per bit
41+
frequency=12_800_000, # to get appropriate sub-bit times in PIO program
3942
first_sideset_pin=NEOPIXEL,
4043
auto_pull=True,
4144
out_shift_right=False,

examples/pioasm_neopixel_bg.py

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# SPDX-FileCopyrightText: 2022 Jeff Epler, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""Demonstrate background writing with NeoPixels
6+
7+
The NeoPixelBackground class defined here is largely compatible with the
8+
standard NeoPixel class, except that the ``show()`` method returns immediately,
9+
writing data to the LEDs in the background.
10+
11+
Writing the LED data in the background will allow more time for your
12+
Python code to run, so it may be possible to slightly increase the refresh
13+
rate of your LEDs or do more complicated processing.
14+
15+
The demonstration code, under ``if __name__ == '__main__':`` is intended
16+
for the Adafruit MacroPad, with 12 NeoPixel LEDs. It shows a cycling rainbow
17+
pattern across all the LEDs.
18+
"""
19+
20+
import struct
21+
import adafruit_pixelbuf
22+
from ulab import numpy as np
23+
from rp2pio import StateMachine
24+
from adafruit_pioasm import Program
25+
26+
# Pixel color order constants
27+
RGB = "RGB"
28+
"""Red Green Blue"""
29+
GRB = "GRB"
30+
"""Green Red Blue"""
31+
RGBW = "RGBW"
32+
"""Red Green Blue White"""
33+
GRBW = "GRBW"
34+
"""Green Red Blue White"""
35+
36+
# NeoPixels are 800khz bit streams. We are choosing zeros as <312ns hi, 936 lo>
37+
# and ones as <700 ns hi, 556 ns lo>.
38+
_program = Program(
39+
"""
40+
.side_set 1 opt
41+
.wrap_target
42+
pull block side 0
43+
out y, 16 side 0 ; get count of NeoPixel bits
44+
45+
bitloop:
46+
pull ifempty side 0 ; drive low
47+
out x 1 side 0 [5]
48+
jmp !x do_zero side 1 [3] ; drive high and branch depending on bit val
49+
jmp y--, bitloop side 1 [4] ; drive high for a one (long pulse)
50+
jmp end_sequence side 0 ; sequence is over
51+
52+
do_zero:
53+
jmp y--, bitloop side 0 [4] ; drive low for a zero (short pulse)
54+
55+
end_sequence:
56+
pull block side 0 ; get fresh 16 bit delay value
57+
out y, 16 side 0 ; get delay count
58+
wait_reset:
59+
jmp y--, wait_reset side 0 ; wait until delay elapses
60+
.wrap
61+
"""
62+
)
63+
64+
65+
class NeoPixelBackground( # pylint: disable=too-few-public-methods
66+
adafruit_pixelbuf.PixelBuf
67+
):
68+
def __init__(
69+
self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None
70+
):
71+
if not pixel_order:
72+
pixel_order = GRB if bpp == 3 else GRBW
73+
elif isinstance(pixel_order, tuple):
74+
order_list = [RGBW[order] for order in pixel_order]
75+
pixel_order = "".join(order_list)
76+
77+
byte_count = bpp * n
78+
bit_count = byte_count * 8
79+
padding_count = byte_count % 2
80+
81+
if bit_count > 65536:
82+
raise ValueError("Too many pixels")
83+
84+
# backwards, so that ulab byteswap corrects it!
85+
header = struct.pack(">H", (bit_count - 1) & 0xFFFF)
86+
trailer = b"\0" * padding_count + struct.pack(">H", 3840)
87+
88+
self._sm = StateMachine(
89+
_program.assembled,
90+
auto_pull=False,
91+
first_sideset_pin=pin,
92+
out_shift_right=False,
93+
pull_threshold=16,
94+
frequency=12_800_000,
95+
**_program.pio_kwargs,
96+
)
97+
98+
super().__init__(
99+
n,
100+
brightness=brightness,
101+
byteorder=pixel_order,
102+
auto_write=auto_write,
103+
header=header,
104+
trailer=trailer,
105+
)
106+
107+
def _transmit(self, buf):
108+
self._sm.background_write(np.frombuffer(buf, dtype=np.uint16).byteswap())
109+
110+
111+
if __name__ == "__main__":
112+
import board
113+
import rainbowio
114+
import time
115+
116+
NEOPIXEL = board.NEOPIXEL
117+
NUM_PIXELS = 12
118+
pixels = NeoPixelBackground(NEOPIXEL, NUM_PIXELS)
119+
i = 0
120+
while True:
121+
pixels.fill(rainbowio.colorwheel(i := (i + 1) % 256))
122+
time.sleep(0.01)

0 commit comments

Comments
 (0)