Rust embedded. Stopwatch.
Rust embedded. Spi и embedded-graphics.
Rust embedded. Gpio.
Rust embedded. Сиквел.
Rust embedded.
Rust – это язык системного программирования, предназначенный для обеспечения безопасности, скорости и параллелизма. Rust имеет множество функций времени и безопасности во время компиляции, чтобы избежать сбоев данных и общих ошибок, все с минимальными издержками до нуля. Язык сфокусирован на безопасной работе с памятью, обеспечивает автоматическое управление памятью и предоставляет средства для достижения высокого параллелизма выполнения заданий, при этом обходясь без использования сборщика мусора и runtime. Автоматическое управление памятью в Rust избавляет разработчика от манипулирования указателями и защищает от проблем, возникающих из-за низкоуровневой работы с памятью, таких как обращение к области памяти после её освобождения, разыменование нулевых указателей, выход за границы буфера и т.п. Для распространения библиотек, обеспечения сборки и управления зависимостями проектом развивается пакетный менеджер Cargo, позволяющий получить нужные для программы библиотеки в один клик.
Rustup – установщик Rust и инструмент для управления версиями. Основным способом установки Rust, который используют разработчики, является Rustup – инструмент для установки и управления версиями Rust. Для загрузки Rustup и установки Rust на Linux, запустите следующее в вашем терминале и следуйте инструкциям (у меня Linux).
curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
Cargo: Менеджер пакетов и инструмент сборки для Rust. При установке через Rustup, вы получаете последнюю стабильную версию пакетного менеджера и средства сборки Rust, известного, как Cargo. Cargo делает многие вещи:
- собирает ваш проект с cargo build
- запускает ваш проект с cargo run
- тестирует ваш проект с cargo test
- собирает документацию для вашего проекта с cargo doc
- публикует библиотеку на crates.io с cargo publish
Чтобы удостовериться, что Rust и Cargo установлены, вы можете запустить в терминале следующую команду: - cargo –version
Cargo – это инструмент, который позволяет указывать необходимые зависимости для проектов на языке Rust и убедиться, что вы получите воспроизводимые сборки.
Для достижения этих целей, Cargo выполняет следующие действия:
- Создает два файла с некоторой необходимой информацией о проекте.
- Получает и собирает зависимости вашего проекта.
- Запускает
rustcили другие инструменты сборки со всеми необходимыми параметрами для правильной сборки вашего проекта. - Предоставляет все необходимые условия, чтобы работа с проектами на Rust стала проще.
Для тех у кого zsh, добавьте следующие строки в файл zshrc.
gedit ~/.zshrc export PATH="$HOME/.cargo/bin:$PATH"
Для программирования на Rust хороший редактор VS Code.
Определите платформу кросс-компиляции для необходимого аппратного обеспечения.
- Использовать thumbv6m-none-eabi для ARM Cortex-M0 and Cortex-M0+
- Использовать thumbv7m-none-eabi для ARM Cortex-M3
- Использовать thumbv7em-none-eabi для ARM Cortex-M4 и Cortex-M7 (без FPU )
- Использовать thumbv7em-none-eabihf для ARM Cortex-M4F и Cortex-M7F (с FPU )
Установите компонент rust-std для вашей аппаратной платформы
$ rustup target add thumbv7em-none-eabihf
Минимально достаточный проект для Cortex M7 (у меня devkit stm32f746g-disco)
Rust экосистема для embedded микроконтроллеров.
Cargo.toml
Синтаксис TOML основан на парах ключ = “значение”, [разделах] и # комментариях. Этот файл называется манифестом и содержит в себе все метаданные, которые необходимы Cargo, чтобы скомпилировать ваш проект.
[package] name = "empty" version = "0.1.0" authors = ["Roman Shulenkov postmaster@mcu.by"] edition = "2018" [dependencies] cortex-m = "0.6.2" cortex-m-log="0.6.1" [dependencies.stm32f7] version = "0.10.0" features = ["stm32f7x6", "rt"] [dependencies.cortex-m-rt] version = "0.6.12" features = ["device"]
.cargo/config
В этом файле мы обозначаем цель компиляции (аппаратная платформа) , а так же флаги компиляции. Все конфигурационные файлы хранятся в TOML формате (как манифесты), в простом формате ключ-значение, которые хранятся внутри секций (таблиц), а потом будут объединены. Ключи для значений, которые указывают на определенную программу, могут быть в формате абсолютного пути, относительного, а также можно просто указать название программы. Абсолютные пути и название программ используются как есть. Относительные пути используются исходя из родительской директории, в которой расположена директория .cargo, в которой находится конфигурационный файл.
# Массив путей к локальным репозиториям, которые будут переопределены в качестве
# зависимостей. Для более подробной информации смотрите документ Specifying Dependencies.
paths = ["/path/to/override"]
[cargo-new]
# Настройки для имени/email, которые будут помещены в блок `authors` в новых Cargo.toml
# Если эти параметры не указаны, будут взяты параметры из конфигурации `git`. А, если и их нет
# запишутся `$USER` и `$EMAIL`.
name = "..."
email = "..."
# По умолчанию команда `cargo new` создан новый Git репозиторий. Это значение может быть
# изменено на `hg`, тогда будет создан Mercurial репозиторий, или `none`, чтобы отключить
# данный функционал.
vcs = "none"
# Для следующего раздела, $triple относится к любой возможной целевой платформой,
# не к строкову литералу "$triple", и будет применяться каждый раз, когда будет сборка
# для целевой платформы.
[target]
# Для сборок Cargo, для которых не указан параметр --target, будет использован компоновщик
# переданный в rustc (с помощью `-C linker=`). По умолчанию этот флаг не передан
# как параметр компилятора.
linker = ".."
[target.$triple]
# Этот раздел похож на раздел, который был описан выше, но тут указывается конкретная
# целевая платформа, которая будет скомпилирована.
linker = ".."
# пользовательские настройки будут переданы в компилятор, каждый раз когда будет $triple
# вызвана компиляция для целевой платформы.
# этот параметр переопределит build.rustflags, если он указан
rustflags = ["..", ".."]
# Настройки для реестра
[registry]
index = "..." # Ссылка для индекса реестра (по умолчанию - центральный репозиторий)
token = "..." # Ключ доступа (можно найти на сайте центрального репозитория)
[http]
proxy = "..." # HTTP прокси. Используется для HTTP запросов (по умолчанию не указан)
timeout = 60000 # Таймаут для каждого HTTP запроса, в миллисекундах
cainfo = "cert.pem" # Путь до ключа Центра Сертификации (опционально)
[build]
jobs = 1 # количество параллельно выполняемых заданий, по умолчанию -
# количество ЦП
rustc = "rustc" # компилятор rust
rustdoc = "rustdoc" # инструмент генерации документации
target = "triple" # build for the target triple
target-dir = "target" # путь к директории, в которой будет скомпилированный проект
rustflags = ["..", ".."] # настройки, которые будут переданы компилятору
[term]
verbose = false # предоставлять ли cargo развернутый вывод
color = 'auto' # предоставлять ли cargo цветной вывод
# Конфигурация сети
[net]
retry = 2 # сколько раз будет вызвана попытка повторной отправки сигнала
# Псевдонимы для команд Cargo. Первые 3 псевдонима встроены.
# Если вы хотите передать параметры в псевдоним, в которых есть пробелы, то используйте список.
[alias]
b = "build"
t = "test"
r = "run"
rr = "run --release"
space_example = ["run", "--release", "--", "\"command list\""]
[target.thumbv7em-none-eabihf] rustflags = ["-C", "link-arg=-Tlink.x"] [build] target = "thumbv7em-none-eabihf"
memory.x
Пакет cortex-m-rt требует от нас создать файл “memory.x” в корневом каталоге проекта. В нём указывается распределение адресного пространства микроконтроллера:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
.vscode/tasks.json
VS Code содержит понятие “сборки проекта”. Редактор можно настроить таким образом, чтобы сборка Rust-проекта происходила необходимым нам способом.
Добавьте task (задание) в файл tasks.json в директории .vscode в корне вашего проекта:
{
"version": "2.0.0",
"tasks": [
{
"label": "Cargo build",
"type": "shell",
"command": "cargo",
"args": ["build"],
"problemMatcher": [
"$rustc"
],
"group": "build"
},
{
"label": "Build binary",
"type": "shell",
"command": "arm-none-eabi-objcopy",
"args": [
"--output-target", "binary",
"./target/thumbv7em-none-eabihf/debug/empty",
"./target/thumbv7em-none-eabihf/debug/empty.bin"],
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
},
"dependsOn": "Cargo build"
}
]
}
.vscode/launch.json
В каталоге проекта создаётся папка .vscode, в которой создаётся файл с конфигурациями отладки launch.json.
{
"version": "0.2.0",
"cortex-debug.armToolchainPath": "/home/mcuby/Downloads/gcc-arm-none-eabi-8-2019-q3-update/bin",
"configurations": [
{
"name": "Debug empty",
"request": "launch",
"type": "cortex-debug",
"cwd": "${workspaceRoot}",
"executable": "${workspaceFolder}/target/thumbv7em-none-eabihf/debug/empty",
"svdFile": "${workspaceFolder}/STM32F7x6.svd",
"servertype": "openocd",
"configFiles": ["STM32F7x6.cfg"],
"preLaunchTask": "Build binary",
"preLaunchCommands": [
"monitor init",
"monitor reset init",
"monitor halt",
"monitor flash write_image erase ./target/thumbv7em-none-eabihf/build/empty.bin 0x08000000"
],
"postLaunchCommands": ["monitor reset halt"]
}
]
}
src/main.rs
Самая простая программа для микроконтроллера пустой цикл с nop.
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt as runtime;
extern crate stm32f7;
use core::panic::PanicInfo;
use cortex_m::asm;
#[no_mangle]
fn main() -> ! {
loop {
for _i in 0..100000 {
asm::nop()
}
}
}
#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}
С помощью cortex_m_log нам доступен механизм отладки. В пакете предусмотрены следующие пункты назначения для записи: Dummy – пункт назначения noop, который не выполняет запись. Полезный режим Itm – использует Cortex-M Itm для отправки вывода. Обратите внимание, что он доступен только на ARMv7-M и более новых версиях ядра Cortex, Semihosting – использует Cortex-M Semihosting для отправки вывода.
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt as runtime;
extern crate stm32f7;
use core::panic::PanicInfo;
use cortex_m::asm;
use cortex_m_log::{print, println, d_print, d_println};
use cortex_m_log::printer::Dummy;
#[no_mangle]
fn main() -> ! {
let mut log = Dummy::new();
println!(log, "Some print with newline!");
//Debug version of print that resolves into nothing in release mode
//Note that you must import print macro for it to work
d_print!(log, "Print stuff: {}", "stuff");
//Note that you must import println macro for it to work
d_println!(log, "Print stuff: {} and also newline", "stuff");
loop {
for _i in 0..1000000 {
asm::nop()
}
}
}
#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}
Необходимые пакеты для VS Code (все кроме C/C++).

Исходники демо проекта на https://github.com/mcuby/rust-embedded-example


