性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

Rust嵌入式
認(rèn)證:普通會員
作者動態(tài)
嵌入式 Rust 開發(fā)推薦安裝的插件
3天前
嵌入式 Rust 如何使用 Timer 外設(shè)
6天前
Py32 如何使用 Rust 開發(fā)CRC 外設(shè)
2星期前
Py32F030 使用Rust驅(qū)動I2C
2星期前
Py32 使用Rust測試獨(dú)立看門狗
2星期前

Rust 國產(chǎn)單片機(jī)入門第一課

深入理解 hello world 例程 

py32f030-hal crate 為 py32f030 芯片的外設(shè)支持庫, 提供基本的外設(shè)訪問接口。程序的運(yùn)行環(huán)境為Py32_Rust_Dev開發(fā)板 。

py32f030-hal crate 的目錄結(jié)構(gòu)如下:

?  py32f030-hal git:(main) ? tree -L 1
.
├── Cargo.lock
├── Cargo.toml
├── Embed.toml
├── LICENSE
├── README.md
├── examples
├── memory.x
└── src

初次學(xué)習(xí)時,該目錄中有以下幾個目錄或文件需要了解:

Cargo.toml

該文件為 crate 的包管理文件,通過 toml 文件格式設(shè)置 crate 的基本信息,常用屬性如下

  • crate 版本
  • 包名
  • 依賴
  • features
  • 編譯屬性

Rust 編譯的最小單位為 crate,發(fā)布的單位也為 crate。通常 crate 分為兩種,

  • 二進(jìn)制 crate:直接編譯成可執(zhí)行的二進(jìn)制,將包含一個 main 函數(shù)入口
  • 庫 crate,提供庫接口,編譯后為 lib 文件。也可添加多個 example 用來提供接口使用樣例,可在 example 文件中包含 main 函數(shù)用于直接生成可執(zhí)行的測試固件。

詳細(xì)可參考:TOML 格式詳解

[package]
name = "py32f030_hal"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bare-metal = { version = "1.0.0" }
cast = "0.3"
cortex-m-rt = "0.7"
critical-section = { version = "1.1.2" }
embedded-hal = { version = "0.2", features = ["unproven"] }
embedded-hal-async = { version = "1.0" }
...
[features]
default = ["example"] # "embassy"
example = ["dep:defmt", "dep:defmt-rtt", "dep:panic-probe", "dep:panic-halt"]
embassy = [
    "dep:embassy-executor",
    "dep:embassy-sync",
    "dep:embassy-time",
    "time-driver",
]
## Enable the timer for use with `embassy-time` with a 1KHz tick rate.
time-driver = ["dep:embassy-time-driver", "embassy-time-driver/tick-hz-1_000"]

[dev-dependencies]

[[example]]
name = "blinky"

[profile.dev]
codegen-units = 1
opt-level = "z"
lto = "fat"
debug = true
overflow-checks = true
strip = false

[profile.release]
codegen-units = 1
opt-level = "z"
lto = true
debug = false
overflow-checks = false
# strip = true   # 開啟后release模式的日志不會顯示

Embed.toml

Embed.toml 是 cargo 插件 cargo-flash 工作依賴的文件,通常來說并不是 Rust crate 中所必備的文件,在嵌入式開發(fā)中通??梢杂脕硎褂貌寮?nbsp;cargo embed   來快速編譯、運(yùn)行、或調(diào)試固件。詳細(xì)可了解:cargo-embed

?  py32f030-hal git:(main) ? cat Embed.toml 

[default.general]
chip = "PY32F030x8"

[default.rtt]
enabled = false

[default.gdb]
enabled = true

[default.reset]
halt_afterwards = true

在以上代碼中則指定命令 cargo embed 執(zhí)行時所依賴的芯片名, 重啟后進(jìn)入 GDB 狀態(tài)。

Examples

該目錄用來存放一些測試樣例代碼,如 blinky,uart 等,初學(xué)者可以通過運(yùn)行這些測試代碼來快速了解如何使用外設(shè)驅(qū)動,crate 根目錄下直接執(zhí)行: cargo r --example expample_file_name

?  py32f030-hal git:(main) ? tree -L 1 examples 
examples
├── adc_block.rs
├── advanced_timer_block.rs
...
├── hello_world.rs
├── i2c_master_block.rs
├── key.rs
├── rtc_block.rs
└── uart.rs

memory.x

memory.x 文件用來指定芯片 RAM 和 Flash 等存儲器的大小和地址,類似 C 中的鏈接腳本 ld 文件。在本 crate 中非必需,目前僅當(dāng)使用 example 時才會用到該文件。在自己新建的 bin crate 工程中需要包含芯片對應(yīng) memory.x 文件。

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 64K
  RAM : ORIGIN = 0x20000000, LENGTH = 8K
}

