from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

## use out as DL1, use side as DL2
@asm_pio(sideset_init=PIO.OUT_LOW, out_init=PIO.OUT_HIGH, out_shiftdir=PIO.SHIFT_RIGHT)
def rsl_prog():
    wrap_target()
    pull(noblock)              # 1# wait for OSR, non-block mode
    jmp(not_osre, "notspace")  # 1# jump if OSR have new data
    
    set(y,24)           # 1# TRR: loop 177 cycles, this block delays 1600us
    label("space")
    set(x,6)            # 1#
    label("space0")
    nop()          [7]  # 8#
    jmp(x_dec, "space0") # 1#
    jmp(y_dec, "space") # 1#
    
    label("notspace")
    nop() .side(1) [1]  # 2# TRR: put SCK high
    irq(rel(0))         # 3# TRR: rise an interrupt do let user programe put new data in
    set(y,10)      [5]  # 6# TRR: loop 11 cycles
    label("loop1")
    nop()          [7]  # 8#
    jmp(y_dec, "loop1") # 1#
    
    nop() .side(0) [4]  # 5# TRR: put SCK low, get data from OSR
    set(y,10)      [5]  # 6# TRR: loop 11 cycles
    label("loop2")
    nop()          [7]  # 8#
    jmp(y_dec, "loop2") # 1#
    set(x,4)            # 1# Initialise bit counter, assert start bit for 8 cycles
    
    ## TRR: loop 5 cycles
    label("bitloop")
    out(pins, 1)   [7]  # 8#
    set(y,8)      [5]   # 6# TRR: loop 9 cycles
    label("loop3")
    nop()          [7]  # 8#
    jmp(y_dec, "loop3") # 1#
    in_(pins, 1)        # 1#
    nop()          [7]  # 8#
    nop()          [7]  # 8#
    jmp(x_dec, "bitloop") # 1#
    
    set(pins, 0)   [7]  # 8#
    set(y,10)      [5]  # 6# TRR: loop 11 cycles
    label("loop4")
    nop()          [7]  # 8#
    jmp(y_dec, "loop4") # 1#
    wrap()              # 1#


class PIORSL:
    def __init__(self, sm_id, pin_in, pin_da, pin_ck):
        count_freq = 10000
        self.counter = 0
        self._sm = StateMachine(sm_id, rsl_prog, freq=count_freq, in_base=Pin(pin_in), out_base=Pin(pin_da), sideset_base=Pin(pin_ck))
        ## Use exec() to load max count into ISR
        #self._sm.exec("pull()")
        #self._sm.exec("mov(isr, osr)")
        self.obuf = [0] * 64
        self.ibuf = [0] * 64
        for i in range(64):
            self.setio(i,0) #initial obuf
        self.obuf_pv = 0
        self._sm.irq(self._irq)
    def setio(self, addr, value):
        if addr < 64:
            value = value & 0x1f
            self.obuf[addr] = (value<<2)|0x01
    def getio(self, addr):
        if addr < 64:
            return self.ibuf[addr]
    def start(self):
        self.obuf_pv = 0
        self._sm.put(self.obuf[self.obuf_pv])
        self.obuf_pv += 1
        self._sm.active(1)
    def _irq(self,pin):
        tmp = self._sm.get()
        #tmp = 0
        if self.counter < 64:
            self._sm.put(self.obuf[self.counter]) # put data to OSR
        elif self.counter < 128:
            self._sm.put(0x01)  # put empty data to OSR
            self.ibuf[self.counter - 64] = tmp
        self.counter += 1
        if self.counter >=130:
            # not put any data to OSR
            self.counter = 0


# Pin 25 on Pico boards
rsl = PIORSL(0, 6, 5, 4)
#for i in range(64):
#    rsl.setio(i,0x00)
rsl.start()

print("RSL running")
for i in range(10):
    sleep(1)
    a = rsl.getio(17)
    print(a)

BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT