Skip to content

rust-使用rust來開發ARM嵌入式裝置

發布於: at 上午12:00

分享該文章至:

所需部分

建立專案

1 初始化

  1. 模板建立
    $ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
    🤷   Project Name: f103c8t6_p1
    🔧   Destination: /home/user/文件/rust/f103c8t6_p1 ...
    🔧   project-name: f103c8t6_p1 ...
    🔧   Generating template ...
    🔧   Moving generated files into: `/home/user/文件/rust/f103c8t6_p1`...
    🔧   Initializing a fresh Git repository
       Done! New project created /home/user/文件/rust/f103c8t6_p1
    
  2. 建立完成到目錄
    $ cd f103c8t6_p1
    
  3. 加入一些必要功能
    • 安裝工具
      $ cargo add rtt-target critical-section defmt-rtt
      
    • 修改cargo.toml
      [dependencies]
      cortex-m = {version="*",features = ["critical-section-single-core"]} # Access to the generic ARM peripherals
      

2 硬體配置

[package]
authors = ["neko0xff <neko_0xff@protonmail.com>"]
edition = "2021"
readme = "README.md"
name = "f103c8t6_p1"
version = "0.1.0"

[dependencies]
cortex-m = {version="*",features = ["critical-section-single-core"]} # Access to the generic ARM peripherals
cortex-m-rt = "*"               # Startup code for the ARM Core
cortex-m-semihosting = "*"
embedded-hal = "*"              # Access to generic embedded functions (`set_high`)
panic-halt = "*"                # Panic handler
nb = "*"
debouncr = "*"
rtt-target = "*"
critical-section = "*"
defmt-rtt = "*"

[dependencies.stm32f1xx-hal]
version = "*"
features = ["rt", "stm32f103", "medium"]

# this lets you use `cargo fix`!
[[bin]]
name = "f103c8t6_p1"
test = false
bench = false

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations

編寫程式

當所有環境和配置都完成後,就可開始撰寫主程式

主程式

#![deny(unsafe_code)]
#![no_std]
#![no_main]

use core::fmt::Write;
use panic_halt as _;
use nb::block;
use cortex_m::asm::nop;
use cortex_m_rt::entry;
use stm32f1xx_hal::{
    pac,
    prelude::*,
    timer::Timer,
    serial::{Config, Serial},
};
use rtt_target::{rprintln, rtt_init_print};


#[entry]
fn main() -> ! {
    // Get access to the core peripherals from the cortex-m crate
    let cp = cortex_m::Peripherals::take().unwrap();
    // Get access to the device specific peripherals from the peripheral access crate
    let dp = pac::Peripherals::take().unwrap();

    // Take ownership over the raw flash and rcc devices and convert them into the corresponding
    // HAL structs
    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();

    // Freeze the configuration of all the clocks in the system and store the frozen frequencies in `clocks`
    let clocks = rcc.cfgr.freeze(&mut flash.acr);
    // Configure the syst timer to trigger an update every second
    let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();
    timer.start(10.Hz()).unwrap();

    // Acquire the GPIOC peripheral
    let mut gpioa = dp.GPIOA.split();
    let mut gpioc = dp.GPIOC.split();
    let mut afio = dp.AFIO.constrain();

    // Configure gpio C pin 13 & 14 & 15 as a push-pull output.
    // The `crh` register is passed to the function in order to configure the port.
    // For pins 0-7, crl should be passed instead.
    let mut led1 = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
    let mut led2 = gpioc.pc14.into_push_pull_output(&mut gpioc.crh);
    let mut led3 = gpioc.pc15.into_push_pull_output(&mut gpioc.crh);

    // USART1 on Pins A9 and A10
    let pin_tx1 = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh);
    let pin_rx1 = gpioa.pa10;
    // Create an interface struct for USART1 with 9600 Baud
    let serial1 = Serial::new(
        dp.USART1,
        (pin_tx1, pin_rx1),
        &mut afio.mapr,
        Config::default()
            .baudrate(9600.bps())
            .parity_none(),
        &clocks,
    );
    let (mut tx1, mut _rx1) = serial1.split(); // Separate into tx and rx channels

    rtt_init_print!();
    rprintln!("RTT Service is String....");
    tx1.write_str("\nUART1 is String....\n").unwrap();
    loop {
        block!(timer.wait()).unwrap();
        rprintln!("Echo ....");
        tx1.write_str("Echo ....\n").unwrap();
        for _ in 0..100_000 {
            nop();
        }
        led1.toggle();
        led2.toggle();
        led3.toggle();
        tx1.write(b'S').unwrap();
        tx1.write(b'\n').unwrap();
    }
}

編譯

當我們寫完功能需要進行除錯時,則需要進行編譯成該顆MCU支援的二進制檔案。

$ cargo build

則編譯完成的結果會直接輸出至f103c8t6_p2/target/thumbv7m-none-eabi/debug/

刷寫編譯完成的軔體

方案1: OpenOCD

方案2: cargo embed

  1. 手動刷寫: $ cargo embed --chip stm32f103c8

  2. 使用設置檔來刷寫

    • 新增Embed.toml

        [default.general]
        chip = "STM32F103C8"
      
        [default.rtt]
        enabled = true
      
        [default.gdb]
        enabled = false
      
    • 開始刷寫: $cargo embed

REF

中文

英文