Skip to content

Commit b9e1832

Browse files
bors[bot]newAM
andauthored
Merge #355
355: Add on-target tests to CI r=thejpster a=newAM A week ago in the rust-embedded matrix chat `@adamgreig` mentioned that on-target CI would be helpful for the `cortex-m` and `cortex-m-rt` crates. This is a pull-request to make that happen. ## History: Bootstrapping and `cortex-m-rt` The first problem I came across was the amount of boilerplate required to build an on-target binary without `cortex-m-rt`. There are two paths forward here: 1. Introduce a lot of boilerplate in `cortex-m`, which will largely be copy-pasted from `cortex-m-rt`. 2. Relocate `cortex-m-rt` to this workspace. In (#391) `cortex-m-rt` was relocated to this workspace to fix the bootstrapping problem. ## Test Execution Tests run with QEMU and physical hardware. QEMU uses the LM3S6965 Cortex-M3 target because it is widely used. The physical hardware is a NUCLEO-F070RB connected to a self-hosted runner. In the future more hardware can be added to cover more CPUs. Due to reliability concerns with self-hosted runners only QEMU will be a required status check in CI, the physical hardware checks will be informational only. ### CI Software The CI software for running on physical hardware is simply a self-hosted github actions runner. A working demonstration of this can be found [here](https://github.com/newAM/totally-not-a-cortex-m-fork/runs/5345451343?check_suite_focus=true) (the repository does not appear as a fork to work around github actions limitations with forks). The runner uses [`probe-run`] to execute the tests on embedded hardware. [`probe-run`] was chosen for several reasons: * Actively maintained by [knurling-rs], with an actively maintained back-end from [`probe-rs`]. * Written in rust. Understanding the code does not require contributors to learn a new language. * Designed with on-target testing as a primary goal (for use with [`defmt-test`]). * Automatic unwinding and backtrace display. ## Test Harness This PR introduces a test harness, `minitest`. `minitest` is almost identical to [`defmt-test`], the only difference is that it replaces [`defmt`] with [`rtt-target`] because [`defmt`] introduces a dependency cycle on `cortex-m`. This is harness is very minimal, adding only 327 lines of rust: ```console $ tokei testsuite/minitest =============================================================================== Language Files Lines Code Comments Blanks =============================================================================== Markdown 1 7 0 4 3 TOML 2 41 34 0 7 ------------------------------------------------------------------------------- Rust 3 406 350 5 51 |- Markdown 1 8 0 7 1 (Total) 414 350 12 52 =============================================================================== Total 6 454 384 9 61 =============================================================================== ``` The test harness does introduce some abstraction, and may not be suitable for all tests. Lower-level tests are still possible without the harness using `asm::udf` to fail the test, and `asm::bkpt` to exit without failure. ## Reliability and Uptime I have been doing automatic on-target testing for the [`stm32wlxx-hal`] using [`probe-run`]. Over hundreds of automatic runs spanning several months I have had no failures as a result of external factors (USB connectivity, programming errors, ect.). I do not anticipate on-target CI being perfect, but at the same time I do not anticipate frequent problems. [`defmt-test`]: https://github.com/knurling-rs/defmt/tree/main/firmware/defmt-test [`defmt`]: https://ferrous-systems.com/blog/defmt/ [`probe-rs`]: https://probe.rs/ [`probe-run`]: https://github.com/knurling-rs/probe-run [`rtt-target`]: https://crates.io/crates/rtt-target [`stm32wlxx-hal`]: https://github.com/stm32-rs/stm32wlxx-hal [knurling-rs]: https://knurling.ferrous-systems.com/ Co-authored-by: Alex Martens <alex@thinglab.org>
2 parents b4eaadc + b4181a8 commit b9e1832

File tree

16 files changed

+735
-3
lines changed

16 files changed

+735
-3
lines changed

.github/bors.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ status = [
88
"rt-ci-linux (1.59.0)",
99
"rt-ci-other-os (macOS-latest)",
1010
"rt-ci-other-os (windows-latest)",
11+
"hil-qemu",
12+
"hil-compile-rtt",
1113
"rustfmt",
1214
"clippy",
1315
]

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ jobs:
2929
toolchain: ${{ matrix.rust }}
3030
override: true
3131
- name: Run tests
32-
run: cargo test --all --exclude cortex-m-rt
32+
run: cargo test --all --exclude cortex-m-rt --exclude testsuite
3333

3434
# FIXME: test on macOS and Windows

