RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板

配置开发环境

这里以 Ubuntu 18.04 作为宿主环境,其它 Linux 发行版类似。Windows 环境待更新。

安装标准 Rust 编译器

wget https://cdn.jsdelivr.net/gh/rust-lang-nursery/rustup.rs/rustup-init.sh
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
sh rustup-init.sh

按默认选项安装即可,安装完成后检查 Rust 编译器:

source $HOME/.cargo/env
rustc -V

如果能打印出类似rustc 1.48.0 (7eac88abb 2020-11-16)的版本信息,说明安装成功了。

source $HOME/.cargo/env 将 rustc 所在的目录加入到 PATH 环境变量,系统重启后会自动添加,不需要再执行这条命令。

RUSTUP_DIST_SERVERRUSTUP_UPDATE_ROOT 这两个环境变量的设置可以放到 .profile 文件内,这样不用每次使用 rustup 都重新设置环境变量。

echo "export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static" >> ~/.profile
echo "export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup" >> ~/.profile

按照官方的文档是这么安装 Rust 的:$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh,不过 sh.rustup.rs 是国外网站,速度很慢,而且经常超时,这里使用国内镜像安装。

安装 RISC-V 后端

为了让 Rust 编译器产生 RISC-V 的指令集,必须安装 RISC-V 编译器后端。

查看 Rust 支持的后端:

rustup target list

可以看到 Rust 支持很多后端,RISC-V 的后端有:

riscv32gc-unknown-linux-gnu
riscv32i-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imc-unknown-none-elf
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-none-elf
riscv64imac-unknown-none-elf

我们需要安装 riscv32imac-unknown-none-elf 后端:

rustup target add riscv32imac-unknown-none-elf

安装 GDB 调试器

下载 riscv-none-embed-gcc ,要用里面的 riscv-none-embed-gdb 作为调试器。

下载 tgz 类型的文件,解压,然后将 /path/to/gnu-mcu-eclipse/riscv-none-gcc/x.y.z-xxx/bin 添加到 PATH 路径。

gdb-multiarch 目前似乎不支持 RISC-V。

安装其它所需工具

cargo install cargo-binutils
rustup component add llvm-tools-preview
sudo apt install pkg-config libssl-dev
cargo install cargo-generate
  • cargo-binutils 提供 objdump、nm、size 等二进制工具。
  • pkg-config libssl-dev 是安装 cargo-generate 所需要的,如果没有 pkg-config 会导致 run pkg_config fail 错误,如果没有 libssl-dev 会导致 Package openssl was not found in the pkg-config search path 错误。
  • cargo-generate 按照模板来创建工程,如果不想安装可以用 git 代替。
  • Cargo 是 Rust 的构建系统和软件包管理器。
  • Rustup 是 Rust 的工具链安装和管理工具。

第一个 Rust 工程

创建工程

cargo generate --git  https://github.com/riscv-rust/riscv-rust-quickstart

通过模板创建工程,根据提示输入工程名称,这里假设输入 app。进入新建的工程目录:

cd app

编译工程

cargo build

新建工程第一次构建,cargo 会自动下载依赖包,然后开始编译程序及依赖包。默认构建 debug 版本,编译好的程序:/path/to/app/target/riscv32imac-unknown-none-elf/debug/app

构建 release 版本:

cargo build --release

release 版本的程序:/path/to/app/target/riscv32imac-unknown-none-elf/release/app

检查编译好的程序

检查文件头:

cargo readobj --bin app -- -file-headers
cargo readobj --bin app --release -- -file-headers

检查程序大小:

cargo size --bin app
cargo size --bin app --release

反汇编程序:

cargo objdump --bin app -- -d
cargo objdump --bin app --release -- -d

在 Renode 模拟器中执行

安装 Renode 模拟器

下载 Renode Linux portable 版本,这是个免安装版,解压后即可使用。

解压:

mkdir renode_portable
tar xf  renode-*.linux-portable.tar.gz -C renode_portable --strip-components=1

将 renode 目录添加到 PATH 环境变量。

参考 Renode - Installation - Using the Linux portable release。

Renode 是开源的模拟器,可以模拟 Cortex-M、RISC-V 等微控制器,不仅可以模拟 CPU 指令,还可以模拟外设,甚至可以模拟板载的外设。它与 QEMU 的关注点不同,QEMU 主要用来模拟标准化的高性能 PC,Renode 主要来用模拟物联网设备,Renode 可以同时模拟多个设备,而且这些设备可以互联互通。这里将用 Renode 模拟 HiFive1 开发板。

