Rost eingebettet. Entwicklung für Cortex-M3-Prozessoren mit der Debug-Karte STM32F103C8T6 (Black Pill)

Hallo! Ich möchte Ihnen das Rust Embedded- Projekt vorstellen . Damit können wir die Programmiersprache Rust für die Entwicklung eingebetteter Plattformen (Embedded Linux / RTOS / Bare Metal) verwenden.


In diesem Artikel werden die Komponenten betrachtet, die erforderlich sind, um mit der Entwicklung von Cortex-M3-Mikroprozessoren zu beginnen. Danach schreiben wir ein einfaches Beispiel - das Blinken der eingebauten LED.

Dazu benötigen wir ein erschwingliches und billiges chinesisches Debug-Board STM32F103C8T6 oder Black Pill (aufgrund der schwarzen Farbe und der geringen Größe). Es gibt auch eine Version des Boards in blau - Blue Pill. Ich empfehle es nicht, da ich gehört habe, dass es den falschen Widerstand hat, was Probleme bei der Verwendung des USB-Anschlusses verursacht. Sein zweiter Unterschied zu Black Pill in der Anordnung der Stifte (Schlussfolgerungen). Aber dazu später mehr.

Wir benötigen auch einen Programmierer für STM32-Debug-Boards. In diesem Artikel verwenden wir den billigen und erschwinglichen chinesischen ST-Link V2-Programmierer.


Rust Compiler Version


Um zu beginnen, müssen Sie sicherstellen, dass Ihre Compilerversion 1.31 oder neuer ist. Sie können Ihre Compilerversion überprüfen, indem Sie den folgenden Befehl eingeben:

> rustc --version

Komponenteninstallation


Jetzt können wir mit der Installation der erforderlichen Komponenten beginnen.

GNU Arm Embedded Toolchain


Wir brauchen einen Debugger für ARM-Chips - arm-none-eabi-gdb. Starten Sie das Installationsprogramm und befolgen Sie die Anweisungen. Stellen Sie am Ende der Installation sicher, dass die Option " Pfad zur Umgebungsvariablen hinzufügen " aktiviert ist .

Download-Link

Nach der Installation können Sie überprüfen, ob alles in Ordnung ist, indem Sie in der Befehlszeile Folgendes eingeben:

> arm-none-eabi-gdb -v

Wenn alles in Ordnung ist, sehen Sie die Version der installierten Komponente.

ST-Link-Treiber


Fahren wir mit der Installation des Treibers für den ST-Link-Programmierer fort.

Befolgen Sie die Anweisungen des Installationsprogramms und stellen Sie sicher, dass Sie die richtige Version des Treibers ( 64-Bit oder 32-Bit ) installieren , abhängig von der Bittiefe Ihres Betriebssystems.

Link zum Download

ST-Link-Tools


Der nächste Schritt ist die Installation der für die Firmware erforderlichen Tools - ST-Link Tools. Laden Sie das Archiv herunter und entpacken Sie es an einen beliebigen Ort. Außerdem müssen Sie den Pfad zum Unterordner bin ( stlink-1.3.0 \ bin ) in der Umgebungsvariablen " PATH " angeben .

Link zum Download

Fracht-Binutils


Installieren Sie abschließend das Paket Cargo-Binutils. Dies erfolgt über zwei Befehle in der Konsole.

> cargo install cargo-binutils
> rustup component add llvm-tools-preview

Damit ist die Installation der Komponenten abgeschlossen.

Projekt erstellen und einrichten


Um fortzufahren, müssen wir ein neues Projekt mit dem Namen " stm32f103c8t6 " erstellen . Ich möchte Sie daran erinnern, dass dies durch den Befehl erfolgt:

> cargo new stm32f103c8t6

Projektabhängigkeiten und Optimierung


Verbinden Sie die erforderlichen Bibliotheken in der Datei 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 #  

Sie können auch sehen, dass am Ende der Datei die Codeoptimierung aktiviert wurde.

Für die cortex-m-rt-Bibliothek müssen wir eine Datei im Stammverzeichnis des Projekts erstellen . Sie muss " memory.x " heißen . Es zeigt an, wie viel Speicher unser Gerät hat und welche Adresse:

MEMORY
{
 FLASH : ORIGIN = 0x08000000, LENGTH = 64K
 RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

Festlegen der Zielplattform und der Standardkompilierungsziele


Die Zielplattform für den Compiler muss festgelegt werden. Dies erfolgt über den folgenden Befehl:

> rustup target add thumbv7m-none-eabi

Erstellen Sie anschließend den Ordner " .cargo " im Stammverzeichnis und die Datei " config " darin .

Der Inhalt der Konfigurationsdatei :

[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

Darin haben wir das Standard-Kompilierungsziel identifiziert. Dadurch können wir unseren Code mit einem einfachen und vertrauten Befehl in eine ARM .elf- Datei kompilieren :

> cargo build --release

Beispiel


Betrachten Sie das einfachste Beispiel, um sicherzustellen, dass es funktioniert - das Blinken einer LED.

Der Inhalt der Datei 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();
    }
}

In der ersten Zeile #![deny(unsafe_code)]entfernen wir mit dem Attribut - die Möglichkeit, unsicheren Code zu verwenden.

In der zweiten Zeile haben wir das Attribut platziert #![no_std], es ist erforderlich, da wir eine Anwendung für Bare Iron erstellen und die Standardbibliothek ein Betriebssystem benötigt.

