Porównaj commity

...

2 Commity

Autor SHA1 Wiadomość Data
Max Carlson 812de90e5e Remove references to delay as it's no longer needed 2024-02-08 17:58:02 +02:00
Max Carlson 51f1f46230 Use a single array as a buffer, including header and trailer
Uses an offset to ensure get/set() happens in the right place. Also caches the memoryview once to make show() as efficient as possible. It turned out passing the header/trailer values as-is from python is the right approach. Everything works well for me now, maybe I'll look into DMA next :)
2024-02-08 17:53:08 +02:00
1 zmienionych plików z 25 dodań i 25 usunięć

Wyświetl plik

@ -4,7 +4,7 @@ import rp2
# based on https://learn.adafruit.com/intro-to-rp2040-pio-with-circuitpython/advanced-using-pio-to-drive-neopixels-in-the-background by https://learn.adafruit.com/u/jepler # based on https://learn.adafruit.com/intro-to-rp2040-pio-with-circuitpython/advanced-using-pio-to-drive-neopixels-in-the-background by https://learn.adafruit.com/u/jepler
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=False, pull_thresh=32) @rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=False, pull_thresh=32)
def sk6812(): def sk6812():
wrap_target() wrap_target()
pull(block) .side(0) # get fresh NeoPixel bit count value pull(block) .side(0) # get fresh NeoPixel bit count value
@ -40,10 +40,6 @@ class slice_maker_class:
slice_maker = slice_maker_class() slice_maker = slice_maker_class()
# Delay here is the reset time. You need a pause to reset the LED strip back to the initial LED
# however, if you have quite a bit of processing to do before the next time you update the strip
# you could put in delay=0 (or a lower delay)
#
# Class supports different order of individual colors (GRB, RGB, WRGB, GWRB ...). In order to achieve # Class supports different order of individual colors (GRB, RGB, WRGB, GWRB ...). In order to achieve
# this, we need to flip the indexes: in 'RGBW', 'R' is on index 0, but we need to shift it left by 3 * 8bits, # this, we need to flip the indexes: in 'RGBW', 'R' is on index 0, but we need to shift it left by 3 * 8bits,
# so in it's inverse, 'WBGR', it has exactly right index. Since micropython doesn't have [::-1] and recursive rev() # so in it's inverse, 'WBGR', it has exactly right index. Since micropython doesn't have [::-1] and recursive rev()
@ -63,11 +59,10 @@ class Neopixel:
# 'W_in_mode', # bool: is 'W' in mode # 'W_in_mode', # bool: is 'W' in mode
# 'sm', # state machine # 'sm', # state machine
# 'shift', # shift amount for each component, in a tuple for (R,B,G,W) # 'shift', # shift amount for each component, in a tuple for (R,B,G,W)
# 'delay', # delay amount
# 'brightnessvalue', # brightness scale factor 1..255 # 'brightnessvalue', # brightness scale factor 1..255
# ] # ]
def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=3): def __init__(self, num_leds, state_machine, pin, mode="RGB"):
""" """
Constructor for library class Constructor for library class
@ -76,9 +71,7 @@ class Neopixel:
:param pin: pin on which data line to led-strip is connected :param pin: pin on which data line to led-strip is connected
:param mode: [default: "RGB"] mode and order of bits representing the color value. :param mode: [default: "RGB"] mode and order of bits representing the color value.
This can be any order of RGB or RGBW (neopixels are usually GRB) This can be any order of RGB or RGBW (neopixels are usually GRB)
:param delay: [default: 0.0001] delay used for latching of leds when sending data
""" """
self.pixels = array.array("I", [0] * num_leds)
# self.pixels_out = array.array("I", [0] * num_leds) # self.pixels_out = array.array("I", [0] * num_leds)
self.mode = mode self.mode = mode
self.W_in_mode = 'W' in mode self.W_in_mode = 'W' in mode
@ -96,18 +89,31 @@ class Neopixel:
((mode.index('B') ^ 3) - 1) * 8, 0) ((mode.index('B') ^ 3) - 1) * 8, 0)
self.sm.active(1) self.sm.active(1)
self.num_leds = num_leds self.num_leds = num_leds
self.delay = delay
self.brightnessvalue = 255 self.brightnessvalue = 255
# from https://learn.adafruit.com/intro-to-rp2040-pio-with-circuitpython/advanced-using-pio-to-drive-neopixels-in-the-background # from https://learn.adafruit.com/intro-to-rp2040-pio-with-circuitpython/advanced-using-pio-to-drive-neopixels-in-the-background
byte_count = bpp * num_leds byte_count = bpp * num_leds
bit_count = byte_count * 8 bit_count = byte_count * 8
padding_count = -byte_count % 4 padding_count = -byte_count % 4
# send number of bits to read
self.header = bytearray(struct.pack("L", bit_count - 1))
# pad if needed, then send number of cycles to delay
self.trailer = bytearray(b"\0" * padding_count + struct.pack("L", 3840))
# use a single array
self.pixels = array.array("I")
# send number of bits to read
self.pixels.append(bit_count - 1)
# store offset into pixels array for get/set later
self.offset = len(self.pixels)
# add starting values for each pixel
pix = array.array("I", [0] * num_leds)
self.pixels.extend(pix)
# send number of cycles to delay
self.pixels.append(3840)
# use a memoryview to
self.mv = memoryview(self.pixels)
def brightness(self, brightness=None): def brightness(self, brightness=None):
""" """
@ -199,12 +205,13 @@ class Neopixel:
white = round(rgb_w[3] * bratio) white = round(rgb_w[3] * bratio)
pix_value = white << sh_W | blue << sh_B | red << sh_R | green << sh_G pix_value = white << sh_W | blue << sh_B | red << sh_R | green << sh_G
offset = self.offset
# set some subset, if pixel_num is a slice: # set some subset, if pixel_num is a slice:
if type(pixel_num) is slice: if type(pixel_num) is slice:
for i in range(*pixel_num.indices(self.num_leds)): for i in range(*pixel_num.indices(self.num_leds)):
self.pixels[i] = pix_value self.pixels[i + offset] = pix_value
else: else:
self.pixels[pixel_num] = pix_value self.pixels[pixel_num + offset] = pix_value
def get_pixel(self, pixel_num): def get_pixel(self, pixel_num):
""" """
@ -213,7 +220,7 @@ class Neopixel:
:param pixel_num: Index of pixel to be set :param pixel_num: Index of pixel to be set
:return rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used :return rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used
""" """
balance = self.pixels[pixel_num] balance = self.pixels[pixel_num + self.offset]
sh_R, sh_G, sh_B, sh_W = self.shift sh_R, sh_G, sh_B, sh_W = self.shift
if self.W_in_mode: if self.W_in_mode:
w = (balance >> sh_W) & 255 w = (balance >> sh_W) & 255
@ -329,14 +336,7 @@ class Neopixel:
This method should be used after every method that changes the state of leds or after a chain of changes. This method should be used after every method that changes the state of leds or after a chain of changes.
:return: None :return: None
""" """
# If mode is RGB, we cut 8 bits of, otherwise we keep all 32 self.sm.put(self.mv)
cut = 8
if self.W_in_mode:
cut = 0
self.sm.put(self.header, 0)
self.sm.put(memoryview(self.pixels), cut)
self.sm.put(self.trailer, 0)
def fill(self, rgb_w, how_bright=None): def fill(self, rgb_w, how_bright=None):
""" """