pico-python/ws2811.py

83 lines
2.3 KiB
Python
Raw Permalink Normal View History

2024-05-14 17:26:58 +02:00
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep_ms, sleep_us
from random import randint
2024-05-14 18:42:12 +02:00
LEDS = 5
2024-05-14 17:26:58 +02:00
PIN = Pin(16)
2024-05-14 18:42:12 +02:00
DELAY = 5
2024-05-14 17:26:58 +02:00
"""
inspired by https://github.com/raspberrypi/pico-micropython-examples/blob/master/pio/pio_ws2812.py
I made this for no other purpose than learning
took me a few hours to understand pio, but if I did it you can too
ws2811 has different timing:
0 - 250ns, then 1000ns
1 - 600ns, then 650ns
rpi cpu cycle = 8ns
to make things easier, we can split timing:
0 -> 250ns high + 350 low + 650 low
1 -> 250ns high + 350 high + 650 low
p1 -> 250ns = 31.25 cycles
p2 -> 350ns = 43.75 cycles
p3 -> 650ns = 81.25 cycles
decimal, but it's fine if it's off by some, so we can round
"""
@asm_pio(sideset_init=PIO.OUT_LOW,
out_shiftdir=PIO.SHIFT_LEFT,
autopull=True, pull_thresh=24)
def prog():
label("loop")
# 3rd part
nop().side(0).delay(14) # 15
nop().side(0).delay(14) # 30
nop().side(0).delay(14) # 45
nop().side(0).delay(14) # 60
nop().side(0).delay(14) # 75
out(x, 1).side(0).delay(5) # 81. get one bit of color
# 1st part
nop().side(1).delay(15) # 16
jmp(not_x, "zero").side(1).delay(14) # 31. check if zero
# 2nd part for 1 bit
nop().side(1).delay(14) # 15
nop().side(1).delay(14) # 30
jmp("loop").side(1).delay(12) # 43
# 2nd part for 0 bit
label("zero")
nop().side(0).delay(14) # 15
nop().side(0).delay(14) # 30
nop().side(0).delay(12) # 43
sm = StateMachine(0, prog, sideset_base=PIN)
sm.active(1)
2024-05-14 18:42:12 +02:00
def transition_step(src_hex: int, tgt_hex: int, prog: float):
src_hex += int(( (tgt_hex >> 16) - (src_hex >> 16) ) * prog) << 16
src_hex += int(( (tgt_hex >> 8 & 0xFF) - (src_hex >> 8 & 0xFF) ) * prog) << 8
src_hex += int(( (tgt_hex & 0xFF) - (src_hex & 0xFF) ) * prog)
return src_hex
cols = [randint(0, 0xFFFFFF) for i in range(LEDS)]
cols_new = cols[1:] + [randint(0, 0xFFFFFF)]
2024-05-14 17:26:58 +02:00
while True:
2024-05-14 18:42:12 +02:00
cols.pop(0)
cols.append(cols_new[-1])
cols_new.pop(0)
cols_new.append(randint(0, 0xFFFFFF))
for i in range(0, 100):
for l in range(LEDS):
cold = transition_step(cols[l], cols_new[l], i / 100)
sm.put(cold, 8) # I don't know why 8 not 24
sleep_ms(DELAY)