.github/workflows/on-target.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
on:
2+
push:
3+
branches: [ staging, trying, master ]
4+
pull_request:
5+
# allows manual triggering
6+
workflow_dispatch:
7+
8+
name: cortex-m on-target tests
9+
10+
jobs:
11+
12+
hil-qemu:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v2
16+
- uses: actions-rs/toolchain@v1
17+
with:
18+
profile: minimal
19+
toolchain: stable
20+
override: true
21+
target: thumbv7m-none-eabi
22+
- name: Build testsuite
23+
env:
24+
RUSTFLAGS: -C link-arg=-Tlink.x -D warnings
25+
run: cargo build -p testsuite --target thumbv7m-none-eabi --features testsuite/semihosting
26+
- name: Install QEMU
27+
run: sudo apt-get update && sudo apt-get install qemu qemu-system-arm
28+
- name: Run testsuite
29+
run: |
30+
qemu-system-arm \
31+
-cpu cortex-m3 \
32+
-machine lm3s6965evb \
33+
-nographic \
34+
-semihosting-config enable=on,target=native \
35+
-kernel target/thumbv7m-none-eabi/debug/testsuite
36+
37+
hil-compile-rtt:
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: actions/checkout@v2
41+
- uses: actions-rs/toolchain@v1
42+
with:
43+
profile: minimal
44+
toolchain: stable
45+
override: true
46+
target: thumbv6m-none-eabi
47+
- name: Modify linkerfile
48+
run: |
49+
sed -i 's/FLASH : ORIGIN = 0x00000000, LENGTH = 256K/FLASH : ORIGIN = 0x8000000, LENGTH = 128K/g' memory.x
50+
sed -i 's/RAM : ORIGIN = 0x20000000, LENGTH = 64K/RAM : ORIGIN = 0x20000000, LENGTH = 16K/g' memory.x
51+
- name: Build testsuite
52+
env:
53+
RUSTFLAGS: -C link-arg=-Tlink.x -D warnings
54+
run: cargo build -p testsuite --target thumbv6m-none-eabi --features testsuite/rtt
55+
- name: Upload testsuite binaries
56+
uses: actions/upload-artifact@v2
57+
with:
58+
name: testsuite-bin
59+
if-no-files-found: error
60+
retention-days: 1
61+
path: target/thumbv6m-none-eabi/debug/testsuite
62+
63+
hil-stm32:
64+
runs-on: self-hosted
65+
needs:
66+
- hil-compile-rtt
67+
steps:
68+
- uses: actions/checkout@v2
69+
- name: Display probe-run version
70+
run: probe-run --version
71+
- name: List probes
72+
run: probe-run --list-probes
73+
- uses: actions/download-artifact@v2
74+
with:
75+
name: testsuite-bin
76+
path: testsuite-bin
77+
- name: Run on-target tests
78+
timeout-minutes: 5
79+
run: |
80+
probe-run \
81+
--chip STM32F070RBTx \
82+
--connect-under-reset \
83+
testsuite-bin/testsuite

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ std = []
3535

3636
[workspace]
3737
members = [
38-
"xtask",
3938
"cortex-m-rt",
4039
"cortex-m-semihosting",
40+
"panic-itm",
4141
"panic-semihosting",
42-
"panic-itm"
42+
"testsuite",
43+
"testsuite/minitest",
44+
"testsuite/minitest/macros",
45+
"xtask",
4346
]
4447

4548
[package.metadata.docs.rs]

src/peripheral/dwt.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ impl DWT {
155155
}
156156
}
157157

158+
/// Disables the cycle counter
159+
#[cfg(not(armv6m))]
160+
#[inline]
161+
pub fn disable_cycle_counter(&mut self) {
162+
unsafe {
163+
self.ctrl.modify(|mut r| {
164+
r.set_cyccntena(false);
165+
r
166+
});
167+
}
168+
}
169+
158170
/// Returns `true` if the cycle counter is enabled
159171
#[cfg(not(armv6m))]
160172
#[inline]

testsuite/.cargo/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2+
rustflags = ["-C", "link-arg=-Tlink.x"]
3+
runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
4+
5+
[build]
6+
target = "thumbv7m-none-eabi"

testsuite/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
authors = ["The Cortex-M Team <cortex-m@teams.rust-embedded.org>"]
3+
name = "testsuite"
4+
publish = false
5+
edition = "2018"
6+
version = "0.1.0"
7+
8+
[features]
9+
rtt = ["rtt-target", "minitest/rtt"]
10+
semihosting = ["cortex-m-semihosting", "minitest/semihosting"]
11+
12+
[dependencies]
13+
cortex-m-rt.path = "../cortex-m-rt"
14+
cortex-m.path = ".."
15+
minitest.path = "minitest"
16+
17+
[dependencies.rtt-target]
18+
version = "0.3.1"
19+
optional = true
20+
21+
[dependencies.cortex-m-semihosting]
22+
path = "../cortex-m-semihosting"
23+
optional = true

