Вграден софтуер
19 януари 2023
Административни неща
- Предложения за проекти се приемат до утре
Общи разсъждения за embedded software
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
- Скоростта зависи и от тактовата честота, тя е предварително дефинирана
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
- Скоростта зависи и от тактовата честота, тя е предварително дефинирана
- Размера на паметта е пряко свързан с планираната себестойност на продукта
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
- Скоростта зависи и от тактовата честота, тя е предварително дефинирана
- Размера на паметта е пряко свързан с планираната себестойност на продукта
- Често се дефинира опционална функционалност и се решава на по-късен етап дали да бъде включена
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
- Скоростта зависи и от тактовата честота, тя е предварително дефинирана
- Размера на паметта е пряко свързан с планираната себестойност на продукта
- Често се дефинира опционална функционалност и се решава на по-късен етап дали да бъде включена
- Консумацията на енергия също в много случаи е критичен фактор
Общи разсъждения за embedded software
- Скоростта на изпълнение и размера на паметта са критични фактори за този софтуер. Ако летящия ви дрон блокира за твърде дълго време, правилата на физиката няма да го изчакат.
- Скоростта зависи и от тактовата честота, тя е предварително дефинирана
- Размера на паметта е пряко свързан с планираната себестойност на продукта
- Често се дефинира опционална функционалност и се решава на по-късен етап дали да бъде включена
- Консумацията на енергия също в много случаи е критичен фактор
- Често се работи с различни таргет платформи и различни toolchain-ове
Възможни решения по дизайна на софтуера
Възможни решения по дизайна на софтуера
Често се налага да се правят компромиси, например
Възможни решения по дизайна на софтуера
Често се налага да се правят компромиси, например
- Дали да се ползват числа с плаваща запетя или някои математически операции да бъдат извъшени с целочислена аритметика за сметка на точността
Възможни решения по дизайна на софтуера
Често се налага да се правят компромиси, например
- Дали да се ползват числа с плаваща запетя или някои математически операции да бъдат извъшени с целочислена аритметика за сметка на точността
- Дали да се ползва preemptive/non-preemptive OS или да не се ползва OS въобще
Възможни решения по дизайна на софтуера
Често се налага да се правят компромиси, например
- Дали да се ползват числа с плаваща запетя или някои математически операции да бъдат извъшени с целочислена аритметика за сметка на точността
- Дали да се ползва preemptive/non-preemptive OS или да не се ползва OS въобще
Embedded ОС с Rust
Embedded ОС с Rust
Типични ОС с Rust: FreeRTOS, RTIC,ChibiOS, Zephyr, Drone OS, VxWorks
Preemptive scheduling
- Нишки: процесора спира таск, кара го да си запази състоянието и сменя на друг.
- Методи: Round Robin, Shortest Remaining Time First
- Предимства на preemptive scheduling: flexible, on demand(interrupt), better response time
- Недостатъци: висок overhead, по-трудна за доказване коректност (препълване на стека)
Embedded ОС с Rust
Типични ОС с Rust: FreeRTOS, RTIC,ChibiOS, Zephyr, Drone OS, VxWorks
Preemptive scheduling
- Нишки: процесора спира таск, кара го да си запази състоянието и сменя на друг.
- Методи: Round Robin, Shortest Remaining Time First
- Предимства на preemptive scheduling: flexible, on demand(interrupt), better response time
- Недостатъци: висок overhead, по-трудна за доказване коректност (препълване на стека)
Non-preemptive (cooperative) scheduling
- Всеки таск решава кога да предаде контрол на друг.
- Методи: First Come First Serve, Priority, Shorted Job First
- Предимства на non-preemptive scheduling: нисък overhead, по-малко ресурси, по-лесна за доказване коректност
- Недостатъци: Ограничена функционалност
WatchDog
WatchDog
- Типична функционалност за embedded, която не позволява вашето вашето устройство да стане купчина старо желязо
- Самостоятелен модул
- Ресет сигнала ще бъде активиран, ако вашето устройство не "нахрани" watchdog-a в рамките на определен брой ms
- Fallback при логически грешки, гранични случаи или външни атаки
- Може да бъде деактивиран
Алгоритмичен дизайн
Алгоритмичен дизайн
- Алгоритмите се разделят между аналоговата, цифровата и софтуерната част при дизайна
Алгоритмичен дизайн
- Алгоритмите се разделят между аналоговата, цифровата и софтуерната част при дизайна
- На софтуерната част винаги се пада честта да коригира грешките на първите две, както и определена контролна част
Алгоритмичен дизайн
- Алгоритмите се разделят между аналоговата, цифровата и софтуерната част при дизайна
- На софтуерната част винаги се пада честта да коригира грешките на първите две, както и определена контролна част
- Често се предвижда и fallback сценарий, където софтуера изключва/избягва/имплементира определена функционалност
Rust в embedded
Rust в embedded
- Това което ще се опитаме да покажем е какви предимства дава Rust пред C/C++
(тоест higher-level concepts и safety guarantees)
Rust в embedded
- Това което ще се опитаме да покажем е какви предимства дава Rust пред C/C++
(тоест higher-level concepts и safety guarantees) - Документация и линкове:
Embedded Rust
Embedonomicon
ESP book
Embedded Ninja
Rust в embedded
- Това което ще се опитаме да покажем е какви предимства дава Rust пред C/C++
(тоест higher-level concepts и safety guarantees) - Документация и линкове:
Embedded Rust
Embedonomicon
ESP book
Embedded Ninja - Обучение:
Ferrous Systems GmbH
Expressif
Някои коментари по отношение на съпътстващите програми
Някои коментари по отношение на съпътстващите програми
- Компилатора използва LLVM
- За някои платформи се използва nightly или fork
Някои коментари по отношение на съпътстващите програми
- Компилатора използва LLVM
- За някои платформи се използва nightly или fork
- (Дис)асемблер:
cargo objdump --bin app ...
Необходимо е да сме инсталирали:
cargo install cargo-binutils
rustup component add llvm-tools-preview
Някои коментари по отношение на съпътстващите програми
- Компилатора използва LLVM
- За някои платформи се използва nightly или fork
- (Дис)асемблер:
cargo objdump --bin app ...
Необходимо е да сме инсталирали:
cargo install cargo-binutils
rustup component add llvm-tools-preview
- Емулатор (QEMU): for Cortex-M3
qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb ... -kernel hello_world
Emulator crates илиcargo search qemu
Някои коментари по отношение на съпътстващите програми
- Компилатора използва LLVM
- За някои платформи се използва nightly или fork
- (Дис)асемблер:
cargo objdump --bin app ...
Необходимо е да сме инсталирали:
cargo install cargo-binutils
rustup component add llvm-tools-preview
- Емулатор (QEMU): for Cortex-M3
qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb ... -kernel hello_world
Emulator crates илиcargo search qemu
- Симулатор: Wokwi за esp32
Някои коментари по отношение на съпътстващите програми
- Компилатора използва LLVM
- За някои платформи се използва nightly или fork
- (Дис)асемблер:
cargo objdump --bin app ...
Необходимо е да сме инсталирали:
cargo install cargo-binutils
rustup component add llvm-tools-preview
- Емулатор (QEMU): for Cortex-M3
qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb ... -kernel hello_world
Emulator crates илиcargo search qemu
- Симулатор: Wokwi за esp32
- Дебъгер: OpenOCD е програма на host-a и превежда от GDB TCP/IP remote debug protocol и USB протокола. Допълнително
комуникира с memory-mapped registers за четене/писане и спиране на CPU-то от debug event.
Environment
Environment
Има няколко фактора при избора между std
(esp-idf-hal
) и no_std
(тоест esp-hal
).
При no_std
приложението е отговорно за използването на свой runtime, примерно riscv-rt
Също така не използване стандартната main функция и не подаваме параметри от командния ред.
ESP32 board
Targets
Имаме 2 таргета за esp32-c3-rust:
За bare-metal (no_std
) applications, ползваме riscv32imc-unknown-none-elf
.
За std
приложения, ползваме riscv32imc-esp-espidf
.
Допълнително -Z build-std
unstable cargo feature е необходима, може да бъде добавена и към .cargo/config.toml.
Темплейтите създават този файл.
Инсталацията на rust за RISC-V също може да бъде извършена от espup.
rustup toolchain install nightly --component rust-src
rustup target add riscv32imc-unknown-none-elf
Темплейти за embedded
Поддържат се два темплейта:
- esp-template - за
no_std
. - esp-idf-template - за
std
.
cargo install cargo-generate
cargo generate --git https://github.com/esp-rs/esp-template
cargo add esp-println --features "esp32c3"
cargo run
- Ние ще разгледаме
no_std
. Заstd
има много примери от Иван Марков
Bare metal или no_std
Bare metal или no_std
- Bare Metal Environment
#![no_std]
Bare metal или no_std
- Bare Metal Environment
#![no_std]
- При
no_std
липсват multitasking primitives и не само … - Вместо
std
се изпозваcore
Bare metal или no_std
- Bare Metal Environment
#![no_std]
- При
no_std
липсват multitasking primitives и не само … - Вместо
std
се изпозваcore
- Липсва динамична памет. Някои заместители на стандартните структури има в heapless пакета.
Bare metal или no_std
- Bare Metal Environment
#![no_std]
- При
no_std
липсват multitasking primitives и не само … - Вместо
std
се изпозваcore
- Липсва динамична памет. Някои заместители на стандартните структури има в heapless пакета.
no_std
може винаги да се колмилира катоstd
, обратното не важи
Bare metal или no_std
- Bare Metal Environment
#![no_std]
- При
no_std
липсват multitasking primitives и не само … - Вместо
std
се изпозваcore
- Липсва динамична памет. Някои заместители на стандартните структури има в heapless пакета.
no_std
може винаги да се колмилира катоstd
, обратното не важи
#![no_std]
fn main() {
let a = Box::new(7);
}
error[E0433]: failed to resolve: use of undeclared type `Box` --> src/bin/main_2027d7438488e4bc0595f7894414ca942a118ce9.rs:3:11 | 3 | let a = Box::new(7); | ^^^ use of undeclared type `Box` For more information about this error, try `rustc --explain E0433`. error: could not compile `rust` due to previous error
#![no_std] fn main() { let a = Box::new(7); }
Hands on 2022
Hands on 2022
Based on RustFest 2019
Installation on Ubuntu and installation on other platforms
sudo apt install -y pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev
cargo install cargo-flash
rustup target add thumbv6m-none-eabi
cargo flash --chip=LPC845M301JBD48
Hands on 2022
Based on RustFest 2019
Installation on Ubuntu and installation on other platforms
sudo apt install -y pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev
cargo install cargo-flash
rustup target add thumbv6m-none-eabi
cargo flash --chip=LPC845M301JBD48
Error Failed to open the debug probe.
Hands on 2022
Based on RustFest 2019
Installation on Ubuntu and installation on other platforms
sudo apt install -y pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev
cargo install cargo-flash
rustup target add thumbv6m-none-eabi
cargo flash --chip=LPC845M301JBD48
Error Failed to open the debug probe.
https://github.com/knurling-rs/probe-run
Hands on 2022
Based on RustFest 2019
Installation on Ubuntu and installation on other platforms
sudo apt install -y pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev
cargo install cargo-flash
rustup target add thumbv6m-none-eabi
cargo flash --chip=LPC845M301JBD48
Error Failed to open the debug probe.
https://github.com/knurling-rs/probe-run
sudo apt-get install openocd
sudo cp /usr/lib/udev/rules.d/60-openocd.rules /etc/udev/rules.d/
Remove GROUP="plugdev" in /etc/udev/rules.d/60-openocd.rules
Hands on 2022
Based on RustFest 2019
Installation on Ubuntu and installation on other platforms
sudo apt install -y pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev
cargo install cargo-flash
rustup target add thumbv6m-none-eabi
cargo flash --chip=LPC845M301JBD48
Error Failed to open the debug probe.
https://github.com/knurling-rs/probe-run
sudo apt-get install openocd
sudo cp /usr/lib/udev/rules.d/60-openocd.rules /etc/udev/rules.d/
Remove GROUP="plugdev" in /etc/udev/rules.d/60-openocd.rules
sudo udevadm control –reload
sudo udevadm trigger
Hands on 2023
Based on ESP Community and ESP book no_std application
- Мониторване (esp-println)
- Дебъгване (
openocd -f board/esp32c3-builtin.cfg
&&(gdb) target extended-remote localhost:3333
) - Симулация (Wokwi)
Hands on 2023
Based on ESP Community and ESP book no_std application
- Мониторване (esp-println)
- Дебъгване (
openocd -f board/esp32c3-builtin.cfg
&&(gdb) target extended-remote localhost:3333
) - Симулация (Wokwi)
Примери:
- esp_print
- panic
- blinking
- button
- interrupt
Memory
Memory and all limitations are described in *.x
files. Example memory.x
:
MEMORY
{
FLASH : ORIGIN = 0x00000000, LENGTH = 64K
RAM : ORIGIN = 0x10000000, LENGTH = 16K
}
Code - setup:
cargo generate --git https://github.com/esp-rs/esp-template
#![no_std]
#![no_main]
use esp32c3_hal::{clock::ClockControl, pac::Peripherals, prelude::*,
timer::TimerGroup, Rtc};
use esp_backtrace as _;
#[riscv_rt::entry]
fn main() -> ! {
//...
}
Code 1 - Message + panic:
let peripherals = Peripherals::take().unwrap();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the RTC and TIMG watchdog timers
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
esp_println::println!("Hello World");
panic!("This is a panic");
Code 2 - Blinking:
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio7.into_push_pull_output();
led.set_high().unwrap();
let mut delay = Delay::new(&clocks);
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
Code 3 - Button pressed:
let button = io.pins.gpio9.into_pull_up_input();
loop {
if button.is_high().unwrap() {
led.set_high().unwrap();
} else {
led.set_low().unwrap();
}
}
Code 4 - Interrupts и Counter:
Добавяме critical_sections
в Cargo.toml
static BUTTON: Mutex<RefCell<Option<Gpio9<Input<PullUp>>>>> = Mutex::new(RefCell::new(None));
static COUNTER: AtomicUsize = AtomicUsize::new(0);
//...
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut button = io.pins.gpio9.into_pull_up_input();
button.listen(Event::FallingEdge); // raise interrupt on falling edge
critical_section::with(|cs| BUTTON.borrow_ref_mut(cs).replace(button));
interrupt::enable(pac::Interrupt::GPIO, interrupt::Priority::Priority3).unwrap();
loop {
COUNTER.fetch_add(1, Ordering::SeqCst);
}
}
#[interrupt]
fn GPIO() {
critical_section::with(|cs| {
esp_println::println!("GPIO interrupt, counter = {:}", COUNTER.load(Ordering::SeqCst));
COUNTER.store(0, Ordering::SeqCst);
BUTTON
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt();
});
}
Процес на develop-ване за embedded
Процес на develop-ване за embedded
Process: Power up the GPIO Peripherals, configure pin as output, set output to high/low
unsafe {
*((GPIOC_START + CHR_OFFSET) as *mut u32) = (OUTPUT_MODE << 20) | (PUSH_PULL << 22);
}
Процес на develop-ване за embedded
Process: Power up the GPIO Peripherals, configure pin as output, set output to high/low
unsafe {
*((GPIOC_START + CHR_OFFSET) as *mut u32) = (OUTPUT_MODE << 20) | (PUSH_PULL << 22);
}
- svd files -> svd2rust generates rust crates => PAC(Peripherial Access Crates)
dp.GPIOC.crh.modify(|_r, w| {
w.mode13().output().cnf13().push_pull()
});
dp.GPIOC.odr.modify(|_r, w| {
w.odr13().high()
});
Процес на develop-ване за embedded - продължение
- Zero cost abstraction (in release mode), mostly safe
Процес на develop-ване за embedded - продължение
- Zero cost abstraction (in release mode), mostly safe
- No check for peripheral dependencies and correct initialization
Процес на develop-ване за embedded - продължение
- Zero cost abstraction (in release mode), mostly safe
- No check for peripheral dependencies and correct initialization
- HALs - higher level interface around PAC
Процес на develop-ване за embedded - продължение
- Zero cost abstraction (in release mode), mostly safe
- No check for peripheral dependencies and correct initialization
- HALs - higher level interface around PAC
- Interoperability with C
#[no_mangle]
pub extern "C" fn rust_function() {}
- cbindgen ще генерира header-и от вашия rust код за C/C++
Обобщение за Embedded-hal, BSP, Crates
Concurrency
Concurrency
- Ferrous Systems
- Обикновенно имаме 1 процесор
- Всеки thread си има собствен стек
- Cooperative scheduling
Concurrency
- Ferrous Systems
- Обикновенно имаме 1 процесор
- Всеки thread си има собствен стек
- Cooperative scheduling
- често се налага да дефинираме
static mut
, опeрациите към него саunsafe
.
Concurrency
- Ferrous Systems
- Обикновенно имаме 1 процесор
- Всеки thread си има собствен стек
- Cooperative scheduling
- често се налага да дефинираме
static mut
, опeрациите към него саunsafe
. - възможни подходи: забрана на прекъсвания при работа с такава променлива или използване на
atomics
cortex_m::interrupt::free(|_| {
unsafe { COUNTER += 1 };
});
static COUNTER: AtomicUsize = AtomicUsize::new(0);
//...
COUNTER.fetch_add(1, Ordering::Relaxed);
Async/await
Async/await
Async/await
Async/await
Async/await
I2C
Популярен комуникационен интерфейс за embedded устройства с минимално натоварване
Definition, Master-Slave, 2 lines, developed by Philips
I2C
Популярен комуникационен интерфейс за embedded устройства с минимално натоварване
Definition, Master-Slave, 2 lines, developed by Philips
Ползи от Rust
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
- Design contracts
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
- Design contracts
- Zero cost abstraction
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
- Design contracts
- Zero cost abstraction
- Async/Await
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
- Design contracts
- Zero cost abstraction
- Async/Await
- Cargo може да е универсално за различни платформи
Ползи от Rust
- Изграждане на системи от embedded до cloud на един език
- Safety (typesafe, strong types, correct composition)
- Peripherals като state machine; Избягва неволни грешки
- Design contracts
- Zero cost abstraction
- Async/Await
- Cargo може да е универсално за различни платформи
- Много analyzer-и на C/C++ струват доста скъпо за да се постигне сравнимо качество