ubuntu安装 rust nightly_Rust 嵌入式开发环境搭建指南 (一):让世界闪烁吧
引
因?yàn)檫@是本專欄的第一篇文章,所以我打算先在這里介紹下專欄的寫作目標(biāo)。
Rust 是一種系統(tǒng)編程語言。 它有著驚人的運(yùn)行速度,能夠防止段錯(cuò)誤,并保證線程安全。Rust 官方一直標(biāo)榜著自己是系統(tǒng)編程語言,然而最根本的系統(tǒng)編程就是嵌入式系統(tǒng)開發(fā)。如果不能在嵌入式系統(tǒng)里大施拳腳,那么 Rust 就沒有底氣能與 C 語言叫板。經(jīng)過了 3 年迭代,Rust 在嵌入式開發(fā)領(lǐng)域已經(jīng)日漸成型,并且官方也成立了嵌入式工作組特別關(guān)注 Rust 嵌入式庫(kù)與工具鏈的開發(fā),同時(shí)也在不斷完善The embedded rust book。這里推薦大家關(guān)注工作組的 newsletter,里面有很多工作組最新工作進(jìn)展。
而本專欄將會(huì)更面向于嵌入式開發(fā)的入門教程和實(shí)踐,也就是說,本專欄的文章并不假定讀者擁有任何嵌入式開發(fā)的知識(shí)或經(jīng)驗(yàn),但是要求讀者有一定 Rust 語言基礎(chǔ),比如說熟悉借用所有權(quán)系統(tǒng),懂得使用 unsafe 手動(dòng)操作內(nèi)存結(jié)構(gòu)等等。
專欄文章會(huì)分為幾大類:
- 單片機(jī)架構(gòu)的基礎(chǔ)知識(shí)
- Rust 嵌入式開發(fā)的技巧
- 各種可以跟著動(dòng)手的實(shí)踐項(xiàng)目
希望通過本專欄可以吸引 Rust 小伙伴加入嵌入式領(lǐng)域,<del>同時(shí)拐騙一波正在使用 C 語言開發(fā)嵌入式的水深火熱的程序員。</del>
準(zhǔn)備
為了能夠自己動(dòng)手實(shí)踐嵌入式開發(fā),我們需要先準(zhǔn)備好一些材料:
- STM32F103 最小系統(tǒng)開發(fā)板 (約 10 元)
- STLINK V2 仿真器 (約 20 元)
- 母對(duì)母杜邦線
- USB 轉(zhuǎn) TTL 串口模塊 (約 5 元)
STM32F103 是現(xiàn)在應(yīng)用非常廣泛,性能強(qiáng)大而且成本低廉的一款單片機(jī),擁有著高達(dá) 72Mhz 的主頻率,完全吊打 Arduino 等開發(fā)平臺(tái)。
STM32F103 最小系統(tǒng)核心版
仿真器是連接 pc 與單片機(jī)的重要模塊,主要用于程序燒寫與調(diào)試。
STLINK V2
串口模塊用于 pc 接收單片機(jī)的串口信息用以調(diào)試,由于現(xiàn)代計(jì)算機(jī)普遍已經(jīng)取消了串口接口,所以使用 USB 串口就是最經(jīng)濟(jì)可靠的選擇。
USB2TTL
Rust 工具鏈
2. 除了默認(rèn)的標(biāo)準(zhǔn)庫(kù)外,我們還需要提前編譯好的 core 核心庫(kù)。在我們這里添加幾個(gè)常用的編譯目標(biāo)指令集,rustup 就會(huì)自動(dòng)把核心庫(kù)下載下來。
> 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. 另外我們還需要一些傳統(tǒng)而好用的二進(jìn)制工具 (binary tool) 和調(diào)試器。在 ARM官網(wǎng)頁(yè)面 下載適合平臺(tái)的最新版安裝即可。這一步安裝的工具包括 arm-none-eabi-nm, arm-none-eabi-gdb, arm-none-eabi-objcopy 還有 arm-none-eabi-size 等等。
4. 最后我們還差 openocd,它負(fù)責(zé)保持與與仿真器的通訊連接,我們需要使用它來進(jìn)行燒寫和調(diào)試指令操作。openocd 的安裝途徑有很多,建議向購(gòu)買仿真器的商家索要,或者可以從這里下載(可能需要科學(xué)上網(wǎng))。
注: 上述 3,4 步的工具需要加入 Path 環(huán)境變量。
Blinky
Blinky 是嵌入式世界的 hello world —— 讓一盞 LED 閃爍。這篇文章的最終目標(biāo)就是把最小系統(tǒng)版上唯一一顆 LED 燈閃爍起來。
我們先創(chuàng)建一個(gè)新的項(xiàng)目。
> cargo new blinkyCreated binary (application) `blinky` package打開 Cargo.toml 添加幾個(gè)依賴項(xiàng)。
[dependencies] cortex-m = "0.5.8" # cortex-m 核心指令集 cortex-m-rt = "0.6.5" # 最小運(yùn)行時(shí),負(fù)責(zé)啟動(dòng)內(nèi)存初始化 panic-halt = "0.2.0" # 定義發(fā)生 panic 時(shí)采取立即停機(jī)的行為同一架構(gòu)的單片機(jī)的內(nèi)存容量往往有很大差異,不同廠家的內(nèi)存排布也不一定相同,所以這里我們要用 memory.x 文件里定義開發(fā)板的內(nèi)存結(jié)構(gòu)。在項(xiàng)目目錄中新建文件 memory.x 并寫入:
MEMORY {FLASH : ORIGIN = 0x08000000, LENGTH = 128KRAM : ORIGIN = 0x20000000, LENGTH = 20K }這里定義了我們這個(gè) MCU 擁有 128k ROM 和 20k RAM,內(nèi)存起點(diǎn)分別在 0x08000000 和 0x20000000。
memory.x 事實(shí)上是一段鏈接器腳本 (Linker Script),鏈接器腳本用來在內(nèi)存中規(guī)劃如何排布代碼和靜態(tài)變量。很明顯僅靠這小段腳本還不足以聲明好運(yùn)行所需的所有段 (SECTION)。幸運(yùn)的是,cortex-m-rt 運(yùn)行庫(kù)已經(jīng)為我們寫好了通用的鏈接腳本,我們僅僅需要在編譯時(shí)將名為 memory.x 的內(nèi)存定義腳本放在編譯目錄,memory.x 就會(huì)被自動(dòng) include 到模板中。 所以這里需要一段編譯時(shí)自動(dòng)拷貝 memory.x 的 build script。在項(xiàng)目目錄中新建文件 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 { } }雖然這段代碼看起來毫無作用,但是對(duì)于編譯來說已經(jīng)足夠了。
可以注意一下這里的 main 函數(shù)并不是 Rust 語言內(nèi)嵌的主函數(shù),事實(shí)上,這個(gè)主函數(shù)僅僅是用戶代碼的入口,真正的主函數(shù)定義在 cortex_m_rt 庫(kù)中,在啟動(dòng)后負(fù)責(zé)靜態(tài)變量和中斷向量表的內(nèi)存初始化,接著才將執(zhí)行權(quán)交回給這里的 main 函數(shù)。
執(zhí)行編譯。
> cargo build --target thumbv7m-none-eabiCompiling blinky v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.62s至此 Blinky 已經(jīng)成功編譯好了,執(zhí)行文件應(yīng)該會(huì)出現(xiàn)在 /target/thumbv7m-none-eabi/debug/blinky 。接下來我們要把這個(gè)程序燒寫到芯片的 ROM 上。首先使用杜邦線連接上仿真器與開發(fā)板,對(duì)應(yīng)著接口上的名字,應(yīng)該很容易將四條連接線接好,四個(gè)接口分別是 SWDIO, SWCLK, 3.3V 和 GND。
接著啟動(dòng) 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這一步以出現(xiàn) xxxxx.cpu: hardware has x breakpoints, x watchpoints 提示為連接成功。 如果出現(xiàn)了其他錯(cuò)誤,先檢查是否已經(jīng)安裝仿真器的驅(qū)動(dòng),4條連接線有沒有松動(dòng),或者更換一個(gè) USB 口試試。
保留 openocd 終端,再打開一個(gè)新的終端啟動(dòng) GDB (GNU Debugger) ,使用 GDB 進(jìn)行執(zhí)行程序燒寫:
> 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)加載目標(biāo)文件
(gdb) file ./target/thumbv7m-none-eabi/debug/blinky Reading symbols from ./target/thumbv7m-none-eabi/debug/blinky...done.連接上 openocd。(openocd 的默認(rèn)端口為 3333)
(gdb) target remote :3333 Remote debugging using :3333 0x00000000 in ?? ()重置 MCU,因?yàn)樵谶\(yùn)行狀態(tài)無法進(jìn)行燒寫。
(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 默認(rèn)會(huì)暫停在初始狀態(tài),這里要手動(dòng)運(yùn)行。
(gdb) continue Continuing.好了到目前為止,如果我們的開發(fā)板毫無反應(yīng),那就對(duì)了,我們現(xiàn)在要給它加上最重要的 Blinky 邏輯。
打開 Cargo.toml 再加上兩個(gè)依賴
stm32f103xx-hal = { git = "https://github.com/japaric/stm32f103xx-hal.git" } # MCU 外圍部件操作的統(tǒng)一接口 nb = "0.1" # stm32f103xx-hal 的異步阻塞模塊,用來實(shí)現(xiàn)時(shí)鐘等待同步修改 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();// 設(shè)置時(shí)鐘總線let clocks = rcc.cfgr.freeze(&mut flash.acr);// 設(shè)置通用引腳 (GPIO)let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);// LED 對(duì)應(yīng)的 PC13 引腳let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);// 淘寶上有些版本的核心板的 LED 會(huì)接在 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();// 點(diǎn)亮 LEDled.set_high();block!(timer.wait()).unwrap();// 關(guān)閉 LEDled.set_low();} }重新編譯 Rust。
> cargo build --target thumbv7m-none-eabiCompiling blinky v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.1s回到 GDB 終端,此時(shí)如果還在運(yùn)行上一段代碼,那按下 Ctrl + C 就可以中斷執(zhí)行。
Continuing. Program received signal SIGINT, Interrupt. 0x08000240 in ?? () (gdb)直接執(zhí)行 load 指令,GDB 會(huì)自動(dòng)識(shí)別到可執(zhí)行文件的變更并進(jìn)行覆寫。
(gdb) load Start address 0x0, load size 0 Transfer rate: 0 bits in <1 sec. (gdb) continue Continuing.至此,我們的藍(lán)色 LED 就應(yīng)該會(huì)開始以一秒間隔開始閃爍了!
如果你有幸看到這,那就幫忙點(diǎn)個(gè)贊,讓更多人看到吧!
總結(jié)
以上是生活随笔為你收集整理的ubuntu安装 rust nightly_Rust 嵌入式开发环境搭建指南 (一):让世界闪烁吧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何让图片开口说话 3DMeNow教程
- 下一篇: Ubuntu安装eog遇到的坑及解决方案