Merge pull request #47 from jepler/example-updates-background
enhance examples
This commit is contained in:
commit
aa651b1e00
4 changed files with 478 additions and 30 deletions
178
examples/pioasm_7seg.py
Normal file
178
examples/pioasm_7seg.py
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jeff Epler, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""Drive a 7-segment display entirely from the PIO peripheral
|
||||
|
||||
By updating the buffer being written to the display, the shown digits can be changed.
|
||||
|
||||
The main program repeatedly shows random digits which 'lock' after a short
|
||||
time. After all digits have locked, it blanks for a short time and then repeats.
|
||||
It also demonstrates the use of `asyncio` to perform multiple tasks.
|
||||
|
||||
This example is designed for a Raspberry Pi Pico and bare LED display. For
|
||||
simplicity, it is wired without any current limiting resistors, instead relying
|
||||
on a combination of the RP2040's pin drive strength and the 1/4 duty cycle to
|
||||
limit LED current to an acceptable level, and longevity of the display was not
|
||||
a priority.
|
||||
|
||||
Before integrating a variant of this example code in a project, evaluate
|
||||
whether your design needs to add current-limiting resistors.
|
||||
|
||||
https://www.adafruit.com/product/4864
|
||||
https://www.adafruit.com/product/865
|
||||
|
||||
Wiring:
|
||||
* Pico GP15 to LED matrix 1 (E SEG)
|
||||
* Pico GP14 to LED matrix 2 (D SEG)
|
||||
* Pico GP13 to LED matrix 3 (DP SEG)
|
||||
* Pico GP12 to LED matrix 4 (C SEG)
|
||||
* Pico GP11 to LED matrix 5 (G SEG)
|
||||
* Pico GP10 to LED matrix 6 (COM4)
|
||||
* Pico GP9 to LED matrix 7 (COLON COM)
|
||||
* Pico GP22 to LED matrix 8 (COLON SEG)
|
||||
* Pico GP21 to LED matrix 9 (B SEG)
|
||||
* Pico GP20 to LED matrix 10 (COM3)
|
||||
* Pico GP19 to LED matrix 11 (COM2)
|
||||
* Pico GP18 to LED matrix 12 (F SEG)
|
||||
* Pico GP17 to LED matrix 13 (A SEG)
|
||||
* Pico GP16 to LED matrix 14 (COM1)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
import array
|
||||
import board
|
||||
import rp2pio
|
||||
import adafruit_pioasm
|
||||
|
||||
_program = adafruit_pioasm.Program(
|
||||
"""
|
||||
out pins, 14 ; set the pins to their new state
|
||||
"""
|
||||
)
|
||||
|
||||
# Display Pins 1-7 are GP 15-9
|
||||
# Display Pins 8-12 are GP 22-16
|
||||
COM1_WT = 1 << 7
|
||||
COM2_WT = 1 << 10
|
||||
COM3_WT = 1 << 11
|
||||
COM4_WT = 1 << 1
|
||||
COMC_WT = 1 << 0
|
||||
|
||||
SEGA_WT = 1 << 8
|
||||
SEGB_WT = 1 << 12
|
||||
SEGC_WT = 1 << 3
|
||||
SEGD_WT = 1 << 5
|
||||
SEGE_WT = 1 << 6
|
||||
SEGF_WT = 1 << 9
|
||||
SEGG_WT = 1 << 2
|
||||
|
||||
SEGDP_WT = 1 << 4
|
||||
SEGCOL_WT = 1 << 13
|
||||
|
||||
ALL_COM = COM1_WT | COM2_WT | COM3_WT | COM4_WT | COMC_WT
|
||||
|
||||
SEG_WT = [
|
||||
SEGA_WT,
|
||||
SEGB_WT,
|
||||
SEGC_WT,
|
||||
SEGD_WT,
|
||||
SEGE_WT,
|
||||
SEGF_WT,
|
||||
SEGG_WT,
|
||||
SEGDP_WT,
|
||||
SEGCOL_WT,
|
||||
]
|
||||
COM_WT = [COM1_WT, COM2_WT, COM3_WT, COM4_WT, COMC_WT]
|
||||
|
||||
DIGITS = [
|
||||
0b0111111, # 0
|
||||
0b0000110, # 1
|
||||
0b1011011, # 2
|
||||
0b1001111, # 3
|
||||
0b1100110, # 4
|
||||
0b1101101, # 5
|
||||
0b1111100, # 6
|
||||
0b0000111, # 7
|
||||
0b1111111, # 8
|
||||
0b1101111, # 9
|
||||
]
|
||||
|
||||
|
||||
def make_digit_wt(v):
|
||||
val = ALL_COM
|
||||
seg = DIGITS[v]
|
||||
for i in range(8):
|
||||
if seg & (1 << i):
|
||||
val |= SEG_WT[i]
|
||||
return val
|
||||
|
||||
|
||||
DIGITS_WT = [make_digit_wt(i) for i in range(10)]
|
||||
|
||||
|
||||
class SMSevenSegment:
|
||||
def __init__(self, first_pin=board.GP9):
|
||||
self._buf = array.array("H", (DIGITS_WT[0] & ~COM_WT[i] for i in range(4)))
|
||||
self._sm = rp2pio.StateMachine(
|
||||
_program.assembled,
|
||||
frequency=2000,
|
||||
first_out_pin=first_pin,
|
||||
out_pin_count=14,
|
||||
auto_pull=True,
|
||||
pull_threshold=14,
|
||||
**_program.pio_kwargs,
|
||||
)
|
||||
self._sm.background_write(loop=self._buf)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.deinit()
|
||||
|
||||
def deinit(self):
|
||||
self._sm.deinit()
|
||||
|
||||
def __setitem__(self, i, v):
|
||||
if v is None:
|
||||
self._buf[i] = 0
|
||||
else:
|
||||
self._buf[i] = DIGITS_WT[v] & ~COM_WT[i]
|
||||
|
||||
|
||||
async def digit_locker(s, i, wait):
|
||||
delay = 30
|
||||
d = random.randint(0, 9)
|
||||
while delay < 300:
|
||||
d = (d + random.randint(1, 9)) % 10 # Tick to a new digit other than 'd'
|
||||
s[i] = d
|
||||
await asyncio.sleep(delay / 1000)
|
||||
if wait:
|
||||
wait -= 1
|
||||
else:
|
||||
delay = delay * 1.1
|
||||
|
||||
|
||||
def shuffle(seq):
|
||||
for i in range(len(seq) - 1):
|
||||
j = random.randrange(i + 1, len(seq))
|
||||
seq[i], seq[j] = seq[j], seq[i]
|
||||
|
||||
|
||||
async def main():
|
||||
waits = [100, 175, 225, 250]
|
||||
with SMSevenSegment(board.GP9) as s:
|
||||
while True:
|
||||
shuffle(waits)
|
||||
await asyncio.gather(
|
||||
*(digit_locker(s, i, di) for i, di in enumerate(waits))
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
for i in range(4):
|
||||
s[i] = None
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
253
examples/pioasm_7seg_fader.py
Normal file
253
examples/pioasm_7seg_fader.py
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jeff Epler, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""Drive a 7-segment display entirely from the PIO peripheral
|
||||
|
||||
Each segment is driven with a 'breathing' waveform that runs at its own pace.
|
||||
It also demonstrates the use of `asyncio` to perform multiple tasks.
|
||||
|
||||
This example is designed for a Raspberry Pi Pico and bare LED display. For
|
||||
simplicity, it is wired without any current limiting resistors, instead relying
|
||||
on a combination of the RP2040's pin drive strength and the 1/45 duty cycle to
|
||||
limit LED current to an acceptable level, and longevity of the display was not
|
||||
a priority.
|
||||
|
||||
Before integrating a variant of this example code in a project, evaluate
|
||||
whether your design needs to add current-limiting resistors.
|
||||
|
||||
https://www.adafruit.com/product/4864
|
||||
https://www.adafruit.com/product/865
|
||||
|
||||
Wiring:
|
||||
* Pico GP15 to LED matrix 1 (E SEG)
|
||||
* Pico GP14 to LED matrix 2 (D SEG)
|
||||
* Pico GP13 to LED matrix 3 (DP SEG)
|
||||
* Pico GP12 to LED matrix 4 (C SEG)
|
||||
* Pico GP11 to LED matrix 5 (G SEG)
|
||||
* Pico GP10 to LED matrix 6 (COM4)
|
||||
* Pico GP9 to LED matrix 7 (COLON COM)
|
||||
* Pico GP22 to LED matrix 8 (COLON SEG)
|
||||
* Pico GP21 to LED matrix 9 (B SEG)
|
||||
* Pico GP20 to LED matrix 10 (COM3)
|
||||
* Pico GP19 to LED matrix 11 (COM2)
|
||||
* Pico GP18 to LED matrix 12 (F SEG)
|
||||
* Pico GP17 to LED matrix 13 (A SEG)
|
||||
* Pico GP16 to LED matrix 14 (COM1)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
import array
|
||||
import board
|
||||
import rp2pio
|
||||
from ulab import numpy as np
|
||||
import adafruit_pioasm
|
||||
|
||||
_pio_source = """
|
||||
mov pins, null ; turn all pins off
|
||||
pull
|
||||
out pindirs, {n} ; set the new direction
|
||||
pull
|
||||
out pins, {n} ; set the new values
|
||||
pull
|
||||
out y, 32
|
||||
delay:
|
||||
jmp y--, delay
|
||||
"""
|
||||
|
||||
# Display Pins 1-7 are GP 15-9 [need to re-wire 9]
|
||||
# Display Pins 8-12 are GP 22-16 [need to re-wire 22]
|
||||
# GP# Display# Function
|
||||
# 15 (+ 6) 1 E SEG
|
||||
# 14 (+ 5) 2 D SEG
|
||||
# 13 (+ 4) 3 DP SEG
|
||||
# 12 (+ 3) 4 C SEG
|
||||
# 11 (+ 2) 5 G SEG
|
||||
# 10 (+ 1) 6 COM4
|
||||
# 9 (+ 0) 7 COLON COM
|
||||
# 22 (+13) 8 COLON SEG
|
||||
# 21 (+12) 9 B SEG
|
||||
# 20 (+11) 10 COM3
|
||||
# 19 (+10) 11 COM2
|
||||
# 18 (+ 9) 12 F SEG
|
||||
# 17 (+ 8) 13 A SEG
|
||||
# 16 (+ 7) 14 COM1
|
||||
|
||||
COM1_WT = 1 << 7
|
||||
COM2_WT = 1 << 10
|
||||
COM3_WT = 1 << 11
|
||||
COM4_WT = 1 << 1
|
||||
COMC_WT = 1 << 0
|
||||
|
||||
SEGA_WT = 1 << 8
|
||||
SEGB_WT = 1 << 12
|
||||
SEGC_WT = 1 << 3
|
||||
SEGD_WT = 1 << 5
|
||||
SEGE_WT = 1 << 6
|
||||
SEGF_WT = 1 << 9
|
||||
SEGG_WT = 1 << 2
|
||||
|
||||
SEGDP_WT = 1 << 4
|
||||
SEGCOL_WT = 1 << 13
|
||||
|
||||
ALL_COM = COM1_WT | COM2_WT | COM3_WT | COM4_WT | COMC_WT
|
||||
|
||||
SEG_WT = [
|
||||
SEGA_WT,
|
||||
SEGB_WT,
|
||||
SEGC_WT,
|
||||
SEGD_WT,
|
||||
SEGE_WT,
|
||||
SEGF_WT,
|
||||
SEGG_WT,
|
||||
SEGDP_WT,
|
||||
SEGCOL_WT,
|
||||
]
|
||||
COM_WT = [COM1_WT, COM2_WT, COM3_WT, COM4_WT, COMC_WT]
|
||||
|
||||
DIGITS = [
|
||||
0b0111111, # 0
|
||||
0b0000110, # 1
|
||||
0b1011011, # 2
|
||||
0b1001111, # 3
|
||||
0b1100110, # 4
|
||||
0b1101101, # 5
|
||||
0b1111100, # 6
|
||||
0b0000111, # 7
|
||||
0b1111111, # 8
|
||||
0b1101111, # 9
|
||||
]
|
||||
|
||||
|
||||
def make_digit_wt(v):
|
||||
val = ALL_COM
|
||||
seg = DIGITS[v]
|
||||
for i in range(8):
|
||||
if seg & (1 << i):
|
||||
val |= SEG_WT[i]
|
||||
return val
|
||||
|
||||
|
||||
class LedFader:
|
||||
def __init__(
|
||||
self, first_pin, pin_count, cathode_weights, anode_weights, levels=64
|
||||
): # pylint: disable=too-many-arguments
|
||||
self._cathode_weights = cathode_weights
|
||||
self._anode_weights = anode_weights
|
||||
self._stream = array.array("L", [0, 0, 1]) * (
|
||||
1 + len(cathode_weights) * len(anode_weights)
|
||||
)
|
||||
self._levels = levels
|
||||
self._max_count = levels * len(self)
|
||||
self._total = len(self)
|
||||
|
||||
program = adafruit_pioasm.Program(_pio_source.format(n=pin_count))
|
||||
self._sm = rp2pio.StateMachine( # pylint: disable=too-many-arguments
|
||||
program.assembled,
|
||||
frequency=125_000_000,
|
||||
first_out_pin=first_pin,
|
||||
out_pin_count=14,
|
||||
auto_pull=True,
|
||||
pull_threshold=14,
|
||||
**program.pio_kwargs,
|
||||
)
|
||||
print(
|
||||
f"Note: approximate refresh rate {self._sm.frequency / self._max_count:.0f}Hz"
|
||||
)
|
||||
self._sm.background_write(loop=self._stream)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.deinit()
|
||||
|
||||
def deinit(self):
|
||||
self._sm.deinit()
|
||||
|
||||
def __setitem__(self, i, v):
|
||||
if not 0 <= v < self._levels:
|
||||
raise ValueError()
|
||||
|
||||
c = i % len(self._cathode_weights)
|
||||
r = i // len(self._cathode_weights)
|
||||
if not v:
|
||||
self._total = self._total - self._stream[3 * i + 2] + 1
|
||||
self._stream[3 * i] = 0
|
||||
self._stream[3 * i + 1] = 0
|
||||
self._stream[3 * i + 2] = 1
|
||||
else:
|
||||
self._total = self._total - self._stream[3 * i + 2] + v
|
||||
self._stream[3 * i] = self._cathode_weights[c] | self._anode_weights[r]
|
||||
self._stream[3 * i + 1] = self._cathode_weights[c]
|
||||
self._stream[3 * i + 2] = v
|
||||
self._stream[3 * len(self) + 2] = self._max_count - self._total
|
||||
|
||||
def __len__(self):
|
||||
return len(self._stream) // 3 - 1
|
||||
|
||||
|
||||
class CyclicSignal:
|
||||
def __init__(self, data, phase=0):
|
||||
self._data = data
|
||||
self._phase = 0
|
||||
self.phase = phase
|
||||
self._scale = len(self._data) - 1
|
||||
|
||||
@property
|
||||
def phase(self):
|
||||
return self._phase
|
||||
|
||||
@phase.setter
|
||||
def phase(self, value):
|
||||
self._phase = value % 1
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
idxf = self._phase * len(self._data)
|
||||
idx = int(idxf)
|
||||
frac = idxf % 1
|
||||
idx1 = (idx + 1) % len(self._data)
|
||||
val = self._data[idx]
|
||||
val1 = self._data[idx1]
|
||||
return val + (val1 - val) * frac
|
||||
|
||||
def advance(self, delta):
|
||||
self._phase = (self._phase + delta) % 1
|
||||
|
||||
|
||||
sine = (np.sin(np.linspace(0, 2 * np.pi, 50, endpoint=False)) * 0.5 + 0.5) ** 2.2 * 64
|
||||
|
||||
|
||||
async def segment_throbber(c, i):
|
||||
signal = CyclicSignal(sine, random.random())
|
||||
velocity = random.random() * 0.04 + 0.005
|
||||
|
||||
while True:
|
||||
signal.advance(velocity)
|
||||
c[i] = int(signal.value)
|
||||
await asyncio.sleep(0)
|
||||
|
||||
|
||||
async def main():
|
||||
with LedFader(
|
||||
board.GP9,
|
||||
14,
|
||||
(
|
||||
SEGA_WT,
|
||||
SEGB_WT,
|
||||
SEGC_WT,
|
||||
SEGD_WT,
|
||||
SEGE_WT,
|
||||
SEGF_WT,
|
||||
SEGG_WT,
|
||||
SEGDP_WT,
|
||||
SEGCOL_WT,
|
||||
),
|
||||
(COM1_WT, COM2_WT, COM3_WT, COM4_WT, COMC_WT),
|
||||
) as c:
|
||||
await asyncio.gather(*(segment_throbber(c, i) for i in range(len(c))))
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
|
|
@ -17,8 +17,8 @@ based on the 'DIT duration' of about 128ms (1MHz / 32 / 4000).
|
|||
https://en.wikipedia.org/wiki/Morse_code
|
||||
"""
|
||||
|
||||
import time
|
||||
import array
|
||||
import time
|
||||
from board import LED
|
||||
from rp2pio import StateMachine
|
||||
from adafruit_pioasm import Program
|
||||
|
|
@ -62,13 +62,6 @@ T = DIT + LETTER_SPACE
|
|||
SOS = S + O + S + WORD_SPACE
|
||||
TEST = T + E + S + T + WORD_SPACE
|
||||
|
||||
# 8 slots of the shortest possible led-off time
|
||||
# A background write is 'complete' as soon as all data has been placed
|
||||
# in the StateMachine's FIFO. This FIFO has either 4 or 8 entries.
|
||||
# By adding 8 very short "led off" times, we can have our 'sm.writing' test
|
||||
# tell us when the actual letter data has all been
|
||||
FILLER = array.array("H", [LED_OFF | 1]) * 8
|
||||
|
||||
sm = StateMachine(
|
||||
pio_code.assembled,
|
||||
frequency=1_000_000,
|
||||
|
|
@ -94,11 +87,11 @@ while True:
|
|||
("TEST", TEST),
|
||||
):
|
||||
print(f"Sending out {plain}", end="")
|
||||
sm.background_write(morse + FILLER)
|
||||
while sm.writing:
|
||||
sm.background_write(morse)
|
||||
sm.clear_txstall()
|
||||
while not sm.txstall:
|
||||
print(end=".")
|
||||
time.sleep(0.1)
|
||||
print()
|
||||
print("Message all sent to StateMachine")
|
||||
time.sleep(1)
|
||||
print("Message all sent to StateMachine (including emptying FIFO)")
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -6,12 +6,17 @@
|
|||
|
||||
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 data to the LEDs in the background, and setting `auto_write` to true
|
||||
causes the data to be continuously sent to the LEDs all the time.
|
||||
|
||||
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.
|
||||
|
||||
Because the pixelbuf storage is also being written out 'live', it is possible
|
||||
(even with auto-show 'false') to experience tearing, where the LEDs are a
|
||||
combination of old and new values at the same time.
|
||||
|
||||
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.
|
||||
|
|
@ -19,7 +24,6 @@ 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
|
||||
|
||||
|
|
@ -40,7 +44,7 @@ _program = Program(
|
|||
.side_set 1 opt
|
||||
.wrap_target
|
||||
pull block side 0
|
||||
out y, 16 side 0 ; get count of NeoPixel bits
|
||||
out y, 32 side 0 ; get count of NeoPixel bits
|
||||
|
||||
bitloop:
|
||||
pull ifempty side 0 ; drive low
|
||||
|
|
@ -53,8 +57,8 @@ 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
|
||||
pull block side 0 ; get fresh delay value
|
||||
out y, 32 side 0 ; get delay count
|
||||
wait_reset:
|
||||
jmp y--, wait_reset side 0 ; wait until delay elapses
|
||||
.wrap
|
||||
|
|
@ -76,47 +80,67 @@ class NeoPixelBackground( # pylint: disable=too-few-public-methods
|
|||
|
||||
byte_count = bpp * n
|
||||
bit_count = byte_count * 8
|
||||
padding_count = byte_count % 2
|
||||
padding_count = -byte_count % 4
|
||||
|
||||
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)
|
||||
# backwards, so that dma byteswap corrects it!
|
||||
header = struct.pack(">L", bit_count - 1)
|
||||
trailer = b"\0" * padding_count + struct.pack(">L", 3840)
|
||||
|
||||
self._sm = StateMachine(
|
||||
_program.assembled,
|
||||
auto_pull=False,
|
||||
first_sideset_pin=pin,
|
||||
out_shift_right=False,
|
||||
pull_threshold=16,
|
||||
pull_threshold=32,
|
||||
frequency=12_800_000,
|
||||
**_program.pio_kwargs,
|
||||
)
|
||||
|
||||
self._first = True
|
||||
super().__init__(
|
||||
n,
|
||||
brightness=brightness,
|
||||
byteorder=pixel_order,
|
||||
auto_write=auto_write,
|
||||
auto_write=False,
|
||||
header=header,
|
||||
trailer=trailer,
|
||||
)
|
||||
|
||||
self._auto_write = False
|
||||
self._auto_writing = False
|
||||
self.auto_write = auto_write
|
||||
|
||||
@property
|
||||
def auto_write(self):
|
||||
return self._auto_write
|
||||
|
||||
@auto_write.setter
|
||||
def auto_write(self, value):
|
||||
self._auto_write = bool(value)
|
||||
if not value and self._auto_writing:
|
||||
self._sm.background_write()
|
||||
self._auto_writing = False
|
||||
elif value:
|
||||
self.show()
|
||||
|
||||
def _transmit(self, buf):
|
||||
self._sm.background_write(np.frombuffer(buf, dtype=np.uint16).byteswap())
|
||||
if self._auto_write:
|
||||
if not self._auto_writing:
|
||||
self._sm.background_write(loop=memoryview(buf).cast("L"), swap=True)
|
||||
self._auto_writing = True
|
||||
else:
|
||||
self._sm.background_write(memoryview(buf).cast("L"), swap=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import board
|
||||
import rainbowio
|
||||
import time
|
||||
import supervisor
|
||||
|
||||
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)
|
||||
# Around 1 cycle per second
|
||||
pixels.fill(rainbowio.colorwheel(supervisor.ticks_ms() // 4))
|
||||
|
|
|
|||
Loading…
Reference in a new issue