ubuntu安装 rust nightly_Rust 嵌入式开发环境搭建指南 (一):让世界闪烁吧
引
因為這是本專欄的第一篇文章,所以我打算先在這里介紹下專欄的寫作目標。
Rust 是一種系統編程語言。 它有著驚人的運行速度,能夠防止段錯誤,并保證線程安全。Rust 官方一直標榜著自己是系統編程語言,然而最根本的系統編程就是嵌入式系統開發。如果不能在嵌入式系統里大施拳腳,那么 Rust 就沒有底氣能與 C 語言叫板。經過了 3 年迭代,Rust 在嵌入式開發領域已經日漸成型,并且官方也成立了嵌入式工作組特別關注 Rust 嵌入式庫與工具鏈的開發,同時也在不斷完善The embedded rust book。這里推薦大家關注工作組的 newsletter,里面有很多工作組最新工作進展。
而本專欄將會更面向于嵌入式開發的入門教程和實踐,也就是說,本專欄的文章并不假定讀者擁有任何嵌入式開發的知識或經驗,但是要求讀者有一定 Rust 語言基礎,比如說熟悉借用所有權系統,懂得使用 unsafe 手動操作內存結構等等。
專欄文章會分為幾大類:
- 單片機架構的基礎知識
- Rust 嵌入式開發的技巧
- 各種可以跟著動手的實踐項目
希望通過本專欄可以吸引 Rust 小伙伴加入嵌入式領域,<del>同時拐騙一波正在使用 C 語言開發嵌入式的水深火熱的程序員。</del>
準備
為了能夠自己動手實踐嵌入式開發,我們需要先準備好一些材料:
- STM32F103 最小系統開發板 (約 10 元)
- STLINK V2 仿真器 (約 20 元)
- 母對母杜邦線
- USB 轉 TTL 串口模塊 (約 5 元)
STM32F103 是現在應用非常廣泛,性能強大而且成本低廉的一款單片機,擁有著高達 72Mhz 的主頻率,完全吊打 Arduino 等開發平臺。
STM32F103 最小系統核心版
仿真器是連接 pc 與單片機的重要模塊,主要用于程序燒寫與調試。
STLINK V2
串口模塊用于 pc 接收單片機的串口信息用以調試,由于現代計算機普遍已經取消了串口接口,所以使用 USB 串口就是最經濟可靠的選擇。
USB2TTL
Rust 工具鏈
2. 除了默認的標準庫外,我們還需要提前編譯好的 core 核心庫。在我們這里添加幾個常用的編譯目標指令集,rustup 就會自動把核心庫下載下來。
> rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf info: downloading component 'rust-std' for 'thumbv6m-none-eabi' info: downloading component 'rust-std' for 'thumbv7m-none-eabi' info: downloading component 'rust-std' for 'thumbv7em-none-eabi' info: downloading component 'rust-std' for 'thumbv7em-none-eabihf'3. 另外我們還需要一些傳統而好用的二進制工具 (binary tool) 和調試器。在 ARM官網頁面 下載適合平臺的最新版安裝即可。這一步安裝的工具包括 arm-none-eabi-nm, arm-none-eabi-gdb, arm-none-eabi-objcopy 還有 arm-none-eabi-size 等等。
4. 最后我們還差 openocd,它負責保持與與仿真器的通訊連接,我們需要使用它來進行燒寫和調試指令操作。openocd 的安裝途徑有很多,建議向購買仿真器的商家索要,或者可以從這里下載(可能需要科學上網)。
注: 上述 3,4 步的工具需要加入 Path 環境變量。
Blinky
Blinky 是嵌入式世界的 hello world —— 讓一盞 LED 閃爍。這篇文章的最終目標就是把最小系統版上唯一一顆 LED 燈閃爍起來。
我們先創建一個新的項目。
> cargo new blinkyCreated binary (application) `blinky` package打開 Cargo.toml 添加幾個依賴項。
[dependencies] cortex-m = "0.5.8" # cortex-m 核心指令集 cortex-m-rt = "0.6.5" # 最小運行時,負責啟動內存初始化 panic-halt = "0.2.0" # 定義發生 panic 時采取立即停機的行為同一架構的單片機的內存容量往往有很大差異,不同廠家的內存排布也不一定相同,所以這里我們要用 memory.x 文件里定義開發板的內存結構。在項目目錄中新建文件 memory.x 并寫入:
MEMORY {FLASH : ORIGIN = 0x08000000, LENGTH = 128KRAM : ORIGIN = 0x20000000, LENGTH = 20K }這里定義了我們這個 MCU 擁有 128k ROM 和 20k RAM,內存起點分別在 0x08000000 和 0x20000000。
memory.x 事實上是一段鏈接器腳本 (Linker Script),鏈接器腳本用來在內存中規劃如何排布代碼和靜態變量。很明顯僅靠這小段腳本還不足以聲明好運行所需的所有段 (SECTION)。幸運的是,cortex-m-rt 運行庫已經為我們寫好了通用的鏈接腳本,我們僅僅需要在編譯時將名為 memory.x 的內存定義腳本放在編譯目錄,memory.x 就會被自動 include 到模板中。 所以這里需要一段編譯時自動拷貝 memory.x 的 build script。在項目目錄中新建文件 build.rs 并寫入:
use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf;fn main() {// Put the linker script somewhere the linker can find itlet out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());File::create(out.join("memory.x")).unwrap().write_all(include_bytes!("memory.x")).unwrap();println!("cargo:rustc-link-search={}", out.display());// Only re-run the build script when memory.x is changed,// instead of when any part of the source code changes.println!("cargo:rerun-if-changed=memory.x"); }接著打開 src/main,寫入:
#![no_std] #![no_main]extern crate panic_halt;use cortex_m::asm; use cortex_m_rt::entry;#[entry] fn main() -> ! {asm::nop();loop { } }雖然這段代碼看起來毫無作用,但是對于編譯來說已經足夠了。
可以注意一下這里的 main 函數并不是 Rust 語言內嵌的主函數,事實上,這個主函數僅僅是用戶代碼的入口,真正的主函數定義在 cortex_m_rt 庫中,在啟動后負責靜態變量和中斷向量表的內存初始化,接著才將執行權交回給這里的 main 函數。
執行編譯。
> cargo build --target thumbv7m-none-eabiCompiling blinky v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.62s至此 Blinky 已經成功編譯好了,執行文件應該會出現在 /target/thumbv7m-none-eabi/debug/blinky 。接下來我們要把這個程序燒寫到芯片的 ROM 上。首先使用杜邦線連接上仿真器與開發板,對應著接口上的名字,應該很容易將四條連接線接好,四個接口分別是 SWDIO, SWCLK, 3.3V 和 GND。
接著啟動 openocd。
> openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg 64-bits Open On-Chip Debugger 0.10.0-dev-00289-g5eb5e34 (2016-09-03-09:40) Licensed under GNU GPL v2 For bug reports, readhttp://openocd.org/doc/doxygen/bugs.html...Polling target stm32f1x.cpu failed, trying to reexamine Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints這一步以出現 xxxxx.cpu: hardware has x breakpoints, x watchpoints 提示為連接成功。 如果出現了其他錯誤,先檢查是否已經安裝仿真器的驅動,4條連接線有沒有松動,或者更換一個 USB 口試試。
保留 openocd 終端,再打開一個新的終端啟動 GDB (GNU Debugger) ,使用 GDB 進行執行程序燒寫:
> arm-none-eabi-gdb GNU gdb (GNU Tools for ARM Embedded Processors 6-2017-q1-update) 7.12.1.20170215-git...For help, type "help". (gdb)加載目標文件
(gdb) file ./target/thumbv7m-none-eabi/debug/blinky Reading symbols from ./target/thumbv7m-none-eabi/debug/blinky...done.連接上 openocd。(openocd 的默認端口為 3333)
(gdb) target remote :3333 Remote debugging using :3333 0x00000000 in ?? ()重置 MCU,因為在運行狀態無法進行燒寫。
(gdb) monitor reset halt stm32f1x.cpu: target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x0800016c msp: 0x20000260開始寫入
(gdb) load Start address 0x0, load size 0 Transfer rate: 0 bits in <1 sec.寫入后 MCU 默認會暫停在初始狀態,這里要手動運行。
(gdb) continue Continuing.好了到目前為止,如果我們的開發板毫無反應,那就對了,我們現在要給它加上最重要的 Blinky 邏輯。
打開 Cargo.toml 再加上兩個依賴
stm32f103xx-hal = { git = "https://github.com/japaric/stm32f103xx-hal.git" } # MCU 外圍部件操作的統一接口 nb = "0.1" # stm32f103xx-hal 的異步阻塞模塊,用來實現時鐘等待同步修改 src/main.rs
#![no_std] #![no_main]extern crate panic_halt; extern crate stm32f103xx_hal as hal; #[macro_use] extern crate nb;use cortex_m_rt::entry;use hal::prelude::*; use hal::stm32f103xx; use hal::timer::Timer;#[entry] fn main() -> ! {let cp = cortex_m::Peripherals::take().unwrap();let dp = stm32f103xx::Peripherals::take().unwrap();let mut flash = dp.FLASH.constrain();let mut rcc = dp.RCC.constrain();// 設置時鐘總線let clocks = rcc.cfgr.freeze(&mut flash.acr);// 設置通用引腳 (GPIO)let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);// LED 對應的 PC13 引腳let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);// 淘寶上有些版本的核心板的 LED 會接在 PB12 引腳上,這樣的話用下面兩行替換// let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);// let mut led = gpiob.pb12.into_push_pull_output(&mut gpiob.crh);let mut timer = Timer::syst(cp.SYST, 1.hz(), clocks);loop {block!(timer.wait()).unwrap();// 點亮 LEDled.set_high();block!(timer.wait()).unwrap();// 關閉 LEDled.set_low();} }重新編譯 Rust。
> cargo build --target thumbv7m-none-eabiCompiling blinky v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.1s回到 GDB 終端,此時如果還在運行上一段代碼,那按下 Ctrl + C 就可以中斷執行。
Continuing. Program received signal SIGINT, Interrupt. 0x08000240 in ?? () (gdb)直接執行 load 指令,GDB 會自動識別到可執行文件的變更并進行覆寫。
(gdb) load Start address 0x0, load size 0 Transfer rate: 0 bits in <1 sec. (gdb) continue Continuing.至此,我們的藍色 LED 就應該會開始以一秒間隔開始閃爍了!
如果你有幸看到這,那就幫忙點個贊,讓更多人看到吧!
總結
以上是生活随笔為你收集整理的ubuntu安装 rust nightly_Rust 嵌入式开发环境搭建指南 (一):让世界闪烁吧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何让图片开口说话 3DMeNow教程
- 下一篇: ubuntu18.04安装pycharm