嵌入式rust中RISCV單片機(jī)PAC庫生成
????????本次嘗試生成CH32V103的PAC(其實(shí)github上有現(xiàn)成的了),自己生成的目的是探索怎么生成PAC,以便在沒有現(xiàn)成PAC的芯片上自己生成并使用rust編程。
嵌入式rust中,生成PAC需要用到對應(yīng)芯片的SVD文件,以及svd2rust工具。
一,準(zhǔn)備工作
1,假設(shè)已經(jīng)安裝好了rust的開發(fā)環(huán)境(這個去網(wǎng)上看怎么安裝,很容易),可以使用cago來安裝svd2rust.
2,準(zhǔn)備芯片對應(yīng)的svd文件,這個一般可以從芯片廠家獲取到。而我取了個巧,去支持這個芯片的現(xiàn)有開發(fā)環(huán)境中找。比如CH32V103的官方推薦開發(fā)環(huán)境是MounRiver Studio,電腦安裝了它后,在其安裝路徑的MounRiver_Studio\template\wizard\WCH\RISC-V\CH32V103\NoneOS中,就有CH32V103xx.svd
二,生成PAC庫
? ? 打開終端,切換到打算存放PAC庫的路徑,執(zhí)行命令:
cargo new ch32v103pac --lib
會在執(zhí)行命令的目錄下自動生成一個ch32v103pac文件夾(這個名字可以自己取),文件夾下有一些內(nèi)容,這是cargo為我們生成的lib庫相關(guān)文件,如下圖:

注:src下也還有東西,只不過不是我們需要的,可以刪除。
接下來把準(zhǔn)備好的svd文件(CH32V103xx.svd)放到自動生成的ch32v103pac文件夾中,在ch32v103pac文件夾中通過svd2rust工具處理svd文件,
執(zhí)行命令:svd2rust --target=riscv -i .\CH32V103xx.svd
命令中--target=riscv指明目標(biāo)是riscv(CH32V103xx就是riscv的),如果不指明,似乎默認(rèn)就會認(rèn)為是cortex-m的。
命令執(zhí)行后生成了一些文件:

其中l(wèi)ib.rs就是對應(yīng)的庫,這個文件包含了很多東西,而且打開看看可以發(fā)現(xiàn),即使你rust學(xué)得很好,里面的代碼看起來也很費(fèi)解,亂七八糟的,而且芯片所有外設(shè)都在里面。
接下來要用form工具整理一下lib.rs,并且把芯片的外設(shè)一個一個歸類好。
安裝form工具:cargo install form
先刪除自動生成的src目錄(因?yàn)槠鋬?nèi)不是我們想要的內(nèi)容)。然后執(zhí)行:
form -i .\lib.rs -o src
這個命令通過上面生成的lib.rs,生成了一系列內(nèi)容,并且輸出到src(src被我們刪了,這個命令會又自動生成)。到此,自動生成的lib.rs已經(jīng)不再需要,可以把它刪了。

進(jìn)到src看可以發(fā)現(xiàn)里面按芯片的外設(shè)分類了,并且生成了很多代碼,其實(shí)這些內(nèi)容都來自之前自動生成的lib.rs,隨便打開一個看看,依舊是亂七八糟。

接下來用cargo的格式化工具處理它們,執(zhí)行命令:cargo fmt

注意:沒有切入src目錄,還是在原來的庫根目錄執(zhí)行命令。
執(zhí)行完后,代碼被格式化好了,就比較好閱讀了:

繼續(xù),
為庫添加依賴,因?yàn)樾酒腔趓iscv的,上面只是生成了芯片外設(shè)(比如定時器,adc)之類的,riscv內(nèi)核有其核心內(nèi)容。所以要添加riscv的一些依賴,如運(yùn)行時環(huán)境。這些不需要自己寫,只要是riscv內(nèi)核的,通用。
打開目錄下的cargo.toml文件,添加如下內(nèi)容:
[dependencies]
critical-section = { version = "1.0", optional = true }
bare-metal = "1.0.0"
riscv = "0.10.0"
vcell = "0.1.0"
riscv-rt = { optional = true, version = "0.11.0" }
[build-dependencies]
svd2rust = { version = "0.29", default-features = false }
[features]
default = ["rt"]
rt = ["dep:riscv-rt"]

