Skip to content

Commit 370336b

Browse files
committed
update examples
- Introduce `defmt` which is very commonly used on embedded systems. It is used to print the allocated structures. - New QEMU runner to support defmt. - Introduce new example which uses a global heap initialized on BSS memory. - Switch to more commonly used thumbv7em-none-eabihf target for the QEMU runner. thumbv6m-none-eabi is still supported as well.
1 parent 83157f6 commit 370336b

File tree

9 files changed

+183
-47
lines changed

9 files changed

+183
-47
lines changed

.cargo/config.toml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
1-
[target.thumbv7m-none-eabi]
1+
[build]
2+
# Common embedded build targets
3+
target = "thumbv7em-none-eabihf"
4+
# target = "thumbv6m-none-eabi"
5+
6+
[target.thumbv7em-none-eabihf]
27
# used to run the qemu_test.rs example with QEMU
3-
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
4-
rustflags = ["-C", "link-arg=-Tlink.x"]
8+
runner = "./qemu-runner.sh --target thumbv7em-none-eabihf"
9+
rustflags = [
10+
"-Clink-arg=-Tlink.x",
11+
"-Clink-arg=-Tdefmt.x",
12+
]
13+
14+
[target.thumbv6m-none-eabi]
15+
# used to run the qemu_test.rs example with QEMU
16+
runner = "./qemu-runner.sh --target thumbv6m-none-eabi"
17+
rustflags = [
18+
"-Clink-arg=-Tlink.x",
19+
"-Clink-arg=-Tdefmt.x",
20+
]
21+
22+
[env]
23+
DEFMT_LOG="info"

.github/workflows/ci.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
target:
1818
- thumbv6m-none-eabi
19-
- thumbv7m-none-eabi
19+
- thumbv7em-none-eabihf
2020
toolchain:
2121
- stable
2222
- nightly
@@ -49,15 +49,15 @@ jobs:
4949
- uses: actions/checkout@v4
5050
- uses: dtolnay/rust-toolchain@master
5151
with:
52-
targets: thumbv7m-none-eabi
52+
targets: thumbv7em-none-eabihf
5353
toolchain: nightly
5454
- name: Install QEMU
5555
run: |
5656
sudo apt update
5757
sudo apt install qemu-system-arm
5858
- run: qemu-system-arm --version
59-
- run: cargo run --target thumbv7m-none-eabi --example llff_integration_test --all-features
60-
- run: cargo run --target thumbv7m-none-eabi --example tlsf_integration_test --all-features
59+
- run: cargo +nightly run --target thumbv7em-none-eabihf --example llff_integration_test --all-features
60+
- run: cargo +nightly run --target thumbv7em-none-eabihf --example tlsf_integration_test --all-features
6161

6262
clippy:
6363
name: Clippy
@@ -88,5 +88,8 @@ jobs:
8888
steps:
8989
- uses: actions/checkout@v4
9090
- uses: dtolnay/rust-toolchain@nightly
91+
with:
92+
targets: thumbv7em-none-eabihf
93+
toolchain: nightly
9194
- name: rustdoc
92-
run: cargo rustdoc --all-features
95+
run: cargo +nightly rustdoc --all-features

Cargo.toml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,18 @@ const-default = { version = "1.0.0", default-features = false, optional = true }
4141
[dev-dependencies]
4242
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
4343
cortex-m-rt = "0.7"
44-
cortex-m-semihosting = "0.5"
45-
panic-semihosting = { version = "0.6", features = ["exit"] }
44+
defmt = "1.0"
45+
defmt-semihosting = "0.3.0"
46+
semihosting = { version = "0.1.20", features = ["stdio"] }
47+
static_cell = "2"
48+
49+
# thumbv6m-none-eabi only
50+
[target.thumbv6m-none-eabi.dev-dependencies]
51+
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
52+
53+
# every other target gets the crate without the feature
54+
[target.'cfg(not(target = "thumbv6m-none-eabi"))'.dev-dependencies]
55+
portable-atomic = { version = "1" }
4656

4757
[[example]]
4858
name = "allocator_api"

examples/allocator_api.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
//! This examples requires nightly for the allocator API.
12
#![feature(allocator_api)]
23
#![no_std]
34
#![no_main]
45

56
extern crate alloc;
67

7-
use alloc::vec::Vec;
8-
use core::mem::MaybeUninit;
9-
use core::panic::PanicInfo;
8+
use core::{mem::MaybeUninit, panic::PanicInfo};
9+
use cortex_m as _;
1010
use cortex_m_rt::entry;
11+
use defmt::Debug2Format;
12+
use defmt_semihosting as _;
1113
use embedded_alloc::LlffHeap as Heap;
1214

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

