aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-05-30 13:24:15 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-05-30 13:24:15 +0200
commit392ed64f6f6a02de2440d1e1c1c7f3a784d9d1f8 (patch)
tree321ee7c844803c306f0f7a364bebc614e85914f4
parent94046f30ffefc96a7b110ed1d9bb60d64cb4780f (diff)
parent1d34078fa11839f88dd2e47a9355c6b35755128f (diff)
Merge remote-tracking branch 'upstream/main' into remove-bootloader-partitions
-rwxr-xr-x.github/ci/build.sh1
-rwxr-xr-x.github/ci/test.sh4
-rw-r--r--.vscode/.gitignore3
-rwxr-xr-xci.sh43
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml4
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml2
-rw-r--r--embassy-boot/nrf/Cargo.toml2
-rw-r--r--embassy-nrf/Cargo.toml33
-rw-r--r--embassy-nrf/README.md2
-rw-r--r--embassy-nrf/src/qdec.rs13
-rw-r--r--embassy-nrf/src/temp.rs13
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/flash.rs1
-rw-r--r--embassy-rp/src/intrinsics.rs19
-rw-r--r--embassy-rp/src/multicore.rs25
-rw-r--r--embassy-rp/src/rtc/mod.rs2
-rw-r--r--embassy-stm32/src/dma/bdma.rs40
-rw-r--r--embassy-stm32/src/dma/dma.rs40
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs537
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/usart/mod.rs50
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs (renamed from embassy-stm32/src/usart/rx_ringbuffered.rs)182
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml4
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml4
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml4
-rw-r--r--tests/nrf/.cargo/config.toml2
-rw-r--r--tests/nrf/Cargo.toml2
-rw-r--r--tests/nrf/build.rs1
-rw-r--r--tests/nrf/src/bin/buffered_uart.rs2
-rw-r--r--tests/nrf/src/bin/buffered_uart_spam.rs2
-rw-r--r--tests/nrf/src/bin/timer.rs2
-rw-r--r--tests/nrf/src/common.rs1
-rw-r--r--tests/rp/.cargo/config.toml4
-rw-r--r--tests/rp/Cargo.toml2
-rw-r--r--tests/rp/build.rs1
-rw-r--r--tests/rp/src/bin/dma_copy_async.rs2
-rw-r--r--tests/rp/src/bin/flash.rs2
-rw-r--r--tests/rp/src/bin/float.rs2
-rw-r--r--tests/rp/src/bin/gpio.rs2
-rw-r--r--tests/rp/src/bin/gpio_async.rs2
-rw-r--r--tests/rp/src/bin/gpio_multicore.rs2
-rw-r--r--tests/rp/src/bin/multicore.rs2
-rw-r--r--tests/rp/src/bin/pwm.rs2
-rw-r--r--tests/rp/src/bin/spi.rs2
-rw-r--r--tests/rp/src/bin/spi_async.rs2
-rw-r--r--tests/rp/src/bin/uart.rs2
-rw-r--r--tests/rp/src/bin/uart_buffered.rs2
-rw-r--r--tests/rp/src/bin/uart_dma.rs2
-rw-r--r--tests/rp/src/bin/uart_upgrade.rs2
-rw-r--r--tests/rp/src/common.rs1
-rw-r--r--tests/stm32/.cargo/config.toml2
-rw-r--r--tests/stm32/Cargo.toml2
-rw-r--r--tests/stm32/build.rs1
-rw-r--r--tests/stm32/src/bin/gpio.rs6
-rw-r--r--tests/stm32/src/bin/rtc.rs8
-rw-r--r--tests/stm32/src/bin/sdmmc.rs2
-rw-r--r--tests/stm32/src/bin/spi.rs6
-rw-r--r--tests/stm32/src/bin/spi_dma.rs6
-rw-r--r--tests/stm32/src/bin/timer.rs6
-rw-r--r--tests/stm32/src/bin/tl_mbox.rs10
-rw-r--r--tests/stm32/src/bin/usart.rs6
-rw-r--r--tests/stm32/src/bin/usart_dma.rs6
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs6
-rw-r--r--tests/stm32/src/common.rs44
-rw-r--r--tests/stm32/src/example_common.rs25
65 files changed, 663 insertions, 559 deletions
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index 1c3a7f3b0..30ca1e6f0 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -9,6 +9,7 @@ export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10if [ -f /ci/secrets/teleprobe-token.txt ]; then 10if [ -f /ci/secrets/teleprobe-token.txt ]; then
11 echo Got teleprobe token! 11 echo Got teleprobe token!
12 export TELEPROBE_HOST=https://teleprobe.embassy.dev
12 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) 13 export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt)
13fi 14fi
14 15
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index a7140cfd9..d014e4bd7 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -21,7 +21,9 @@ cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly
21cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-dalek 21cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-dalek
22cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-salty 22cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-salty
23 23
24#cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nightly,nrf52840,time-driver-rtc1 ## broken doctests 24cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nightly,nrf52840,time-driver-rtc1,gpiote
25
26cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features nightly,time-driver
25 27
26cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti 28cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti
27cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti 29cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti
diff --git a/.vscode/.gitignore b/.vscode/.gitignore
index 9fbb9ec95..8c3dd8a31 100644
--- a/.vscode/.gitignore
+++ b/.vscode/.gitignore
@@ -1,3 +1,4 @@
1*.cortex-debug.*.json 1*.cortex-debug.*.json
2launch.json 2launch.json
3tasks.json \ No newline at end of file 3tasks.json
4*.cfg
diff --git a/ci.sh b/ci.sh
index 11c569328..1eafda3a3 100755
--- a/ci.sh
+++ b/ci.sh
@@ -12,7 +12,7 @@ if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then
12 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" 12 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std"
13fi 13fi
14 14
15find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2018 15find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
16 16
17cargo batch \ 17cargo batch \
18 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ 18 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
@@ -127,45 +127,24 @@ cargo batch \
127 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 127 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
128 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 128 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
129 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 129 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
130 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/bluepill-stm32f103c8 \ 130 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
131 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/nucleo-stm32f429zi \ 131 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
132 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/nucleo-stm32g491re \ 132 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \
133 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/nucleo-stm32g071rb \ 133 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
134 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/nucleo-stm32c031c6 \ 134 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
135 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ 135 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
136 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ 136 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
137 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/nucleo-stm32h563zi \ 137 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
138 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ 138 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
139 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 139 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
140 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ 140 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
141 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ 141 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
142 $BUILD_EXTRA 142 $BUILD_EXTRA
143 143
144 144
145
146function run_elf {
147 echo Running target=$1 elf=$2
148 STATUSCODE=$(
149 curl \
150 -sS \
151 --output /dev/stderr \
152 --write-out "%{http_code}" \
153 -H "Authorization: Bearer $TELEPROBE_TOKEN" \
154 https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2
155 )
156 echo
157 echo HTTP Status code: $STATUSCODE
158 test "$STATUSCODE" -eq 200
159}
160
161if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 145if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
162 echo No teleprobe token found, skipping running HIL tests 146 echo No teleprobe token found, skipping running HIL tests
163 exit 147 exit
164fi 148fi
165 149
166for board in $(ls out/tests); do 150teleprobe client run -r out/tests \ No newline at end of file
167 echo Running tests for board: $board
168 for elf in $(ls out/tests/$board); do
169 run_elf $board out/tests/$board/$elf
170 done
171done
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
index 523de0ddf..a7236ed5e 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
@@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8cortex-m = "0.7" 8cortex-m = "0.7"
9cortex-m-rt = "0.7" 9cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"], default-features = false } 10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
11embassy-executor = { version = "0.2.0", default-features = false, features = ["nightly", "arch-cortex-m", "executor-thread"] } 11embassy-executor = { version = "0.2.0", features = ["nightly", "arch-cortex-m", "executor-thread"] }
12 12
13defmt = "0.3.0" 13defmt = "0.3.0"
14defmt-rtt = "0.3.0" 14defmt-rtt = "0.3.0"
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml
index f86361dd5..c15de2db2 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8cortex-m = "0.7" 8cortex-m = "0.7"
9cortex-m-rt = "0.7" 9cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x"], default-features = false } 10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x"] }
11 11
12defmt = "0.3.0" 12defmt = "0.3.0"
13defmt-rtt = "0.3.0" 13defmt-rtt = "0.3.0"
diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml
index e46736889..8186a9958 100644
--- a/embassy-boot/nrf/Cargo.toml
+++ b/embassy-boot/nrf/Cargo.toml
@@ -17,7 +17,7 @@ target = "thumbv7em-none-eabi"
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
18 18
19embassy-sync = { path = "../../embassy-sync" } 19embassy-sync = { path = "../../embassy-sync" }
20embassy-nrf = { path = "../../embassy-nrf", default-features = false } 20embassy-nrf = { path = "../../embassy-nrf" }
21embassy-boot = { path = "../boot", default-features = false } 21embassy-boot = { path = "../boot", default-features = false }
22cortex-m = { version = "0.7.6" } 22cortex-m = { version = "0.7.6" }
23cortex-m-rt = { version = "0.7" } 23cortex-m-rt = { version = "0.7" }
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 15d0f6872..83900d4d0 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -16,6 +16,18 @@ flavors = [
16] 16]
17 17
18[features] 18[features]
19default = [
20 "nrf52805-pac?/rt",
21 "nrf52810-pac?/rt",
22 "nrf52811-pac?/rt",
23 "nrf52820-pac?/rt",
24 "nrf52832-pac?/rt",
25 "nrf52833-pac?/rt",
26 "nrf52840-pac?/rt",
27 "nrf5340-app-pac?/rt",
28 "nrf5340-net-pac?/rt",
29 "nrf9160-pac?/rt",
30]
19 31
20time = ["dep:embassy-time"] 32time = ["dep:embassy-time"]
21 33
@@ -103,13 +115,14 @@ embedded-storage = "0.3.0"
103embedded-storage-async = { version = "0.4.0", optional = true } 115embedded-storage-async = { version = "0.4.0", optional = true }
104cfg-if = "1.0.0" 116cfg-if = "1.0.0"
105 117
106nrf52805-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 118nrf52805-pac = { version = "0.12.0", optional = true }
107nrf52810-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 119nrf52810-pac = { version = "0.12.0", optional = true }
108nrf52811-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 120nrf52811-pac = { version = "0.12.0", optional = true }
109nrf52820-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 121nrf52820-pac = { version = "0.12.0", optional = true }
110nrf52832-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 122nrf52832-pac = { version = "0.12.0", optional = true }
111nrf52833-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 123nrf52833-pac = { version = "0.12.0", optional = true }
112nrf52840-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 124nrf52840-pac = { version = "0.12.0", optional = true }
113nrf5340-app-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 125nrf5340-app-pac = { version = "0.12.0", optional = true }
114nrf5340-net-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 126nrf5340-net-pac = { version = "0.12.0", optional = true }
115nrf9160-pac = { version = "0.12.0", optional = true, features = [ "rt" ] } 127nrf9160-pac = { version = "0.12.0", optional = true }
128
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index a31cfae68..129ec0c01 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -13,7 +13,7 @@ with peripherals. It takes care of sending/receiving data over a variety of bus
13However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust 13However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
14slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen: 14slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen:
15 15
16```no_run 16```rust,ignore
17// As we pass a slice to the function whose contents will not ever change, 17// As we pass a slice to the function whose contents will not ever change,
18// the compiler writes it into the flash and thus the pointer to it will 18// the compiler writes it into the flash and thus the pointer to it will
19// reference static memory. Since EasyDMA requires slices to reside in RAM, 19// reference static memory. Since EasyDMA requires slices to reside in RAM,
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 4d2a09198..c845492fc 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -154,10 +154,19 @@ impl<'d, T: Instance> Qdec<'d, T> {
154 /// # Example 154 /// # Example
155 /// 155 ///
156 /// ```no_run 156 /// ```no_run
157 /// let irq = interrupt::take!(QDEC); 157 /// use embassy_nrf::qdec::{self, Qdec};
158 /// use embassy_nrf::{bind_interrupts, peripherals};
159 ///
160 /// bind_interrupts!(struct Irqs {
161 /// QDEC => qdec::InterruptHandler<peripherals::QDEC>;
162 /// });
163 ///
164 /// # async {
165 /// # let p: embassy_nrf::Peripherals = todo!();
158 /// let config = qdec::Config::default(); 166 /// let config = qdec::Config::default();
159 /// let mut q = Qdec::new(p.QDEC, p.P0_31, p.P0_30, config); 167 /// let mut q = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
160 /// let delta = q.read().await; 168 /// let delta = q.read().await;
169 /// # };
161 /// ``` 170 /// ```
162 pub async fn read(&mut self) -> i16 { 171 pub async fn read(&mut self) -> i16 {
163 let t = T::regs(); 172 let t = T::regs();
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 3a75ec629..0653710af 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -56,8 +56,19 @@ impl<'d> Temp<'d> {
56 /// # Example 56 /// # Example
57 /// 57 ///
58 /// ```no_run 58 /// ```no_run
59 /// let mut t = Temp::new(p.TEMP, interrupt::take!(TEMP)); 59 /// use embassy_nrf::{bind_interrupts, temp};
60 /// use embassy_nrf::temp::Temp;
61 /// use embassy_time::{Duration, Timer};
62 ///
63 /// bind_interrupts!(struct Irqs {
64 /// TEMP => temp::InterruptHandler;
65 /// });
66 ///
67 /// # async {
68 /// # let p: embassy_nrf::Peripherals = todo!();
69 /// let mut t = Temp::new(p.TEMP, Irqs);
60 /// let v: u16 = t.read().await.to_num::<u16>(); 70 /// let v: u16 = t.read().await.to_num::<u16>();
71 /// # };
61 /// ``` 72 /// ```
62 pub async fn read(&mut self) -> I30F2 { 73 pub async fn read(&mut self) -> I30F2 {
63 // In case the future is dropped, stop the task and reset events. 74 // In case the future is dropped, stop the task and reset events.
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index e395a994f..e032dfdae 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -13,6 +13,8 @@ flavors = [
13] 13]
14 14
15[features] 15[features]
16default = [ "rp-pac/rt" ]
17
16defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"] 18defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
17 19
18# critical section that is safe for multicore use 20# critical section that is safe for multicore use
@@ -70,7 +72,7 @@ embedded-storage = { version = "0.3" }
70rand_core = "0.6.4" 72rand_core = "0.6.4"
71fixed = "1.23.1" 73fixed = "1.23.1"
72 74
73rp-pac = { version = "4", features = ["rt"] } 75rp-pac = { version = "4" }
74 76
75embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 77embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
76embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 78embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
@@ -81,3 +83,7 @@ paste = "1.0"
81pio-proc = {version= "0.2" } 83pio-proc = {version= "0.2" }
82pio = {version= "0.2.1" } 84pio = {version= "0.2.1" }
83rp2040-boot2 = "0.3" 85rp2040-boot2 = "0.3"
86
87[dev-dependencies]
88embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
89static_cell = "1.0"
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 929bd028c..0410429e0 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -575,6 +575,7 @@ mod ram_helpers {
575 #[inline(never)] 575 #[inline(never)]
576 #[link_section = ".data.ram_func"] 576 #[link_section = ".data.ram_func"]
577 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { 577 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
578 #[cfg(target_arch = "arm")]
578 core::arch::asm!( 579 core::arch::asm!(
579 "mov r10, r0", // cmd 580 "mov r10, r0", // cmd
580 "mov r5, r1", // ptrs 581 "mov r5, r1", // ptrs
diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs
index 3baabb287..5b9c127ba 100644
--- a/embassy-rp/src/intrinsics.rs
+++ b/embassy-rp/src/intrinsics.rs
@@ -61,16 +61,17 @@ macro_rules! intrinsics_aliases {
61/// Like the compiler-builtins macro, it accepts a series of functions that 61/// Like the compiler-builtins macro, it accepts a series of functions that
62/// looks like normal Rust code: 62/// looks like normal Rust code:
63/// 63///
64/// intrinsics! { 64/// ```rust,ignore
65/// extern "C" fn foo(a: i32) -> u32 { 65/// intrinsics! {
66/// // ... 66/// extern "C" fn foo(a: i32) -> u32 {
67/// } 67/// // ...
68/// 68/// }
69/// #[nonstandard_attribute] 69/// #[nonstandard_attribute]
70/// extern "C" fn bar(a: i32) -> u32 { 70/// extern "C" fn bar(a: i32) -> u32 {
71/// // ... 71/// // ...
72/// }
73/// } 72/// }
73/// }
74/// ```
74/// 75///
75/// Each function can also be decorated with nonstandard attributes to control 76/// Each function can also be decorated with nonstandard attributes to control
76/// additional behaviour: 77/// additional behaviour:
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index bbc775105..a13209f74 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -9,22 +9,41 @@
9//! the `embassy-sync` primitives and `CriticalSectionRawMutex`. 9//! the `embassy-sync` primitives and `CriticalSectionRawMutex`.
10//! 10//!
11//! # Usage 11//! # Usage
12//!
12//! ```no_run 13//! ```no_run
14//! # #![feature(type_alias_impl_trait)]
15//! use embassy_rp::multicore::Stack;
16//! use static_cell::StaticCell;
17//! use embassy_executor::Executor;
18//!
13//! static mut CORE1_STACK: Stack<4096> = Stack::new(); 19//! static mut CORE1_STACK: Stack<4096> = Stack::new();
14//! static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); 20//! static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
15//! static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); 21//! static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
16//! 22//!
23//! # // workaround weird error: `main` function not found in crate `rust_out`
24//! # let _ = ();
25//!
26//! #[embassy_executor::task]
27//! async fn core0_task() {
28//! // ...
29//! }
30//!
31//! #[embassy_executor::task]
32//! async fn core1_task() {
33//! // ...
34//! }
35//!
17//! #[cortex_m_rt::entry] 36//! #[cortex_m_rt::entry]
18//! fn main() -> ! { 37//! fn main() -> ! {
19//! let p = embassy_rp::init(Default::default()); 38//! let p = embassy_rp::init(Default::default());
20//! 39//!
21//! spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { 40//! embassy_rp::multicore::spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
22//! let executor1 = EXECUTOR1.init(Executor::new()); 41//! let executor1 = EXECUTOR1.init(Executor::new());
23//! executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); 42//! executor1.run(|spawner| spawner.spawn(core1_task()).unwrap());
24//! }); 43//! });
25//! 44//!
26//! let executor0 = EXECUTOR0.init(Executor::new()); 45//! let executor0 = EXECUTOR0.init(Executor::new());
27//! executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); 46//! executor0.run(|spawner| spawner.spawn(core0_task()).unwrap())
28//! } 47//! }
29//! ``` 48//! ```
30 49
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index c213ad174..e1d886d4a 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -121,7 +121,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
121 /// # #[cfg(not(feature = "chrono"))] 121 /// # #[cfg(not(feature = "chrono"))]
122 /// # fn main() { 122 /// # fn main() {
123 /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter}; 123 /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter};
124 /// # let mut real_time_clock: RealTimeClock = unsafe { core::mem::zeroed() }; 124 /// # let mut real_time_clock: RealTimeClock<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
125 /// let now = real_time_clock.now().unwrap(); 125 /// let now = real_time_clock.now().unwrap();
126 /// real_time_clock.schedule_alarm( 126 /// real_time_clock.schedule_alarm(
127 /// DateTimeFilter::default() 127 /// DateTimeFilter::default()
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 0202ec379..9dafa26d0 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -111,24 +111,18 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
111 panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); 111 panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num);
112 } 112 }
113 113
114 let mut wake = false;
115
116 if isr.htif(channel_num) && cr.read().htie() { 114 if isr.htif(channel_num) && cr.read().htie() {
117 // Acknowledge half transfer complete interrupt 115 // Acknowledge half transfer complete interrupt
118 dma.ifcr().write(|w| w.set_htif(channel_num, true)); 116 dma.ifcr().write(|w| w.set_htif(channel_num, true));
119 wake = true; 117 } else if isr.tcif(channel_num) && cr.read().tcie() {
120 }
121
122 if isr.tcif(channel_num) && cr.read().tcie() {
123 // Acknowledge transfer complete interrupt 118 // Acknowledge transfer complete interrupt
124 dma.ifcr().write(|w| w.set_tcif(channel_num, true)); 119 dma.ifcr().write(|w| w.set_tcif(channel_num, true));
125 STATE.complete_count[index].fetch_add(1, Ordering::Release); 120 STATE.complete_count[index].fetch_add(1, Ordering::Release);
126 wake = true; 121 } else {
122 return;
127 } 123 }
128 124
129 if wake { 125 STATE.ch_wakers[index].wake();
130 STATE.ch_wakers[index].wake();
131 }
132} 126}
133 127
134#[cfg(any(bdma_v2, dmamux))] 128#[cfg(any(bdma_v2, dmamux))]
@@ -371,7 +365,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
371struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); 365struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
372 366
373impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 367impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
374 fn ndtr(&self) -> usize { 368 fn get_remaining_transfers(&self) -> usize {
375 let ch = self.0.regs().ch(self.0.num()); 369 let ch = self.0.regs().ch(self.0.num());
376 unsafe { ch.ndtr().read() }.ndt() as usize 370 unsafe { ch.ndtr().read() }.ndt() as usize
377 } 371 }
@@ -457,21 +451,17 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
457 } 451 }
458 452
459 /// Read bytes from the ring buffer 453 /// Read bytes from the ring buffer
454 /// Return a tuple of the length read and the length remaining in the buffer
455 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining
456 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
460 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 457 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
461 pub fn read(&mut self, buf: &mut [W]) -> Result<usize, OverrunError> { 458 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
462 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 459 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
463 } 460 }
464 461
465 pub fn is_empty(&self) -> bool { 462 /// The capacity of the ringbuffer
466 self.ringbuf.is_empty() 463 pub fn cap(&self) -> usize {
467 } 464 self.ringbuf.cap()
468
469 pub fn len(&self) -> usize {
470 self.ringbuf.len()
471 }
472
473 pub fn capacity(&self) -> usize {
474 self.ringbuf.dma_buf.len()
475 } 465 }
476 466
477 pub fn set_waker(&mut self, waker: &Waker) { 467 pub fn set_waker(&mut self, waker: &Waker) {
@@ -506,12 +496,6 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
506 let ch = self.channel.regs().ch(self.channel.num()); 496 let ch = self.channel.regs().ch(self.channel.num());
507 unsafe { ch.cr().read() }.en() 497 unsafe { ch.cr().read() }.en()
508 } 498 }
509
510 /// Synchronize the position of the ring buffer to the actual DMA controller position
511 pub fn reload_position(&mut self) {
512 let ch = self.channel.regs().ch(self.channel.num());
513 self.ringbuf.ndtr = unsafe { ch.ndtr().read() }.ndt() as usize;
514 }
515} 499}
516 500
517impl<'a, C: Channel, W: Word> Drop for RingBuffer<'a, C, W> { 501impl<'a, C: Channel, W: Word> Drop for RingBuffer<'a, C, W> {
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 7b17d9e49..47b749ece 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -187,24 +187,18 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
187 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); 187 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
188 } 188 }
189 189
190 let mut wake = false;
191
192 if isr.htif(channel_num % 4) && cr.read().htie() { 190 if isr.htif(channel_num % 4) && cr.read().htie() {
193 // Acknowledge half transfer complete interrupt 191 // Acknowledge half transfer complete interrupt
194 dma.ifcr(channel_num / 4).write(|w| w.set_htif(channel_num % 4, true)); 192 dma.ifcr(channel_num / 4).write(|w| w.set_htif(channel_num % 4, true));
195 wake = true; 193 } else if isr.tcif(channel_num % 4) && cr.read().tcie() {
196 }
197
198 if isr.tcif(channel_num % 4) && cr.read().tcie() {
199 // Acknowledge transfer complete interrupt 194 // Acknowledge transfer complete interrupt
200 dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true)); 195 dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
201 STATE.complete_count[index].fetch_add(1, Ordering::Release); 196 STATE.complete_count[index].fetch_add(1, Ordering::Release);
202 wake = true; 197 } else {
198 return;
203 } 199 }
204 200
205 if wake { 201 STATE.ch_wakers[index].wake();
206 STATE.ch_wakers[index].wake();
207 }
208} 202}
209 203
210#[cfg(any(dma_v2, dmamux))] 204#[cfg(any(dma_v2, dmamux))]
@@ -612,7 +606,7 @@ impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> {
612struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); 606struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
613 607
614impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 608impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
615 fn ndtr(&self) -> usize { 609 fn get_remaining_transfers(&self) -> usize {
616 let ch = self.0.regs().st(self.0.num()); 610 let ch = self.0.regs().st(self.0.num());
617 unsafe { ch.ndtr().read() }.ndt() as usize 611 unsafe { ch.ndtr().read() }.ndt() as usize
618 } 612 }
@@ -713,21 +707,17 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
713 } 707 }
714 708
715 /// Read bytes from the ring buffer 709 /// Read bytes from the ring buffer
710 /// Return a tuple of the length read and the length remaining in the buffer
711 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining
712 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
716 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 713 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
717 pub fn read(&mut self, buf: &mut [W]) -> Result<usize, OverrunError> { 714 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
718 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 715 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
719 } 716 }
720 717
721 pub fn is_empty(&self) -> bool { 718 // The capacity of the ringbuffer
722 self.ringbuf.is_empty() 719 pub fn cap(&self) -> usize {
723 } 720 self.ringbuf.cap()
724
725 pub fn len(&self) -> usize {
726 self.ringbuf.len()
727 }
728
729 pub fn capacity(&self) -> usize {
730 self.ringbuf.dma_buf.len()
731 } 721 }
732 722
733 pub fn set_waker(&mut self, waker: &Waker) { 723 pub fn set_waker(&mut self, waker: &Waker) {
@@ -766,12 +756,6 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
766 let ch = self.channel.regs().st(self.channel.num()); 756 let ch = self.channel.regs().st(self.channel.num());
767 unsafe { ch.cr().read() }.en() 757 unsafe { ch.cr().read() }.en()
768 } 758 }
769
770 /// Synchronize the position of the ring buffer to the actual DMA controller position
771 pub fn reload_position(&mut self) {
772 let ch = self.channel.regs().st(self.channel.num());
773 self.ringbuf.ndtr = unsafe { ch.ndtr().read() }.ndt() as usize;
774 }
775} 759}
776 760
777impl<'a, C: Channel, W: Word> Drop for RingBuffer<'a, C, W> { 761impl<'a, C: Channel, W: Word> Drop for RingBuffer<'a, C, W> {
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index 38cc87ae9..a2bde986f 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -25,14 +25,13 @@ use super::word::Word;
25/// +-----------------------------------------+ +-----------------------------------------+ 25/// +-----------------------------------------+ +-----------------------------------------+
26/// ^ ^ ^ ^ ^ ^ 26/// ^ ^ ^ ^ ^ ^
27/// | | | | | | 27/// | | | | | |
28/// +- first --+ | +- end ------+ | 28/// +- start --+ | +- end ------+ |
29/// | | | | 29/// | | | |
30/// +- end --------------------+ +- first ----------------+ 30/// +- end --------------------+ +- start ----------------+
31/// ``` 31/// ```
32pub struct DmaRingBuffer<'a, W: Word> { 32pub struct DmaRingBuffer<'a, W: Word> {
33 pub(crate) dma_buf: &'a mut [W], 33 pub(crate) dma_buf: &'a mut [W],
34 first: usize, 34 start: usize,
35 pub ndtr: usize,
36} 35}
37 36
38#[derive(Debug, PartialEq)] 37#[derive(Debug, PartialEq)]
@@ -41,7 +40,7 @@ pub struct OverrunError;
41pub trait DmaCtrl { 40pub trait DmaCtrl {
42 /// Get the NDTR register value, i.e. the space left in the underlying 41 /// Get the NDTR register value, i.e. the space left in the underlying
43 /// buffer until the dma writer wraps. 42 /// buffer until the dma writer wraps.
44 fn ndtr(&self) -> usize; 43 fn get_remaining_transfers(&self) -> usize;
45 44
46 /// Get the transfer completed counter. 45 /// Get the transfer completed counter.
47 /// This counter is incremented by the dma controller when NDTR is reloaded, 46 /// This counter is incremented by the dma controller when NDTR is reloaded,
@@ -54,151 +53,131 @@ pub trait DmaCtrl {
54 53
55impl<'a, W: Word> DmaRingBuffer<'a, W> { 54impl<'a, W: Word> DmaRingBuffer<'a, W> {
56 pub fn new(dma_buf: &'a mut [W]) -> Self { 55 pub fn new(dma_buf: &'a mut [W]) -> Self {
57 let ndtr = dma_buf.len(); 56 Self { dma_buf, start: 0 }
58 Self {
59 dma_buf,
60 first: 0,
61 ndtr,
62 }
63 } 57 }
64 58
65 /// Reset the ring buffer to its initial state 59 /// Reset the ring buffer to its initial state
66 pub fn clear(&mut self, mut dma: impl DmaCtrl) { 60 pub fn clear(&mut self, mut dma: impl DmaCtrl) {
67 self.first = 0; 61 self.start = 0;
68 self.ndtr = self.dma_buf.len();
69 dma.reset_complete_count(); 62 dma.reset_complete_count();
70 } 63 }
71 64
72 /// The buffer end position 65 /// The capacity of the ringbuffer
73 fn end(&self) -> usize { 66 pub const fn cap(&self) -> usize {
74 self.dma_buf.len() - self.ndtr 67 self.dma_buf.len()
75 }
76
77 /// Returns whether the buffer is empty
78 pub fn is_empty(&self) -> bool {
79 self.first == self.end()
80 } 68 }
81 69
82 /// The current number of bytes in the buffer 70 /// The current position of the ringbuffer
83 /// This may change at any time if dma is currently active 71 fn pos(&self, remaining_transfers: usize) -> usize {
84 pub fn len(&self) -> usize { 72 self.cap() - remaining_transfers
85 // Read out a stable end (the dma periheral can change it at anytime)
86 let end = self.end();
87 if self.first <= end {
88 // No wrap
89 end - self.first
90 } else {
91 self.dma_buf.len() - self.first + end
92 }
93 } 73 }
94 74
95 /// Read bytes from the ring buffer 75 /// Read bytes from the ring buffer
76 /// Return a tuple of the length read and the length remaining in the buffer
77 /// If not all of the bytes were read, then there will be some bytes in the buffer remaining
78 /// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
96 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 79 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
97 pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<usize, OverrunError> { 80 pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
98 let end = self.end(); 81 /*
82 This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check
83 after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed
84 to fire in the same clock cycle that a register is read, so checking get_complete_count early does
85 not yield relevant information.
86
87 Therefore, the only variable we really need to know is ndtr. If the dma has overrun by more than a full
88 buffer, we will do a bit more work than we have to, but algorithms should not be optimized for error
89 conditions.
90
91 After we've done our work, we confirm that we haven't overrun more than a full buffer, and also that
92 the dma has not overrun within the data we could have copied. We check the data we could have copied
93 rather than the data we actually copied because it costs nothing and confirms an error condition
94 earlier.
95 */
96 let end = self.pos(dma.get_remaining_transfers());
97 if self.start == end && dma.get_complete_count() == 0 {
98 // No bytes are available in the buffer
99 Ok((0, self.cap()))
100 } else if self.start < end {
101 // The available, unread portion in the ring buffer DOES NOT wrap
102 // Copy out the bytes from the dma buffer
103 let len = self.copy_to(buf, self.start..end);
99 104
100 compiler_fence(Ordering::SeqCst); 105 compiler_fence(Ordering::SeqCst);
101 106
102 if self.first == end { 107 /*
103 // The buffer is currently empty 108 first, check if the dma has wrapped at all if it's after end
109 or more than once if it's before start
104 110
105 if dma.get_complete_count() > 0 { 111 this is in a critical section to try to reduce mushy behavior.
106 // The DMA has written such that the ring buffer wraps at least once 112 it's not ideal but it's the best we can do
107 self.ndtr = dma.ndtr();
108 if self.end() > self.first || dma.get_complete_count() > 1 {
109 return Err(OverrunError);
110 }
111 }
112 113
113 Ok(0) 114 then, get the current position of of the dma write and check
114 } else if self.first < end { 115 if it's inside data we could have copied
115 // The available, unread portion in the ring buffer DOES NOT wrap 116 */
117 let (pos, complete_count) =
118 critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count()));
119 if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 {
120 Err(OverrunError)
121 } else {
122 self.start = (self.start + len) % self.cap();
116 123
117 if dma.get_complete_count() > 1 { 124 Ok((len, self.cap() - self.start))
118 return Err(OverrunError);
119 } 125 }
126 } else if self.start + buf.len() < self.cap() {
127 // The available, unread portion in the ring buffer DOES wrap
128 // The DMA writer has wrapped since we last read and is currently
129 // writing (or the next byte added will be) in the beginning of the ring buffer.
120 130
121 // Copy out the bytes from the dma buffer 131 // The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
122 let len = self.copy_to(buf, self.first..end); 132
133 // Copy out from the dma buffer
134 let len = self.copy_to(buf, self.start..self.cap());
123 135
124 compiler_fence(Ordering::SeqCst); 136 compiler_fence(Ordering::SeqCst);
125 137
126 match dma.get_complete_count() { 138 /*
127 0 => { 139 first, check if the dma has wrapped around more than once
128 // The DMA writer has not wrapped before nor after the copy
129 }
130 1 => {
131 // The DMA writer has written such that the ring buffer now wraps
132 self.ndtr = dma.ndtr();
133 if self.end() > self.first || dma.get_complete_count() > 1 {
134 // The bytes that we have copied out have overflowed
135 // as the writer has now both wrapped and is currently writing
136 // within the region that we have just copied out
137 return Err(OverrunError);
138 }
139 }
140 _ => {
141 return Err(OverrunError);
142 }
143 }
144 140
145 self.first = (self.first + len) % self.dma_buf.len(); 141 then, get the current position of of the dma write and check
146 Ok(len) 142 if it's inside data we could have copied
143 */
144 let pos = self.pos(dma.get_remaining_transfers());
145 if pos > self.start || pos < end || dma.get_complete_count() > 1 {
146 Err(OverrunError)
147 } else {
148 self.start = (self.start + len) % self.cap();
149
150 Ok((len, self.start + end))
151 }
147 } else { 152 } else {
148 // The available, unread portion in the ring buffer DOES wrap 153 // The available, unread portion in the ring buffer DOES wrap
149 // The DMA writer has wrapped since we last read and is currently 154 // The DMA writer has wrapped since we last read and is currently
150 // writing (or the next byte added will be) in the beginning of the ring buffer. 155 // writing (or the next byte added will be) in the beginning of the ring buffer.
151 156
152 let complete_count = dma.get_complete_count(); 157 // The provided read buffer is large enough to include all bytes from the tail of the dma buffer,
153 if complete_count > 1 { 158 // so the next read will not have any unread tail bytes in the ring buffer.
154 return Err(OverrunError);
155 }
156
157 // If the unread portion wraps then the writer must also have wrapped
158 assert!(complete_count == 1);
159
160 if self.first + buf.len() < self.dma_buf.len() {
161 // The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
162 159
163 // Copy out from the dma buffer 160 // Copy out from the dma buffer
164 let len = self.copy_to(buf, self.first..self.dma_buf.len()); 161 let tail = self.copy_to(buf, self.start..self.cap());
162 let head = self.copy_to(&mut buf[tail..], 0..end);
165 163
166 compiler_fence(Ordering::SeqCst); 164 compiler_fence(Ordering::SeqCst);
167 165
168 // We have now copied out the data from dma_buf 166 /*
169 // Make sure that the just read part was not overwritten during the copy 167 first, check if the dma has wrapped around more than once
170 self.ndtr = dma.ndtr();
171 if self.end() > self.first || dma.get_complete_count() > 1 {
172 // The writer has entered the data that we have just read since we read out `end` in the beginning and until now.
173 return Err(OverrunError);
174 }
175 168
176 self.first = (self.first + len) % self.dma_buf.len(); 169 then, get the current position of of the dma write and check
177 Ok(len) 170 if it's inside data we could have copied
171 */
172 let pos = self.pos(dma.get_remaining_transfers());
173 if pos > self.start || pos < end || dma.reset_complete_count() > 1 {
174 Err(OverrunError)
178 } else { 175 } else {
179 // The provided read buffer is large enough to include all bytes from the tail of the dma buffer, 176 self.start = head;
180 // so the next read will not have any unread tail bytes in the ring buffer. 177 Ok((tail + head, self.cap() - self.start))
181
182 // Copy out from the dma buffer
183 let tail = self.copy_to(buf, self.first..self.dma_buf.len());
184 let head = self.copy_to(&mut buf[tail..], 0..end);
185
186 compiler_fence(Ordering::SeqCst);
187
188 // We have now copied out the data from dma_buf
189 // Reset complete counter and make sure that the just read part was not overwritten during the copy
190 self.ndtr = dma.ndtr();
191 let complete_count = dma.reset_complete_count();
192 if self.end() > self.first || complete_count > 1 {
193 return Err(OverrunError);
194 }
195
196 self.first = head;
197 Ok(tail + head)
198 } 178 }
199 } 179 }
200 } 180 }
201
202 /// Copy from the dma buffer at `data_range` into `buf` 181 /// Copy from the dma buffer at `data_range` into `buf`
203 fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize { 182 fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
204 // Limit the number of bytes that can be copied 183 // Limit the number of bytes that can be copied
@@ -218,203 +197,289 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
218 length 197 length
219 } 198 }
220} 199}
221
222#[cfg(test)] 200#[cfg(test)]
223mod tests { 201mod tests {
224 use core::array; 202 use core::array;
225 use core::cell::RefCell; 203 use std::{cell, vec};
226 204
227 use super::*; 205 use super::*;
228 206
229 struct TestCtrl { 207 #[allow(dead_code)]
230 next_ndtr: RefCell<Option<usize>>, 208 #[derive(PartialEq, Debug)]
231 complete_count: usize, 209 enum TestCircularTransferRequest {
210 GetCompleteCount(usize),
211 ResetCompleteCount(usize),
212 PositionRequest(usize),
232 } 213 }
233 214
234 impl TestCtrl { 215 struct TestCircularTransfer {
235 pub const fn new() -> Self { 216 len: usize,
236 Self { 217 requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
237 next_ndtr: RefCell::new(None), 218 }
238 complete_count: 0, 219
220 impl DmaCtrl for &mut TestCircularTransfer {
221 fn get_remaining_transfers(&self) -> usize {
222 match self.requests.borrow_mut().pop().unwrap() {
223 TestCircularTransferRequest::PositionRequest(pos) => {
224 let len = self.len;
225
226 assert!(len >= pos);
227
228 len - pos
229 }
230 _ => unreachable!(),
239 } 231 }
240 } 232 }
241 233
242 pub fn set_next_ndtr(&mut self, ndtr: usize) { 234 fn get_complete_count(&self) -> usize {
243 self.next_ndtr.borrow_mut().replace(ndtr); 235 match self.requests.borrow_mut().pop().unwrap() {
236 TestCircularTransferRequest::GetCompleteCount(complete_count) => complete_count,
237 _ => unreachable!(),
238 }
244 } 239 }
245 }
246 240
247 impl DmaCtrl for &mut TestCtrl { 241 fn reset_complete_count(&mut self) -> usize {
248 fn ndtr(&self) -> usize { 242 match self.requests.get_mut().pop().unwrap() {
249 self.next_ndtr.borrow_mut().unwrap() 243 TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count,
244 _ => unreachable!(),
245 }
250 } 246 }
247 }
251 248
252 fn get_complete_count(&self) -> usize { 249 impl TestCircularTransfer {
253 self.complete_count 250 pub fn new(len: usize) -> Self {
251 Self {
252 requests: cell::RefCell::new(vec![]),
253 len: len,
254 }
254 } 255 }
255 256
256 fn reset_complete_count(&mut self) -> usize { 257 pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) {
257 let old = self.complete_count; 258 requests.reverse();
258 self.complete_count = 0; 259 self.requests.replace(requests);
259 old
260 } 260 }
261 } 261 }
262 262
263 #[test] 263 #[test]
264 fn empty() { 264 fn empty_and_read_not_started() {
265 let mut dma_buf = [0u8; 16]; 265 let mut dma_buf = [0u8; 16];
266 let ringbuf = DmaRingBuffer::new(&mut dma_buf); 266 let ringbuf = DmaRingBuffer::new(&mut dma_buf);
267 267
268 assert!(ringbuf.is_empty()); 268 assert_eq!(0, ringbuf.start);
269 assert_eq!(0, ringbuf.len());
270 } 269 }
271 270
272 #[test] 271 #[test]
273 fn can_read() { 272 fn can_read() {
273 let mut dma = TestCircularTransfer::new(16);
274
274 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 275 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
275 let mut ctrl = TestCtrl::new();
276 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 276 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
277 ringbuf.ndtr = 6;
278 277
279 assert!(!ringbuf.is_empty()); 278 assert_eq!(0, ringbuf.start);
280 assert_eq!(10, ringbuf.len()); 279 assert_eq!(16, ringbuf.cap());
281 280
281 dma.setup(vec![
282 TestCircularTransferRequest::PositionRequest(8),
283 TestCircularTransferRequest::PositionRequest(10),
284 TestCircularTransferRequest::GetCompleteCount(0),
285 ]);
282 let mut buf = [0; 2]; 286 let mut buf = [0; 2];
283 assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 287 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
284 assert_eq!([0, 1], buf); 288 assert_eq!([0, 1], buf);
285 assert_eq!(8, ringbuf.len()); 289 assert_eq!(2, ringbuf.start);
286 290
291 dma.setup(vec![
292 TestCircularTransferRequest::PositionRequest(10),
293 TestCircularTransferRequest::PositionRequest(12),
294 TestCircularTransferRequest::GetCompleteCount(0),
295 ]);
287 let mut buf = [0; 2]; 296 let mut buf = [0; 2];
288 assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 297 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
289 assert_eq!([2, 3], buf); 298 assert_eq!([2, 3], buf);
290 assert_eq!(6, ringbuf.len()); 299 assert_eq!(4, ringbuf.start);
291 300
301 dma.setup(vec![
302 TestCircularTransferRequest::PositionRequest(12),
303 TestCircularTransferRequest::PositionRequest(14),
304 TestCircularTransferRequest::GetCompleteCount(0),
305 ]);
292 let mut buf = [0; 8]; 306 let mut buf = [0; 8];
293 assert_eq!(6, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 307 assert_eq!(8, ringbuf.read(&mut dma, &mut buf).unwrap().0);
294 assert_eq!([4, 5, 6, 7, 8, 9], buf[..6]); 308 assert_eq!([4, 5, 6, 7, 8, 9], buf[..6]);
295 assert_eq!(0, ringbuf.len()); 309 assert_eq!(12, ringbuf.start);
296
297 let mut buf = [0; 2];
298 assert_eq!(0, ringbuf.read(&mut ctrl, &mut buf).unwrap());
299 } 310 }
300 311
301 #[test] 312 #[test]
302 fn can_read_with_wrap() { 313 fn can_read_with_wrap() {
314 let mut dma = TestCircularTransfer::new(16);
315
303 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 316 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
304 let mut ctrl = TestCtrl::new();
305 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 317 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
306 ringbuf.first = 12;
307 ringbuf.ndtr = 10;
308
309 // The dma controller has written 4 + 6 bytes and has reloaded NDTR
310 ctrl.complete_count = 1;
311 ctrl.set_next_ndtr(10);
312
313 assert!(!ringbuf.is_empty());
314 assert_eq!(6 + 4, ringbuf.len());
315 318
316 let mut buf = [0; 2]; 319 assert_eq!(0, ringbuf.start);
317 assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 320 assert_eq!(16, ringbuf.cap());
318 assert_eq!([12, 13], buf); 321
319 assert_eq!(6 + 2, ringbuf.len()); 322 /*
320 323 Read to close to the end of the buffer
321 let mut buf = [0; 4]; 324 */
322 assert_eq!(4, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 325 dma.setup(vec![
323 assert_eq!([14, 15, 0, 1], buf); 326 TestCircularTransferRequest::PositionRequest(14),
324 assert_eq!(4, ringbuf.len()); 327 TestCircularTransferRequest::PositionRequest(16),
328 TestCircularTransferRequest::GetCompleteCount(0),
329 ]);
330 let mut buf = [0; 14];
331 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
332 assert_eq!(14, ringbuf.start);
333
334 /*
335 Now, read around the buffer
336 */
337 dma.setup(vec![
338 TestCircularTransferRequest::PositionRequest(6),
339 TestCircularTransferRequest::PositionRequest(8),
340 TestCircularTransferRequest::ResetCompleteCount(1),
341 ]);
342 let mut buf = [0; 6];
343 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
344 assert_eq!(4, ringbuf.start);
325 } 345 }
326 346
327 #[test] 347 #[test]
328 fn can_read_when_dma_writer_is_wrapped_and_read_does_not_wrap() { 348 fn can_read_when_dma_writer_is_wrapped_and_read_does_not_wrap() {
349 let mut dma = TestCircularTransfer::new(16);
350
329 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 351 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
330 let mut ctrl = TestCtrl::new();
331 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 352 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
332 ringbuf.first = 2;
333 ringbuf.ndtr = 6;
334
335 // The dma controller has written 6 + 2 bytes and has reloaded NDTR
336 ctrl.complete_count = 1;
337 ctrl.set_next_ndtr(14);
338 353
354 assert_eq!(0, ringbuf.start);
355 assert_eq!(16, ringbuf.cap());
356
357 /*
358 Read to close to the end of the buffer
359 */
360 dma.setup(vec![
361 TestCircularTransferRequest::PositionRequest(14),
362 TestCircularTransferRequest::PositionRequest(16),
363 TestCircularTransferRequest::GetCompleteCount(0),
364 ]);
365 let mut buf = [0; 14];
366 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
367 assert_eq!(14, ringbuf.start);
368
369 /*
370 Now, read to the end of the buffer
371 */
372 dma.setup(vec![
373 TestCircularTransferRequest::PositionRequest(6),
374 TestCircularTransferRequest::PositionRequest(8),
375 TestCircularTransferRequest::ResetCompleteCount(1),
376 ]);
339 let mut buf = [0; 2]; 377 let mut buf = [0; 2];
340 assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap()); 378 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
341 assert_eq!([2, 3], buf); 379 assert_eq!(0, ringbuf.start);
342
343 assert_eq!(1, ctrl.complete_count); // The interrupt flag IS NOT cleared
344 } 380 }
345 381
346 #[test] 382 #[test]
347 fn can_read_when_dma_writer_is_wrapped_and_read_wraps() { 383 fn can_read_when_dma_writer_wraps_once_with_same_ndtr() {
384 let mut dma = TestCircularTransfer::new(16);
385
348 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 386 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
349 let mut ctrl = TestCtrl::new();
350 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 387 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
351 ringbuf.first = 12;
352 ringbuf.ndtr = 10;
353
354 // The dma controller has written 6 + 2 bytes and has reloaded NDTR
355 ctrl.complete_count = 1;
356 ctrl.set_next_ndtr(14);
357
358 let mut buf = [0; 10];
359 assert_eq!(10, ringbuf.read(&mut ctrl, &mut buf).unwrap());
360 assert_eq!([12, 13, 14, 15, 0, 1, 2, 3, 4, 5], buf);
361 388
362 assert_eq!(0, ctrl.complete_count); // The interrupt flag IS cleared 389 assert_eq!(0, ringbuf.start);
363 } 390 assert_eq!(16, ringbuf.cap());
364 391
365 #[test] 392 /*
366 fn cannot_read_when_dma_writer_wraps_with_same_ndtr() { 393 Read to about the middle of the buffer
367 let mut dma_buf = [0u8; 16]; 394 */
368 let mut ctrl = TestCtrl::new(); 395 dma.setup(vec![
369 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 396 TestCircularTransferRequest::PositionRequest(6),
370 ringbuf.first = 6; 397 TestCircularTransferRequest::PositionRequest(6),
371 ringbuf.ndtr = 10; 398 TestCircularTransferRequest::GetCompleteCount(0),
372 ctrl.set_next_ndtr(9); 399 ]);
373 400 let mut buf = [0; 6];
374 assert!(ringbuf.is_empty()); // The ring buffer thinks that it is empty 401 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
375 402 assert_eq!(6, ringbuf.start);
376 // The dma controller has written exactly 16 bytes 403
377 ctrl.complete_count = 1; 404 /*
378 405 Now, wrap the DMA controller around
379 let mut buf = [0; 2]; 406 */
380 assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf)); 407 dma.setup(vec![
381 408 TestCircularTransferRequest::PositionRequest(6),
382 assert_eq!(1, ctrl.complete_count); // The complete counter is not reset 409 TestCircularTransferRequest::GetCompleteCount(1),
410 TestCircularTransferRequest::PositionRequest(6),
411 TestCircularTransferRequest::GetCompleteCount(1),
412 ]);
413 let mut buf = [0; 6];
414 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
415 assert_eq!(12, ringbuf.start);
383 } 416 }
384 417
385 #[test] 418 #[test]
386 fn cannot_read_when_dma_writer_overwrites_during_not_wrapping_read() { 419 fn cannot_read_when_dma_writer_overwrites_during_not_wrapping_read() {
420 let mut dma = TestCircularTransfer::new(16);
421
387 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 422 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
388 let mut ctrl = TestCtrl::new();
389 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 423 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
390 ringbuf.first = 2;
391 ringbuf.ndtr = 6;
392
393 // The dma controller has written 6 + 3 bytes and has reloaded NDTR
394 ctrl.complete_count = 1;
395 ctrl.set_next_ndtr(13);
396
397 let mut buf = [0; 2];
398 assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
399 424
400 assert_eq!(1, ctrl.complete_count); // The complete counter is not reset 425 assert_eq!(0, ringbuf.start);
426 assert_eq!(16, ringbuf.cap());
427
428 /*
429 Read a few bytes
430 */
431 dma.setup(vec![
432 TestCircularTransferRequest::PositionRequest(2),
433 TestCircularTransferRequest::PositionRequest(2),
434 TestCircularTransferRequest::GetCompleteCount(0),
435 ]);
436 let mut buf = [0; 6];
437 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
438 assert_eq!(2, ringbuf.start);
439
440 /*
441 Now, overtake the reader
442 */
443 dma.setup(vec![
444 TestCircularTransferRequest::PositionRequest(4),
445 TestCircularTransferRequest::PositionRequest(6),
446 TestCircularTransferRequest::GetCompleteCount(1),
447 ]);
448 let mut buf = [0; 6];
449 assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err());
401 } 450 }
402 451
403 #[test] 452 #[test]
404 fn cannot_read_when_dma_writer_overwrites_during_wrapping_read() { 453 fn cannot_read_when_dma_writer_overwrites_during_wrapping_read() {
454 let mut dma = TestCircularTransfer::new(16);
455
405 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 456 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
406 let mut ctrl = TestCtrl::new();
407 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf); 457 let mut ringbuf = DmaRingBuffer::new(&mut dma_buf);
408 ringbuf.first = 12;
409 ringbuf.ndtr = 10;
410
411 // The dma controller has written 6 + 13 bytes and has reloaded NDTR
412 ctrl.complete_count = 1;
413 ctrl.set_next_ndtr(3);
414
415 let mut buf = [0; 2];
416 assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
417 458
418 assert_eq!(1, ctrl.complete_count); // The complete counter is not reset 459 assert_eq!(0, ringbuf.start);
460 assert_eq!(16, ringbuf.cap());
461
462 /*
463 Read to close to the end of the buffer
464 */
465 dma.setup(vec![
466 TestCircularTransferRequest::PositionRequest(14),
467 TestCircularTransferRequest::PositionRequest(16),
468 TestCircularTransferRequest::GetCompleteCount(0),
469 ]);
470 let mut buf = [0; 14];
471 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
472 assert_eq!(14, ringbuf.start);
473
474 /*
475 Now, overtake the reader
476 */
477 dma.setup(vec![
478 TestCircularTransferRequest::PositionRequest(8),
479 TestCircularTransferRequest::PositionRequest(10),
480 TestCircularTransferRequest::ResetCompleteCount(2),
481 ]);
482 let mut buf = [0; 6];
483 assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err());
419 } 484 }
420} 485}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index b9d7a15c7..6533509eb 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,4 +1,4 @@
1#![no_std] 1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] 2#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
3 3
4// This must go FIRST so that all the other modules see its macros. 4// This must go FIRST so that all the other modules see its macros.
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 061c859a8..05ccb8749 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -13,6 +13,12 @@ use futures::future::{select, Either};
13use crate::dma::{NoDma, Transfer}; 13use crate::dma::{NoDma, Transfer};
14use crate::gpio::sealed::AFType; 14use crate::gpio::sealed::AFType;
15#[cfg(not(any(usart_v1, usart_v2)))] 15#[cfg(not(any(usart_v1, usart_v2)))]
16#[allow(unused_imports)]
17use crate::pac::usart::regs::Isr as Sr;
18#[cfg(any(usart_v1, usart_v2))]
19#[allow(unused_imports)]
20use crate::pac::usart::regs::Sr;
21#[cfg(not(any(usart_v1, usart_v2)))]
16use crate::pac::usart::Lpuart as Regs; 22use crate::pac::usart::Lpuart as Regs;
17#[cfg(any(usart_v1, usart_v2))] 23#[cfg(any(usart_v1, usart_v2))]
18use crate::pac::usart::Usart as Regs; 24use crate::pac::usart::Usart as Regs;
@@ -32,7 +38,6 @@ impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T>
32 38
33 let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; 39 let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
34 40
35 let mut wake = false;
36 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); 41 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
37 if has_errors { 42 if has_errors {
38 // clear all interrupts and DMA Rx Request 43 // clear all interrupts and DMA Rx Request
@@ -52,35 +57,24 @@ impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T>
52 w.set_dmar(false); 57 w.set_dmar(false);
53 }); 58 });
54 } 59 }
55 60 } else if cr1.idleie() && sr.idle() {
56 wake = true; 61 // IDLE detected: no more data will come
57 } else { 62 unsafe {
58 if cr1.idleie() && sr.idle() { 63 r.cr1().modify(|w| {
59 // IDLE detected: no more data will come 64 // disable idle line detection
60 unsafe { 65 w.set_idleie(false);
61 r.cr1().modify(|w| { 66 });
62 // disable idle line detection
63 w.set_idleie(false);
64 });
65 }
66
67 wake = true;
68 } 67 }
68 } else if cr1.rxneie() {
69 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller
69 70
70 if cr1.rxneie() { 71 // It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection
71 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller 72 } else {
72 73 return;
73 // It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection
74
75 wake = true;
76 }
77 } 74 }
78 75
79 if wake { 76 compiler_fence(Ordering::SeqCst);
80 compiler_fence(Ordering::SeqCst); 77 s.rx_waker.wake();
81
82 s.rx_waker.wake();
83 }
84 } 78 }
85} 79}
86 80
@@ -1109,9 +1103,9 @@ pub use crate::usart::buffered::InterruptHandler as BufferedInterruptHandler;
1109mod buffered; 1103mod buffered;
1110 1104
1111#[cfg(not(gpdma))] 1105#[cfg(not(gpdma))]
1112mod rx_ringbuffered; 1106mod ringbuffered;
1113#[cfg(not(gpdma))] 1107#[cfg(not(gpdma))]
1114pub use rx_ringbuffered::RingBufferedUartRx; 1108pub use ringbuffered::RingBufferedUartRx;
1115 1109
1116use self::sealed::Kind; 1110use self::sealed::Kind;
1117 1111
diff --git a/embassy-stm32/src/usart/rx_ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 33b750497..511b71c7f 100644
--- a/embassy-stm32/src/usart/rx_ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -2,13 +2,12 @@ use core::future::poll_fn;
2use core::sync::atomic::{compiler_fence, Ordering}; 2use core::sync::atomic::{compiler_fence, Ordering};
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_common::drop::OnDrop;
6use embassy_hal_common::PeripheralRef; 5use embassy_hal_common::PeripheralRef;
7use futures::future::{select, Either}; 6use futures::future::{select, Either};
8 7
9use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx}; 8use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx};
10use crate::dma::ringbuffer::OverrunError;
11use crate::dma::RingBuffer; 9use crate::dma::RingBuffer;
10use crate::usart::{Regs, Sr};
12 11
13pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { 12pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
14 _peri: PeripheralRef<'d, T>, 13 _peri: PeripheralRef<'d, T>,
@@ -24,7 +23,9 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
24 23
25 let request = self.rx_dma.request(); 24 let request = self.rx_dma.request();
26 let opts = Default::default(); 25 let opts = Default::default();
26
27 let ring_buf = unsafe { RingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 27 let ring_buf = unsafe { RingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) };
28
28 RingBufferedUartRx { 29 RingBufferedUartRx {
29 _peri: self._peri, 30 _peri: self._peri,
30 ring_buf, 31 ring_buf,
@@ -42,11 +43,18 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
42 Ok(()) 43 Ok(())
43 } 44 }
44 45
46 fn stop(&mut self, err: Error) -> Result<usize, Error> {
47 self.teardown_uart();
48
49 Err(err)
50 }
51
45 /// Start uart background receive 52 /// Start uart background receive
46 fn setup_uart(&mut self) { 53 fn setup_uart(&mut self) {
47 // fence before starting DMA. 54 // fence before starting DMA.
48 compiler_fence(Ordering::SeqCst); 55 compiler_fence(Ordering::SeqCst);
49 56
57 // start the dma controller
50 self.ring_buf.start(); 58 self.ring_buf.start();
51 59
52 let r = T::regs(); 60 let r = T::regs();
@@ -58,8 +66,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
58 w.set_rxneie(false); 66 w.set_rxneie(false);
59 // enable parity interrupt if not ParityNone 67 // enable parity interrupt if not ParityNone
60 w.set_peie(w.pce()); 68 w.set_peie(w.pce());
61 // disable idle line interrupt 69 // enable idle line interrupt
62 w.set_idleie(false); 70 w.set_idleie(true);
63 }); 71 });
64 r.cr3().modify(|w| { 72 r.cr3().modify(|w| {
65 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 73 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
@@ -72,6 +80,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
72 80
73 /// Stop uart background receive 81 /// Stop uart background receive
74 fn teardown_uart(&mut self) { 82 fn teardown_uart(&mut self) {
83 self.ring_buf.request_stop();
84
75 let r = T::regs(); 85 let r = T::regs();
76 // clear all interrupts and DMA Rx Request 86 // clear all interrupts and DMA Rx Request
77 // SAFETY: only clears Rx related flags 87 // SAFETY: only clears Rx related flags
@@ -93,9 +103,6 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
93 } 103 }
94 104
95 compiler_fence(Ordering::SeqCst); 105 compiler_fence(Ordering::SeqCst);
96
97 self.ring_buf.request_stop();
98 while self.ring_buf.is_running() {}
99 } 106 }
100 107
101 /// Read bytes that are readily available in the ring buffer. 108 /// Read bytes that are readily available in the ring buffer.
@@ -111,96 +118,49 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
111 118
112 // Start background receive if it was not already started 119 // Start background receive if it was not already started
113 // SAFETY: read only 120 // SAFETY: read only
114 let is_started = unsafe { r.cr3().read().dmar() }; 121 match unsafe { r.cr3().read().dmar() } {
115 if !is_started { 122 false => self.start()?,
116 self.start()?; 123 _ => {}
117 } 124 };
118 125
119 // SAFETY: read only and we only use Rx related flags 126 check_for_errors(clear_idle_flag(T::regs()))?;
120 let s = unsafe { sr(r).read() };
121 let has_errors = s.pe() || s.fe() || s.ne() || s.ore();
122 if has_errors {
123 self.teardown_uart();
124
125 if s.pe() {
126 return Err(Error::Parity);
127 } else if s.fe() {
128 return Err(Error::Framing);
129 } else if s.ne() {
130 return Err(Error::Noise);
131 } else {
132 return Err(Error::Overrun);
133 }
134 }
135
136 self.ring_buf.reload_position();
137 match self.ring_buf.read(buf) {
138 Ok(len) if len == 0 => {}
139 Ok(len) => {
140 assert!(len > 0);
141 return Ok(len);
142 }
143 Err(OverrunError) => {
144 // Stop any transfer from now on
145 // The user must re-start to receive any more data
146 self.teardown_uart();
147 return Err(Error::Overrun);
148 }
149 }
150 127
151 loop { 128 loop {
152 self.wait_for_data_or_idle().await?; 129 match self.ring_buf.read(buf) {
130 Ok((0, _)) => {}
131 Ok((len, _)) => {
132 return Ok(len);
133 }
134 Err(_) => {
135 return self.stop(Error::Overrun);
136 }
137 }
153 138
154 self.ring_buf.reload_position(); 139 match self.wait_for_data_or_idle().await {
155 if !self.ring_buf.is_empty() { 140 Ok(_) => {}
156 break; 141 Err(err) => {
142 return self.stop(err);
143 }
157 } 144 }
158 } 145 }
159
160 let len = self.ring_buf.read(buf).map_err(|_err| Error::Overrun)?;
161 assert!(len > 0);
162
163 Ok(len)
164 } 146 }
165 147
166 /// Wait for uart idle or dma half-full or full 148 /// Wait for uart idle or dma half-full or full
167 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 149 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
168 let r = T::regs();
169
170 // make sure USART state is restored to neutral state
171 let _on_drop = OnDrop::new(move || {
172 // SAFETY: only clears Rx related flags
173 unsafe {
174 r.cr1().modify(|w| {
175 // disable idle line interrupt
176 w.set_idleie(false);
177 });
178 }
179 });
180
181 // SAFETY: only sets Rx related flags
182 unsafe {
183 r.cr1().modify(|w| {
184 // enable idle line interrupt
185 w.set_idleie(true);
186 });
187 }
188
189 compiler_fence(Ordering::SeqCst); 150 compiler_fence(Ordering::SeqCst);
190 151
152 let mut dma_init = false;
191 // Future which completes when there is dma is half full or full 153 // Future which completes when there is dma is half full or full
192 let dma = poll_fn(|cx| { 154 let dma = poll_fn(|cx| {
193 self.ring_buf.set_waker(cx.waker()); 155 self.ring_buf.set_waker(cx.waker());
194 156
195 compiler_fence(Ordering::SeqCst); 157 let status = match dma_init {
158 false => Poll::Pending,
159 true => Poll::Ready(()),
160 };
196 161
197 self.ring_buf.reload_position(); 162 dma_init = true;
198 if !self.ring_buf.is_empty() { 163 status
199 // Some data is now available
200 Poll::Ready(())
201 } else {
202 Poll::Pending
203 }
204 }); 164 });
205 165
206 // Future which completes when idle line is detected 166 // Future which completes when idle line is detected
@@ -210,28 +170,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
210 170
211 compiler_fence(Ordering::SeqCst); 171 compiler_fence(Ordering::SeqCst);
212 172
213 // SAFETY: read only and we only use Rx related flags 173 // Critical section is needed so that IDLE isn't set after
214 let sr = unsafe { sr(r).read() }; 174 // our read but before we clear it.
215 175 let sr = critical_section::with(|_| clear_idle_flag(T::regs()));
216 // SAFETY: only clears Rx related flags
217 unsafe {
218 // This read also clears the error and idle interrupt flags on v1.
219 rdr(r).read_volatile();
220 clear_interrupt_flags(r, sr);
221 }
222 176
223 let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); 177 check_for_errors(sr)?;
224 if has_errors {
225 if sr.pe() {
226 return Poll::Ready(Err(Error::Parity));
227 } else if sr.fe() {
228 return Poll::Ready(Err(Error::Framing));
229 } else if sr.ne() {
230 return Poll::Ready(Err(Error::Noise));
231 } else {
232 return Poll::Ready(Err(Error::Overrun));
233 }
234 }
235 178
236 if sr.idle() { 179 if sr.idle() {
237 // Idle line is detected 180 // Idle line is detected
@@ -243,11 +186,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
243 186
244 match select(dma, uart).await { 187 match select(dma, uart).await {
245 Either::Left(((), _)) => Ok(()), 188 Either::Left(((), _)) => Ok(()),
246 Either::Right((Ok(()), _)) => Ok(()), 189 Either::Right((result, _)) => result,
247 Either::Right((Err(e), _)) => {
248 self.teardown_uart();
249 Err(e)
250 }
251 } 190 }
252 } 191 }
253} 192}
@@ -257,6 +196,37 @@ impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T
257 self.teardown_uart(); 196 self.teardown_uart();
258 } 197 }
259} 198}
199/// Return an error result if the Sr register has errors
200fn check_for_errors(s: Sr) -> Result<(), Error> {
201 if s.pe() {
202 Err(Error::Parity)
203 } else if s.fe() {
204 Err(Error::Framing)
205 } else if s.ne() {
206 Err(Error::Noise)
207 } else if s.ore() {
208 Err(Error::Overrun)
209 } else {
210 Ok(())
211 }
212}
213
214/// Clear IDLE and return the Sr register
215fn clear_idle_flag(r: Regs) -> Sr {
216 unsafe {
217 // SAFETY: read only and we only use Rx related flags
218
219 let sr = sr(r).read();
220
221 // This read also clears the error and idle interrupt flags on v1.
222 rdr(r).read_volatile();
223 clear_interrupt_flags(r, sr);
224
225 r.cr1().modify(|w| w.set_idleie(true));
226
227 sr
228 }
229}
260 230
261#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 231#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
262mod eio { 232mod eio {
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index cd0be5b48..8c2fb4c5f 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } 12embassy-nrf = { path = "../../../../embassy-nrf", features = ["nightly"] }
13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } 13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15cortex-m-rt = { version = "0.7" } 15cortex-m-rt = { version = "0.7" }
16cfg-if = "1.0.0" 16cfg-if = "1.0.0"
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index b4167bcd8..bf9226993 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-rp = { path = "../../../../embassy-rp", default-features = false, features = ["nightly"] } 12embassy-rp = { path = "../../../../embassy-rp", features = ["nightly"] }
13embassy-boot-rp = { path = "../../../../embassy-boot/rp", default-features = false } 13embassy-boot-rp = { path = "../../../../embassy-boot/rp" }
14embassy-time = { path = "../../../../embassy-time", features = ["nightly"] } 14embassy-time = { path = "../../../../embassy-time", features = ["nightly"] }
15 15
16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index f2675aa73..fbc80b34c 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = ["nightly"] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } 13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15cortex-m-rt = { version = "0.7" } 15cortex-m-rt = { version = "0.7" }
16embedded-storage = "0.3.0" 16embedded-storage = "0.3.0"
diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf/.cargo/config.toml
index 4eec189d4..03995f963 100644
--- a/tests/nrf/.cargo/config.toml
+++ b/tests/nrf/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "teleprobe local run --chip nRF52840_xxAA --elf" 2#runner = "teleprobe local run --chip nRF52840_xxAA --elf"
3runner = "teleprobe client run --target nrf52840-dk --elf" 3runner = "teleprobe client run"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index ac38229a6..9735c87d9 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -5,6 +5,8 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8teleprobe-meta = "1"
9
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } 11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
10embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
diff --git a/tests/nrf/build.rs b/tests/nrf/build.rs
index 6f4872249..93e2a28cf 100644
--- a/tests/nrf/build.rs
+++ b/tests/nrf/build.rs
@@ -11,6 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
11 println!("cargo:rustc-link-arg-bins=--nmagic"); 11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); 12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
14 15
15 Ok(()) 16 Ok(())
16} 17}
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs
index e73d4f0b0..72a4cb4ef 100644
--- a/tests/nrf/src/bin/buffered_uart.rs
+++ b/tests/nrf/src/bin/buffered_uart.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs
index 74eda6d01..50960206f 100644
--- a/tests/nrf/src/bin/buffered_uart_spam.rs
+++ b/tests/nrf/src/bin/buffered_uart_spam.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use core::mem; 7use core::mem;
6use core::ptr::NonNull; 8use core::ptr::NonNull;
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf/src/bin/timer.rs
index 9b9b5fb28..607c5bbf1 100644
--- a/tests/nrf/src/bin/timer.rs
+++ b/tests/nrf/src/bin/timer.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert, info}; 7use defmt::{assert, info};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs
new file mode 100644
index 000000000..1a05ac1c5
--- /dev/null
+++ b/tests/nrf/src/common.rs
@@ -0,0 +1 @@
teleprobe_meta::target!(b"nrf52840-dk");
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml
index e1744c703..bc92e788b 100644
--- a/tests/rp/.cargo/config.toml
+++ b/tests/rp/.cargo/config.toml
@@ -5,8 +5,8 @@
5#build-std-features = ["panic_immediate_abort"] 5#build-std-features = ["panic_immediate_abort"]
6 6
7[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 7[target.'cfg(all(target_arch = "arm", target_os = "none"))']
8#runner = "teleprobe client run --target rpi-pico --elf" 8runner = "teleprobe client run"
9runner = "teleprobe local run --chip RP2040 --elf" 9#runner = "teleprobe local run --chip RP2040 --elf"
10 10
11rustflags = [ 11rustflags = [
12 # Code-size optimizations. 12 # Code-size optimizations.
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 43167166e..1786baee3 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -5,6 +5,8 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8teleprobe-meta = "1"
9
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
diff --git a/tests/rp/build.rs b/tests/rp/build.rs
index 6f4872249..93e2a28cf 100644
--- a/tests/rp/build.rs
+++ b/tests/rp/build.rs
@@ -11,6 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
11 println!("cargo:rustc-link-arg-bins=--nmagic"); 11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); 12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
14 15
15 Ok(()) 16 Ok(())
16} 17}
diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs
index c53f644bd..2c0b559a9 100644
--- a/tests/rp/src/bin/dma_copy_async.rs
+++ b/tests/rp/src/bin/dma_copy_async.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs
index 00bebe2b6..cf9b86df5 100644
--- a/tests/rp/src/bin/flash.rs
+++ b/tests/rp/src/bin/flash.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::*; 7use defmt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs
index 6715271e6..6a982507a 100644
--- a/tests/rp/src/bin/float.rs
+++ b/tests/rp/src/bin/float.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::*; 7use defmt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index 80e92d0fd..51112d319 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert, *}; 7use defmt::{assert, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs
index f20b8fcbd..532494de5 100644
--- a/tests/rp/src/bin/gpio_async.rs
+++ b/tests/rp/src/bin/gpio_async.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert, *}; 7use defmt::{assert, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs
index 6c13ccaae..780112bc1 100644
--- a/tests/rp/src/bin/gpio_multicore.rs
+++ b/tests/rp/src/bin/gpio_multicore.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
6use embassy_executor::Executor; 8use embassy_executor::Executor;
diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs
index da78e887a..114889dec 100644
--- a/tests/rp/src/bin/multicore.rs
+++ b/tests/rp/src/bin/multicore.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
6use embassy_executor::Executor; 8use embassy_executor::Executor;
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs
index b8cbe74c8..c71d21ef9 100644
--- a/tests/rp/src/bin/pwm.rs
+++ b/tests/rp/src/bin/pwm.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert, assert_eq, assert_ne, *}; 7use defmt::{assert, assert_eq, assert_ne, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs
index 478d62ee0..84dfa5a2c 100644
--- a/tests/rp/src/bin/spi.rs
+++ b/tests/rp/src/bin/spi.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs
index 2e22c9de7..a4080b03d 100644
--- a/tests/rp/src/bin/spi_async.rs
+++ b/tests/rp/src/bin/spi_async.rs
@@ -4,6 +4,8 @@
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
7#[path = "../common.rs"]
8mod common;
7 9
8use defmt::{assert_eq, *}; 10use defmt::{assert_eq, *};
9use embassy_executor::Spawner; 11use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs
index 80c18c02e..2331c7d36 100644
--- a/tests/rp/src/bin/uart.rs
+++ b/tests/rp/src/bin/uart.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index 1dcf57d07..e74e9986c 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, panic, *}; 7use defmt::{assert_eq, panic, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs
index 75be76eda..fee6c825d 100644
--- a/tests/rp/src/bin/uart_dma.rs
+++ b/tests/rp/src/bin/uart_dma.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_upgrade.rs b/tests/rp/src/bin/uart_upgrade.rs
index 8605bb1c5..760e53954 100644
--- a/tests/rp/src/bin/uart_upgrade.rs
+++ b/tests/rp/src/bin/uart_upgrade.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5use defmt::{assert_eq, *}; 7use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/tests/rp/src/common.rs b/tests/rp/src/common.rs
new file mode 100644
index 000000000..955674f27
--- /dev/null
+++ b/tests/rp/src/common.rs
@@ -0,0 +1 @@
teleprobe_meta::target!(b"rpi-pico");
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
index 426d6e67f..07761b01c 100644
--- a/tests/stm32/.cargo/config.toml
+++ b/tests/stm32/.cargo/config.toml
@@ -3,7 +3,7 @@ build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" 6runner = "teleprobe client run"
7#runner = "teleprobe local run --chip STM32F103C8 --elf" 7#runner = "teleprobe local run --chip STM32F103C8 --elf"
8 8
9rustflags = [ 9rustflags = [
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 4c0597746..f1b0ba121 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -22,6 +22,8 @@ ble = []
22not-gpdma = [] 22not-gpdma = []
23 23
24[dependencies] 24[dependencies]
25teleprobe-meta = "1"
26
25embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 27embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
26embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 28embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
27embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } 29embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index b4583147e..2e71954d7 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -26,6 +26,7 @@ fn main() -> Result<(), Box<dyn Error>> {
26 } 26 }
27 27
28 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 28 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
29 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
29 30
30 Ok(()) 31 Ok(())
31} 32}
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index 8b99b08a5..67f44317e 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -1,13 +1,13 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert; 8use defmt::assert;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Speed}; 10use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Speed};
10use example_common::*;
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index ccf2ca609..32d35c42c 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -1,18 +1,16 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5// required-features: chrono
6
7#[path = "../example_common.rs"]
8mod example_common;
9use chrono::{NaiveDate, NaiveDateTime}; 7use chrono::{NaiveDate, NaiveDateTime};
8use common::*;
10use defmt::assert; 9use defmt::assert;
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
12use embassy_stm32::pac; 11use embassy_stm32::pac;
13use embassy_stm32::rtc::{Rtc, RtcConfig}; 12use embassy_stm32::rtc::{Rtc, RtcConfig};
14use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
15use example_common::*;
16 14
17#[embassy_executor::main] 15#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
index 7d96cf41e..515025386 100644
--- a/tests/stm32/src/bin/sdmmc.rs
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -2,6 +2,8 @@
2#![no_std] 2#![no_std]
3#![no_main] 3#![no_main]
4#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
5#[path = "../common.rs"]
6mod common;
5 7
6use defmt::{assert_eq, *}; 8use defmt::{assert_eq, *};
7use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index a87ac3237..819ecae3c 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -1,15 +1,15 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
10use embassy_stm32::spi::{self, Spi}; 11use embassy_stm32::spi::{self, Spi};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12use example_common::*;
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index 74776ebf8..78aad24e1 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -1,14 +1,14 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::spi::{self, Spi};
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11use example_common::*;
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/timer.rs b/tests/stm32/src/bin/timer.rs
index e00e43bf1..f8b453cda 100644
--- a/tests/stm32/src/bin/timer.rs
+++ b/tests/stm32/src/bin/timer.rs
@@ -1,13 +1,13 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert; 8use defmt::assert;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_time::{Duration, Instant, Timer}; 10use embassy_time::{Duration, Instant, Timer};
10use example_common::*;
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index 626e7ac6f..fab9f0e1b 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -1,16 +1,16 @@
1// required-features: ble
2
1#![no_std] 3#![no_std]
2#![no_main] 4#![no_main]
3#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
4 8
5// required-features: ble 9use common::*;
6
7#[path = "../example_common.rs"]
8mod example_common;
9use embassy_executor::Spawner; 10use embassy_executor::Spawner;
10use embassy_stm32::tl_mbox::{Config, TlMbox}; 11use embassy_stm32::tl_mbox::{Config, TlMbox};
11use embassy_stm32::{bind_interrupts, tl_mbox}; 12use embassy_stm32::{bind_interrupts, tl_mbox};
12use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
13use example_common::*;
14 14
15bind_interrupts!(struct Irqs{ 15bind_interrupts!(struct Irqs{
16 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 16 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler;
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 415c7afa9..394005b82 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -1,16 +1,16 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Error, Uart}; 11use embassy_stm32::usart::{Config, Error, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 12use embassy_stm32::{bind_interrupts, peripherals, usart};
12use embassy_time::{Duration, Instant}; 13use embassy_time::{Duration, Instant};
13use example_common::*;
14 14
15#[cfg(any( 15#[cfg(any(
16 feature = "stm32f103c8", 16 feature = "stm32f103c8",
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index 7f002b97e..50dd2893e 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -1,15 +1,15 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_futures::join::join; 10use embassy_futures::join::join;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 12use embassy_stm32::{bind_interrupts, peripherals, usart};
12use example_common::*;
13 13
14#[cfg(any( 14#[cfg(any(
15 feature = "stm32f103c8", 15 feature = "stm32f103c8",
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index 3a34773f7..c8dd2643b 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -3,15 +3,15 @@
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
6 8
7#[path = "../example_common.rs"] 9use common::*;
8mod example_common;
9use defmt::{assert_eq, panic}; 10use defmt::{assert_eq, panic};
10use embassy_executor::Spawner; 11use embassy_executor::Spawner;
11use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; 12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
12use embassy_stm32::{bind_interrupts, peripherals, usart}; 13use embassy_stm32::{bind_interrupts, peripherals, usart};
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14use example_common::*;
15use rand_chacha::ChaCha8Rng; 15use rand_chacha::ChaCha8Rng;
16use rand_core::{RngCore, SeedableRng}; 16use rand_core::{RngCore, SeedableRng};
17 17
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
new file mode 100644
index 000000000..3d2a9b8ef
--- /dev/null
+++ b/tests/stm32/src/common.rs
@@ -0,0 +1,44 @@
1#![macro_use]
2
3pub use defmt::*;
4#[allow(unused)]
5use embassy_stm32::time::Hertz;
6use embassy_stm32::Config;
7use {defmt_rtt as _, panic_probe as _};
8
9#[cfg(feature = "stm32f103c8")]
10teleprobe_meta::target!(b"bluepill-stm32f103c8");
11#[cfg(feature = "stm32g491re")]
12teleprobe_meta::target!(b"nucleo-stm32g491re");
13#[cfg(feature = "stm32g071rb")]
14teleprobe_meta::target!(b"nucleo-stm32g071rb");
15#[cfg(feature = "stm32f429zi")]
16teleprobe_meta::target!(b"nucleo-stm32f429zi");
17#[cfg(feature = "stm32wb55rg")]
18teleprobe_meta::target!(b"nucleo-stm32wb55rg");
19#[cfg(feature = "stm32h755zi")]
20teleprobe_meta::target!(b"nucleo-stm32h755zi");
21#[cfg(feature = "stm32u585ai")]
22teleprobe_meta::target!(b"iot-stm32u585ai");
23#[cfg(feature = "stm32h563zi")]
24teleprobe_meta::target!(b"nucleo-stm32h563zi");
25#[cfg(feature = "stm32c031c6")]
26teleprobe_meta::target!(b"nucleo-stm32c031c6");
27
28pub fn config() -> Config {
29 #[allow(unused_mut)]
30 let mut config = Config::default();
31
32 #[cfg(feature = "stm32h755zi")]
33 {
34 config.rcc.sys_ck = Some(Hertz(400_000_000));
35 config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
36 }
37
38 #[cfg(feature = "stm32u585ai")]
39 {
40 config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
41 }
42
43 config
44}
diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs
deleted file mode 100644
index 3d150da60..000000000
--- a/tests/stm32/src/example_common.rs
+++ /dev/null
@@ -1,25 +0,0 @@
1#![macro_use]
2
3pub use defmt::*;
4#[allow(unused)]
5use embassy_stm32::time::Hertz;
6use embassy_stm32::Config;
7use {defmt_rtt as _, panic_probe as _};
8
9pub fn config() -> Config {
10 #[allow(unused_mut)]
11 let mut config = Config::default();
12
13 #[cfg(feature = "stm32h755zi")]
14 {
15 config.rcc.sys_ck = Some(Hertz(400_000_000));
16 config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
17 }
18
19 #[cfg(feature = "stm32u585ai")]
20 {
21 config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
22 }
23
24 config
25}