使用arduino操作RP2040 PIO之簡要筆記
前情提要:
RP2040是一個雙核133MHz的ARM M0+微處理器,具有264k RAM,支持最大16M外置ROM。?
最吸引人的一點是它還具有可編程IO,在較小的晶圓面積下做出了可編程的效果,使得通用性和DIY性更強。
PIO結(jié)構(gòu)&必要知識介紹:
RP2040具有兩個PIO塊,每個PIO塊有四個狀態(tài)機。通過測試程序可知,如果不設(shè)置分頻則狀態(tài)機每步指令都可以運行在133MHz下,速度非常快。
每個PIO塊具有32步程序空間,PIO內(nèi)的四個狀態(tài)機共享32步的程序空間。狀態(tài)機初始化時需要指定程序的起始和結(jié)束地址。如果覺得空間不夠用,也可以通過FIFO傳輸程序給狀態(tài)機運行。
每個狀態(tài)機用OSR和ISR寄存器對接了兩個FIFO,分別是TX和RX,使用pull指令將會從TXFIFO中拉取數(shù)據(jù)到OSR寄存器,使用push則會把ISR寄存器中數(shù)據(jù)壓入RXFIFO中。(這里的TX和RX是相對于CPU的)FIFO可以通過CPU或者DMA讀寫。
狀態(tài)機對接IO使用了任意映射的方式,首先指定一個映射IO號,例如15,再指定映射數(shù)量例如5,則15-19這5個IO都會被映射到狀態(tài)機。
狀態(tài)機映射IO時有四種映射,包括IN、OUT、SET和SIDE SET指令對應(yīng)的IO,它們四個可以映射到不同的IO。
狀態(tài)機還可以發(fā)出和等待中斷。

PIO可以執(zhí)行如下九種指令:

其中Delay/side-set 這5位是很有用的。
sideset的作用:
Delay/side-set共用了5位的空間,當初始化狀態(tài)機時需要設(shè)定SIDESET_COUNT和SIDE_EN,SIDESET_COUNT決定了sideset需要占用5位中最高的多少位,SIDE_EN決定了指令中sideset的最高位是否用于使能sideset操作。
例如sideset指令映射到了pin15。設(shè)初始化為sideset count=3,并且最高位用于使能。
則當某條指令的bit12=1,bit11=1,bit10=0,在執(zhí)行這條指令時,狀態(tài)機會同時設(shè)置io16=1(bit11) , io15=0(bit10)。如果bit12=0則狀態(tài)機不操作IO。
這使得狀態(tài)機可以在執(zhí)行指令的同時操作IO,實現(xiàn)一步程序做兩步的事情,減少空間占用,并且其指令頻率保持不變。這意味著133M的時鐘下PIO操作IO比CPU更快。還有一種情況是當需要編寫SPI這種協(xié)議時,sideset可以使得在SDA移出的同時SCLK變化,達到產(chǎn)生精準時序的目的。
Delay的作用:
Delay占用的是這5位中的低幾位,當設(shè)置Delay時,在狀態(tài)機執(zhí)行指令后會等待幾個周期,這對于程序空間緊缺的狀態(tài)機非常重要,可以實現(xiàn)一步程序同時做到延時,不需要浪費空間寫延時函數(shù)(如果所需延時較短的話)。狀態(tài)機也可以設(shè)置時鐘分頻來改變指令周期。
JMP指令:當滿足Condition(條件)時,跳轉(zhuǎn)到指定地址(0-31),條件可以是always,或者 !X,!Y,X--,Y--,X!=Y,input pin,OSR非空這幾個。
OUT指令:將OSR寄存器移出指定位數(shù)到指定寄存器中,空位補零。bitcount決定了移出多少位,Destination決定要移出到哪里,可以是output pin或者X,Y等。
如果Destination是EXEC寄存器則下一步將立即執(zhí)行移到EXEC中的指令。如果設(shè)定了OSR自動pull,則移出指令到EXEC后,OSR將從TXFIFO中自動拉取下一個數(shù)據(jù),搭配DMA應(yīng)當可以實現(xiàn)自動運行一系列程序,但每條指令要多花費一個周期來運行OUT。
MOV指令:MOV可以將一個寄存器中數(shù)據(jù)移到另一個里面,當目標寄存器是EXEC時就會執(zhí)行指令。當目標是pin將使用out指令映射到的引腳,當來源寄存器是pin則將使用in指令映射到的引腳。MOV指令有兩位op操作,可以將原寄存器進行補碼或取反后再移動到目標寄存器。
如何將自己編寫的匯編內(nèi)容運行搭配PIO上:
對于Arduino及PlatformIO里面的pico開發(fā)板,庫中已經(jīng)包含有了pico-sdk,其中有一個pio.h文件,直接包含它即可使用操作PIO的基本函數(shù)。
對于其他C++編程的玩家,則需要自己移植一份pico-sdk。
這里我編寫了個簡單的PIO操作程序,封裝了常用PIO操作,讀者直接調(diào)用即可。
首先是myPIO_program.h
然后是myPIO_program.cpp
最后是main.cpp中的點燈測試代碼(必須運行在有LED的PICO上):
編譯、燒錄,看到燈亮則說明PIO運行成功。
根據(jù)rp2040-datasheet中對9種指令的介紹,使用encoder.put_code()函數(shù)一個個放入程序指令即可,不能超過32步。
pio_pin_program_init函數(shù)是用來設(shè)定狀態(tài)機初始化參數(shù)的,包括sideset,IO映射,OSR移位順序和是否自動拉取等等。如果閑下來了可以單獨講一下。
隨手小記,如有紕漏還請指正