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 工具链
- 文章下面将会使用
nightly-msvc
channel 的 Rust 编译器工具链(因为作者使用 Windows 平台开发),读者也可以使用gnu
或者linux
平台,步骤上如果有所出入相信使用linux
的老手是可以自己解决的。
> rustup default nightly-msvc
info: using existing install for 'nightly-x86_64-pc-windows-msvc'
info: default toolchain set to 'nightly-x86_64-pc-windows-msvc'nightly-x86_64-pc-windows-msvc unchanged - rustc 1.32.0-nightly (36a50c29f 2018-11-09)
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 嵌入式开发环境搭建指南 (一):让世界闪烁吧相关推荐
- ubuntu12.04嵌入式开发环境搭建(各种问题、各种配置)
ubuntu-12.04嵌入式开发环境搭建 先安装ubuntu-16.04 *** 想使用root用户登陆的,操作如下 给root用户设定一个密码 supreme@supreme:~# sudo p ...
- Ubuntu 下无人机飞控 ArduPilot 开发环境搭建
Ubuntu 下无人机飞控 ArduPilot 开发环境搭建 Ubuntu 下无人机飞控 ArduPilot 开发环境搭建 操作流程 升级安装包 安装 git 克隆代码 安装交叉编译工具链 将编译器添 ...
- 蓝鲸智云统一开发环境搭建指南
腾讯官方的<蓝鲸智云统一开发环境搭建指南> 蓝鲸应用统一开发环境指南 一:背景 蓝鲸应用开发需要依赖django,celery,mysql-client等第三方库,而像celery又依赖其 ...
- 【教程】Windows下Miniconda+Pytorch+Pycharm开发环境搭建指南
Windows下Miniconda+Pytorch+Pycharm开发环境搭建指南 给本科生写的新手教程,遇到很多新手的共性问题,可供大家参考.在开始阅读之前,请注意两个要关键:1.为什么要使用Con ...
- linux skype 接口,ubuntu /linux下skype api开发环境搭建
1.安装Skype: 下载skype for linux,地址:http://www.skype.com/download/skype/linux/choose/ 可以下载一个ubuntu 8.10 ...
- stm32mp1安装linux系统,stm32mp1linux开发环境搭建(cortex a7)
原标题:stm32mp1linux开发环境搭建(cortex a7) 写在前面: 本文章为<STM32MP1系列教程之Cortex-A7开发篇>系列中的一篇,全系列总计11篇.笔者使用的开 ...
- 黑莓java文件怎么安装程序_黑莓开发环境搭建windows7+eclipse+BlackBerry Java Plug+JDK6...
最近有点空闲时间,所以就学学黑莓开发,当然要开发第一步就是搭建开发环境,google了一下,有很多教程,但都是很老的了,可能是因为国内开发黑莓的人很少吧.黑莓的好处就是出了名的安全,所以有一批忠实的粉 ...
- Ubuntu 12.04下Pomelo开发环境搭建(转)
关于Pomelo的开发之前一直是在Win7下搞的,最近决定迁移到Ubuntu下,我用的是Ubuntu 12.04,个人认为Ubuntu下搭建Pomelo开发环境,最重要的工作就是安装Nodejs,搞定 ...
- #Kinect之路#基于ubuntu 12.04的Kinect开发环境搭建 OpenNI+NITE+AVIN2+qt
之前基于Win7搭建了kinect的开发环境,由于本人的机子太慢,编一个qt的hello world都要半分钟,所以为了方便以后的开发调试,尝试在ubuntu 12.04下搭建开发环境. 注意,如果你 ...
最新文章
- 从原理上搞懂如何设置线程池参数大小?
- NPOI 导出 excel 性能测试
- [Leedcode][JAVA][第69题][x的平方根][二分查找][数学]
- python3.7怎么安装turtle_python3绘图程序教学:载入和查询Turtle模组(一)
- java.rmi.ConnectException: Connection refused to host:
- 萌新接触前端的第三课——JavaScript
- Report Builder:SRW包
- 漏洞编号 cve can bugtraq cncve cnvd cnnvd 简介
- powerdesigner16 license key过期问题
- Java 五子棋 包含强大人机 步骤流程 包含源码
- 面对境外网络攻击,作为安全技术人员该如何有效防御?
- 大聪明教你学Java | 实现邮件发送(以163邮箱向QQ邮箱发送邮件为例)
- 视频剪辑自学怎么入门?借助这款软件可以达到意想不到的效果
- 14、守护线程(thread.setDaemon(true))
- 3万字干货HTML+CSS入门指南(建议收藏)
- Kafka工作原理-数据写入、ACK、查询、消费原理
- MATLAB读取中文txt
- 阿里云国际站:阿里云发布云数据中心专用处理器
- 【效率特工队】如何在很多张JPG图片中,批量获取所有JPG图片的名称提取到Excel表格,用这个方法一并解决
- python分配buffer_Python3 Buffered I/O浅析
热门文章
- mpi tcp连接报错_关于WinCC与真实PLC之间的TCP/IP连接问题-工业支持中心-西门子中国...
- matlab 第二类边界条件,第二类边界条件.ppt
- 清华计算机考研笔记,[考研天地]清华计算机,电子,自动化全套考研资料
- html 常见hack,针对主流浏览器的CSS-HACK写法及IE常用条件注释
- android 置顶窗口位置,Android 滑动悬浮置顶指南
- php柱状图html代码,html5生成柱状图(条形图)效果的实例代码
- 11旋转编码器原理_旋转编码器的原理是什么?增量式编码器和绝对式编码器有什么区别?...
- python中module的意思_python中module的意思
- mean项目的分模块开发
- Redis与Memocache的区别