25-
let mut xs = Vec::new_in(heap);
26-
xs.push(1);
27+
let mut vec = alloc::vec::Vec::new_in(heap);
28+
vec.push(1);
2729

28-
#[allow(clippy::empty_loop)]
29-
loop { /* .. */ }
30+
defmt::info!("Allocated vector: {:?}", Debug2Format(&vec));
31+
32+
semihosting::process::exit(0);
3033
}
3134

3235
#[panic_handler]
33-
fn panic(_: &PanicInfo) -> ! {
34-
loop {}
36+
fn panic(info: &PanicInfo) -> ! {
37+
defmt::error!("{}", info);
38+
semihosting::process::exit(0);
3539
}

examples/global_alloc.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
extern crate alloc;
55

6-
use alloc::vec::Vec;
7-
use core::panic::PanicInfo;
6+
use cortex_m as _;
87
use cortex_m_rt::entry;
8+
use defmt::Debug2Format;
9+
use defmt_semihosting as _;
10+
11+
use core::panic::PanicInfo;
912
// Linked-List First Fit Heap allocator (feature = "llff")
1013
use embedded_alloc::LlffHeap as Heap;
1114
// Two-Level Segregated Fit Heap allocator (feature = "tlsf")
@@ -21,14 +24,19 @@ fn main() -> ! {
2124
embedded_alloc::init!(HEAP, 1024);
2225
}
2326

24-
let mut xs = Vec::new();
25-
xs.push(1);
27+
let vec = alloc::vec![1];
28+
29+
defmt::info!("Allocated vector: {:?}", Debug2Format(&vec));
30+
31+
let string = alloc::string::String::from("Hello, world!");
32+
33+
defmt::info!("Allocated string: {:?}", Debug2Format(&string));
2634

27-
#[allow(clippy::empty_loop)]
28-
loop { /* .. */ }
35+
semihosting::process::exit(0);
2936
}
3037