准备 Renode 脚本

:name: HiFive1

$name?="HiFive1"

using sysbus
mach create $name
machine LoadPlatformDescription @platforms/cpus/sifive-fe310.repl
machine StartGdbServer 3333

showAnalyzer uart0

sysbus Tag <0x10008000 4> "PRCI_HFROSCCFG" 0xFFFFFFFF
sysbus Tag <0x10008004 4> "PRCI_HFXOSCCFG" 0xFFFFFFFF
sysbus Tag <0x10008008 4> "PRCI_PLLCFG" 0xFFFFFFFF

cpu PC 0x20010000
cpu PerformanceInMips 320

将上述内容保存到文件 hifive1.resc。

上述文件根据 renode 安装目录下 /path/to/renode/scripts/single-node/sifive_fe310.resc 修改。

启动 Renode 模拟器

renode

启动Renode模拟器,Renode 启动后会开启新的命令窗口用作 Renode 命令输入,原来的命令行窗口作为 Renode 的日志输出窗口使用。下图所示的窗口是 Renode 命令窗口,在该窗口输入 Renode 命令。

RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板_第1张图片
执行 Renode 脚本:

(monitor) i @/path/to/hifive1.resc

请根据 hifive1.resc 的存储路径修改上面的命令。

执行了这个命令后,还会弹出一个 HiFive1:sysbus.uart0 窗口,这个是串口数据监视窗口,暂时不去理会它。

用 GDB 调试程序

启动 GDB 调试器:

riscv-none-embed-gdb /path/to/app/target/riscv32imac-unknown-none-elf/release/app

GDB 连接到 Renode 模拟器,Renode 通过 machine StartGdbServer 3333 开启了 GDB Server,监听端口 3333 :

(gdb) target remote :3333

装载程序:

(gdb) load

设置断点:

(gdb) b main

运行程序:

(gdb) monitor start
(gdb) c

monitor start 指令是传达给 Renode 的,告知 Renode 可以开始执行了。

接下来,该怎么调试就怎么调试了。

调试完成后,在 Renode 控制窗口输入 quit 推出模拟器:

(monitor) quit

集成开发环境

推荐使用 Eclipse IDE for Rust Developers,原因有二:一是 Eclipse 几乎是嵌入式开发领域的事实标准,国内国外的半导体厂商以及开发工具厂商推出的嵌入式开发工具几乎都是基于 Eclipse 平台,甚至有些厂商废弃原来自有平台转向 Eclipse 平台。二是 Eclipse 的调试功能比较完备,支持各种类型的断点、反汇编、指令单步、函数调用栈、局部变量、全局变量、处理器寄存器、外设寄存器等等。

除了 Eclipse 外,更多的开发工具见 Rust Tools。

安装 Eclipse

安装 RLS

首先安装 RLS(Rust 语言服务器),Eclipse 需要这个:

rustup component add rls rust-analysis rust-src

RLS 提供了一个在后台运行的服务器,提供了Rust编程的相关信息,包括IDE,编辑器和其它工具。参考 Rust 语言服务器 (RLS) ,Rust Language Server (RLS)。如果没有安装 RLS,打开 Eclipse 会报告 Rust Support Not Found 错误。

下载 Eclipse

前往 Eclipse 下载中心 下载 Eclipse IDE for Rust Developers。

解压 Eclipse

tar -xf /path/to/eclipse-rust-2020-09-R-linux-gtk-x86_64.tar.gz

安装 Eclipse Embedded C/C++ 插件

解压后打开 eclipse:

cd eclipse
./eclipse

选择菜单 Help >> Eclipse Marketplace … 打开应用市场,搜索安装 Eclipse Embedded C/C++ 插件,后面的调试需要用到这个插件。

打开工程

选择菜单 File >> Open Projects form File System … 打开 Import Projects from File System or Archive 对话框,Import source 填入前面用 cargo generate 创建的app工程目录,点击 Finish 打开工程。

构建工程

Eclipse 2020-09 还 不支持 通过菜单 Project >> Build Project 构建工程,因此还是只能在命令行中用 cargo 命令来构建。

可以在 Eclipse 中打开 Terminal 视图,在 Terminal 视图输入 cargo 命令,这样不需要来回切换窗口。

