Skip to content
Snippets Groups Projects
WS2812onRP2040.py 4.36 KiB
Newer Older
Werner Jarmatz's avatar
Werner Jarmatz committed
# Using PIO to drive a set of WS2812 LEDs.

import array, utime, _thread
from machine import Pin
import rp2

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()
    

class strip:
    ''' Methods to manipulate 2812 stripes:
        pset     ( position, color,[optional show(0 or 1)]) 
        fill     ( (r,g,b),[optional show(0 or 1)] )
        rotate   ( steps,[optional show(0 or 1)] )
        shift    ( steps,[optional show(0 or 1)] )
        rainbow  ( [starthue , [endhue]],[optional show(0 or 1)] )
        show     ()
        Properties:
        BRIGHTNESS (value between 0 and 1)
    '''
    counter = 0
    thread_user = None
    def __init__(self,NUM_LEDS, PIN_NUM, BRIGHTNESS):
        self.NUM_LEDS = NUM_LEDS
        self.PIN_NUM = PIN_NUM
        self.BRIGHTNESS = BRIGHTNESS
        self.now = 0
        if strip.counter < 4:
            # Create the StateMachine 
            self.sm = rp2.StateMachine(strip.counter, ws2812, freq=8_000_000, sideset_base=Pin(self.PIN_NUM))
            self.counter=strip.counter
            # Start the StateMachine
            self.sm.active(1)
            # Displayarray on the LEDs 
            self.ar = array.array("I", [0 for _ in range(self.NUM_LEDS)])
            print("Strip with state machine",strip.counter,"on pin",self.PIN_NUM,"active")
        else:
            print("the maximum of 4 state machines was reached ")
        strip.counter += 1
    
    def renew(self,attr,obj):
        print("renew state machine",self.counter)
        del self
    
    def _dimm(self,col):
        c1 = int(((col >> 16) & 0xFF) * self.BRIGHTNESS)
        c2 = int(((col >> 8) & 0xFF)  * self.BRIGHTNESS)
        c3 = int((col & 0xFF)         * self.BRIGHTNESS)
        return (c1<<16) + (c2<<8) + c3
        
    def show(self):
        if strip.thread_user == None:
            _thread.start_new_thread(self._put_thread,())
        elif (strip.thread_user == self):
            #Waiting for tread completion
            while strip.thread_user != None:
                pass
            _thread.start_new_thread(self._put_thread,())
        else:
            self.sm.put(self.ar, 8)
            utime.sleep_us(50)

    def _put_thread(self):
        strip.thread_user = self
        ar_out=self.ar[:]
        self.sm.put(ar_out, 8)
        utime.sleep_us(50)
        strip.thread_user = None
        
    def pset(self,i, col,show=False):
        self.ar[i] = self._dimm((col[1]<<16) + (col[0]<<8) + col[2])
        if show==1:
            self.show()
                     
    def fill(self,col,show=False):
        fillcol=self._dimm((col[1]<<16) + (col[0]<<8) + col[2])
        self.ar = array.array("I", [fillcol for _ in range(self.NUM_LEDS)])
        if show:
            self.show()
        
    def rotate(self,step,show=False):
        cp = array.array("I", self.ar[-step:])
        cp.extend(self.ar[:-step])
        self.ar = cp
        if show:
            self.show()
        
    def shift(self,step,show=False):
        if step >= 0:
            cp = array.array("I",[0 for _ in range(step)])
            cp.extend(self.ar[:-step])
        else:
            cp = array.array("I",self.ar[-step:])
            blackpix = array.array("I",[0]*-step)
            cp.extend(blackpix[:])           
        self.ar = cp
        if show:
            self.show()
            
    def rainbow(self, start=0, end=360,show=False):
        steps=int((end-start)/self.NUM_LEDS)
        for i in range(self.NUM_LEDS):
            self.pset(i, hue2col(start+(i*steps)))
        if show:
            self.show()
##########################################################################
# color definations    
def hue2col(angle):
    rgb = [0,0,0]
    sec = ((0,1),(1,2),(2,0))
    rgb[sec[int(angle/120)][1]]=int(255/120*(angle%120))
    rgb[sec[int(angle/120)][0]]=int(255/120*(120-(angle%120)))
    return (rgb[0],rgb[1],rgb[2])

RED = (hue2col(0))
YEL = (hue2col(60))
GRE = (hue2col(120))
CYA = (hue2col(180))
BLU = (hue2col(240))
PUR = (hue2col(300))
WHT = (255, 255, 255)
BLK = (0,0,0)
COLORS = (RED, YEL, GRE, CYA, BLU, PUR, WHT, BLK)