在本篇中,將帶你手把手新建一個(gè)基于Py32F030的學(xué)習(xí)板的 hello world 工程。
工具鏈準(zhǔn)備
如果您還沒有安裝 Rust 的基本開發(fā)環(huán)境,您可參考 快速搭建環(huán)境。
首先,你需要了解你手上的單片機(jī)的處理器內(nèi)核,如 STM32F103 為 Arm® Cortex®-M3 CPU,NRF52840 為 Arm® Cortex®-M4F CPU,CH32V307 為 RISC-V4F 內(nèi)核。因此你需要根據(jù)你芯片內(nèi)核的來安裝相應(yīng)的交叉編譯鏈。 常見的嵌入式交叉編譯工具如下。
? rust-embedded-start git:(main) ? rustup target list | grep none
aarch64-unknown-none
aarch64-unknown-none-softfloat
armebv7r-none-eabi
armebv7r-none-eabihf
armv7a-none-eabi
armv7r-none-eabi
armv7r-none-eabihf
loongarch64-unknown-none
loongarch64-unknown-none-softfloat
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imafc-unknown-none-elf
riscv32imc-unknown-none-elf
riscv64gc-unknown-none-elf
riscv64imac-unknown-none-elf
thumbv6m-none-eabi (installed)
thumbv7em-none-eabi
thumbv7em-none-eabihf
thumbv7m-none-eabi (installed)
thumbv8m.base-none-eabi
thumbv8m.main-none-eabi
thumbv8m.main-none-eabihf
x86_64-unknown-none
Rust 交叉工具鏈的目標(biāo)是由三元組組成,也叫目標(biāo)三元組。
它通常采用 ---
的形式來描述目標(biāo)平臺(tái)的架構(gòu)、供應(yīng)商、操作系統(tǒng)和應(yīng)用程序二進(jìn)制接口(ABI)。
- 架構(gòu)(arch)
- 例如,
thumbv7m - none - eabi
中的thumbv7m
表示 ARM 架構(gòu)下的 Thumb - 2 指令集的 v7m 版本。這告訴編譯器生成的代碼要符合這種特定的 ARM 架構(gòu)指令集要求,不同的 ARM 指令集(如 ARMv8、Thumb - 2 等)有不同的性能和功能特點(diǎn),編譯器需要根據(jù)這個(gè)信息生成合適的機(jī)器碼。 - 對(duì)于
powerpc - unknown - linux - gnu
中的powerpc
,它代表 PowerPC 架構(gòu),這是一種與 ARM 不同的處理器架構(gòu),具有自己的指令集和硬件特性,編譯器要按照 PowerPC 的規(guī)則來生成代碼。 - 供應(yīng)商(vendor)
- 在目標(biāo)三元組中,供應(yīng)商部分可以提供關(guān)于硬件制造商的信息。不過在很多情況下,
none
這樣的標(biāo)識(shí)被使用,表示這不是特定某個(gè)供應(yīng)商的硬件定義,或者是通用的定義。例如,在thumbv7m - none - eabi
中,none
表示這個(gè)定義不是針對(duì)某一個(gè)特定的 ARM 芯片供應(yīng)商(如三星、恩智浦等),而是一種通用的 ARM Thumb - 2 v7m 指令集的定義。 - 操作系統(tǒng)(sys)
- 操作系統(tǒng)部分明確了目標(biāo)代碼運(yùn)行的操作系統(tǒng)環(huán)境。例如,
linux
表示目標(biāo)代碼是運(yùn)行在 Linux 操作系統(tǒng)之上。這會(huì)影響編譯器如何處理系統(tǒng)調(diào)用、庫(kù)鏈接等操作。對(duì)于嵌入式系統(tǒng),可能會(huì)看到none
(表示沒有操作系統(tǒng),如裸機(jī)環(huán)境),像thumbv7m - none - eabi
中的none
就表明這個(gè)代碼可能是用于沒有操作系統(tǒng)的 ARM 嵌入式設(shè)備,編譯器就不會(huì)生成與復(fù)雜操作系統(tǒng)交互的代碼部分。 - 而
powerpc - unknown - linux - gnu
中的linux
說明代碼是為運(yùn)行在 PowerPC 架構(gòu)的 Linux 系統(tǒng)準(zhǔn)備的,編譯器需要確保生成的代碼能夠與 Linux 的系統(tǒng)調(diào)用接口、文件系統(tǒng)等兼容。 - 應(yīng)用程序二進(jìn)制接口(ABI)
- ABI 部分定義了二進(jìn)制層面上函數(shù)調(diào)用、數(shù)據(jù)結(jié)構(gòu)布局等的規(guī)則。例如,
eabi
(嵌入式應(yīng)用程序二進(jìn)制接口)在thumbv7m - none - eabi
中是用于嵌入式系統(tǒng)的 ABI 標(biāo)準(zhǔn)。它規(guī)定了如何在二進(jìn)制層面上傳遞參數(shù)、返回值等。不同的 ABI 標(biāo)準(zhǔn)適用于不同的應(yīng)用場(chǎng)景,gnu
(如在powerpc - unknown - linux - gnu
中)是一種在 Linux 系統(tǒng)上常用的 ABI,遵循 GNU 的規(guī)則來處理函數(shù)調(diào)用和數(shù)據(jù)結(jié)構(gòu)布局等。
在清楚對(duì)應(yīng)的交叉編譯起三元組名后,你需要使用命令安裝它,如對(duì)于 Py32f030 芯片來說,內(nèi)核是 ARM Cortex-M0+
, 無浮點(diǎn)加速,因此需要安裝 thumbv6m-none-eabi
rustup target add thumbv6m-none-eabi
其他常見 內(nèi)核 的單片機(jī)與交叉編譯器對(duì)應(yīng)如下:
- ARM Cortex-M0:
thumbv6m-none-eabi
- ARM Cortex-M3:
thumbv7m-none-eabi
- ARM Cortex-M4:
thumbv7em-none-eabi
- ARM Cortex-M7:
thumbv7em-none-eabi
- ARM Cortex-M33:
thumbv8m.main-none-eabi
- ARM Cortex-M4F:
thumbv7em-none-eabihf
- ARM Cortex-M7F:
thumbv7em-none-eabihf
如果使用錯(cuò)誤的交叉編譯器編譯 Rust 代碼,可能編譯失敗或生成的固件運(yùn)行指令會(huì)異常。
創(chuàng)建工程
基于模板創(chuàng)建新工程。使用命令:cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
, 然后輸入合適的工程名字即可。
? tmp cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart --name py32f030_hello_world_start
???? Destination: /Users/hunter/Desktop/tmp/tmp/py32f030_hello_world_start ...
???? project-name: py32f030_hello_world_start ...
???? Generating template ...
???? Moving generated files into: `/Users/hunter/Desktop/tmp/tmp/py32f030_hello_world_start`...
???? Initializing a fresh Git repository
? Done! New project created /Users/hunter/Desktop/tmp/tmp/py32f030_hello_world_start
修改
創(chuàng)建的 工程可能與你的芯片并不完全匹配,因此你可能需要檢查以下幾個(gè)部分:
- 初步編譯,可以正常通過,但此時(shí)可能并不能在您的主板上運(yùn)行正常。
修改
創(chuàng)建的 工程可能與你的芯片并不完全匹配,因此你可能需要檢查以下幾個(gè)部分:
- 初步編譯,可以正常通過,但此時(shí)可能并不能在您的主板上運(yùn)行正常。
? py32f030_hello_world_start git:(master) ? cargo b
Updating crates.io index
Locking 31 packages to latest compatible versions
Adding aligned v0.3.5 (latest: v0.4.2)
Adding as-slice v0.1.5 (latest: v0.2.1)
Adding bare-metal v0.2.5 (latest: v1.0.0)
Adding bitfield v0.13.2 (latest: v0.17.0)
Adding cortex-m v0.6.7 (latest: v0.7.7)
Adding cortex-m-rt v0.6.15 (latest: v0.7.5)
Adding cortex-m-rt-macros v0.6.15 (latest: v0.7.5)
Adding cortex-m-semihosting v0.3.7 (latest: v0.5.0)
Adding embedded-hal v0.2.7 (latest: v1.0.0)
Adding generic-array v0.12.4 (latest: v1.1.0)
Adding generic-array v0.13.3 (latest: v1.1.0)
Adding generic-array v0.14.7 (latest: v1.1.0)
Adding nb v0.1.3 (latest: v1.1.0)
Adding panic-halt v0.2.0 (latest: v1.0.0)
Adding r0 v0.2.2 (latest: v1.0.0)
Adding rustc_version v0.2.3 (latest: v0.4.1)
Adding semver v0.9.0 (latest: v1.0.23)
Adding semver-parser v0.7.0 (latest: v0.10.2)
Adding syn v1.0.109 (latest: v2.0.87)
Compiling semver-parser v0.7.0
Compiling typenum v1.17.0
Compiling cortex-m v0.7.7
Compiling proc-macro2 v1.0.89
Compiling version_check v0.9.5
Compiling unicode-ident v1.0.13
Compiling nb v1.1.0
Compiling void v1.0.2
Compiling vcell v0.1.3
Compiling syn v1.0.109
Compiling stable_deref_trait v1.2.0
Compiling cortex-m-rt v0.6.15
Compiling bitfield v0.13.2
Compiling cortex-m-semihosting v0.3.7
Compiling volatile-register v0.2.2
Compiling cortex-m v0.6.7
Compiling nb v0.1.3
Compiling r0 v0.2.2
Compiling embedded-hal v0.2.7
Compiling py32f030_hello_world_start v0.1.0 (/Users/hunter/Desktop/tmp/tmp/py32f030_hello_world_start)
Compiling panic-halt v0.2.0
Compiling semver v0.9.0
Compiling rustc_version v0.2.3
Compiling generic-array v0.14.7
Compiling bare-metal v0.2.5
Compiling quote v1.0.37
Compiling generic-array v0.13.3
Compiling generic-array v0.12.4
Compiling as-slice v0.1.5
Compiling aligned v0.3.5
Compiling cortex-m-rt-macros v0.6.15
Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.98s
- 修改
memory.x
, 指定 flash 和 ram 信息, 修改如下:
diff --git a/memory.x b/memory.x
index b271f22..0f0d381 100644
--- a/memory.x
+++ b/memory.x
@@ -2,9 +2,9 @@ MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* TODO Adjust these memory regions to match your device memory layout */
- /* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
- FLASH : ORIGIN = 0x00000000, LENGTH = 256K
- RAM : ORIGIN = 0x20000000, LENGTH = 64K
+ /* PY32F030K28T6: */
+ FLASH : ORIGIN = 0x08000000, LENGTH = 64K
+ RAM : ORIGIN = 0x20000000, LENGTH = 8K
}
/* This is where the call stack will be allocated. */
- 修改編譯目標(biāo)和運(yùn)行命令
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 9709a75..cb7fde1 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -2,6 +2,9 @@
# uncomment this to make `cargo run` execute programs on QEMU
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+[target.thumbv6m-none-eabi]
+runner = 'probe-rs run --chip PY32F030x8'
+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
@@ -28,8 +31,8 @@ rustflags = [
[build]
# Pick ONE of these default compilation targets
-# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
-target = "thumbv7m-none-eabi" # Cortex-M3
+target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
+# target = "thumbv7m-none-eabi" # Cortex-M3
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
# target = "thumbv8m.base-none-eabi" # Cortex-M23
如上修改后,執(zhí)行 cargo r
:
? py32f030_hello_world_start git:(main) ? cargo r
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `probe-rs run --chip PY32F030x8 target/thumbv6m-none-eabi/debug/py32f030_hello_world_start`
WARN probe_rs::util::rtt: No RTT header info was present in the ELF file. Does your firmware run RTT?
Erasing ? [00:00:00] [####################################] 4.00 KiB/4.00 KiB @ 53.93 KiB/s (eta 0s )
Programming ? [00:00:00] [#####################################] 2.00 KiB/2.00 KiB @ 3.87 KiB/s (eta 0s ) Finished in 0.63s
cargo 將編譯工程,然后執(zhí)行 runner
配置命令,即使用 probe-rs
命令下載固件到芯片,并執(zhí)行。可以看到,下載完成成后并沒有其他日志打印,因此我們需要繼續(xù)添加打印日志。
- 添加日志 crate
rtt-target
,讓日志打印像本地端一樣簡(jiǎn)單。修改如下:
diff --git a/Cargo.toml b/Cargo.toml
index 1d1df47..a2b897d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,11 +6,13 @@ name = "py32f030_hello_world_start"
version = "0.1.0"
[dependencies]
-cortex-m = "0.6.0"
+cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]}
cortex-m-rt = "0.6.10"
cortex-m-semihosting = "0.3.3"
panic-halt = "0.2.0"
+rtt-target = "0.5.0"
+
# Uncomment for the panic example.
# panic-itm = "0.4.1"
添加 crate 后,在 main.rs 需要添加以下代碼:
diff --git a/src/main.rs b/src/main.rs
index 7922596..dbeaf9c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,18 +3,26 @@
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
-// use panic_abort as _; // requires nightly
-// use panic_itm as _; // logs messages over ITM; requires ITM support
-// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
+ // use panic_abort as _; // requires nightly
+ // use panic_itm as _; // logs messages over ITM; requires ITM support
+ // use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
use cortex_m::asm;
use cortex_m_rt::entry;
+use rtt_target::{rprintln, rtt_init_print};
+
#[entry]
fn main() -> ! {
- asm::nop(); // To not have main optimize to abort in release mode, remove when you add code
+ // init rtt
+ rtt_init_print!();
+
+ asm::nop();
+
+ rprintln!("Hello, world!");
loop {
- // your code goes here
+ // Wait For Interrupt
+ cortex_m::asm::wfi();
}
}
最后運(yùn)行,下載完成后馬上打印 hello, world
。在此,你已經(jīng)成功踏入了嵌入式 Rust 的小門。
? py32f030_hello_world_start git:(main) ? cargo r
Compiling py32f030_hello_world_start v0.1.0 (/Users/hunter/Desktop/tmp/tttttt/py32f030_hello_world_start)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s
Running `probe-rs run --chip PY32F030x8 target/thumbv6m-none-eabi/debug/py32f030_hello_world_start`
Erasing ? [00:00:00] [##################################] 16.00 KiB/16.00 KiB @ 98.89 KiB/s (eta 0s )
Programming ? [00:00:02] [###################################] 12.25 KiB/12.25 KiB @ 4.21 KiB/s (eta 0s ) Finished in 3.112s
Hello, world!
查看編譯信息
固件信息
- Debug 模式
? py32f030_hello_world_start git:(main) ? cargo size
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
text data bss dec hex filename
12464 0 1088 13552 34f0 py32f030_hello_world_start
? py32f030_hello_world_start git:(main) ? arm-none-eabi-readelf target/thumbv6m-none-eabi/debug/py32f030_hello_world_start -S
There are 22 section headers, starting at offset 0xbf9e4:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .vector_table PROGBITS 08000000 0000f4 0000c0 00 A 0 0 4
[ 2] .text PROGBITS 080000c0 0001b4 002404 00 AX 0 0 4
[ 3] .rodata PROGBITS 080024c4 0025b8 000bec 00 AM 0 0 4
[ 4] .data PROGBITS 20000000 0031a4 000000 00 A 0 0 4
[ 5] .bss NOBITS 20000000 0031a4 000440 00 WA 0 0 4
[ 6] .uninit NOBITS 20000440 0031a4 000000 00 WA 0 0 4
[ 7] .debug_abbrev PROGBITS 00000000 0031a4 0024cf 00 0 0 1
[ 8] .debug_info PROGBITS 00000000 005673 02d143 00 0 0 1
[ 9] .debug_aranges PROGBITS 00000000 0327b6 001ab0 00 0 0 1
[10] .debug_ranges PROGBITS 00000000 034266 017248 00 0 0 1
[11] .debug_str PROGBITS 00000000 04b4ae 0443c6 01 MS 0 0 1
[12] .comment PROGBITS 00000000 08f874 00007b 01 MS 0 0 1
[13] .ARM.attributes ARM_ATTRIBUTES 00000000 08f8ef 000032 00 0 0 1
[14] .debug_frame PROGBITS 00000000 08f924 0057a8 00 0 0 4
[15] .debug_line PROGBITS 00000000 0950cc 0262da 00 0 0 1
[16] .debug_loc PROGBITS 00000000 0bb3a6 00027b 00 0 0 1
[17] .debug_pubnames PROGBITS 00000000 0bb621 0001e9 00 0 0 1
[18] .debug_pubtypes PROGBITS 00000000 0bb80a 000047 00 0 0 1
[19] .symtab SYMTAB 00000000 0bb854 0016b0 10 21 271 4
[20] .shstrtab STRTAB 00000000 0bcf04 0000e9 00 0 0 1
[21] .strtab STRTAB 00000000 0bcfed 0029f4 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
- Release 模式
? py32f030_hello_world_start git:(main) ? cargo size --release
Finished `release` profile [optimized + debuginfo] target(s) in 0.01s
text data bss dec hex filename
1992 0 1088 3080 c08 py32f030_hello_world_start
? py32f030_hello_world_start git:(main) ? arm-none-eabi-readelf target/thumbv6m-none-eabi/release/py32f030_hello_world_start -S
There are 22 section headers, starting at offset 0x1184c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .vector_table PROGBITS 08000000 0000f4 0000c0 00 A 0 0 4
[ 2] .text PROGBITS 080000c0 0001b4 0006ec 00 AX 0 0 4
[ 3] .rodata PROGBITS 080007ac 0008a0 00001c 00 A 0 0 4
[ 4] .data PROGBITS 20000000 0008bc 000000 00 A 0 0 4
[ 5] .bss NOBITS 20000000 0008bc 000440 00 WA 0 0 4
[ 6] .uninit NOBITS 20000440 0008bc 000000 00 WA 0 0 4
[ 7] .debug_loc PROGBITS 00000000 0008bc 0013d4 00 0 0 1
[ 8] .debug_abbrev PROGBITS 00000000 001c90 0009bc 00 0 0 1
[ 9] .debug_info PROGBITS 00000000 00264c 005097 00 0 0 1
[10] .debug_aranges PROGBITS 00000000 0076e3 000340 00 0 0 1
[11] .debug_ranges PROGBITS 00000000 007a23 000dc0 00 0 0 1
[12] .debug_str PROGBITS 00000000 0087e3 005524 01 MS 0 0 1
[13] .comment PROGBITS 00000000 00dd07 000048 01 MS 0 0 1
[14] .ARM.attributes ARM_ATTRIBUTES 00000000 00dd4f 000032 00 0 0 1
[15] .debug_frame PROGBITS 00000000 00dd84 000680 00 0 0 4
[16] .debug_line PROGBITS 00000000 00e404 0024c5 00 0 0 1
[17] .debug_pubnames PROGBITS 00000000 0108c9 0001e9 00 0 0 1
[18] .debug_pubtypes PROGBITS 00000000 010ab2 000047 00 0 0 1
[19] .symtab SYMTAB 00000000 010afc 0005c0 10 21 57 4
[20] .shstrtab STRTAB 00000000 0110bc 0000e9 00 0 0 1
[21] .strtab STRTAB 00000000 0111a5 0006a5 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
參考
hysonglet/py32f030_hello_world_start
cortex_m_quickstart - Rust (rust-embedded.org)
probe-rs - probe-rs