在  memory.x 腳本中可以看到,

  • Flash 的起始地址:0x08000000, 大小為 64K
  • RAM 的起始地址:0x20000000, 大小為 8K

src

src 目錄為該庫的源文件,通常在單片機(jī)外設(shè)庫中,每個外設(shè)作為一個單獨(dú)的模塊。模塊的根節(jié)點(diǎn)在 lib.rs 中,模塊名即為包名,也就是 py32f030_hal

?  py32f030-hal git:(main) ? tree -L 1 src     
src
├── lib.rs
├── adc
...
├── rtc
├── spi
├── syscfg
├── timer
└── usart

main 函數(shù) 

對于大多數(shù)嵌入式工程來說,因 flash 和 ram 資源有限,無法容納標(biāo)準(zhǔn) std 接口的代碼 ,因此需要指定 rust 引用 非標(biāo)準(zhǔn)庫(no_std)。

hello-world.rs 代碼如下:

#![no_std]
#![no_main]

use py32f030_hal as _;
use {defmt_rtt as _, panic_probe as _};

#[cortex_m_rt::entry]
fn main_fun() -> ! {
    defmt::info!("hello world");
    loop {
        cortex_m::asm::wfe();
    }
}

文件的 前行代碼是 Rust 語言的屬性宏,用于指定編譯時的特定行為。感嘆號 !代表該屬性在整個  crate 生效。

  • #![no_std]:  這個屬性宏告訴 Rust 編譯器在編譯目標(biāo)程序時不使用標(biāo)準(zhǔn)庫(std)。標(biāo)準(zhǔn)庫提供了很多常用的功能,比如文件I/O、錯誤處理、集合類型等。不使用標(biāo)準(zhǔn)庫通常意味著你需要自己提供這些功能,或者使用其他庫來替代。
  • #![no_main]:  這個屬性宏告訴 Rust 編譯器不自動生成 main 函數(shù)。在 Rust 中,main 函數(shù)是程序的入口點(diǎn)。如果你不使用這個屬性宏,編譯器會自動尋找一個返回 () 類型的 main 函數(shù)。如果你使用了這個屬性宏,你需要自己提供一個 #[entry] 屬性的函數(shù)作為程序的入口點(diǎn)。也就是說,應(yīng)用程序的入口函數(shù)名可以不為 main

第4行 use py32f030_hal as _; 引用入本 py32f030_hal.第5行引入 defmt_rtt 和 panic_probe。

第6行 #[cortex_m_rt::entry] 的屬性宏將告訴編譯起后面的函數(shù)名將作為程序入口。

第8行 fn main_fun() -> !!表明函數(shù) main_fun 將永不返回。這樣設(shè)計(jì)避免編譯檢查警告。

第9 行 defmt::info!("hello world"); 該語句將會在終端中打印字符串。然后系統(tǒng)進(jìn)入停止模式。

 編譯 

通過命令:cargo b --example hello_world 編譯程序。首次編譯可能耗時較長。

?  py32f030-hal git:(main) ? cargo b --example hello_world
warning: unused manifest key: dependencies.embedded-io-async.option
   Compiling proc-macro2 v1.0.85
   Compiling unicode-ident v1.0.12
   Compiling version_check v0.9.4
   Compiling syn v1.0.109
   Compiling semver-parser v0.7.0
   Compiling nb v1.1.0
   Compiling cortex-m v0.7.7
   Compiling void v1.0.2
   Compiling nb v0.1.3
   Compiling thiserror v1.0.61
   Compiling critical-section v1.1.2
   Compiling embedded-hal v0.2.7
   Compiling semver v1.0.23
   Compiling semver v0.9.0
   Compiling defmt v0.3.8
   Compiling rustc_version v0.2.3
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling autocfg v1.3.0
   Compiling bare-metal v0.2.5
   Compiling num-traits v0.2.19
   Compiling ident_case v1.0.1
   Compiling byteorder v1.5.0
   Compiling vcell v0.1.3
   Compiling fnv v1.0.7
   Compiling defmt-macros v0.3.9
   Compiling az v1.2.1
   Compiling volatile-register v0.2.2
   Compiling quote v1.0.36
   Compiling syn v2.0.66
   Compiling bitfield v0.13.2
   Compiling cortex-m-rt v0.7.3
   Compiling atomic-polyfill v1.0.3
   Compiling rustc_version v0.4.0
   Compiling bitflags v1.3.2
   Compiling panic-probe v0.3.2
   Compiling defmt-rtt v0.4.1
   Compiling ssd1309 v0.3.0
   Compiling heapless v0.7.17
   Compiling PY32f030xx-pac v0.1.0
   Compiling display-interface v0.4.1
   Compiling embedded-io-async v0.6.1
   Compiling embedded-hal-async v1.0.0
   Compiling embassy-hal-internal v0.1.0
   Compiling gcd v2.3.0
   Compiling fugit v0.3.7
   Compiling embedded-graphics-core v0.3.3
   Compiling float-cmp v0.8.0
   Compiling darling_core v0.20.9
   Compiling hash32 v0.2.1
   Compiling micromath v1.1.1
   Compiling stable_deref_trait v1.2.0
   Compiling embedded-hal v1.0.0
   Compiling embedded-io v0.6.1
   Compiling embedded-graphics v0.7.1
   Compiling fugit-timer v0.1.3
   Compiling display-interface-i2c v0.4.0
   Compiling embassy-futures v0.1.1
   Compiling panic-halt v0.2.0
   Compiling bare-metal v1.0.0
   Compiling cast v0.3.0
   Compiling drop-move v0.1.0
   Compiling cortex-m-rt-macros v0.7.0
   Compiling thiserror-impl v1.0.61
   Compiling darling_macro v0.20.9
   Compiling darling v0.20.9
   Compiling enumset_derive v0.10.0
   Compiling enumset v1.1.5
   Compiling defmt-parser v0.3.4
   Compiling py32f030_hal v0.1.0 (/Users/hunter/mywork/py32/py32f030-hal)
    Finished `dev` profile [optimized + debuginfo] target(s) in 38.96s

