Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
[target.thumbv7m-none-eabi]
[build]
# Common embedded build targets
target = "thumbv7em-none-eabihf"
# target = "thumbv6m-none-eabi"

[target.thumbv7em-none-eabihf]
# used to run the qemu_test.rs example with QEMU
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
rustflags = ["-C", "link-arg=-Tlink.x"]
runner = "./qemu-runner.sh --target thumbv7em-none-eabihf"
rustflags = [
"-Clink-arg=-Tlink.x",
"-Clink-arg=-Tdefmt.x",
# Can be useful for debugging and to inspect where the heap memory is placed/linked.
# "-Clink-args=-Map=app.map"
]

[target.thumbv6m-none-eabi]
# used to run the qemu_test.rs example with QEMU
runner = "./qemu-runner.sh --target thumbv6m-none-eabi"
rustflags = [
"-Clink-arg=-Tlink.x",
"-Clink-arg=-Tdefmt.x",
]

[env]
DEFMT_LOG="info"
13 changes: 8 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
matrix:
target:
- thumbv6m-none-eabi
- thumbv7m-none-eabi
- thumbv7em-none-eabihf
toolchain:
- stable
- nightly
Expand Down Expand Up @@ -49,15 +49,15 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
targets: thumbv7m-none-eabi
targets: thumbv7em-none-eabihf
toolchain: nightly
- name: Install QEMU
run: |
sudo apt update
sudo apt install qemu-system-arm
- run: qemu-system-arm --version
- run: cargo run --target thumbv7m-none-eabi --example llff_integration_test --all-features
- run: cargo run --target thumbv7m-none-eabi --example tlsf_integration_test --all-features
- run: cargo +nightly run --target thumbv7em-none-eabihf --example llff_integration_test --all-features
- run: cargo +nightly run --target thumbv7em-none-eabihf --example tlsf_integration_test --all-features

clippy:
name: Clippy
Expand Down Expand Up @@ -88,5 +88,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
targets: thumbv7em-none-eabihf
toolchain: nightly
- name: rustdoc
run: cargo rustdoc --all-features
run: cargo +nightly rustdoc --all-features
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

- Added a `init` macro to make initialization easier.
- Added `Heap::free` and `Heap::used` for the TLSF heap.

### Changed

Expand Down
16 changes: 13 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,24 @@ llff = ["linked_list_allocator"]
[dependencies]
critical-section = "1.0"
linked_list_allocator = { version = "0.10.5", default-features = false, optional = true }
rlsf = { version = "0.2.1", default-features = false, optional = true }
rlsf = { version = "0.2.1", default-features = false, features = ["unstable"], optional = true }
const-default = { version = "1.0.0", default-features = false, optional = true }

[dev-dependencies]
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
cortex-m-semihosting = "0.5"
panic-semihosting = { version = "0.6", features = ["exit"] }
defmt = "1.0"
defmt-semihosting = "0.3.0"
semihosting = { version = "0.1.20", features = ["stdio"] }
static_cell = "2"

# thumbv6m-none-eabi only
[target.thumbv6m-none-eabi.dev-dependencies]
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }

# every other target gets the crate without the feature
[target.'cfg(not(target = "thumbv6m-none-eabi"))'.dev-dependencies]
portable-atomic = { version = "1" }

[[example]]
name = "allocator_api"
Expand Down
22 changes: 13 additions & 9 deletions examples/allocator_api.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! This examples requires nightly for the allocator API.
#![feature(allocator_api)]
#![no_std]
#![no_main]

extern crate alloc;

use alloc::vec::Vec;
use core::mem::MaybeUninit;
use core::panic::PanicInfo;
use core::{mem::MaybeUninit, panic::PanicInfo};
use cortex_m as _;
use cortex_m_rt::entry;
use defmt::Debug2Format;
use defmt_semihosting as _;
use embedded_alloc::LlffHeap as Heap;

// This is not used, but as of 2023-10-29 allocator_api cannot be used without
Expand All @@ -22,14 +24,16 @@ fn main() -> ! {
let heap: Heap = Heap::empty();
unsafe { heap.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }

let mut xs = Vec::new_in(heap);
xs.push(1);
let mut vec = alloc::vec::Vec::new_in(heap);
vec.push(1);

#[allow(clippy::empty_loop)]
loop { /* .. */ }
defmt::info!("Allocated vector: {:?}", Debug2Format(&vec));

semihosting::process::exit(0);
}

#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", info);
semihosting::process::exit(-1);
}
38 changes: 38 additions & 0 deletions examples/exhaustion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Example which shows behavior on pool exhaustion. It simply panics.
#![no_std]
#![no_main]

extern crate alloc;

use cortex_m as _;
use cortex_m_rt::entry;
use defmt::Debug2Format;
use defmt_semihosting as _;

use core::panic::PanicInfo;
use embedded_alloc::TlsfHeap as Heap;

#[global_allocator]
static HEAP: Heap = Heap::empty();

#[entry]
fn main() -> ! {
// Initialize the allocator BEFORE you use it
unsafe {
embedded_alloc::init!(HEAP, 16);
}

let _vec = alloc::vec![0; 16];

defmt::error!("unexpected vector allocation success");

// Panic is expected here.
semihosting::process::exit(-1);
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::warn!("received expected heap exhaustion panic");
defmt::warn!("{}: {}", info, Debug2Format(&info.message()));
semihosting::process::exit(0);
}
24 changes: 16 additions & 8 deletions examples/global_alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