到這里,這個單片機(jī)的PAC就算完成了,那到底正不正常呢,接下來得試試。
三,驗(yàn)證
為了測試生成的PAC是否正常,我們寫一個應(yīng)用例程來測試它。
回到ch32v103pac同級的目錄下(路徑不一定要同級,只是為了方便應(yīng)用例程引用PAC),執(zhí)行cargo new testpac --bin

進(jìn)入testpac,在目錄下新建一個.cargo文件夾,注意文件夾名字前面是有個.的,再在.cargo里面建立一個config文件,加入如下內(nèi)容:
# .cargo/config
[target.risCV32imac-unknown-none-elf]
rustflags = [
? "-C", "link-arg=-Tmemory.x",
]
[build]
target = "risCV32imac-unknown-none-elf"

我們要用cargo來管理這個工程,cargo會去工程下的這個文件夾里面的config獲取一些配置,所以我們建立了它。
例如:"-C", "link-arg=-Tmemory.x",指明一個連接腳本memory.x,名字看就是和內(nèi)存有關(guān)的。target = "risCV32imac-unknown-none-elf"指明要用risCV32imac-unknown-none-elf編譯,因?yàn)檫@個單片機(jī)的內(nèi)核是risCV32imac的。
當(dāng)然,risCV32imac-unknown-none-elf要安裝,使用rustup target add?risCV32imac-unknown-none-elf即可安裝。
繼續(xù)。。。。。
上面提到memory.x,就類似單片機(jī)以前的連接腳本,指明芯片ram有多大,rom有多少,把它們分成什么數(shù)據(jù)段,bss段之類的,接下來我們在應(yīng)用例程的工程根目錄創(chuàng)建這個文件,并寫入內(nèi)容:
/* GD32VF103C8 */
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64k
RAM : ORIGIN = 0x20000000, LENGTH = 20k
}
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_RODATA", FLASH);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);

同pac庫一樣,應(yīng)用例程也添加依賴,比如PAC庫就是應(yīng)用例程的依賴項(xiàng),打開應(yīng)用例程下從cargo.toml,加入如下內(nèi)容:
[dependencies]
# use pac with critical-section features
critical-section = { version = "1.0", optional = true }
ch32v103pac = { path = "../ch32v103pac", features = ["rt", "critical-section"]}
riscv = { version = "0.10.1",features = ["critical-section-single-hart"]}
panic-halt = "0.2.0"
riscv-rt = "0.11.0"
[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations?

上圖截圖中,紅框處就是生成的PAC庫,通過相對路徑引用到。
打開src下的main.rs,編寫一下代碼,引用到PAC里面的內(nèi)容:

編譯應(yīng)用例程
cargo build
注意,編譯的時候,會下載相關(guān)依賴,需要網(wǎng)絡(luò),而且有可能下載失敗,失敗的話重新執(zhí)行上面的命令。

編譯完成顯示如下:

可以看到,提示了Finished了,其中有個警告是因?yàn)槲覀兌x了一個per,但是沒有使用它。
到此,我們應(yīng)用了生成的PAC庫內(nèi)容,并且能順利編譯。然而,我們的應(yīng)用例程實(shí)際沒有操作硬件,生成的PAC庫到底能不能操作硬件呢,去main函數(shù)里面嘗試點(diǎn)燈吧?。。?!
值得一提的是,PAC庫畢竟還是寄存器級別的封裝,要像更好用,還要在其上繼續(xù)封裝出HAL庫。
提兩點(diǎn):
1,上面生成的內(nèi)容不太會用,可以生成幫助文檔,在工程根目錄執(zhí)行cargo doc --open,執(zhí)行后,在根目錄的target目錄里會出現(xiàn)一個doc文件夾:

cargo doc會幫我們生成工程中相關(guān)內(nèi)容的使用文檔,后面的--open是生成后順便打開的意思,也可以不加--open,生成后自己去打開(使用網(wǎng)頁瀏覽器打開的)

2,單片機(jī)需要hex或者bin來燒錄,上面編譯沒有生成這類文件,需要使用命令來生成bin文件:cargo objcopy --target risCV32imac-unknown-none-elf --release -- -O binary app.bin