編譯完成后生成的 elf 文件路徑為:

  • Debug模式: target/thumbv6m-none-eabi/debug/examples/hello_world
  • Release模式:target/thumbv6m-none-eabi/debug/examples/hello_world

常使用size 命令查看 flash 和 ram 占用情況。

arm-none-eabi-size target/thumbv6m-none-eabi/debug/examples/hello_world 
   text    data     bss     dec     hex filename
   6344      56    1032    7432    1d08 target/thumbv6m-none-eabi/debug/examples/hello_world

在默認(rèn)情況下,Debug 模式可能會占用較多的空間,但通常在 Release 模式下,則會減少很多。由于目前使用了 defmt 作為打印接口,因此會占用較多資源,如果資源限制,可選用其他占用較少的 crate。

查看匯編 

elf 文件轉(zhuǎn)匯編語言通過命令:arm-none-eabi-objdump -d target/thumbv6m-none-eabi/debug/examples/hello_world > debug.asm

target/thumbv6m-none-eabi/debug/examples/hello_world:     file format elf32-littlearm


Disassembly of section .text:

080000bc :
 80000bc: f000 fe25 bl 8000d0a 
 80000c0: 4808       ldr r0, [pc, #32] ; (80000e4 )
 80000c2: 4909       ldr r1, [pc, #36] ; (80000e8 )
 80000c4: 2200       movs r2, #0
 80000c6: 4281       cmp r1, r0
 80000c8: d001       beq.n 80000ce 
 80000ca: c004       stmia r0!, {r2}
 80000cc: e7fb       b.n 80000c6 
 80000ce: 4807       ldr r0, [pc, #28] ; (80000ec )
 80000d0: 4907       ldr r1, [pc, #28] ; (80000f0 )
 80000d2: 4a08       ldr r2, [pc, #32] ; (80000f4 )
 80000d4: 4281       cmp r1, r0
 80000d6: d002       beq.n 80000de 
 80000d8: ca08       ldmia r2!, {r3}
 80000da: c008       stmia r0!, {r3}
 80000dc: e7fa       b.n 80000d4 
 80000de: f000 f895 bl 800020c 
 80000e2: de00       udf #0
 80000e4: 20000038 .word 0x20000038
 80000e8: 20000040 .word 0x20000040
 80000ec: 20000000 .word 0x20000000
 80000f0: 20000038 .word 0x20000038
 80000f4: 080018c8 .word 0x080018c8

...

0800020c :
 800020c: b580       push {r7, lr}
 800020e: af00       add r7, sp, #0
 8000210: f000 f800 bl 8000214 <_ZN11hello_world22__cortex_m_rt_main_fun17h27b2c8ae827133dbE>

08000214 <_ZN11hello_world22__cortex_m_rt_main_fun17h27b2c8ae827133dbE>:
 8000214: b580       push {r7, lr}
 8000216: af00       add r7, sp, #0
 8000218: f000 febe bl 8000f98 <_defmt_acquire>
 800021c: 4803       ldr r0, [pc, #12] ; (800022c <_ZN11hello_world22__cortex_m_rt_main_fun17h27b2c8ae827133dbE+0x18>)
 800021e: f000 fddc bl 8000dda <_ZN5defmt6export6header17hdbd91843ccf33f48E>
 8000222: f000 fee5 bl 8000ff0 <_defmt_release>
 8000226: bf20       wfe
 8000228: e7fd       b.n 8000226 <_ZN11hello_world22__cortex_m_rt_main_fun17h27b2c8ae827133dbE+0x12>
 800022a: 46c0       nop ; (mov r8, r8)
 800022c: 00000003 .word 0x00000003    

...     

細(xì)心的讀者可以看到匯編的 main 函數(shù)里面最終調(diào)用了函數(shù) _ZN11hello_world22__cortex_m_rt_main_fun17h27b2c8ae827133dbE, 與我們定義的

#[cortex_m_rt::entry]
fn main_fun() -> ! 

Rust 源碼編譯后的函數(shù)和變量符號變化規(guī)律與C++相似,變量在編譯后的名字通常按照一定規(guī)律進(jìn)行 manging(名字改編),確保在鏈接階段能夠正確識別和處理符號,因此模板變量、不同作用域的變量可以允許相同名字。

如果在編寫代碼時為避免函數(shù)名被重命名,可以使用屬性#[no_mangle]標(biāo)記避免重命名。通常在以下場景被使用:

  • 其他語言綁定,如調(diào)用C的函數(shù)或變量, 確保接口兼容
  • 提供接口給其他語言,如匯編等
  • 動態(tài)庫開發(fā)

 查看符號信息 

通常使用 arm-none-eabi-readelf 命令查看編譯后的固件的指令格式,大小端,CPU架構(gòu),段信息,如中斷向量表的偏移、各信息段的大小,方便了解固件各段的具體大小,為優(yōu)化固件大小提供重要信息。

?  py32f030-hal git:(main) ? arm-none-eabi-readelf target/thumbv6m-none-eabi/debug/examples/hello_world -A
Attribute Section: aeabi
File Attributes
  Tag_conformance: "2.09"
  Tag_CPU_arch: v6S-M
  Tag_CPU_arch_profile: Microcontroller
  Tag_ARM_ISA_use: No
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_R9_use: V6
  Tag_ABI_PCS_GOT_use: direct
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_CPU_unaligned_access: None
  Tag_ABI_FP_16bit_format: IEEE 754
?  py32f030-hal git:(main) ? arm-none-eabi-readelf target/thumbv6m-none-eabi/debug/examples/hello_world -S
There are 22 section headers, starting at offset 0x5ef20:

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 010000 0000bc 00   A  0   0  4
  [ 2] .text             PROGBITS        080000bc 0100bc 001d98 00  AX  0   0  4
  [ 3] .rodata           PROGBITS        08001e54 011e54 000738 00  AM  0   0  4
  [ 4] .data             PROGBITS        20000000 020000 000040 00  WA  0   0  8
  [ 5] .gnu.sgstubs      PROGBITS        080025e0 020040 000000 08   A  0   0 32
  [ 6] .bss              NOBITS          20000040 020040 000140 00  WA  0   0  8
  [ 7] .uninit           NOBITS          20000180 020040 000400 00  WA  0   0  4
  [ 8] .defmt            PROGBITS        00000000 020040 000006 00      0   0  1
  [ 9] .debug_loc        PROGBITS        00000000 020046 0036a7 00      0   0  1
  [10] .debug_abbrev     PROGBITS        00000000 0236ed 000f37 00      0   0  1
  [11] .debug_info       PROGBITS        00000000 024624 0121c5 00      0   0  1
  [12] .debug_aranges    PROGBITS        00000000 0367e9 000bd0 00      0   0  1
  [13] .debug_ranges     PROGBITS        00000000 0373b9 002018 00      0   0  1
  [14] .debug_str        PROGBITS        00000000 0393d1 01bd34 01  MS  0   0  1
  [15] .comment          PROGBITS        00000000 055105 000048 01  MS  0   0  1
  [16] .ARM.attributes   ARM_ATTRIBUTES  00000000 05514d 000030 00      0   0  1
  [17] .debug_frame      PROGBITS        00000000 055180 000d1c 00      0   0  4
  [18] .debug_line       PROGBITS        00000000 055e9c 00632f 00      0   0  1
  [19] .symtab           SYMTAB          00000000 05c1cc 001200 10     21 218  4
  [20] .shstrtab         STRTAB          00000000 05d3cc 0000dd 00      0   0  1
  [21] .strtab           STRTAB          00000000 05d4a9 001a76 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)

如上所示,可以看到中斷向量表 vector_table 的地址為 0x08000000 ,  data 段的起始地址為 0x20000000 , 與 memory.x 定義的一致。

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 2
收藏 3
關(guān)注 13
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