3138
#[panic_handler]
32-
fn panic(_: &PanicInfo) -> ! {
33-
loop {}
39+
fn panic(info: &PanicInfo) -> ! {
40+
defmt::error!("{}", info);
41+
semihosting::process::exit(0);
3442
}

examples/global_alloc_bss_heap.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate alloc;
5+
6+
use cortex_m as _;
7+
use cortex_m_rt::entry;
8+
use defmt::Debug2Format;
9+
use defmt_semihosting as _;
10+
11+
use core::panic::PanicInfo;
12+
use embedded_alloc::TlsfHeap as Heap;
13+
14+
#[global_allocator]
15+
static HEAP: Heap = Heap::empty();
16+
17+
#[entry]
18+
fn main() -> ! {
19+
const HEAP_SIZE: usize = 16 * 1024;
20+
static HEAP_MEM: static_cell::ConstStaticCell<[u8; HEAP_SIZE]> =
21+
static_cell::ConstStaticCell::new([0; HEAP_SIZE]);
22+
unsafe {
23+
HEAP.init(HEAP_MEM.take().as_mut_ptr() as usize, HEAP_SIZE);
24+
}
25+
26+
let vec = alloc::vec![1];
27+
28+
defmt::info!("Allocated vector: {:?}", Debug2Format(&vec));
29+
30+
let string = alloc::string::String::from("Hello, world!");
31+
32+
defmt::info!("Allocated string: {:?}", Debug2Format(&string));
33+
34+
semihosting::process::exit(0);
35+
}
36+
37+
#[panic_handler]
38+
fn panic(info: &PanicInfo) -> ! {
39+
defmt::error!("{}", info);
40+
semihosting::process::exit(0);
41+
}

examples/llff_integration_test.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
#![no_std]
1818

1919
extern crate alloc;
20-
extern crate panic_semihosting;
2120

2221
use alloc::vec::Vec;
23-
use core::mem::{size_of, MaybeUninit};
22+
use core::{
23+
mem::{size_of, MaybeUninit},
24+
panic::PanicInfo,
25+
};
26+
use cortex_m as _;
2427
use cortex_m_rt::entry;
25-
use cortex_m_semihosting::{debug, hprintln};
28+
use defmt_semihosting as _;
2629
use embedded_alloc::LlffHeap as Heap;
2730

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

67+
pub type TestTable<'a> = &'a [(fn() -> (), &'static str)];
68+
6469
#[entry]
6570
fn main() -> ! {
6671
unsafe {
6772
embedded_alloc::init!(HEAP, 1024);
6873
}
6974

70-
#[allow(clippy::type_complexity)]
71-
let tests: &[(fn() -> (), &'static str)] = &[
75+
let tests: TestTable = &[
7276
(test_global_heap, "test_global_heap"),
7377
(test_allocator_api, "test_allocator_api"),
7478
];
7579

7680
for (test_fn, test_name) in tests {
77-
hprintln!("{}: start", test_name);
81+
defmt::info!("{}: start", test_name);
7882
test_fn();
79-
hprintln!("{}: pass", test_name);
83+
defmt::info!("{}: pass", test_name);
8084
}
8185

8286
// exit QEMU with a success status
83-
debug::exit(debug::EXIT_SUCCESS);
84-
#[allow(clippy::empty_loop)]
85-
loop {}
87+
semihosting::process::exit(0);
88+
}
89+
90+
#[panic_handler]
91+
fn panic(info: &PanicInfo) -> ! {
92+
defmt::error!("{}", info);
93+
semihosting::process::exit(-1);
8694
}

examples/tlsf_integration_test.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@
1717
#![no_std]
1818

1919
extern crate alloc;
20-
extern crate panic_semihosting;
20+
use defmt_semihosting as _;
2121

2222
use alloc::collections::LinkedList;
23-
use core::mem::MaybeUninit;
23+
use core::{mem::MaybeUninit, panic::PanicInfo};
24+
use cortex_m as _;
2425
use cortex_m_rt::entry;
25-
use cortex_m_semihosting::{debug, hprintln};
2626
use embedded_alloc::TlsfHeap as Heap;
2727

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

32+
pub type TestTable<'a> = &'a [(fn() -> (), &'static str)];
33+
3234
fn test_global_heap() {
3335
const ELEMS: usize = 250;
3436

@@ -85,20 +87,23 @@ fn main() -> ! {
8587
embedded_alloc::init!(HEAP, HEAP_SIZE);
8688
}
8789

88-
#[allow(clippy::type_complexity)]
89-
let tests: &[(fn() -> (), &'static str)] = &[
90+
let tests: TestTable = &[
9091
(test_global_heap, "test_global_heap"),
9192
(test_allocator_api, "test_allocator_api"),
9293
];
9394

9495
for (test_fn, test_name) in tests {
95-
hprintln!("{}: start", test_name);
96+
defmt::info!("{}: start", test_name);
9697
test_fn();
97-
hprintln!("{}: pass", test_name);
98+
defmt::info!("{}: pass", test_name);
9899
}
99100

100101
// exit QEMU with a success status
101-
debug::exit(debug::EXIT_SUCCESS);
102-
#[allow(clippy::empty_loop)]
103-
loop {}
102+
semihosting::process::exit(0);
103+
}
104+
105+
#[panic_handler]
106+
fn panic(info: &PanicInfo) -> ! {
107+
defmt::error!("{}", info);
108+
semihosting::process::exit(-1);
104109
}

qemu-runner.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
3+
# This requires you to previously run `cargo install defmt-print`
4+
5+
# See https://ferroussystems.hackmd.io/@jonathanpallant/ryA1S6QDJx for a description of all the relevant QEMU machines
6+
TARGET=""
7+
ELF_BINARY=""
8+
9+
# very small argument parser
10+
while [[ $# -gt 0 ]]; do
11+
case "$1" in
12+
--target) TARGET="$2"; shift 2 ;;
13+
*) ELF_BINARY="$1"; shift ;;
14+
esac
15+
done
16+
17+
# default to the target cargo is currently building for
18+
TARGET="${TARGET:-thumbv7em-none-eabihf}"
19+
20+
case "$TARGET" in
21+
thumbv6m-none-eabi)
22+
MACHINE="-cpu cortex-m3 -machine mps2-an385" ;;
23+
thumbv7em-none-eabihf)
24+
# All suitable for thumbv7em-none-eabihf
25+
MACHINE="-cpu cortex-m4 -machine mps2-an386" ;;
26+
# MACHINE="-cpu cortex-m7 -machine mps2-387" ;;
27+
# MACHINE="-cpu cortex-m7 -machine mps2-500"
28+
*)
29+
echo "Unsupported target: $TARGET" >&2
30+
exit 1 ;;
31+
esac
32+
33+
LOG_FORMAT='{[{L}]%bold} {s} {({ff}:{l:1})%dimmed}'
34+
35+
echo "Running on '$MACHINE'..."
36+
echo "------------------------------------------------------------------------"
37+
qemu-system-arm $MACHINE -semihosting-config enable=on,target=native -nographic -kernel $ELF_BINARY | defmt-print -e $ELF_BINARY --log-format="$LOG_FORMAT"
38+
echo "------------------------------------------------------------------------"

0 commit comments

Comments
 (0)