Skip to content

Commit d51f81b

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.
1 parent 83157f6 commit d51f81b

File tree

9 files changed

+133
-41
lines changed

9 files changed

+133
-41
lines changed

.cargo/config.toml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
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"
9+
10+
rustflags = [
11+
"-Clink-arg=-Tlink.x",
12+
"-Clink-arg=-Tdefmt.x",
13+
]
14+
15+
[env]
16+
DEFMT_LOG="info"

.github/workflows/ci.yml

Lines changed: 2 additions & 2 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,7 +49,7 @@ 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: |

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@ 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+
# cortex-m-semihosting = "0.5"
45+
defmt = "1.0"
46+
defmt-semihosting = "0.3.0"
47+
semihosting = { version = "0.1.20", features = ["stdio"] }
48+
static_cell = "2"
4649

4750
[[example]]
4851
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: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
#![no_std]
1818

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

21+
use defmt_semihosting as _;
2222
use alloc::vec::Vec;
23-
use core::mem::{size_of, MaybeUninit};
23+
use core::{mem::{MaybeUninit, size_of}, panic::PanicInfo};
2424
use cortex_m_rt::entry;
25-
use cortex_m_semihosting::{debug, hprintln};
25+
use cortex_m as _;
2626
use embedded_alloc::LlffHeap as Heap;
2727

2828
#[global_allocator]
@@ -67,20 +67,23 @@ fn main() -> ! {
6767
embedded_alloc::init!(HEAP, 1024);
6868
}
6969

70-
#[allow(clippy::type_complexity)]
7170
let tests: &[(fn() -> (), &'static str)] = &[
7271
(test_global_heap, "test_global_heap"),
7372
(test_allocator_api, "test_allocator_api"),
7473
];
7574

7675
for (test_fn, test_name) in tests {
77-
hprintln!("{}: start", test_name);
76+
defmt::info!("{}: start", test_name);
7877
test_fn();
79-
hprintln!("{}: pass", test_name);
78+
defmt::info!("{}: pass", test_name);
8079
}
8180

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

examples/tlsf_integration_test.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
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};
2424
use cortex_m_rt::entry;
25-
use cortex_m_semihosting::{debug, hprintln};
25+
use cortex_m as _;
2626
use embedded_alloc::TlsfHeap as Heap;
2727

2828
#[global_allocator]
@@ -92,13 +92,17 @@ fn main() -> ! {
9292
];
9393

9494
for (test_fn, test_name) in tests {
95-
hprintln!("{}: start", test_name);
95+
defmt::info!("{}: start", test_name);
9696
test_fn();
97-
hprintln!("{}: pass", test_name);
97+
defmt::info!("{}: pass", test_name);
9898
}
9999

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

qemu-runner.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
ELF_BINARY="$1"
7+
8+
# All suitable for thumbv7em-none-eabihf
9+
MACHINE="-cpu cortex-m4 -machine mps2-an386"
10+
# MACHINE="-cpu cortex-m7 -machine mps2-387"
11+
# MACHINE="-cpu cortex-m7 -machine mps2-500"
12+
LOG_FORMAT='{[{L}]%bold} {s} {({ff}:{l:1})%dimmed}'
13+
14+
echo "Running on '$MACHINE'..."
15+
echo "------------------------------------------------------------------------"
16+
qemu-system-arm $MACHINE -semihosting-config enable=on,target=native -nographic -kernel $ELF_BINARY | defmt-print -e $ELF_BINARY --log-format="$LOG_FORMAT"
17+
echo "------------------------------------------------------------------------"

0 commit comments

Comments
 (0)