一、Raspberry PIO簡述:
Raspberry Pi pico比較獨特的是具有PIO(programmable IO),相當於具有8小型的專門處理IO的處理器,分為兩個PIO區塊,每個區塊有4個StateMachine,其架構如下圖所示:
(PIO block, 取自RP2040 datasheet)
- 每個PIO block的4個StateMachine共用32 Instructions 的Instruction Memory,雖然小但也夠用。
- 每個StateMachine有4個32 bits output FIFO與4個32 bits input FIFO,有可結合成單一方向的8個32 bits FIFO。
- 有兩個通用32 bits register: X and Y
- ISR 與OSR: input shift register and output shift register
- Clock Div: 可除頻1~65536。
(StateMachine, 取自RP2040 datasheet)
指令集:
二、4x4 Keypad:
腳位從左到右為pin1~pin8,pin1~4同一時間只能有一個腳位設為High,當pin1為high時,按下key 1,則pin5輸出為hight。
三、實做Raspberry Pi Pico PIO:
使用MicroPython程式語言來實作。
4x4 keypad與raspberry pi pico腳位接線如上圖所示。
@rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW)) def scanRowHigh(): wrap_target() set(pins, 1) [3] # each pin is high for at least 8 cycles (1+3+1+1+1+1) wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 2) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 4) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 8) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) wrap() smr = rp2.StateMachine(4, scanRowHigh, freq=2000, set_base=Pin(2), in_base=col1pin) smr.active(1)
第一行(1,4,7,*)鍵按下時,則pin5為高電位,使用PIO0 StateMachine(0) 的指令jmp(pin, "which_row")來判斷是否有按鍵按下。若有按鍵按下則使用in_(pins,4)來讀取GPIO2~5是那一個pin是高電位,則可判斷是那一個按鍵按下。接下來觸發irq,使用指令irq(rel(0))輸出按鍵內容。最後等待按鍵釋放(wait(0, pin, 0)。第二行按鍵使用PIO0 StateMachine(1) ,第三行按鍵使用PIO0 StateMachine(2),第四行按鍵使用PIO0 StateMachine(3)。程式碼如下所示。
@rp2.asm_pio() def keypad(): wrap_target() label("start") jmp(pin, "which_row") jmp("start") label("which_row") in_(pins,4) push() irq(rel(0)) [31] #wait for button bounce(at least 30ms: (32+32)*0.5ms) label("delay") nop() [31] jmp(pin, "delay") # wait for key to be released wrap() def getkeyvalue(sm): row=-1 if sm == rp2.StateMachine(0): row=0 elif sm == rp2.StateMachine(1): row=1 elif sm == rp2.StateMachine(2): row=2 elif sm == rp2.StateMachine(3): row=3 while sm.rx_fifo() : term = sm.get() for i in range(4): if term >> i == 1: print(keyvalues[row][i]) break; keyvalues=[["1","4","7","*"], ["2","5","8","0"], ["3","6","9","#"], ["A","B","C","D"]] col1pin=Pin(6, Pin.IN, Pin.PULL_DOWN) col2pin=Pin(7, Pin.IN, Pin.PULL_DOWN) col3pin=Pin(8, Pin.IN, Pin.PULL_DOWN) col4pin=Pin(9, Pin.IN, Pin.PULL_DOWN) smc1=rp2.StateMachine(0, keypad, freq=2000, in_base=Pin(2),jmp_pin=col1pin) smc2=rp2.StateMachine(1, keypad, freq=2000, in_base=Pin(2),jmp_pin=col2pin) smc3=rp2.StateMachine(2, keypad, freq=2000, in_base=Pin(2),jmp_pin=col3pin) smc4=rp2.StateMachine(3, keypad, freq=2000, in_base=Pin(2),jmp_pin=col4pin) smc1.irq(getkeyvalue) smc2.irq(getkeyvalue) smc3.irq(getkeyvalue) smc4.irq(getkeyvalue) smc1.active(1) smc2.active(1) smc3.active(1) smc4.active(1)
四、成果影片:
五、完整程式碼:
第二個程式碼為修正第二版,程式碼更簡潔。
👉第一版
from machine import Pin import rp2 @rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW)) def scanRowHigh(): wrap_target() set(pins, 1) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 2) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 4) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) set(pins, 8) [3] wait(0,pin,0) wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) wrap() @rp2.asm_pio() def keypad(): wrap_target() label("start") jmp(pin, "which_row") jmp("start") label("which_row") in_(pins,4) push() irq(rel(0)) [31] label("delay") nop() [31] jmp(pin, "delay") # wait for key to be released wrap() def getkeyvalue(sm): row=-1 if sm == rp2.StateMachine(0): row=0 elif sm == rp2.StateMachine(1): row=1 elif sm == rp2.StateMachine(2): row=2 elif sm == rp2.StateMachine(3): row=3 while sm.rx_fifo() : term = sm.get() for i in range(4): if term >> i == 1: print(keyvalues[row][i]) break; keyvalues=[["1","4","7","*"], ["2","5","8","0"], ["3","6","9","#"], ["A","B","C","D"]] col1pin=Pin(6, Pin.IN, Pin.PULL_DOWN) col2pin=Pin(7, Pin.IN, Pin.PULL_DOWN) col3pin=Pin(8, Pin.IN, Pin.PULL_DOWN) col4pin=Pin(9, Pin.IN, Pin.PULL_DOWN) smc1=rp2.StateMachine(0, keypad, freq=2000, in_base=Pin(2),jmp_pin=col1pin) smc2=rp2.StateMachine(1, keypad, freq=2000, in_base=Pin(2),jmp_pin=col2pin) smc3=rp2.StateMachine(2, keypad, freq=2000, in_base=Pin(2),jmp_pin=col3pin) smc4=rp2.StateMachine(3, keypad, freq=2000, in_base=Pin(2),jmp_pin=col4pin) smr = rp2.StateMachine(4, scanRowHigh, freq=2000, set_base=Pin(2), in_base=col1pin) smr.active(1) smc1.irq(getkeyvalue) smc2.irq(getkeyvalue) smc3.irq(getkeyvalue) smc4.irq(getkeyvalue) smc1.active(1) smc2.active(1) smc3.active(1) smc4.active(1)
from machine import Pin import rp2 @rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW,)*4) def keypad(): wrap_target() label("set_row_1") set(pins, 1) [31] #set row_1 High and wait for button bounce set(x,0x1) in_(pins,4) mov(y, isr) jmp(not_y,"set_row_2") jmp("rx_fifo") label("set_row_2") set(pins, 2) [31] set(x,0x2) in_(pins,4) mov(y, isr) jmp(not_y,"set_row_3") jmp("rx_fifo") label("set_row_3") set(pins, 4) [31] set(x,0x4) in_(pins,4) mov(y, isr) jmp(not_y,"set_row_4") jmp("rx_fifo") label("set_row_4") set(pins, 8) [31] set(x,0x8) in_(pins,4) mov(y, isr) jmp(not_y,"set_row_1") label("rx_fifo") push() #push y(col) in_(x,4)[2] push() #and then x(row) irq(rel(0)) wait(0,pin,0) # check whether key is released wait(0,pin,1) wait(0,pin,2) wait(0,pin,3) wrap() # total 31 instructions keys=[["1","2","3","A"], ["4","5","6","B"], ["7","8","9","C"], ["*","0","#","D"]] def keypad_irq(sm): y=sm.get() x=sm.get() for i in range(4): if x >> i == 1: break; for j in range(4): if y >> j == 1: break; print(keys[i][j]) smkeypad=rp2.StateMachine(0, keypad, freq=2000, set_base=Pin(2), in_base=Pin(6)) smkeypad.irq(keypad_irq) smkeypad.active(1)
沒有留言:
張貼留言