aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/rust.yml3
-rw-r--r--.vscode/settings.json2
-rwxr-xr-xci.sh38
-rw-r--r--tests/stm32/.cargo/config.toml17
-rw-r--r--tests/stm32/Cargo.toml51
-rw-r--r--tests/stm32/build.rs16
-rw-r--r--tests/stm32/link_ram.x254
-rw-r--r--tests/stm32/src/bin/gpio.rs79
-rw-r--r--tests/stm32/src/example_common.rs17
9 files changed, 472 insertions, 5 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 7904c3856..4f5970c03 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -18,6 +18,9 @@ jobs:
18 run: exit 0 18 run: exit 0
19 build: 19 build:
20 runs-on: ubuntu-latest 20 runs-on: ubuntu-latest
21 permissions:
22 id-token: write
23 contents: read
21 steps: 24 steps:
22 - uses: actions/checkout@v2 25 - uses: actions/checkout@v2
23 with: 26 with:
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 87dd158ec..a35be8054 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,7 +16,7 @@
16 //"embassy-net/pool-16", 16 //"embassy-net/pool-16",
17 ], 17 ],
18 "rust-analyzer.linkedProjects": [ 18 "rust-analyzer.linkedProjects": [
19 "examples/stm32g4/Cargo.toml" 19 "examples/stm32f1/Cargo.toml"
20 ], 20 ],
21 "rust-analyzer.procMacro.enable": true, 21 "rust-analyzer.procMacro.enable": true,
22 "rust-analyzer.cargo.runBuildScripts": true, 22 "rust-analyzer.cargo.runBuildScripts": true,
diff --git a/ci.sh b/ci.sh
index b5f1bdb73..613210b34 100755
--- a/ci.sh
+++ b/ci.sh
@@ -4,15 +4,16 @@ set -euo pipefail
4 4
5export CARGO_TARGET_DIR=$PWD/target_ci 5export CARGO_TARGET_DIR=$PWD/target_ci
6export RUSTFLAGS=-Dwarnings 6export RUSTFLAGS=-Dwarnings
7export DEFMT_LOG=trace
7 8
8find . -name '*.rs' -not -path '*target*' -not -path '*stm32-metapac-gen/out/*' | xargs rustfmt --check --skip-children --unstable-features --edition 2018 9#find . -name '*.rs' -not -path '*target*' -not -path '*stm32-metapac-gen/out/*' | xargs rustfmt --check --skip-children --unstable-features --edition 2018
9 10
10# Generate stm32-metapac 11# Generate stm32-metapac
11# for some reason Cargo stomps the cache if we don't specify --target. 12# for some reason Cargo stomps the cache if we don't specify --target.
12# This happens with vanilla Cargo, not just cargo-batch. Bug? 13# This happens with vanilla Cargo, not just cargo-batch. Bug?
13(cd stm32-metapac-gen; cargo run --release --target x86_64-unknown-linux-gnu) 14#(cd stm32-metapac-gen; cargo run --release --target x86_64-unknown-linux-gnu)
14rm -rf stm32-metapac 15#rm -rf stm32-metapac
15mv stm32-metapac-gen/out stm32-metapac 16#mv stm32-metapac-gen/out stm32-metapac
16 17
17cargo batch \ 18cargo batch \
18 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \ 19 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \
@@ -56,3 +57,32 @@ cargo batch \
56 --- build --release --manifest-path examples/stm32wb55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb55 \ 57 --- build --release --manifest-path examples/stm32wb55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb55 \
57 --- build --release --manifest-path examples/stm32wl55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl55 \ 58 --- build --release --manifest-path examples/stm32wl55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl55 \
58 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 59 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
60 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/stm32f4 \
61
62
63function run_elf {
64 echo Running target=$1 elf=$2
65 STATUSCODE=$(
66 curl \
67 -sS \
68 --output /dev/stderr \
69 --write-out "%{http_code}" \
70 -H "Authorization: Bearer $TELEPROBE_TOKEN" \
71 https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2
72 )
73 echo HTTP Status code: $STATUSCODE
74 test "$STATUSCODE" -eq 200
75}
76
77if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
78 if [[ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN-}" ]]; then
79 echo No teleprobe token found, skipping running HIL tests
80 exit
81 fi
82
83 export TELEPROBE_TOKEN=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value')
84fi
85
86
87run_elf nucleo-stm32f429zi out/tests/stm32f4/gpio
88
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
new file mode 100644
index 000000000..40a13ddd3
--- /dev/null
+++ b/tests/stm32/.cargo/config.toml
@@ -0,0 +1,17 @@
1[unstable]
2build-std = ["core"]
3build-std-features = ["panic_immediate_abort"]
4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips`
7runner = "probe-run --chip STM32F429ZITx"
8
9rustflags = [
10 # Code-size optimizations.
11 "-Z", "trap-unreachable=no",
12 "-C", "inline-threshold=5",
13 "-C", "no-vectorize-loops",
14]
15
16[build]
17target = "thumbv7em-none-eabi"
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
new file mode 100644
index 000000000..f64043a86
--- /dev/null
+++ b/tests/stm32/Cargo.toml
@@ -0,0 +1,51 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-stm32-tests"
5version = "0.1.0"
6resolver = "2"
7
8[dependencies]
9embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] }
10embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim2"] }
12
13defmt = "0.3.0"
14defmt-rtt = "0.3.0"
15
16cortex-m = "0.7.3"
17cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6"
19panic-probe = { version = "0.3.0", features = ["print-defmt"] }
20
21[profile.dev]
22codegen-units = 1
23debug = 2
24debug-assertions = true
25incremental = false
26opt-level = 's'
27overflow-checks = true
28
29[profile.release]
30codegen-units = 1
31debug = 2
32debug-assertions = false
33incremental = false
34lto = "fat"
35opt-level = 's'
36overflow-checks = false
37
38# do not optimize proc-macro crates = faster builds from scratch
39[profile.dev.build-override]
40codegen-units = 8
41debug = false
42debug-assertions = false
43opt-level = 0
44overflow-checks = false
45
46[profile.release.build-override]
47codegen-units = 8
48debug = false
49debug-assertions = false
50opt-level = 0
51overflow-checks = false
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
new file mode 100644
index 000000000..6f4872249
--- /dev/null
+++ b/tests/stm32/build.rs
@@ -0,0 +1,16 @@
1use std::error::Error;
2use std::path::PathBuf;
3use std::{env, fs};
4
5fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=link_ram.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14
15 Ok(())
16}
diff --git a/tests/stm32/link_ram.x b/tests/stm32/link_ram.x
new file mode 100644
index 000000000..d23ffc747
--- /dev/null
+++ b/tests/stm32/link_ram.x
@@ -0,0 +1,254 @@
1/* ##### EMBASSY NOTE
2 Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in
3 Adjusted to put everything in RAM
4*/
5
6/* # Developer notes
7
8- Symbols that start with a double underscore (__) are considered "private"
9
10- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
11 overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
12 static mut __sbss }`).
13
14- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
15 symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
16 needed" by any of the preceding objects (linker arguments)
17
18- `PROVIDE` is used to provide default values that can be overridden by a user linker script
19
20- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
21 the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
22 routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
23 "Address (..) is out of bounds" in the disassembly produced by `objdump`.
24*/
25
26/* Provides information about the memory layout of the device */
27/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */
28INCLUDE memory.x
29
30/* # Entry point = reset vector */
31EXTERN(__RESET_VECTOR);
32EXTERN(Reset);
33ENTRY(Reset);
34
35/* # Exception vectors */
36/* This is effectively weak aliasing at the linker level */
37/* The user can override any of these aliases by defining the corresponding symbol themselves (cf.
38 the `exception!` macro) */
39EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */
40
41EXTERN(DefaultHandler);
42
43PROVIDE(NonMaskableInt = DefaultHandler);
44EXTERN(HardFaultTrampoline);
45PROVIDE(MemoryManagement = DefaultHandler);
46PROVIDE(BusFault = DefaultHandler);
47PROVIDE(UsageFault = DefaultHandler);
48PROVIDE(SecureFault = DefaultHandler);
49PROVIDE(SVCall = DefaultHandler);
50PROVIDE(DebugMonitor = DefaultHandler);
51PROVIDE(PendSV = DefaultHandler);
52PROVIDE(SysTick = DefaultHandler);
53
54PROVIDE(DefaultHandler = DefaultHandler_);
55PROVIDE(HardFault = HardFault_);
56
57/* # Interrupt vectors */
58EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
59
60/* # Pre-initialization function */
61/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
62 then the function this points to will be called before the RAM is initialized. */
63PROVIDE(__pre_init = DefaultPreInit);
64
65/* # Sections */
66SECTIONS
67{
68 PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
69
70 /* ## Sections in RAM */
71 /* ### Vector table */
72 .vector_table ORIGIN(RAM) :
73 {
74 /* Initial Stack Pointer (SP) value */
75 LONG(_stack_start);
76
77 /* Reset vector */
78 KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
79 __reset_vector = .;
80
81 /* Exceptions */
82 KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
83 __eexceptions = .;
84
85 /* Device specific interrupts */
86 KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
87 } > RAM
88
89 PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
90
91 /* ### .text */
92 .text _stext :
93 {
94 __stext = .;
95 *(.Reset);
96
97 *(.text .text.*);
98
99 /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
100 so must be placed close to it. */
101 *(.HardFaultTrampoline);
102 *(.HardFault.*);
103
104 . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */
105 __etext = .;
106 } > RAM
107
108 /* ### .rodata */
109 .rodata : ALIGN(4)
110 {
111 . = ALIGN(4);
112 __srodata = .;
113 *(.rodata .rodata.*);
114
115 /* 4-byte align the end (VMA) of this section.
116 This is required by LLD to ensure the LMA of the following .data
117 section will have the correct alignment. */
118 . = ALIGN(4);
119 __erodata = .;
120 } > RAM
121
122 /* ## Sections in RAM */
123 /* ### .data */
124 .data : ALIGN(4)
125 {
126 . = ALIGN(4);
127 __sdata = .;
128 *(.data .data.*);
129 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
130 } > RAM
131 /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to
132 * use the .data loading mechanism by pushing __edata. Note: do not change
133 * output region or load region in those user sections! */
134 . = ALIGN(4);
135 __edata = .;
136
137 /* LMA of .data */
138 __sidata = LOADADDR(.data);
139
140 /* ### .gnu.sgstubs
141 This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
142 /* Security Attribution Unit blocks must be 32 bytes aligned. */
143 /* Note that this pads the RAM usage to 32 byte alignment. */
144 .gnu.sgstubs : ALIGN(32)
145 {
146 . = ALIGN(32);
147 __veneer_base = .;
148 *(.gnu.sgstubs*)
149 . = ALIGN(32);
150 __veneer_limit = .;
151 } > RAM
152
153 /* ### .bss */
154 .bss (NOLOAD) : ALIGN(4)
155 {
156 . = ALIGN(4);
157 __sbss = .;
158 *(.bss .bss.*);
159 *(COMMON); /* Uninitialized C statics */
160 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
161 } > RAM
162 /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to
163 * use the .bss zeroing mechanism by pushing __ebss. Note: do not change
164 * output region or load region in those user sections! */
165 . = ALIGN(4);
166 __ebss = .;
167
168 /* ### .uninit */
169 .uninit (NOLOAD) : ALIGN(4)
170 {
171 . = ALIGN(4);
172 __suninit = .;
173 *(.uninit .uninit.*);
174 . = ALIGN(4);
175 __euninit = .;
176 } > RAM
177
178 /* Place the heap right after `.uninit` in RAM */
179 PROVIDE(__sheap = __euninit);
180
181 /* ## .got */
182 /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
183 the input files and raise an error if relocatable code is found */
184 .got (NOLOAD) :
185 {
186 KEEP(*(.got .got.*));
187 }
188
189 /* ## Discarded sections */
190 /DISCARD/ :
191 {
192 /* Unused exception related info that only wastes space */
193 *(.ARM.exidx);
194 *(.ARM.exidx.*);
195 *(.ARM.extab.*);
196 }
197}
198
199/* Do not exceed this mark in the error messages below | */
200/* # Alignment checks */
201ASSERT(ORIGIN(RAM) % 4 == 0, "
202ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
203
204ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
205BUG(cortex-m-rt): .data is not 4-byte aligned");
206
207ASSERT(__sidata % 4 == 0, "
208BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
209
210ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
211BUG(cortex-m-rt): .bss is not 4-byte aligned");
212
213ASSERT(__sheap % 4 == 0, "
214BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
215
216/* # Position checks */
217
218/* ## .vector_table */
219ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
220BUG(cortex-m-rt): the reset vector is missing");
221
222ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
223BUG(cortex-m-rt): the exception vectors are missing");
224
225ASSERT(SIZEOF(.vector_table) > 0x40, "
226ERROR(cortex-m-rt): The interrupt vectors are missing.
227Possible solutions, from most likely to less likely:
228- Link to a svd2rust generated device crate
229- Check that you actually use the device/hal/bsp crate in your code
230- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
231may be enabling it)
232- Supply the interrupt handlers yourself. Check the documentation for details.");
233
234/* ## .text */
235ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
236ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
237Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
238
239ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), "
240ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory.
241Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'");
242
243/* # Other checks */
244ASSERT(SIZEOF(.got) == 0, "
245ERROR(cortex-m-rt): .got section detected in the input object files
246Dynamic relocations are not supported. If you are linking to C code compiled using
247the 'cc' crate then modify your build script to compile the C code _without_
248the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
249/* Do not exceed this mark in the error messages above | */
250
251
252/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */
253/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */
254INCLUDE device.x \ No newline at end of file
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
new file mode 100644
index 000000000..7f7fccbfd
--- /dev/null
+++ b/tests/stm32/src/bin/gpio.rs
@@ -0,0 +1,79 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use defmt::assert;
8use embassy::executor::Spawner;
9use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
10use embassy_stm32::Peripherals;
11use embedded_hal::digital::v2::{InputPin, OutputPin};
12use example_common::*;
13
14#[embassy::main]
15async fn main(_spawner: Spawner, p: Peripherals) {
16 info!("Hello World!");
17
18 let (mut a, mut b) = (p.PG14, p.PG9);
19
20 // Test initial output
21 {
22 let b = Input::new(&mut b, Pull::None);
23
24 {
25 let _a = Output::new(&mut a, Level::Low, Speed::Low);
26 cortex_m::asm::delay(1000);
27 assert!(b.is_low().unwrap());
28 }
29 {
30 let _a = Output::new(&mut a, Level::High, Speed::Low);
31 cortex_m::asm::delay(1000);
32 assert!(b.is_high().unwrap());
33 }
34 }
35
36 // Test input no pull
37 {
38 let b = Input::new(&mut b, Pull::None);
39 // no pull, the status is undefined
40
41 let mut a = Output::new(&mut a, Level::Low, Speed::Low);
42 cortex_m::asm::delay(1000);
43 assert!(b.is_low().unwrap());
44 a.set_high().unwrap();
45 cortex_m::asm::delay(1000);
46 assert!(b.is_high().unwrap());
47 }
48
49 // Test input pulldown
50 {
51 let b = Input::new(&mut b, Pull::Down);
52 cortex_m::asm::delay(1000);
53 assert!(b.is_low().unwrap());
54
55 let mut a = Output::new(&mut a, Level::Low, Speed::Low);
56 cortex_m::asm::delay(1000);
57 assert!(b.is_low().unwrap());
58 a.set_high().unwrap();
59 cortex_m::asm::delay(1000);
60 assert!(b.is_high().unwrap());
61 }
62
63 // Test input pullup
64 {
65 let b = Input::new(&mut b, Pull::Up);
66 cortex_m::asm::delay(1000);
67 assert!(b.is_high().unwrap());
68
69 let mut a = Output::new(&mut a, Level::Low, Speed::Low);
70 cortex_m::asm::delay(1000);
71 assert!(b.is_low().unwrap());
72 a.set_high().unwrap();
73 cortex_m::asm::delay(1000);
74 assert!(b.is_high().unwrap());
75 }
76
77 info!("Test OK");
78 cortex_m::asm::bkpt();
79}
diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs
new file mode 100644
index 000000000..54d633837
--- /dev/null
+++ b/tests/stm32/src/example_common.rs
@@ -0,0 +1,17 @@
1#![macro_use]
2
3use defmt_rtt as _; // global logger
4use panic_probe as _;
5
6pub use defmt::*;
7
8use core::sync::atomic::{AtomicUsize, Ordering};
9
10defmt::timestamp! {"{=u64}", {
11 static COUNT: AtomicUsize = AtomicUsize::new(0);
12 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
13 let n = COUNT.load(Ordering::Relaxed);
14 COUNT.store(n + 1, Ordering::Relaxed);
15 n as u64
16 }
17}