一、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)


沒有留言:
張貼留言