选择菜单 Window >> Show View >> Others … ,找到 Terminal 打开视图。点击 Terminal 工具栏最左边的按钮启动一个终端:
RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板_第2张图片

选择 Local Terminal 。然后就可以在新建的终端内输入 cargo 命令。

调试程序

启动 Renode 模拟器

首先启动 Renode 模拟器,假如还没有启动的话:

renode -e "i @/path/to/hifive1.resc" --hide-analyzers

这次直接在 renode 命令行就指定了要在 (monitor) 输入的命令 i @/path/to/hifive1.resc--hide-analyzers 将隐藏串口输出窗口,现在暂时用不到。

在 Eclipse 中创建调试配置

选择菜单 Run >> Debug Configurations … 打开调试配置对话框。左边类型栏选择 GDB Hardware Debugging,点击右键弹出菜单选择 New Configuration。

Main 选项页,Project 填入工程名,C/C++ Application 填入要调试的程序,即 cargo build 生成的程序。

RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板_第3张图片

Debugger 选项页,GDB Command 填入 riscv-none-embed-gdb,JTAG Device 选择 Generic TCP/IP,GDB Connection String 填入 localhost:3333

RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板_第4张图片

Startup 选项页,勾上 Set breakpoint at,后面输入框填入 main,下方输入框填入 monitor start,如果不希望停在 _start 的位置,勾上Resume。

RISC-V 嵌入式 Rust 快速入门,基于 Renode 模拟器和 HiFive1 开发板_第5张图片

完成配置后,点击 Debug 按钮进入调试模式。

在 HiFive1 开发板中运行

在 Renode 模拟器中运行时,GDB 连接到模拟器开启的 GDB Server,在 HiFive1 开发板中运行时,GDB 连接到 OpenOCD 开启的 GDB Server。OpenOCD 通过 JTAG 和物理上的处理器进行交互。

安装 OpenOCD

这里下载 OpenOCD。

解压:

tar -xf /path/to/xpack-openocd-0.10.0-15-linux-x64.tar.gz

将 openocd 所在目录加入 PATH 环境变量。

拷贝 openocd.rules 文件到系统目录:

sudo cp xpack-openocd-0.10.0-15/contrib/60-openocd.rules /etc/udev/rules.d/

重启系统,让 openocd-rules 生效。

OpenOCD 连接开发板

将 HiFive1 开发板通过数据线连接到计算机。

打开 OpenOCD :

openocd -f board/sifive-hifive1.cfg

调整调试配置

调整调试配置 Debugger 选项页的 GDB Connection String,OpenOCD 默认端口为 3333。

Startup 选项页删除 monitor start

调整好了之后,点击 Debug 按钮开始调试。

其它示例

通过 riscv-rust-quickstart 模板创建的工程,在 examples 目录下包含了多个示例程序,其中就有闪灯的 led_gpio 示例、串口打印的 hello_world 示例等。 以 hello_world 示例为例。

构建示例

构建 hello_world 示例:

cargo build --example hello_world

启动 Renode 模拟器

renode -e "i @/path/to/hifive1.resc"

创建调试配置项

创建 Eclipse 调试配置项,Main 选项页的 C/C++ Application 填入刚生成的 hello_world:/path/to/app/target/riscv32imac-unknown-none-elf/debug/examples/hello_world,其它选项与之前的一样。

编译好的示例程序位于 target/riscv32imac-unknown-none-elf/debug/examples 目录下。发布版位于 target/riscv32imac-unknown-none-elf/release/examples 目录下

开始调试

配置完成后点击 Debug 开始调试。执行到 sprintln!("hello world!"); 这一句可以看到 HiFive1:sysbus.uart0 串口打印出了字符串 hello world!

闪灯的示例在模拟器里执行看不到 LED 灯,按照 在 HiFive1 开发板中执行 跑在 HiFive1 开发板就可以看到 LED 闪烁了。

Eclipse 调试 leds_blink 会失去响应?调试 hello_world 和 led_gpio 这两个示例不会有这个问题。这是何故?

参考资料

  • 《Rust 程序设计语言》,英文原版《The Rust Programming Language》。
  • 《The Embedded Rust Book》
  • 《RISC-V手册:一本开源指令集的指南》。
  • GitHub: riscv-rust-quickstart
  • Renode - documentation

你可能感兴趣的:(嵌入式硬件,嵌入式软件,rust,risc-v)