嵌入式Rust。使用STM32F103C8T6(Black Pill)调试板为Cortex-M3处理器开发

你好!我想向您介绍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);

    //   b12   .
    //  "crh"      .
    //   0-7,    "crl".
    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.3VGND引脚与板上的相应引脚相连。 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编程语言相关的其他内容的各种翻译。在这里,您可以找到几个聊天室的链接,以便提出问题并获得帮助,提交项目或与志趣相投的人聊天。

感谢您的关注!

All Articles