你好!我想向您介绍Rust Embedded项目。它允许我们使用Rust编程语言进行嵌入式平台(嵌入式Linux / RTOS / Bare Metal)的开发。
在本文中,我们将考虑开始开发Cortex-M3微处理器所需的组件。之后,我们将编写一个简单的示例-内置LED闪烁。为此,我们需要价格合理且便宜的中文调试板STM32F103C8T6或Black Pill(由于黑色和小尺寸)。还有一个蓝色的董事会版本-Blue Pill。我不建议这样做,因为我听说它的电阻器错误,这会在使用USB端口时引起问题。它与Black Pill的第二个区别是引脚排列(结论)。但是稍后会更多。我们还将需要一个用于STM32调试板的程序员。在本文中,我们将使用价格低廉的中文ST-Link V2编程器。
Rust编译器版本
首先,您需要确保编译器版本为1.31或更高版本。您可以通过输入以下命令来检查编译器版本:> rustc --version
组件安装
现在我们可以开始安装必要的组件。GNU Arm嵌入式工具链
我们将需要用于ARM芯片的调试器-arm-none-eabi-gdb。启动安装程序,然后按照说明进行操作。在安装结束时,请确保选中“ 将路径添加到环境变量 ” 选项。下载链接安装后,您可以通过在命令行中输入以下内容来检查是否一切正常:> arm-none-eabi-gdb -v
如果一切正常,那么您将看到已安装组件的版本。ST-Link驱动程序
让我们继续为ST-Link编程器安装驱动程序。按照安装程序的说明进行操作,并确保安装正确的驱动程序版本(六十四位或三十二位),具体取决于操作系统的位深度。链接下载ST-Link工具
下一步是安装固件所需的工具-ST-Link Tools。下载档案并将其解压缩到任何方便的位置,您还需要在环境变量“ PATH ”中指定bin子文件夹(stlink-1.3.0 \ bin)的路径。链接下载货仓
最后,安装软件包cargo-binutils,这是通过控制台中的两个命令完成的。> cargo install cargo-binutils
> rustup component add llvm-tools-preview
这样就完成了组件的安装。创建和设置项目
要继续,我们需要创建一个名为“ stm32f103c8t6 ” 的新项目。让我提醒您,这是通过以下命令完成的:> cargo new stm32f103c8t6
项目依赖性和优化
在Cargo.toml文件中连接必要的库:[package]
name = "stm32f103c8t6"
version = "0.1.0"
authors = ["Nick"]
edition = "2018"
# Cortex-M3
[dependencies]
cortex-m = "*"
cortex-m-rt = "*"
cortex-m-semihosting = "*"
panic-halt = "*"
nb = "0.1.2"
embedded-hal = "0.2.3"
# stm32f1
[dependencies.stm32f1xx-hal]
version = "0.5.2"
features = ["stm32f100", "rt"]
# `cargo fix`!
[[bin]]
name = "stm32f103c8t6"
test = false
bench = false
#
[profile.release]
codegen-units = 1 #
debug = true # , Flash
lto = true #
此外,您可以看到在文件末尾,已启用代码优化。cortex-m-rt库要求我们在项目的根目录中创建一个文件,该文件必须称为“ memory.x ”。它指示我们的设备有多少内存及其地址:MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}
设置目标平台和默认编译目标
必须为编译器设置目标平台,这是通过以下命令完成的:> rustup target add thumbv7m-none-eabi
之后,在根目录中创建“ .cargo ” 文件夹,并在其中创建“ config ” 文件。配置文件的内容:[target.thumbv7m-none-eabi]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = ["-C", "link-arg=-Tlink.x"]
[build]
target = "thumbv7m-none-eabi" # Cortex-M3
在其中,我们确定了默认的编译目标,这使我们可以使用简单且熟悉的命令将代码编译为ARM .elf文件:> cargo build --release
例
为确保其正常工作,请考虑最简单的示例-使LED闪烁。main.rs文件的内容:#![deny(unsafe_code)]
#![no_std]
#![no_main]
use panic_halt as _;
use nb::block;
use stm32f1xx_hal::{
prelude::*,
pac,
timer::Timer,
};
use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
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, &clocks)
.start_count_down(1.hz());
loop {
block!(timer.wait()).unwrap();
led.set_high().unwrap();
block!(timer.wait()).unwrap();
led.set_low().unwrap();
}
}
在第一行中,使用-属性#![deny(unsafe_code)]
,我们消除了使用不安全代码的可能性。在第二行中,我们放置了属性#![no_std]
,这是必需的,因为我们正在为裸机创建应用程序,并且标准库需要一个操作系统。接下来是一个属性#![no_main]
,该属性告诉编译器我们没有使用带有参数vector和return type的默认默认函数。这没有任何意义,因为我们没有操作系统或其他运行时来调用函数并处理返回值。在属性之后,我们将必要的模块插入范围。接下来是一个函数,在我们的案例中,出于习惯,我们称其为-main()
。这是程序的入口,由属性确定#[entry]
。在main函数内部,我们为“拥有”所有外围设备的外围对象创建一个句柄。之后,我们可以将负责板上内置LED的引脚设置为输出。由于我的情况是黑色药丸板,因此其中的LED连接到引脚B12。如果您有蓝色药丸板,则引脚C13负责内置LED 。因此,我们将引脚B12设置为推挽输出并将其分配给变量led
。现在我们可以为系统计时器设置更新事件触发时间,并将其保存在变量中timer
。在我们的示例中,这个时间是一秒钟。然后,在一个无穷循环中,我们可以描述程序的逻辑。这很简单,首先timer
阻止程序执行,直到经过指定的时间为止。下一步是将内置LED的引脚设置为high,使其点亮。之后,该程序的执行再次被同一计时器阻塞一秒钟。并且LED的引脚设置为低电平,因此熄灭。此外,该程序被循环重复。汇编
现在我们已经弄清了程序代码和逻辑,我们可以使用以下命令将其编译成一个.elf文件:> cargo build --release
此格式不仅包含二进制代码,还包含一些标头和更多内容。当文件由其他软件(例如操作系统或引导程序)启动时,此功能很有用。但是,要在裸机上运行程序,我们不需要.elf文件,而需要.bin文件。.bin文件是一种软件映像,可以按字节写入微控制器的内存。可以使用以下命令将.elf文件转换为.bin文件:> cargo objcopy --bin stm32f103c8t6 --target thumbv7m-none-eabi --release -- -O binary stm32f103c8t6.bin
现在,我们的二进制文件已准备好用于固件。连接
我们将使用ST-Link V2编程器对开发板进行刷新。为此,您必须首先将其连接到板上。在编程器外壳上,有一个插针连接器。您需要注意连接器中的切口,该切口也显示在图表上,以使您了解如何进行连接。将编程器的3.3V和GND引脚与板上的相应引脚相连。 Ping SWDIO连接到DIO引脚,SWCLK引脚连接到CLK。将开发板连接到编程器后,我们可以将ST-Link连接到计算机。注意!连接之前,请从板上断开所有其他电源的连接,如果有的话,否则可能会损坏板或计算机。现在我们可以检查连接:> st-info --descr
在控制台中,我们应该看到“ F1中密度设备 ”行。固件
(可选)在闪烁之前,如果上面有东西,您可以清除板子的内存:> st-flash erase
最后,我们可以启动固件:> st-flash write stm32f1.bin 0x8000000
如果一切操作正确,您应该会看到一个闪烁的LED。恭喜你!结论
因此,要刷新该板,必须使用顺序输入的以下命令集:> cargo build --release
> cargo objcopy --bin stm32f103c8t6 --target thumbv7m-none-eabi --release -- -O binary stm32f103c8t6.bin
> st-flash erase
> st-flash write stm32f1.bin 0x8000000
为了简化我们的生活,我们可以使用这些命令创建一个.bat文件,然后从控制台运行它。来自作者
如果您对这些指南感兴趣,欢迎访问我的YouTube频道。另外,最近,我开通了Telegram频道,在其中发布手册和书籍,新闻,幽默以及与Rust编程语言相关的其他内容的各种翻译。在这里,您可以找到几个聊天室的链接,以便提出问题并获得帮助,提交项目或与志趣相投的人聊天。感谢您的关注!