Crates.io | emcell |
lib.rs | emcell |
version | 0.0.3 |
source | src |
created_at | 2024-05-28 18:22:59.840579 |
updated_at | 2024-09-10 15:48:30.093278 |
description | Reserve flash memory regions to safely keep multiple binary and library binaries (cells) on a microcontroller. The cells can call functions from other cells. |
homepage | |
repository | https://github.com/skibon02/emcell |
max_upload_size | |
id | 1254647 |
size | 18,455 |
emcell (EMbedded CELL) - is a library, which make it very easy
to keep several binaries on a single microcontroller. You just need to create
a separate crate with cells definitions and create simple build.rs
, specifying which cell
is a current crate for.
Cell is an abstract word for a binary or library, which have a specific region of FLASH and RAM memory assigned. You can keep several cells on a single microcontroller, and even define header for each of them to cross-call different functions.
Emcell also allow you to define a special function with signature fn() -> !
, which will
perform vector table switch. For example, you can define function run() -> !
in your main code,
and run it from bootloader cell.
Example of lib.rs
for cells definitions crate:
#![no_std]
#[macro_use]
extern crate emcell_macro;
emcell_configuration! {
device!{
initial_stack_ptr: 0x2000_6000,
ram_range_start: 0x2000_0000,
ram_range_end: 0x2001_8000, // 96Kb RAM
flash_range_start: 0x0800_0000,
flash_range_end: 0x0810_0000, // 1Mb flash
}
#[cell(primary)]
#[ram_region(0x6000, 0x6400)]
#[flash_region(0x0, 0x4000)]
pub struct Cell1 {
}
#[cell]
#[ram_region(0x6400, 0xA000)]
#[flash_region(0x0_4000, 0xF_1000)]
pub struct Cell2 {
#[switch_vectors]
pub run: fn() -> !,
pub a: u32,
pub print_some_value: fn(u32),
}
#[cell]
#[ram_region(0xA000, 0x1_0000)]
#[flash_region(0xF_1000, 0x10_0000)]
pub struct Cell3 {
pub b: u32,
pub run_some_code: fn(),
pub access_static: fn() -> u32,
}
}
In this example you define 3 cells: Cell1
, Cell2
and Cell3
. Each of them have
separate crate and can call functions from other crates using safe wrapper, which is created automatically
with macro.
Example of main.rs
for cell1 crate:
#![no_std]
#![no_main]
#![feature(const_refs_to_static)]
use emcell_macro::{define_primary_header, extern_header_forward};
use cells_defs::{Cell1, Cell2};
use cortex_m::asm::delay;
extern crate panic_halt;
define_primary_header!{
Cell1 {
}
}
extern_header_forward!(Cell2Wrapper: Cell2);
#[cortex_m_rt::entry]
unsafe fn main() -> ! {
gpio_cfgr();
led_on();
if let Some(cell2) = Cell2Wrapper::new() {
cell2.switch_vectors_and_run() // execute run() -> ! for cell2
}
else {
loop {
delay(1_000_000);
}
}
}
build.rs:
fn main() {
emcell::build_rs::<cells_defs::Cell1>();
}
Cell2Wrapper::new()
is created automatically and perform additional checks to ensure, that header for cell2
was not modified (by comparing hash) and is compatible with current crate.
Currently, emcell requires nightly because of const_refs_to_static
feature.
You can use rustup override set nightly
to set nightly for the current directory.