diff --git a/pico/test/rainbow.py b/pico/test/rainbow.py new file mode 100644 index 0000000..a00b916 --- /dev/null +++ b/pico/test/rainbow.py @@ -0,0 +1,94 @@ +import sys +# So "from ws2812 import WS2812B" finds pico/lib when run from device / or test/ +if "lib" not in sys.path: + sys.path.insert(0, "lib") +if "../lib" not in sys.path: + sys.path.insert(0, "../lib") +from ws2812 import WS2812B +import time + +# --- Rainbow pattern (outside ws2812): pregen double buffer, show via head offset --- + +def hue_to_rgb(hue): + """Hue 0..360 -> (r, g, b). Simple HSV with S=V=1.""" + h = hue % 360 + x = 1 - abs((h / 60) % 2 - 1) + if h < 60: + r, g, b = 1, x, 0 + elif h < 120: + r, g, b = x, 1, 0 + elif h < 180: + r, g, b = 0, 1, x + elif h < 240: + r, g, b = 0, x, 1 + elif h < 300: + r, g, b = x, 0, 1 + else: + r, g, b = 1, 0, x + return (int(r * 255), int(g * 255), int(b * 255)) + + +def make_rainbow_double(num_leds, brightness=1.0): + """Build 2 full rainbow cycles (2*num_leds pixels, GRB). Returns (double_buf, strip_len). + head must be in 0..strip_len-1 so DMA reads double_buf[head:head+strip_len] with no copy.""" + n = 2 * num_leds + double_buf = bytearray(n * 3) + for i in range(n): + hue = (i / n) * 360 * 2 + r, g, b = hue_to_rgb(hue) + g = int(g * brightness) & 0xFF + r = int(r * brightness) & 0xFF + b = int(b * brightness) & 0xFF + o = i * 3 + double_buf[o] = g + double_buf[o + 1] = r + double_buf[o + 2] = b + strip_len = num_leds * 3 + return (double_buf, strip_len) + + +def show_rainbow(strip, double_buf, strip_len, head): + """DMA reads directly from double_buf at head; no copy. head in 0..strip_len-1.""" + strip.show(double_buf, head) + + +# --- Strips + rainbow buffers per strip --- + +strips = [] +pins = ((2, 291), + (3, 290), + (4, 283), + (7, 278), + (0, 275), + (28, 278), + (29, 283), + (6, 290)) +sm = 0 +for pin, num_leds in pins: + print(pin, num_leds) + ws = WS2812B(num_leds, pin, sm, brightness=1.0) # 1.0 so fill() is visible + strips.append(ws) + sm += 1 + +# One rainbow double buffer per strip (num_leds can differ); no transfer buffer +now = time.ticks_ms() +rainbow_data = [make_rainbow_double(ws.num_leds, ws.brightness) for ws in strips] +# Cumulative LEDs before each strip so rainbow lines up around the ring +cumulative_leds = [0] +for ws in strips[:-1]: + cumulative_leds.append(cumulative_leds[-1] + ws.num_leds) +# Global phase (bytes); each strip gets head = (phase + cumulative_leds * 3) % strip_len +total_ring_leds = cumulative_leds[-1] + strips[-1].num_leds +bytes_per_cycle = total_ring_leds * 3 +print(time.ticks_diff(time.ticks_ms(), now), "ms") +rainbow_head = 0 +step = 3 + +while True: + now = time.ticks_ms() + for i, (strip, (double_buf, strip_len)) in enumerate(zip(strips, rainbow_data)): + head = (rainbow_head + cumulative_leds[i] * 3) % strip_len + show_rainbow(strip, double_buf, strip_len, head) + rainbow_head = (rainbow_head + step) % bytes_per_cycle + #print(time.ticks_diff(time.ticks_ms(), now), "ms") + time.sleep_ms(10)