Als nächstes folgt ein Attribut #![no_main], das dem Compiler mitteilt, dass wir die Standardstandardfunktion mit dem Argumentvektor und dem Rückgabetyp nicht verwenden. Dies ist nicht sinnvoll, da wir kein Betriebssystem oder keine andere Laufzeit haben, die die Funktion aufruft und den Rückgabewert verarbeitet.

Nach den Attributen fügen wir die erforderlichen Module in den Bereich ein.

Darauf folgt eine Funktion, in unserem Fall aus Gewohnheit, die wir sie nannten -main(). Dies ist der Einstiegspunkt in das Programm, er wird durch das Attribut bestimmt #[entry].

Innerhalb der Hauptfunktion erstellen wir ein Handle für ein Peripherieobjekt, das alle Peripheriegeräte „besitzt“.

Danach können wir den Pin, der für die in die Platine eingebaute LED verantwortlich ist, auf den Ausgang setzen. Da es sich in meinem Fall um eine Black Pill- Karte handelt , ist die LED darin mit Pin B12 verbunden . Wenn Sie eine Blue Pill- Karte haben , ist Pin C13 für die eingebaute LED verantwortlich . Daher setzen wir Pin B12 als Push-Pull-Ausgang und weisen ihn einer Variablen zu led.

Jetzt können wir die Auslösezeit für das Aktualisierungsereignis für den Systemzeitgeber festlegen und in einer Variablen speicherntimer. In unserem Beispiel beträgt diese Zeit eine Sekunde.

Dann können wir in einer Endlosschleife die Logik unseres Programms beschreiben. Es ist sehr einfach, zunächst timerdie Ausführung des Programms zu blockieren, bis die darin angegebene Zeit abgelaufen ist. Der nächste Schritt besteht darin, den Pin der eingebauten LED auf High zu setzen , damit sie aufleuchtet. Danach wird die Programmausführung erneut für eine Sekunde von demselben Timer blockiert. Und der Pin der LED ist auf niedrig gesetzt , daher geht er aus. Ferner wird das Programm zyklisch wiederholt.

Zusammenstellung


Nachdem wir den Programmcode und die Logik herausgefunden haben, können wir ihn mit dem folgenden Befehl in eine .elf- Datei kompilieren :

> cargo build --release

Dieses Format enthält nicht nur Binärcode, sondern auch einige Header und mehr. Dies ist nützlich, wenn die Datei von einer anderen Software wie dem Betriebssystem oder dem Bootloader gestartet wird. Um

das Programm auf Bare Metal auszuführen , benötigen wir jedoch keine .elf- Datei , sondern eine .bin- Datei . Eine .bin- Datei ist ein Software-Image, das byteweise in den Speicher des Mikrocontrollers geschrieben werden kann. Die .elf- Datei kann mit dem folgenden Befehl in eine .bin- Datei konvertiert werden :

> cargo objcopy --bin stm32f103c8t6 --target thumbv7m-none-eabi --release -- -O binary stm32f103c8t6.bin

Jetzt ist unsere Binärdatei bereit für die Firmware.

Verbindung


Wir werden die Karte mit dem ST-Link V2-Programmierer flashen. Dazu müssen Sie es zuerst an die Karte anschließen.

Auf dem Programmiergehäuse befindet sich eine Stiftanordnung des Steckers. Sie müssen auf die Aussparung im Anschluss achten. Sie wird auch im Diagramm angezeigt, damit Sie verstehen, wie die Verbindung hergestellt wird.

Verbinden Sie die 3,3 V- und GND- Pins des Programmiergeräts mit den entsprechenden Pins auf der Platine. Ping- SWDIO- Verbindung zum Pin des DIO und Pin- SWCLK zum Pin des CLK .

Nachdem wir die Karte an den Programmierer angeschlossen haben, können wir den ST-Link an den Computer anschließen.

Beachtung!Trennen Sie vor dem Anschließen alle anderen Stromquellen von der Karte, falls vorhanden, da dies sonst die Karte oder den Computer beschädigen kann.

Jetzt können wir die Verbindung überprüfen:

> st-info --descr

In der Konsole sollte die Zeile " F1 Gerät mittlerer Dichte " angezeigt werden .

Firmware


Optional können Sie vor dem Flashen den Speicher der Karte löschen, wenn etwas darauf geschrieben ist:

> st-flash erase

Endlich können wir die Firmware starten:

> st-flash write stm32f1.bin 0x8000000

Wenn alles richtig gemacht wurde, sollte eine blinkende LED angezeigt werden. Herzliche Glückwünsche!

Fazit


Um die Karte zu flashen, müssen Sie diesen Befehlssatz verwenden, der nacheinander eingegeben wird:

> 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

Um unser Leben zu vereinfachen, können wir mit diesen Befehlen eine .bat- Datei erstellen und von der Konsole aus ausführen.

Vom Autor


Wenn Sie an diesen Anleitungen interessiert sind, begrüßen Sie auf meinem YouTube-Kanal .
Außerdem habe ich kürzlich einen Telegrammkanal gestartet , in dem ich verschiedene Übersetzungen von Handbüchern und Büchern, Nachrichten, Humor und anderen Dingen im Zusammenhang mit der Programmiersprache Rust veröffentliche. Dort finden Sie Links zu mehreren Chatrooms, um Ihre Fragen zu stellen und Hilfe zu erhalten, Ihre Projekte einzureichen oder einfach mit Gleichgesinnten zu chatten.

Vielen Dank für Ihre Aufmerksamkeit!

All Articles