extern crate alloc;

use alloc::vec::Vec;
use core::panic::PanicInfo;
use cortex_m as _;
use cortex_m_rt::entry;
use defmt::Debug2Format;
use defmt_semihosting as _;

use core::panic::PanicInfo;
// Linked-List First Fit Heap allocator (feature = "llff")
use embedded_alloc::LlffHeap as Heap;
// Two-Level Segregated Fit Heap allocator (feature = "tlsf")
Expand All @@ -21,14 +24,19 @@ fn main() -> ! {
embedded_alloc::init!(HEAP, 1024);
}

let mut xs = Vec::new();
xs.push(1);
let vec = alloc::vec![1];

defmt::info!("Allocated vector: {:?}", Debug2Format(&vec));

let string = alloc::string::String::from("Hello, world!");

defmt::info!("Allocated string: {:?}", Debug2Format(&string));

#[allow(clippy::empty_loop)]
loop { /* .. */ }
semihosting::process::exit(0);
}

#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", info);
semihosting::process::exit(-1);
}
28 changes: 18 additions & 10 deletions examples/llff_integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
#![no_std]

extern crate alloc;
extern crate panic_semihosting;

use alloc::vec::Vec;
use core::mem::{size_of, MaybeUninit};
use core::{
mem::{size_of, MaybeUninit},
panic::PanicInfo,
};
use cortex_m as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};
use defmt_semihosting as _;
use embedded_alloc::LlffHeap as Heap;

#[global_allocator]
Expand Down Expand Up @@ -61,26 +64,31 @@ fn test_allocator_api() {
assert_eq!(v.as_slice(), &[0xCAFE, 0xDEAD, 0xFEED]);
}

pub type TestTable<'a> = &'a [(fn() -> (), &'static str)];

#[entry]
fn main() -> ! {
unsafe {
embedded_alloc::init!(HEAP, 1024);
}

#[allow(clippy::type_complexity)]
let tests: &[(fn() -> (), &'static str)] = &[
let tests: TestTable = &[
(test_global_heap, "test_global_heap"),
(test_allocator_api, "test_allocator_api"),
];

for (test_fn, test_name) in tests {
hprintln!("{}: start", test_name);
defmt::info!("{}: start", test_name);
test_fn();
hprintln!("{}: pass", test_name);
defmt::info!("{}: pass", test_name);
}

// exit QEMU with a success status
debug::exit(debug::EXIT_SUCCESS);
#[allow(clippy::empty_loop)]
loop {}
semihosting::process::exit(0);
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", info);
semihosting::process::exit(-1);
}
25 changes: 15 additions & 10 deletions examples/tlsf_integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@
#![no_std]

extern crate alloc;
extern crate panic_semihosting;
use defmt_semihosting as _;

use alloc::collections::LinkedList;
use core::mem::MaybeUninit;
use core::{mem::MaybeUninit, panic::PanicInfo};
use cortex_m as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};
use embedded_alloc::TlsfHeap as Heap;

#[global_allocator]
static HEAP: Heap = Heap::empty();
const HEAP_SIZE: usize = 30 * 1024;

pub type TestTable<'a> = &'a [(fn() -> (), &'static str)];

fn test_global_heap() {
const ELEMS: usize = 250;

Expand Down Expand Up @@ -85,20 +87,23 @@ fn main() -> ! {
embedded_alloc::init!(HEAP, HEAP_SIZE);
}

#[allow(clippy::type_complexity)]
let tests: &[(fn() -> (), &'static str)] = &[
let tests: TestTable = &[
(test_global_heap, "test_global_heap"),
(test_allocator_api, "test_allocator_api"),
];

for (test_fn, test_name) in tests {
hprintln!("{}: start", test_name);
defmt::info!("{}: start", test_name);
test_fn();
hprintln!("{}: pass", test_name);
defmt::info!("{}: pass", test_name);
}

// exit QEMU with a success status
debug::exit(debug::EXIT_SUCCESS);
#[allow(clippy::empty_loop)]
loop {}
semihosting::process::exit(0);
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}", info);
semihosting::process::exit(-1);
}
54 changes: 54 additions & 0 deletions examples/track_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#![no_std]
#![no_main]

extern crate alloc;

use cortex_m as _;
use cortex_m_rt::entry;
use defmt::Debug2Format;
use defmt_semihosting as _;

use core::{mem::MaybeUninit, panic::PanicInfo};
use embedded_alloc::TlsfHeap as Heap;
//use embedded_alloc::LlffHeap as Heap;

#[global_allocator]
static HEAP: Heap = Heap::empty();

#[entry]
fn main() -> ! {
// Initialize the allocator BEFORE you use it
const HEAP_SIZE: usize = 4096;
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }

let mut long_vec = alloc::vec::Vec::new();
let mut free_memory = HEAP_SIZE;
// Keep allocating until we are getting low on memory. It doesn't have to end in a panic.
while free_memory > 512 {
defmt::info!(
"{} of {} heap memory allocated so far...",
HEAP_SIZE - free_memory,
HEAP_SIZE
);
long_vec.push([1; 16].to_vec());
free_memory = HEAP.free();
}

drop(long_vec);

defmt::warn!(
"{} of {} heap memory are allocated after drop",
HEAP_SIZE - HEAP.free(),
HEAP_SIZE
);

// Panic is expected here.
semihosting::process::exit(0);
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
defmt::error!("{}: {}", info, Debug2Format(&info.message()));
semihosting::process::exit(-1);
}
Loading