testsuite/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Testsuite
2+
3+
This workspace contains tests that run on physical and simulated Cortex-M CPUs.
4+
5+
## Building
6+
7+
Exactly one of these features are required:
8+
9+
* `semihosting` Use semihosting for logging, this is used for QEMU.
10+
* `rtt` Use RTT for logging, this is used with physical cortex-m CPUs.
11+
12+
Assuming you are at the root of the repository you can build like this:
13+
14+
```console
15+
$ cd testsuite
16+
$ cargo build --features semihosting
17+
Compiling testsuite v0.1.0 (cortex-m/testsuite)
18+
Finished dev [unoptimized + debuginfo] target(s) in 0.08
19+
```
20+
21+
## Running with QEMU
22+
23+
The runner is already configured for QEMU in `testsuite/.cargo/config.toml`.
24+
Use the `semihosting` feature for logging, QEMU does not have native support for RTT.
25+
26+
For more information on QEMU reference the QEMU section in [The Embedded Rust Book].
27+
28+
```console
29+
$ cd testsuite
30+
$ cargo run --features semihosting
31+
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
32+
Running `qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel /cortex-m/target/thumbv7m-none-eabi/debug/testsuite`
33+
Timer with period zero, disabling
34+
Hello world!
35+
(1/1) running `double_take`...
36+
all tests passed!
37+
```
38+
39+
## Running with Physical Hardware
40+
41+
No implementation-specific features are tested right now; any physical `thumbv7m` target should work.
42+
43+
Tests are executed with [probe-run](https://github.com/knurling-rs/probe-run).
44+
45+
* Update `memory.x` in the root of the repository to match your target memory layout.
46+
* Change the `probe-run` chip argument to match your chip, supported chips can be found with `probe-run --list-chips`
47+
* Change the target to match your CPU
48+
49+
```console
50+
$ sed -i 's/FLASH : ORIGIN = 0x00000000, LENGTH = 256K/FLASH : ORIGIN = 0x8000000, LENGTH = 256K/g' memory.x
51+
$ cd testsuite
52+
$ cargo build --target thumbv7em-none-eabi --features rtt
53+
Compiling minitest v0.1.0 (/cortex-m/testsuite/minitest)
54+
Compiling testsuite v0.1.0 (/cortex-m/testsuite)
55+
Finished dev [unoptimized + debuginfo] target(s) in 0.16s
56+
$ probe-run --chip STM32WLE5JCIx --connect-under-reset ../target/thumbv7em-none-eabi/debug/testsuite
57+
(HOST) INFO flashing program (19 pages / 19.00 KiB)
58+
(HOST) INFO success!
59+
────────────────────────────────────────────────────────────────────────────────
60+
Hello world!
61+
(1/2) running `double_take`...
62+
(2/2) running `cycle_count`...
63+
all tests passed!
64+
────────────────────────────────────────────────────────────────────────────────
65+
(HOST) INFO device halted without error
66+
```
67+
68+
[The Embedded Rust Book]: https://docs.rust-embedded.org/book/start/qemu.html
69+
[probe-run]: https://github.com/knurling-rs/probe-run

testsuite/build.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fn main() {
2+
let target = std::env::var("TARGET").unwrap();
3+
4+
if target.starts_with("thumbv6m-") {
5+
println!("cargo:rustc-cfg=armv6m");
6+
} else if target.starts_with("thumbv7m-") {
7+
println!("cargo:rustc-cfg=armv7m");
8+
} else if target.starts_with("thumbv7em-") {
9+
println!("cargo:rustc-cfg=armv7m");
10+
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
11+
} else if target.starts_with("thumbv8m.base") {
12+
println!("cargo:rustc-cfg=armv8m");
13+
println!("cargo:rustc-cfg=armv8m_base");
14+
} else if target.starts_with("thumbv8m.main") {
15+
println!("cargo:rustc-cfg=armv8m");
16+
println!("cargo:rustc-cfg=armv8m_main");
17+
}
18+
}

testsuite/minitest/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
authors = ["The Cortex-M Team <cortex-m@teams.rust-embedded.org>"]
3+
name = "minitest"
4+
publish = false
5+
edition = "2018"
6+
version = "0.1.0"
7+
8+
[features]
9+
semihosting = ["cortex-m-semihosting", "minitest-macros/semihosting"]
10+
rtt = ["rtt-target", "minitest-macros/rtt"]
11+
12+
[dependencies]
13+
cortex-m.path = "../.."
14+
cortex-m-rt.path = "../../cortex-m-rt"
15+
minitest-macros.path = "macros"
16+
17+
[dependencies.rtt-target]
18+
version = "0.3.1"
19+
optional = true
20+
21+
[dependencies.cortex-m-semihosting]
22+
path = "../../cortex-m-semihosting"
23+
optional = true

0 commit comments

Comments
 (0)