aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2024-04-16 13:48:18 +0200
committerDion Dokter <[email protected]>2024-04-16 13:48:18 +0200
commitc8c7c718f39d441492aa37d1404851d08a708098 (patch)
treec98b52116524cf39d06c229c6c0857a98ab4262b
parente224e6cef4e0508f14bb9ffd1d9d0fc9220c07d8 (diff)
parente38f1011d6234fbc51fbbbb2d93365517705e3ac (diff)
Merge branch 'master' into u0-dion
-rwxr-xr-x.github/ci/test-nightly.sh1
-rwxr-xr-x.github/ci/test.sh1
-rw-r--r--.vscode/settings.json3
-rwxr-xr-xci.sh3
-rw-r--r--cyw43/src/control.rs10
-rw-r--r--embassy-futures/src/yield_now.rs8
-rw-r--r--embassy-nrf/CHANGELOG.md40
-rw-r--r--embassy-stm32/Cargo.toml3
-rw-r--r--embassy-stm32/build.rs1
-rw-r--r--embassy-stm32/src/dma/mod.rs3
-rw-r--r--embassy-stm32/src/dma/util.rs60
-rw-r--r--embassy-stm32/src/flash/h50.rs50
-rw-r--r--embassy-stm32/src/flash/u5.rs39
-rw-r--r--embassy-stm32/src/i2c/mod.rs61
-rw-r--r--embassy-stm32/src/i2c/v1.rs50
-rw-r--r--embassy-stm32/src/i2c/v2.rs276
-rw-r--r--embassy-stm32/src/i2s.rs24
-rw-r--r--embassy-stm32/src/lib.rs25
-rw-r--r--embassy-stm32/src/macros.rs (renamed from embassy-stm32/src/traits.rs)26
-rw-r--r--embassy-stm32/src/rcc/mod.rs18
-rw-r--r--embassy-stm32/src/spi/mod.rs541
-rw-r--r--embassy-stm32/src/usart/mod.rs854
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs20
-rw-r--r--embassy-sync/src/mutex.rs133
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/i2c.rs18
-rw-r--r--examples/stm32f4/src/bin/spi.rs3
-rw-r--r--examples/stm32f4/src/bin/usart.rs3
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/ws2812_spi.rs4
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs3
-rw-r--r--examples/stm32h5/src/bin/usart.rs8
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs18
-rw-r--r--examples/stm32h7/src/bin/spi.rs6
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs6
-rw-r--r--examples/stm32h7/src/bin/usart.rs8
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs18
-rw-r--r--examples/stm32l0/src/bin/spi.rs3
-rw-r--r--examples/stm32l1/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/i2c.rs18
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs18
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs26
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs3
-rw-r--r--examples/stm32l4/src/bin/usart.rs3
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs3
-rw-r--r--examples/stm32u0/.cargo/config.toml4
-rw-r--r--examples/stm32u0/Cargo.toml2
-rw-r--r--examples/stm32u5/Cargo.toml4
-rw-r--r--examples/stm32u5/src/bin/i2c.rs18
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--tests/stm32/src/bin/spi.rs5
-rw-r--r--tests/stm32/src/bin/usart.rs8
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs3
57 files changed, 1502 insertions, 984 deletions
diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh
index d6e5dc574..1724ffe89 100755
--- a/.github/ci/test-nightly.sh
+++ b/.github/ci/test-nightly.sh
@@ -11,3 +11,4 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml
11 11
12MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml 12MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
13MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly 13MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly
14MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-sync/Cargo.toml
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 6cb3a4bff..41da644fc 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -8,6 +8,7 @@ export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10 10
11cargo test --manifest-path ./embassy-futures/Cargo.toml
11cargo test --manifest-path ./embassy-sync/Cargo.toml 12cargo test --manifest-path ./embassy-sync/Cargo.toml
12cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml 13cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
13cargo test --manifest-path ./embassy-hal-internal/Cargo.toml 14cargo test --manifest-path ./embassy-hal-internal/Cargo.toml
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 0c195a13b..220d25914 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,10 +15,11 @@
15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
17 "rust-analyzer.cargo.features": [ 17 "rust-analyzer.cargo.features": [
18 "stm32f103c8", 18 "stm32f446re",
19 "time-driver-any", 19 "time-driver-any",
20 "unstable-pac", 20 "unstable-pac",
21 "exti", 21 "exti",
22 "rt",
22 ], 23 ],
23 "rust-analyzer.linkedProjects": [ 24 "rust-analyzer.linkedProjects": [
24 // Uncomment ONE line for the chip you want to work on. 25 // Uncomment ONE line for the chip you want to work on.
diff --git a/ci.sh b/ci.sh
index 1393b9d47..514c6769b 100755
--- a/ci.sh
+++ b/ci.sh
@@ -253,6 +253,9 @@ rm out/tests/stm32f207zg/eth
253# doesn't work, gives "noise error", no idea why. usart_dma does pass. 253# doesn't work, gives "noise error", no idea why. usart_dma does pass.
254rm out/tests/stm32u5a5zj/usart 254rm out/tests/stm32u5a5zj/usart
255 255
256# flaky, perhaps bad wire
257rm out/tests/stm32l152re/usart_rx_ringbuffered
258
256if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 259if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
257 echo No teleprobe token found, skipping running HIL tests 260 echo No teleprobe token found, skipping running HIL tests
258 exit 261 exit
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 135b8c245..a3808f56f 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -124,8 +124,7 @@ impl<'a> Control<'a> {
124 self.set_iovar_u32("apsta", 1).await; 124 self.set_iovar_u32("apsta", 1).await;
125 125
126 // read MAC addr. 126 // read MAC addr.
127 let mut mac_addr = [0; 6]; 127 let mac_addr = self.address().await;
128 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
129 debug!("mac addr: {:02x}", Bytes(&mac_addr)); 128 debug!("mac addr: {:02x}", Bytes(&mac_addr));
130 129
131 let country = countries::WORLD_WIDE_XX; 130 let country = countries::WORLD_WIDE_XX;
@@ -574,6 +573,13 @@ impl<'a> Control<'a> {
574 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; 573 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
575 info!("Disassociated") 574 info!("Disassociated")
576 } 575 }
576
577 /// Gets the MAC address of the device
578 pub async fn address(&mut self) -> [u8; 6] {
579 let mut mac_addr = [0; 6];
580 assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
581 mac_addr
582 }
577} 583}
578 584
579/// WiFi network scanner. 585/// WiFi network scanner.
diff --git a/embassy-futures/src/yield_now.rs b/embassy-futures/src/yield_now.rs
index bb3c67d17..4d4e535f2 100644
--- a/embassy-futures/src/yield_now.rs
+++ b/embassy-futures/src/yield_now.rs
@@ -9,10 +9,16 @@ use core::task::{Context, Poll};
9/// hold, while still allowing other tasks to run concurrently (not monopolizing 9/// hold, while still allowing other tasks to run concurrently (not monopolizing
10/// the executor thread). 10/// the executor thread).
11/// 11///
12/// ```rust,no_run 12/// ```rust
13/// # use embassy_futures::{block_on, yield_now};
14/// # async fn test_fn() {
15/// # let mut iter_count: u32 = 0;
16/// # let mut some_condition = || { iter_count += 1; iter_count > 10 };
13/// while !some_condition() { 17/// while !some_condition() {
14/// yield_now().await; 18/// yield_now().await;
15/// } 19/// }
20/// # }
21/// # block_on(test_fn());
16/// ``` 22/// ```
17/// 23///
18/// The downside is this will spin in a busy loop, using 100% of the CPU, while 24/// The downside is this will spin in a busy loop, using 100% of the CPU, while
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
new file mode 100644
index 000000000..773a1a108
--- /dev/null
+++ b/embassy-nrf/CHANGELOG.md
@@ -0,0 +1,40 @@
1# Changelog for embassy-nrf
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10- Drop `sealed` mod
11- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
12- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral
13- spim: Reduce trace-level messages ("Copying SPIM tx buffer..")
14- uart: Add support for rx- or tx-only BufferedUart
15- uart: Implement splitting Rx/Tx
16- spi: Allow specifying OutputDrive for SPI spins
17- pdm: Fix gain register value derivation
18- spim: Implement chunked DMA transfers
19- spi: Add bounds checks for EasyDMA buffer size
20- uarte: Add support for handling RX errors
21- nrf51: Implement support for nrf51 chip
22- pwm: Expose `duty` method
23- pwm: Fix infinite loop
24- spi: Add support for configuring bit order for bus
25- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
26- gpio: Drop GPIO Pin generics (API break)
27
28## 0.1.0 - 2024-01-12
29
30- First release with support for following NRF chips:
31 - nrf52805
32 - nrf52810
33 - nrf52811
34 - nrf52820
35 - nrf52832
36 - nrf52833
37 - nrf52840
38 - nrf5340
39 - nrf9160
40
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 459d2e370..1f9a51678 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -115,6 +115,9 @@ low-power-debug-with-sleep = []
115## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) 115## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/)
116memory-x = ["stm32-metapac/memory-x"] 116memory-x = ["stm32-metapac/memory-x"]
117 117
118## Use secure registers when TrustZone is enabled
119trustzone-secure = []
120
118## Re-export stm32-metapac at `embassy_stm32::pac`. 121## Re-export stm32-metapac at `embassy_stm32::pac`.
119## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. 122## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
120## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 123## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 0f87dd8ac..67fceda56 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -662,6 +662,7 @@ fn main() {
662 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* 662 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
663 663
664 #[derive(Clone, Copy)] 664 #[derive(Clone, Copy)]
665 #[non_exhaustive]
665 pub struct ClockMux { 666 pub struct ClockMux {
666 #( #struct_fields, )* 667 #( #struct_fields, )*
667 } 668 }
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 7e3681469..8766d0a60 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -16,6 +16,9 @@ mod dmamux;
16#[cfg(dmamux)] 16#[cfg(dmamux)]
17pub use dmamux::*; 17pub use dmamux::*;
18 18
19mod util;
20pub(crate) use util::*;
21
19pub(crate) mod ringbuffer; 22pub(crate) mod ringbuffer;
20pub mod word; 23pub mod word;
21 24
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
new file mode 100644
index 000000000..962ea2501
--- /dev/null
+++ b/embassy-stm32/src/dma/util.rs
@@ -0,0 +1,60 @@
1use embassy_hal_internal::PeripheralRef;
2
3use super::word::Word;
4use super::{AnyChannel, Request, Transfer, TransferOptions};
5
6/// Convenience wrapper, contains a channel and a request number.
7///
8/// Commonly used in peripheral drivers that own DMA channels.
9pub(crate) struct ChannelAndRequest<'d> {
10 pub channel: PeripheralRef<'d, AnyChannel>,
11 pub request: Request,
12}
13
14impl<'d> ChannelAndRequest<'d> {
15 pub unsafe fn read<'a, W: Word>(
16 &'a mut self,
17 peri_addr: *mut W,
18 buf: &'a mut [W],
19 options: TransferOptions,
20 ) -> Transfer<'a> {
21 Transfer::new_read(&mut self.channel, self.request, peri_addr, buf, options)
22 }
23
24 pub unsafe fn read_raw<'a, W: Word>(
25 &'a mut self,
26 peri_addr: *mut W,
27 buf: *mut [W],
28 options: TransferOptions,
29 ) -> Transfer<'a> {
30 Transfer::new_read_raw(&mut self.channel, self.request, peri_addr, buf, options)
31 }
32
33 pub unsafe fn write<'a, W: Word>(
34 &'a mut self,
35 buf: &'a [W],
36 peri_addr: *mut W,
37 options: TransferOptions,
38 ) -> Transfer<'a> {
39 Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options)
40 }
41
42 pub unsafe fn write_raw<'a, W: Word>(
43 &'a mut self,
44 buf: *const [W],
45 peri_addr: *mut W,
46 options: TransferOptions,
47 ) -> Transfer<'a> {
48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
49 }
50
51 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self,
53 repeated: &'a W,
54 count: usize,
55 peri_addr: *mut W,
56 options: TransferOptions,
57 ) -> Transfer<'a> {
58 Transfer::new_write_repeated(&mut self.channel, self.request, repeated, count, peri_addr, options)
59 }
60}
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index 5b15be261..56ea7a421 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -61,9 +61,12 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
61 61
62 interrupt::free(|_| { 62 interrupt::free(|_| {
63 pac::FLASH.nscr().modify(|w| { 63 pac::FLASH.nscr().modify(|w| {
64 w.set_bksel(match sector.bank { 64 // BKSEL ignores SWAP_BANK, so we must take it into account here
65 FlashBank::Bank1 => Bksel::BANK1, 65 w.set_bksel(match (sector.bank, banks_swapped()) {
66 FlashBank::Bank2 => Bksel::BANK2, 66 (FlashBank::Bank1, false) => Bksel::BANK1,
67 (FlashBank::Bank2, true) => Bksel::BANK1,
68 (FlashBank::Bank2, false) => Bksel::BANK2,
69 (FlashBank::Bank1, true) => Bksel::BANK2,
67 }); 70 });
68 w.set_snb(sector.index_in_bank); 71 w.set_snb(sector.index_in_bank);
69 w.set_ser(true); 72 w.set_ser(true);
@@ -111,6 +114,47 @@ pub(crate) unsafe fn clear_all_err() {
111 }) 114 })
112} 115}
113 116
117/// Get the current SWAP_BANK option.
118///
119/// This value is only loaded on system or power-on reset. `perform_bank_swap()`
120/// will not reflect here.
121pub fn banks_swapped() -> bool {
122 pac::FLASH.optcr().read().swap_bank()
123}
124
125/// Logical, persistent swap of flash banks 1 and 2.
126///
127/// This allows the application to write a new firmware blob into bank 2, then
128/// swap the banks and perform a reset, loading the new firmware.
129///
130/// Swap does not take effect until system or power-on reset.
131///
132/// PLEASE READ THE REFERENCE MANUAL - there are nuances to this feature. For
133/// instance, erase commands and interrupt enables which take a flash bank as a
134/// parameter ignore the swap!
135pub fn perform_bank_swap() {
136 while busy() {}
137
138 unsafe {
139 clear_all_err();
140 }
141
142 // unlock OPTLOCK
143 pac::FLASH.optkeyr().write(|w| *w = 0x0819_2A3B);
144 pac::FLASH.optkeyr().write(|w| *w = 0x4C5D_6E7F);
145 while pac::FLASH.optcr().read().optlock() {}
146
147 // toggle SWAP_BANK option
148 pac::FLASH.optsr_prg().modify(|w| w.set_swap_bank(!banks_swapped()));
149
150 // load option bytes
151 pac::FLASH.optcr().modify(|w| w.set_optstrt(true));
152 while pac::FLASH.optcr().read().optstrt() {}
153
154 // re-lock OPTLOCK
155 pac::FLASH.optcr().modify(|w| w.set_optlock(true));
156}
157
114fn sr_busy(sr: Nssr) -> bool { 158fn sr_busy(sr: Nssr) -> bool {
115 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE 159 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE
116 sr.bsy() || sr.dbne() || sr.wbne() 160 sr.bsy() || sr.dbne() || sr.wbne()
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 580c490da..ddd4d73ff 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -14,26 +14,43 @@ pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14} 14}
15 15
16pub(crate) unsafe fn lock() { 16pub(crate) unsafe fn lock() {
17 #[cfg(feature = "trustzone-secure")]
17 pac::FLASH.seccr().modify(|w| w.set_lock(true)); 18 pac::FLASH.seccr().modify(|w| w.set_lock(true));
19 #[cfg(not(feature = "trustzone-secure"))]
20 pac::FLASH.nscr().modify(|w| w.set_lock(true));
18} 21}
19 22
20pub(crate) unsafe fn unlock() { 23pub(crate) unsafe fn unlock() {
24 #[cfg(feature = "trustzone-secure")]
21 if pac::FLASH.seccr().read().lock() { 25 if pac::FLASH.seccr().read().lock() {
22 pac::FLASH.seckeyr().write_value(0x4567_0123); 26 pac::FLASH.seckeyr().write_value(0x4567_0123);
23 pac::FLASH.seckeyr().write_value(0xCDEF_89AB); 27 pac::FLASH.seckeyr().write_value(0xCDEF_89AB);
24 } 28 }
29 #[cfg(not(feature = "trustzone-secure"))]
30 if pac::FLASH.nscr().read().lock() {
31 pac::FLASH.nskeyr().write_value(0x4567_0123);
32 pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
33 }
25} 34}
26 35
27pub(crate) unsafe fn enable_blocking_write() { 36pub(crate) unsafe fn enable_blocking_write() {
28 assert_eq!(0, WRITE_SIZE % 4); 37 assert_eq!(0, WRITE_SIZE % 4);
29 38
39 #[cfg(feature = "trustzone-secure")]
30 pac::FLASH.seccr().write(|w| { 40 pac::FLASH.seccr().write(|w| {
31 w.set_pg(pac::flash::vals::SeccrPg::B_0X1); 41 w.set_pg(pac::flash::vals::SeccrPg::B_0X1);
32 }); 42 });
43 #[cfg(not(feature = "trustzone-secure"))]
44 pac::FLASH.nscr().write(|w| {
45 w.set_pg(pac::flash::vals::NscrPg::B_0X1);
46 });
33} 47}
34 48
35pub(crate) unsafe fn disable_blocking_write() { 49pub(crate) unsafe fn disable_blocking_write() {
50 #[cfg(feature = "trustzone-secure")]
36 pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0)); 51 pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0));
52 #[cfg(not(feature = "trustzone-secure"))]
53 pac::FLASH.nscr().write(|w| w.set_pg(pac::flash::vals::NscrPg::B_0X0));
37} 54}
38 55
39pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 56pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
@@ -50,19 +67,35 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
50} 67}
51 68
52pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 69pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
70 #[cfg(feature = "trustzone-secure")]
53 pac::FLASH.seccr().modify(|w| { 71 pac::FLASH.seccr().modify(|w| {
54 w.set_per(pac::flash::vals::SeccrPer::B_0X1); 72 w.set_per(pac::flash::vals::SeccrPer::B_0X1);
55 w.set_pnb(sector.index_in_bank) 73 w.set_pnb(sector.index_in_bank)
56 }); 74 });
75 #[cfg(not(feature = "trustzone-secure"))]
76 pac::FLASH.nscr().modify(|w| {
77 w.set_per(pac::flash::vals::NscrPer::B_0X1);
78 w.set_pnb(sector.index_in_bank)
79 });
57 80
81 #[cfg(feature = "trustzone-secure")]
58 pac::FLASH.seccr().modify(|w| { 82 pac::FLASH.seccr().modify(|w| {
59 w.set_strt(true); 83 w.set_strt(true);
60 }); 84 });
85 #[cfg(not(feature = "trustzone-secure"))]
86 pac::FLASH.nscr().modify(|w| {
87 w.set_strt(true);
88 });
61 89
62 let ret: Result<(), Error> = blocking_wait_ready(); 90 let ret: Result<(), Error> = blocking_wait_ready();
91 #[cfg(feature = "trustzone-secure")]
63 pac::FLASH 92 pac::FLASH
64 .seccr() 93 .seccr()
65 .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0)); 94 .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0));
95 #[cfg(not(feature = "trustzone-secure"))]
96 pac::FLASH
97 .nscr()
98 .modify(|w| w.set_per(pac::flash::vals::NscrPer::B_0X0));
66 clear_all_err(); 99 clear_all_err();
67 ret 100 ret
68} 101}
@@ -70,12 +103,18 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
70pub(crate) unsafe fn clear_all_err() { 103pub(crate) unsafe fn clear_all_err() {
71 // read and write back the same value. 104 // read and write back the same value.
72 // This clears all "write 1 to clear" bits. 105 // This clears all "write 1 to clear" bits.
106 #[cfg(feature = "trustzone-secure")]
73 pac::FLASH.secsr().modify(|_| {}); 107 pac::FLASH.secsr().modify(|_| {});
108 #[cfg(not(feature = "trustzone-secure"))]
109 pac::FLASH.nssr().modify(|_| {});
74} 110}
75 111
76unsafe fn blocking_wait_ready() -> Result<(), Error> { 112unsafe fn blocking_wait_ready() -> Result<(), Error> {
77 loop { 113 loop {
114 #[cfg(feature = "trustzone-secure")]
78 let sr = pac::FLASH.secsr().read(); 115 let sr = pac::FLASH.secsr().read();
116 #[cfg(not(feature = "trustzone-secure"))]
117 let sr = pac::FLASH.nssr().read();
79 118
80 if !sr.bsy() { 119 if !sr.bsy() {
81 if sr.pgserr() { 120 if sr.pgserr() {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index a46061d54..ccbea9831 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -14,9 +14,10 @@ use embassy_sync::waitqueue::AtomicWaker;
14#[cfg(feature = "time")] 14#[cfg(feature = "time")]
15use embassy_time::{Duration, Instant}; 15use embassy_time::{Duration, Instant};
16 16
17use crate::dma::NoDma; 17use crate::dma::ChannelAndRequest;
18use crate::gpio::{AFType, Pull}; 18use crate::gpio::{AFType, Pull};
19use crate::interrupt::typelevel::Interrupt; 19use crate::interrupt::typelevel::Interrupt;
20use crate::mode::{Async, Blocking, Mode};
20use crate::time::Hertz; 21use crate::time::Hertz;
21use crate::{interrupt, peripherals}; 22use crate::{interrupt, peripherals};
22 23
@@ -71,17 +72,16 @@ impl Default for Config {
71} 72}
72 73
73/// I2C driver. 74/// I2C driver.
74pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { 75pub struct I2c<'d, T: Instance, M: Mode> {
75 _peri: PeripheralRef<'d, T>, 76 _peri: PeripheralRef<'d, T>,
76 #[allow(dead_code)] 77 tx_dma: Option<ChannelAndRequest<'d>>,
77 tx_dma: PeripheralRef<'d, TXDMA>, 78 rx_dma: Option<ChannelAndRequest<'d>>,
78 #[allow(dead_code)]
79 rx_dma: PeripheralRef<'d, RXDMA>,
80 #[cfg(feature = "time")] 79 #[cfg(feature = "time")]
81 timeout: Duration, 80 timeout: Duration,
81 _phantom: PhantomData<M>,
82} 82}
83 83
84impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 84impl<'d, T: Instance> I2c<'d, T, Async> {
85 /// Create a new I2C driver. 85 /// Create a new I2C driver.
86 pub fn new( 86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd, 87 peri: impl Peripheral<P = T> + 'd,
@@ -90,12 +90,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
92 + 'd, 92 + 'd,
93 tx_dma: impl Peripheral<P = TXDMA> + 'd, 93 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
94 rx_dma: impl Peripheral<P = RXDMA> + 'd, 94 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
95 freq: Hertz, 95 freq: Hertz,
96 config: Config, 96 config: Config,
97 ) -> Self { 97 ) -> Self {
98 into_ref!(peri, scl, sda, tx_dma, rx_dma); 98 Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config)
99 }
100}
101
102impl<'d, T: Instance> I2c<'d, T, Blocking> {
103 /// Create a new blocking I2C driver.
104 pub fn new_blocking(
105 peri: impl Peripheral<P = T> + 'd,
106 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
107 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
108 freq: Hertz,
109 config: Config,
110 ) -> Self {
111 Self::new_inner(peri, scl, sda, None, None, freq, config)
112 }
113}
114
115impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
116 /// Create a new I2C driver.
117 fn new_inner(
118 peri: impl Peripheral<P = T> + 'd,
119 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
120 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
121 tx_dma: Option<ChannelAndRequest<'d>>,
122 rx_dma: Option<ChannelAndRequest<'d>>,
123 freq: Hertz,
124 config: Config,
125 ) -> Self {
126 into_ref!(peri, scl, sda);
99 127
100 T::enable_and_reset(); 128 T::enable_and_reset();
101 129
@@ -125,6 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
125 rx_dma, 153 rx_dma,
126 #[cfg(feature = "time")] 154 #[cfg(feature = "time")]
127 timeout: config.timeout, 155 timeout: config.timeout,
156 _phantom: PhantomData,
128 }; 157 };
129 158
130 this.init(freq, config); 159 this.init(freq, config);
@@ -249,7 +278,7 @@ foreach_peripheral!(
249 }; 278 };
250); 279);
251 280
252impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 281impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
253 type Error = Error; 282 type Error = Error;
254 283
255 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { 284 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
@@ -257,7 +286,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
257 } 286 }
258} 287}
259 288
260impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { 289impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
261 type Error = Error; 290 type Error = Error;
262 291
263 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { 292 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
@@ -265,7 +294,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
265 } 294 }
266} 295}
267 296
268impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { 297impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
269 type Error = Error; 298 type Error = Error;
270 299
271 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { 300 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
@@ -289,11 +318,11 @@ impl embedded_hal_1::i2c::Error for Error {
289 } 318 }
290} 319}
291 320
292impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> { 321impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> {
293 type Error = Error; 322 type Error = Error;
294} 323}
295 324
296impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { 325impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
297 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 326 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
298 self.blocking_read(address, read) 327 self.blocking_read(address, read)
299 } 328 }
@@ -315,7 +344,7 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
315 } 344 }
316} 345}
317 346
318impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { 347impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> {
319 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 348 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
320 self.read(address, read).await 349 self.read(address, read).await
321 } 350 }
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index d45c48b24..13a473344 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -13,7 +13,7 @@ use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation; 13use embedded_hal_1::i2c::Operation;
14 14
15use super::*; 15use super::*;
16use crate::dma::Transfer; 16use crate::mode::Mode as PeriMode;
17use crate::pac::i2c; 17use crate::pac::i2c;
18 18
19// /!\ /!\ 19// /!\ /!\
@@ -41,7 +41,7 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
46 T::regs().cr1().modify(|reg| { 46 T::regs().cr1().modify(|reg| {
47 reg.set_pe(false); 47 reg.set_pe(false);
@@ -326,11 +326,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
326 w.set_itevten(true); 326 w.set_itevten(true);
327 }); 327 });
328 } 328 }
329}
329 330
330 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> 331impl<'d, T: Instance> I2c<'d, T, Async> {
331 where 332 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> {
332 TXDMA: crate::i2c::TxDma<T>,
333 {
334 T::regs().cr2().modify(|w| { 333 T::regs().cr2().modify(|w| {
335 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 334 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
336 // reception. 335 // reception.
@@ -415,9 +414,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
415 // this address from the memory after each TxE event. 414 // this address from the memory after each TxE event.
416 let dst = T::regs().dr().as_ptr() as *mut u8; 415 let dst = T::regs().dr().as_ptr() as *mut u8;
417 416
418 let ch = &mut self.tx_dma; 417 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
419 let request = ch.request();
420 Transfer::new_write(ch, request, write, dst, Default::default())
421 }; 418 };
422 419
423 // Wait for bytes to be sent, or an error to occur. 420 // Wait for bytes to be sent, or an error to occur.
@@ -479,10 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
479 } 476 }
480 477
481 /// Write. 478 /// Write.
482 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 479 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
483 where
484 TXDMA: crate::i2c::TxDma<T>,
485 {
486 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 480 self.write_frame(address, write, FrameOptions::FirstAndLastFrame)
487 .await?; 481 .await?;
488 482
@@ -490,20 +484,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
490 } 484 }
491 485
492 /// Read. 486 /// Read.
493 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 487 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
494 where
495 RXDMA: crate::i2c::RxDma<T>,
496 {
497 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 488 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame)
498 .await?; 489 .await?;
499 490
500 Ok(()) 491 Ok(())
501 } 492 }
502 493
503 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> 494 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
504 where
505 RXDMA: crate::i2c::RxDma<T>,
506 {
507 if buffer.is_empty() { 495 if buffer.is_empty() {
508 return Err(Error::Overrun); 496 return Err(Error::Overrun);
509 } 497 }
@@ -623,9 +611,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
623 // from this address from the memory after each RxE event. 611 // from this address from the memory after each RxE event.
624 let src = T::regs().dr().as_ptr() as *mut u8; 612 let src = T::regs().dr().as_ptr() as *mut u8;
625 613
626 let ch = &mut self.rx_dma; 614 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
627 let request = ch.request();
628 Transfer::new_read(ch, request, src, buffer, Default::default())
629 }; 615 };
630 616
631 // Wait for bytes to be received, or an error to occur. 617 // Wait for bytes to be received, or an error to occur.
@@ -664,11 +650,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
664 } 650 }
665 651
666 /// Write, restart, read. 652 /// Write, restart, read.
667 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 653 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
668 where
669 RXDMA: crate::i2c::RxDma<T>,
670 TXDMA: crate::i2c::TxDma<T>,
671 {
672 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 654 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
673 // stop condition below. 655 // stop condition below.
674 if read.is_empty() { 656 if read.is_empty() {
@@ -684,11 +666,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
684 /// Consecutive operations of same type are merged. See [transaction contract] for details. 666 /// Consecutive operations of same type are merged. See [transaction contract] for details.
685 /// 667 ///
686 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 668 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
687 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> 669 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
688 where
689 RXDMA: crate::i2c::RxDma<T>,
690 TXDMA: crate::i2c::TxDma<T>,
691 {
692 for (op, frame) in operation_frames(operations)? { 670 for (op, frame) in operation_frames(operations)? {
693 match op { 671 match op {
694 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 672 Operation::Read(read) => self.read_frame(addr, read, frame).await?,
@@ -700,7 +678,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
700 } 678 }
701} 679}
702 680
703impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 681impl<'d, T: Instance, M: PeriMode> Drop for I2c<'d, T, M> {
704 fn drop(&mut self) { 682 fn drop(&mut self) {
705 T::disable(); 683 T::disable();
706 } 684 }
@@ -806,7 +784,7 @@ impl Timings {
806 } 784 }
807} 785}
808 786
809impl<'d, T: Instance> SetConfig for I2c<'d, T> { 787impl<'d, T: Instance, M: PeriMode> SetConfig for I2c<'d, T, M> {
810 type Config = Hertz; 788 type Config = Hertz;
811 type ConfigError = (); 789 type ConfigError = ();
812 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 790 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index da3b0ee30..12df98534 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -7,7 +7,6 @@ use embassy_hal_internal::drop::OnDrop;
7use embedded_hal_1::i2c::Operation; 7use embedded_hal_1::i2c::Operation;
8 8
9use super::*; 9use super::*;
10use crate::dma::Transfer;
11use crate::pac::i2c; 10use crate::pac::i2c;
12 11
13pub(crate) unsafe fn on_interrupt<T: Instance>() { 12pub(crate) unsafe fn on_interrupt<T: Instance>() {
@@ -24,7 +23,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
24 }); 23 });
25} 24}
26 25
27impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 26impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
28 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 27 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
29 T::regs().cr1().modify(|reg| { 28 T::regs().cr1().modify(|reg| {
30 reg.set_pe(false); 29 reg.set_pe(false);
@@ -302,6 +301,119 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
302 result 301 result
303 } 302 }
304 303
304 // =========================
305 // Blocking public API
306
307 /// Blocking read.
308 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
309 self.read_internal(address, read, false, self.timeout())
310 // Automatic Stop
311 }
312
313 /// Blocking write.
314 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
315 self.write_internal(address, write, true, self.timeout())
316 }
317
318 /// Blocking write, restart, read.
319 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
320 let timeout = self.timeout();
321 self.write_internal(address, write, false, timeout)?;
322 self.read_internal(address, read, true, timeout)
323 // Automatic Stop
324 }
325
326 /// Blocking transaction with operations.
327 ///
328 /// Consecutive operations of same type are merged. See [transaction contract] for details.
329 ///
330 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
331 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
332 let _ = addr;
333 let _ = operations;
334 todo!()
335 }
336
337 /// Blocking write multiple buffers.
338 ///
339 /// The buffers are concatenated in a single write transaction.
340 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
341 if write.is_empty() {
342 return Err(Error::ZeroLengthTransfer);
343 }
344
345 let timeout = self.timeout();
346
347 let first_length = write[0].len();
348 let last_slice_index = write.len() - 1;
349
350 if let Err(err) = Self::master_write(
351 address,
352 first_length.min(255),
353 Stop::Software,
354 (first_length > 255) || (last_slice_index != 0),
355 timeout,
356 ) {
357 self.master_stop();
358 return Err(err);
359 }
360
361 for (idx, slice) in write.iter().enumerate() {
362 let slice_len = slice.len();
363 let completed_chunks = slice_len / 255;
364 let total_chunks = if completed_chunks * 255 == slice_len {
365 completed_chunks
366 } else {
367 completed_chunks + 1
368 };
369 let last_chunk_idx = total_chunks.saturating_sub(1);
370
371 if idx != 0 {
372 if let Err(err) = Self::master_continue(
373 slice_len.min(255),
374 (idx != last_slice_index) || (slice_len > 255),
375 timeout,
376 ) {
377 self.master_stop();
378 return Err(err);
379 }
380 }
381
382 for (number, chunk) in slice.chunks(255).enumerate() {
383 if number != 0 {
384 if let Err(err) = Self::master_continue(
385 chunk.len(),
386 (number != last_chunk_idx) || (idx != last_slice_index),
387 timeout,
388 ) {
389 self.master_stop();
390 return Err(err);
391 }
392 }
393
394 for byte in chunk {
395 // Wait until we are allowed to send data
396 // (START has been ACKed or last byte when
397 // through)
398 if let Err(err) = self.wait_txe(timeout) {
399 self.master_stop();
400 return Err(err);
401 }
402
403 // Put byte on the wire
404 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
405 T::regs().txdr().write(|w| w.set_txdata(*byte));
406 }
407 }
408 }
409 // Wait until the write finishes
410 let result = self.wait_tc(timeout);
411 self.master_stop();
412 result
413 }
414}
415
416impl<'d, T: Instance> I2c<'d, T, Async> {
305 async fn write_dma_internal( 417 async fn write_dma_internal(
306 &mut self, 418 &mut self,
307 address: u8, 419 address: u8,
@@ -309,10 +421,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
309 first_slice: bool, 421 first_slice: bool,
310 last_slice: bool, 422 last_slice: bool,
311 timeout: Timeout, 423 timeout: Timeout,
312 ) -> Result<(), Error> 424 ) -> Result<(), Error> {
313 where
314 TXDMA: crate::i2c::TxDma<T>,
315 {
316 let total_len = write.len(); 425 let total_len = write.len();
317 426
318 let dma_transfer = unsafe { 427 let dma_transfer = unsafe {
@@ -325,9 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
325 }); 434 });
326 let dst = regs.txdr().as_ptr() as *mut u8; 435 let dst = regs.txdr().as_ptr() as *mut u8;
327 436
328 let ch = &mut self.tx_dma; 437 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
329 let request = ch.request();
330 Transfer::new_write(ch, request, write, dst, Default::default())
331 }; 438 };
332 439
333 let state = T::state(); 440 let state = T::state();
@@ -398,10 +505,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
398 buffer: &mut [u8], 505 buffer: &mut [u8],
399 restart: bool, 506 restart: bool,
400 timeout: Timeout, 507 timeout: Timeout,
401 ) -> Result<(), Error> 508 ) -> Result<(), Error> {
402 where
403 RXDMA: crate::i2c::RxDma<T>,
404 {
405 let total_len = buffer.len(); 509 let total_len = buffer.len();
406 510
407 let dma_transfer = unsafe { 511 let dma_transfer = unsafe {
@@ -412,9 +516,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
412 }); 516 });
413 let src = regs.rxdr().as_ptr() as *mut u8; 517 let src = regs.rxdr().as_ptr() as *mut u8;
414 518
415 let ch = &mut self.rx_dma; 519 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
416 let request = ch.request();
417 Transfer::new_read(ch, request, src, buffer, Default::default())
418 }; 520 };
419 521
420 let state = T::state(); 522 let state = T::state();
@@ -475,10 +577,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
475 // Async public API 577 // Async public API
476 578
477 /// Write. 579 /// Write.
478 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 580 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
479 where
480 TXDMA: crate::i2c::TxDma<T>,
481 {
482 let timeout = self.timeout(); 581 let timeout = self.timeout();
483 if write.is_empty() { 582 if write.is_empty() {
484 self.write_internal(address, write, true, timeout) 583 self.write_internal(address, write, true, timeout)
@@ -492,10 +591,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
492 /// Write multiple buffers. 591 /// Write multiple buffers.
493 /// 592 ///
494 /// The buffers are concatenated in a single write transaction. 593 /// The buffers are concatenated in a single write transaction.
495 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> 594 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
496 where
497 TXDMA: crate::i2c::TxDma<T>,
498 {
499 let timeout = self.timeout(); 595 let timeout = self.timeout();
500 596
501 if write.is_empty() { 597 if write.is_empty() {
@@ -518,10 +614,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
518 } 614 }
519 615
520 /// Read. 616 /// Read.
521 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 617 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
522 where
523 RXDMA: crate::i2c::RxDma<T>,
524 {
525 let timeout = self.timeout(); 618 let timeout = self.timeout();
526 619
527 if buffer.is_empty() { 620 if buffer.is_empty() {
@@ -533,11 +626,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
533 } 626 }
534 627
535 /// Write, restart, read. 628 /// Write, restart, read.
536 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 629 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
537 where
538 TXDMA: super::TxDma<T>,
539 RXDMA: super::RxDma<T>,
540 {
541 let timeout = self.timeout(); 630 let timeout = self.timeout();
542 631
543 if write.is_empty() { 632 if write.is_empty() {
@@ -562,129 +651,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
562 /// Consecutive operations of same type are merged. See [transaction contract] for details. 651 /// Consecutive operations of same type are merged. See [transaction contract] for details.
563 /// 652 ///
564 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 653 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
565 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> 654 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
566 where
567 RXDMA: crate::i2c::RxDma<T>,
568 TXDMA: crate::i2c::TxDma<T>,
569 {
570 let _ = addr;
571 let _ = operations;
572 todo!()
573 }
574
575 // =========================
576 // Blocking public API
577
578 /// Blocking read.
579 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
580 self.read_internal(address, read, false, self.timeout())
581 // Automatic Stop
582 }
583
584 /// Blocking write.
585 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
586 self.write_internal(address, write, true, self.timeout())
587 }
588
589 /// Blocking write, restart, read.
590 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
591 let timeout = self.timeout();
592 self.write_internal(address, write, false, timeout)?;
593 self.read_internal(address, read, true, timeout)
594 // Automatic Stop
595 }
596
597 /// Blocking transaction with operations.
598 ///
599 /// Consecutive operations of same type are merged. See [transaction contract] for details.
600 ///
601 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
602 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
603 let _ = addr; 655 let _ = addr;
604 let _ = operations; 656 let _ = operations;
605 todo!() 657 todo!()
606 } 658 }
607
608 /// Blocking write multiple buffers.
609 ///
610 /// The buffers are concatenated in a single write transaction.
611 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
612 if write.is_empty() {
613 return Err(Error::ZeroLengthTransfer);
614 }
615
616 let timeout = self.timeout();
617
618 let first_length = write[0].len();
619 let last_slice_index = write.len() - 1;
620
621 if let Err(err) = Self::master_write(
622 address,
623 first_length.min(255),
624 Stop::Software,
625 (first_length > 255) || (last_slice_index != 0),
626 timeout,
627 ) {
628 self.master_stop();
629 return Err(err);
630 }
631
632 for (idx, slice) in write.iter().enumerate() {
633 let slice_len = slice.len();
634 let completed_chunks = slice_len / 255;
635 let total_chunks = if completed_chunks * 255 == slice_len {
636 completed_chunks
637 } else {
638 completed_chunks + 1
639 };
640 let last_chunk_idx = total_chunks.saturating_sub(1);
641
642 if idx != 0 {
643 if let Err(err) = Self::master_continue(
644 slice_len.min(255),
645 (idx != last_slice_index) || (slice_len > 255),
646 timeout,
647 ) {
648 self.master_stop();
649 return Err(err);
650 }
651 }
652
653 for (number, chunk) in slice.chunks(255).enumerate() {
654 if number != 0 {
655 if let Err(err) = Self::master_continue(
656 chunk.len(),
657 (number != last_chunk_idx) || (idx != last_slice_index),
658 timeout,
659 ) {
660 self.master_stop();
661 return Err(err);
662 }
663 }
664
665 for byte in chunk {
666 // Wait until we are allowed to send data
667 // (START has been ACKed or last byte when
668 // through)
669 if let Err(err) = self.wait_txe(timeout) {
670 self.master_stop();
671 return Err(err);
672 }
673
674 // Put byte on the wire
675 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
676 T::regs().txdr().write(|w| w.set_txdata(*byte));
677 }
678 }
679 }
680 // Wait until the write finishes
681 let result = self.wait_tc(timeout);
682 self.master_stop();
683 result
684 }
685} 659}
686 660
687impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 661impl<'d, T: Instance, M: Mode> Drop for I2c<'d, T, M> {
688 fn drop(&mut self) { 662 fn drop(&mut self) {
689 T::disable(); 663 T::disable();
690 } 664 }
@@ -814,7 +788,7 @@ impl Timings {
814 } 788 }
815} 789}
816 790
817impl<'d, T: Instance> SetConfig for I2c<'d, T> { 791impl<'d, T: Instance, M: Mode> SetConfig for I2c<'d, T, M> {
818 type Config = Hertz; 792 type Config = Hertz;
819 type ConfigError = (); 793 type ConfigError = ();
820 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 794 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c5a606b21..9b80dc1d0 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -2,6 +2,7 @@
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use crate::gpio::{AFType, AnyPin, SealedPin}; 4use crate::gpio::{AFType, AnyPin, SealedPin};
5use crate::mode::Async;
5use crate::pac::spi::vals; 6use crate::pac::spi::vals;
6use crate::spi::{Config as SpiConfig, *}; 7use crate::spi::{Config as SpiConfig, *};
7use crate::time::Hertz; 8use crate::time::Hertz;
@@ -152,15 +153,15 @@ impl Default for Config {
152} 153}
153 154
154/// I2S driver. 155/// I2S driver.
155pub struct I2S<'d, T: Instance, Tx, Rx> { 156pub struct I2S<'d, T: Instance> {
156 _peri: Spi<'d, T, Tx, Rx>, 157 _peri: Spi<'d, T, Async>,
157 sd: Option<PeripheralRef<'d, AnyPin>>, 158 sd: Option<PeripheralRef<'d, AnyPin>>,
158 ws: Option<PeripheralRef<'d, AnyPin>>, 159 ws: Option<PeripheralRef<'d, AnyPin>>,
159 ck: Option<PeripheralRef<'d, AnyPin>>, 160 ck: Option<PeripheralRef<'d, AnyPin>>,
160 mck: Option<PeripheralRef<'d, AnyPin>>, 161 mck: Option<PeripheralRef<'d, AnyPin>>,
161} 162}
162 163
163impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { 164impl<'d, T: Instance> I2S<'d, T> {
164 /// Note: Full-Duplex modes are not supported at this time 165 /// Note: Full-Duplex modes are not supported at this time
165 pub fn new( 166 pub fn new(
166 peri: impl Peripheral<P = T> + 'd, 167 peri: impl Peripheral<P = T> + 'd,
@@ -168,8 +169,8 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
168 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 169 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
169 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 170 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
170 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 171 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
171 txdma: impl Peripheral<P = Tx> + 'd, 172 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
172 rxdma: impl Peripheral<P = Rx> + 'd, 173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
173 freq: Hertz, 174 freq: Hertz,
174 config: Config, 175 config: Config,
175 ) -> Self { 176 ) -> Self {
@@ -265,24 +266,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
265 } 266 }
266 267
267 /// Write audio data. 268 /// Write audio data.
268 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 269 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
269 where
270 Tx: TxDma<T>,
271 {
272 self._peri.write(data).await 270 self._peri.write(data).await
273 } 271 }
274 272
275 /// Read audio data. 273 /// Read audio data.
276 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 274 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
277 where
278 Tx: TxDma<T>,
279 Rx: RxDma<T>,
280 {
281 self._peri.read(data).await 275 self._peri.read(data).await
282 } 276 }
283} 277}
284 278
285impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { 279impl<'d, T: Instance> Drop for I2S<'d, T> {
286 fn drop(&mut self) { 280 fn drop(&mut self) {
287 self.sd.as_ref().map(|x| x.set_as_disconnected()); 281 self.sd.as_ref().map(|x| x.set_as_disconnected());
288 self.ws.as_ref().map(|x| x.set_as_disconnected()); 282 self.ws.as_ref().map(|x| x.set_as_disconnected());
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index ea17f8477..7d2b49ff4 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -15,8 +15,31 @@ mod fmt;
15include!(concat!(env!("OUT_DIR"), "/_macros.rs")); 15include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
16 16
17// Utilities 17// Utilities
18mod macros;
18pub mod time; 19pub mod time;
19mod traits; 20/// Operating modes for peripherals.
21pub mod mode {
22 trait SealedMode {}
23
24 /// Operating mode for a peripheral.
25 #[allow(private_bounds)]
26 pub trait Mode: SealedMode {}
27
28 macro_rules! impl_mode {
29 ($name:ident) => {
30 impl SealedMode for $name {}
31 impl Mode for $name {}
32 };
33 }
34
35 /// Blocking mode.
36 pub struct Blocking;
37 /// Async mode.
38 pub struct Async;
39
40 impl_mode!(Blocking);
41 impl_mode!(Async);
42}
20 43
21// Always-present hardware 44// Always-present hardware
22pub mod dma; 45pub mod dma;
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/macros.rs
index 13f695821..14137bc37 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/macros.rs
@@ -69,3 +69,29 @@ macro_rules! dma_trait_impl {
69 } 69 }
70 }; 70 };
71} 71}
72
73macro_rules! new_dma {
74 ($name:ident) => {{
75 let dma = $name.into_ref();
76 let request = dma.request();
77 Some(crate::dma::ChannelAndRequest {
78 channel: dma.map_into(),
79 request,
80 })
81 }};
82}
83
84macro_rules! new_pin {
85 ($name:ident, $aftype:expr) => {{
86 new_pin!($name, $aftype, crate::gpio::Speed::Medium, crate::gpio::Pull::None)
87 }};
88 ($name:ident, $aftype:expr, $speed:expr) => {
89 new_pin!($name, $aftype, $speed, crate::gpio::Pull::None)
90 };
91 ($name:ident, $aftype:expr, $speed:expr, $pull:expr) => {{
92 let pin = $name.into_ref();
93 pin.set_as_af_pull(pin.af_num(), $aftype, $pull);
94 pin.set_speed($speed);
95 Some(pin.map_into())
96 }};
97}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 00f21ed68..a4e497fe7 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -119,3 +119,21 @@ mod util {
119pub fn frequency<T: RccPeripheral>() -> Hertz { 119pub fn frequency<T: RccPeripheral>() -> Hertz {
120 T::frequency() 120 T::frequency()
121} 121}
122
123/// Enables and resets peripheral `T`.
124///
125/// # Safety
126///
127/// Peripheral must not be in use.
128pub unsafe fn enable_and_reset<T: RccPeripheral>() {
129 T::enable_and_reset();
130}
131
132/// Disables peripheral `T`.
133///
134/// # Safety
135///
136/// Peripheral must not be in use.
137pub unsafe fn disable<T: RccPeripheral>() {
138 T::disable();
139}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 340cfde03..c39ef1913 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,6 +1,7 @@
1//! Serial Peripheral Interface (SPI) 1//! Serial Peripheral Interface (SPI)
2#![macro_use] 2#![macro_use]
3 3
4use core::marker::PhantomData;
4use core::ptr; 5use core::ptr;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -8,8 +9,9 @@ use embassy_futures::join::join;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::{into_ref, PeripheralRef};
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 10pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
10 11
11use crate::dma::{slice_ptr_parts, word, Transfer}; 12use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
12use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; 13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode};
13use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{regs, vals, Spi as Regs};
14use crate::rcc::RccPeripheral; 16use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 17use crate::time::Hertz;
@@ -81,163 +83,37 @@ impl Config {
81 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 83 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
82 } 84 }
83 } 85 }
84}
85 86
87 fn sck_pull_mode(&self) -> Pull {
88 match self.mode.polarity {
89 Polarity::IdleLow => Pull::Down,
90 Polarity::IdleHigh => Pull::Up,
91 }
92 }
93}
86/// SPI driver. 94/// SPI driver.
87pub struct Spi<'d, T: Instance, Tx, Rx> { 95pub struct Spi<'d, T: Instance, M: PeriMode> {
88 _peri: PeripheralRef<'d, T>, 96 _peri: PeripheralRef<'d, T>,
89 sck: Option<PeripheralRef<'d, AnyPin>>, 97 sck: Option<PeripheralRef<'d, AnyPin>>,
90 mosi: Option<PeripheralRef<'d, AnyPin>>, 98 mosi: Option<PeripheralRef<'d, AnyPin>>,
91 miso: Option<PeripheralRef<'d, AnyPin>>, 99 miso: Option<PeripheralRef<'d, AnyPin>>,
92 txdma: PeripheralRef<'d, Tx>, 100 tx_dma: Option<ChannelAndRequest<'d>>,
93 rxdma: PeripheralRef<'d, Rx>, 101 rx_dma: Option<ChannelAndRequest<'d>>,
102 _phantom: PhantomData<M>,
94 current_word_size: word_impl::Config, 103 current_word_size: word_impl::Config,
95} 104}
96 105
97impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 106impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
98 /// Create a new SPI driver.
99 pub fn new(
100 peri: impl Peripheral<P = T> + 'd,
101 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
102 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
103 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
104 txdma: impl Peripheral<P = Tx> + 'd,
105 rxdma: impl Peripheral<P = Rx> + 'd,
106 config: Config,
107 ) -> Self {
108 into_ref!(peri, sck, mosi, miso);
109
110 let sck_pull_mode = match config.mode.polarity {
111 Polarity::IdleLow => Pull::Down,
112 Polarity::IdleHigh => Pull::Up,
113 };
114
115 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
116 sck.set_speed(crate::gpio::Speed::VeryHigh);
117 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
118 mosi.set_speed(crate::gpio::Speed::VeryHigh);
119 miso.set_as_af(miso.af_num(), AFType::Input);
120 miso.set_speed(crate::gpio::Speed::VeryHigh);
121
122 Self::new_inner(
123 peri,
124 Some(sck.map_into()),
125 Some(mosi.map_into()),
126 Some(miso.map_into()),
127 txdma,
128 rxdma,
129 config,
130 )
131 }
132
133 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
134 pub fn new_rxonly(
135 peri: impl Peripheral<P = T> + 'd,
136 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
137 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
138 txdma: impl Peripheral<P = Tx> + 'd, // TODO remove
139 rxdma: impl Peripheral<P = Rx> + 'd,
140 config: Config,
141 ) -> Self {
142 into_ref!(sck, miso);
143 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
144 sck.set_speed(crate::gpio::Speed::VeryHigh);
145 miso.set_as_af(miso.af_num(), AFType::Input);
146 miso.set_speed(crate::gpio::Speed::VeryHigh);
147
148 Self::new_inner(
149 peri,
150 Some(sck.map_into()),
151 None,
152 Some(miso.map_into()),
153 txdma,
154 rxdma,
155 config,
156 )
157 }
158
159 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
160 pub fn new_txonly(
161 peri: impl Peripheral<P = T> + 'd,
162 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
163 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
164 txdma: impl Peripheral<P = Tx> + 'd,
165 rxdma: impl Peripheral<P = Rx> + 'd, // TODO remove
166 config: Config,
167 ) -> Self {
168 into_ref!(sck, mosi);
169 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
170 sck.set_speed(crate::gpio::Speed::VeryHigh);
171 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
172 mosi.set_speed(crate::gpio::Speed::VeryHigh);
173
174 Self::new_inner(
175 peri,
176 Some(sck.map_into()),
177 Some(mosi.map_into()),
178 None,
179 txdma,
180 rxdma,
181 config,
182 )
183 }
184
185 /// Create a new SPI driver, in TX-only mode, without SCK pin.
186 ///
187 /// This can be useful for bit-banging non-SPI protocols.
188 pub fn new_txonly_nosck(
189 peri: impl Peripheral<P = T> + 'd,
190 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
191 txdma: impl Peripheral<P = Tx> + 'd,
192 rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
193 config: Config,
194 ) -> Self {
195 into_ref!(mosi);
196 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
197 mosi.set_speed(crate::gpio::Speed::Medium);
198
199 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, config)
200 }
201
202 #[cfg(stm32wl)]
203 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
204 pub fn new_subghz(
205 peri: impl Peripheral<P = T> + 'd,
206 txdma: impl Peripheral<P = Tx> + 'd,
207 rxdma: impl Peripheral<P = Rx> + 'd,
208 ) -> Self {
209 // see RM0453 rev 1 section 7.2.13 page 291
210 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
211 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
212 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
213 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
214 let mut config = Config::default();
215 config.mode = MODE_0;
216 config.bit_order = BitOrder::MsbFirst;
217 config.frequency = freq;
218 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
219 }
220
221 #[allow(dead_code)]
222 pub(crate) fn new_internal(
223 peri: impl Peripheral<P = T> + 'd,
224 txdma: impl Peripheral<P = Tx> + 'd,
225 rxdma: impl Peripheral<P = Rx> + 'd,
226 config: Config,
227 ) -> Self {
228 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
229 }
230
231 fn new_inner( 107 fn new_inner(
232 peri: impl Peripheral<P = T> + 'd, 108 peri: impl Peripheral<P = T> + 'd,
233 sck: Option<PeripheralRef<'d, AnyPin>>, 109 sck: Option<PeripheralRef<'d, AnyPin>>,
234 mosi: Option<PeripheralRef<'d, AnyPin>>, 110 mosi: Option<PeripheralRef<'d, AnyPin>>,
235 miso: Option<PeripheralRef<'d, AnyPin>>, 111 miso: Option<PeripheralRef<'d, AnyPin>>,
236 txdma: impl Peripheral<P = Tx> + 'd, 112 tx_dma: Option<ChannelAndRequest<'d>>,
237 rxdma: impl Peripheral<P = Rx> + 'd, 113 rx_dma: Option<ChannelAndRequest<'d>>,
238 config: Config, 114 config: Config,
239 ) -> Self { 115 ) -> Self {
240 into_ref!(peri, txdma, rxdma); 116 into_ref!(peri);
241 117
242 let pclk = T::frequency(); 118 let pclk = T::frequency();
243 let freq = config.frequency; 119 let freq = config.frequency;
@@ -333,9 +209,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
333 sck, 209 sck,
334 mosi, 210 mosi,
335 miso, 211 miso,
336 txdma, 212 tx_dma,
337 rxdma, 213 rx_dma,
338 current_word_size: <u8 as SealedWord>::CONFIG, 214 current_word_size: <u8 as SealedWord>::CONFIG,
215 _phantom: PhantomData,
339 } 216 }
340 } 217 }
341 218
@@ -462,11 +339,251 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
462 self.current_word_size = word_size; 339 self.current_word_size = word_size;
463 } 340 }
464 341
342 /// Blocking write.
343 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
344 T::REGS.cr1().modify(|w| w.set_spe(true));
345 flush_rx_fifo(T::REGS);
346 self.set_word_size(W::CONFIG);
347 for word in words.iter() {
348 let _ = transfer_word(T::REGS, *word)?;
349 }
350 Ok(())
351 }
352
353 /// Blocking read.
354 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
355 T::REGS.cr1().modify(|w| w.set_spe(true));
356 flush_rx_fifo(T::REGS);
357 self.set_word_size(W::CONFIG);
358 for word in words.iter_mut() {
359 *word = transfer_word(T::REGS, W::default())?;
360 }
361 Ok(())
362 }
363
364 /// Blocking in-place bidirectional transfer.
365 ///
366 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
367 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
368 T::REGS.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(T::REGS);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter_mut() {
372 *word = transfer_word(T::REGS, *word)?;
373 }
374 Ok(())
375 }
376
377 /// Blocking bidirectional transfer.
378 ///
379 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
380 ///
381 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
382 /// If `write` is shorter it is padded with zero bytes.
383 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
384 T::REGS.cr1().modify(|w| w.set_spe(true));
385 flush_rx_fifo(T::REGS);
386 self.set_word_size(W::CONFIG);
387 let len = read.len().max(write.len());
388 for i in 0..len {
389 let wb = write.get(i).copied().unwrap_or_default();
390 let rb = transfer_word(T::REGS, wb)?;
391 if let Some(r) = read.get_mut(i) {
392 *r = rb;
393 }
394 }
395 Ok(())
396 }
397}
398
399impl<'d, T: Instance> Spi<'d, T, Blocking> {
400 /// Create a new blocking SPI driver.
401 pub fn new_blocking(
402 peri: impl Peripheral<P = T> + 'd,
403 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
404 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
405 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
406 config: Config,
407 ) -> Self {
408 Self::new_inner(
409 peri,
410 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
411 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
412 new_pin!(miso, AFType::Input, Speed::VeryHigh),
413 None,
414 None,
415 config,
416 )
417 }
418
419 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
420 pub fn new_blocking_rxonly(
421 peri: impl Peripheral<P = T> + 'd,
422 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
423 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
424 config: Config,
425 ) -> Self {
426 Self::new_inner(
427 peri,
428 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
429 None,
430 new_pin!(miso, AFType::Input, Speed::VeryHigh),
431 None,
432 None,
433 config,
434 )
435 }
436
437 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
438 pub fn new_blocking_txonly(
439 peri: impl Peripheral<P = T> + 'd,
440 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
441 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
442 config: Config,
443 ) -> Self {
444 Self::new_inner(
445 peri,
446 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
447 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
448 None,
449 None,
450 None,
451 config,
452 )
453 }
454
455 /// Create a new SPI driver, in TX-only mode, without SCK pin.
456 ///
457 /// This can be useful for bit-banging non-SPI protocols.
458 pub fn new_blocking_txonly_nosck(
459 peri: impl Peripheral<P = T> + 'd,
460 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
461 config: Config,
462 ) -> Self {
463 Self::new_inner(
464 peri,
465 None,
466 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
467 None,
468 None,
469 None,
470 config,
471 )
472 }
473}
474
475impl<'d, T: Instance> Spi<'d, T, Async> {
476 /// Create a new SPI driver.
477 pub fn new(
478 peri: impl Peripheral<P = T> + 'd,
479 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
480 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
481 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
482 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
483 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
484 config: Config,
485 ) -> Self {
486 Self::new_inner(
487 peri,
488 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
489 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
490 new_pin!(miso, AFType::Input, Speed::VeryHigh),
491 new_dma!(tx_dma),
492 new_dma!(rx_dma),
493 config,
494 )
495 }
496
497 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
498 pub fn new_rxonly(
499 peri: impl Peripheral<P = T> + 'd,
500 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
501 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
502 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
503 config: Config,
504 ) -> Self {
505 Self::new_inner(
506 peri,
507 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
508 None,
509 new_pin!(miso, AFType::Input, Speed::VeryHigh),
510 None,
511 new_dma!(rx_dma),
512 config,
513 )
514 }
515
516 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
517 pub fn new_txonly(
518 peri: impl Peripheral<P = T> + 'd,
519 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
520 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
521 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
522 config: Config,
523 ) -> Self {
524 Self::new_inner(
525 peri,
526 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
527 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
528 None,
529 new_dma!(tx_dma),
530 None,
531 config,
532 )
533 }
534
535 /// Create a new SPI driver, in TX-only mode, without SCK pin.
536 ///
537 /// This can be useful for bit-banging non-SPI protocols.
538 pub fn new_txonly_nosck(
539 peri: impl Peripheral<P = T> + 'd,
540 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
541 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
542 config: Config,
543 ) -> Self {
544 Self::new_inner(
545 peri,
546 None,
547 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
548 None,
549 new_dma!(tx_dma),
550 None,
551 config,
552 )
553 }
554
555 #[cfg(stm32wl)]
556 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
557 pub fn new_subghz(
558 peri: impl Peripheral<P = T> + 'd,
559 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
560 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
561 ) -> Self {
562 // see RM0453 rev 1 section 7.2.13 page 291
563 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
564 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
565 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
566 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
567 let mut config = Config::default();
568 config.mode = MODE_0;
569 config.bit_order = BitOrder::MsbFirst;
570 config.frequency = freq;
571
572 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
573 }
574
575 #[allow(dead_code)]
576 pub(crate) fn new_internal(
577 peri: impl Peripheral<P = T> + 'd,
578 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
579 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
580 config: Config,
581 ) -> Self {
582 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
583 }
584
465 /// SPI write, using DMA. 585 /// SPI write, using DMA.
466 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 586 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
467 where
468 Tx: TxDma<T>,
469 {
470 if data.is_empty() { 587 if data.is_empty() {
471 return Ok(()); 588 return Ok(());
472 } 589 }
@@ -476,9 +593,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
476 w.set_spe(false); 593 w.set_spe(false);
477 }); 594 });
478 595
479 let tx_request = self.txdma.request();
480 let tx_dst = T::REGS.tx_ptr(); 596 let tx_dst = T::REGS.tx_ptr();
481 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; 597 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
482 598
483 set_txdmaen(T::REGS, true); 599 set_txdmaen(T::REGS, true);
484 T::REGS.cr1().modify(|w| { 600 T::REGS.cr1().modify(|w| {
@@ -497,11 +613,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
497 } 613 }
498 614
499 /// SPI read, using DMA. 615 /// SPI read, using DMA.
500 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 616 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
501 where
502 Tx: TxDma<T>,
503 Rx: RxDma<T>,
504 {
505 if data.is_empty() { 617 if data.is_empty() {
506 return Ok(()); 618 return Ok(());
507 } 619 }
@@ -519,22 +631,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
519 631
520 let clock_byte_count = data.len(); 632 let clock_byte_count = data.len();
521 633
522 let rx_request = self.rxdma.request();
523 let rx_src = T::REGS.rx_ptr(); 634 let rx_src = T::REGS.rx_ptr();
524 let rx_f = unsafe { Transfer::new_read(&mut self.rxdma, rx_request, rx_src, data, Default::default()) }; 635 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
525 636
526 let tx_request = self.txdma.request();
527 let tx_dst = T::REGS.tx_ptr(); 637 let tx_dst = T::REGS.tx_ptr();
528 let clock_byte = 0x00u8; 638 let clock_byte = 0x00u8;
529 let tx_f = unsafe { 639 let tx_f = unsafe {
530 Transfer::new_write_repeated( 640 self.tx_dma
531 &mut self.txdma, 641 .as_mut()
532 tx_request, 642 .unwrap()
533 &clock_byte, 643 .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
534 clock_byte_count,
535 tx_dst,
536 Default::default(),
537 )
538 }; 644 };
539 645
540 set_txdmaen(T::REGS, true); 646 set_txdmaen(T::REGS, true);
@@ -553,11 +659,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
553 Ok(()) 659 Ok(())
554 } 660 }
555 661
556 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> 662 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
557 where
558 Tx: TxDma<T>,
559 Rx: RxDma<T>,
560 {
561 let (_, rx_len) = slice_ptr_parts(read); 663 let (_, rx_len) = slice_ptr_parts(read);
562 let (_, tx_len) = slice_ptr_parts(write); 664 let (_, tx_len) = slice_ptr_parts(write);
563 assert_eq!(rx_len, tx_len); 665 assert_eq!(rx_len, tx_len);
@@ -576,13 +678,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
576 678
577 set_rxdmaen(T::REGS, true); 679 set_rxdmaen(T::REGS, true);
578 680
579 let rx_request = self.rxdma.request();
580 let rx_src = T::REGS.rx_ptr(); 681 let rx_src = T::REGS.rx_ptr();
581 let rx_f = unsafe { Transfer::new_read_raw(&mut self.rxdma, rx_request, rx_src, read, Default::default()) }; 682 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
582 683
583 let tx_request = self.txdma.request();
584 let tx_dst = T::REGS.tx_ptr(); 684 let tx_dst = T::REGS.tx_ptr();
585 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; 685 let tx_f = unsafe {
686 self.tx_dma
687 .as_mut()
688 .unwrap()
689 .write_raw(write, tx_dst, Default::default())
690 };
586 691
587 set_txdmaen(T::REGS, true); 692 set_txdmaen(T::REGS, true);
588 T::REGS.cr1().modify(|w| { 693 T::REGS.cr1().modify(|w| {
@@ -606,83 +711,19 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
606 /// 711 ///
607 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 712 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
608 /// If `write` is shorter it is padded with zero bytes. 713 /// If `write` is shorter it is padded with zero bytes.
609 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 714 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
610 where
611 Tx: TxDma<T>,
612 Rx: RxDma<T>,
613 {
614 self.transfer_inner(read, write).await 715 self.transfer_inner(read, write).await
615 } 716 }
616 717
617 /// In-place bidirectional transfer, using DMA. 718 /// In-place bidirectional transfer, using DMA.
618 /// 719 ///
619 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 720 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
620 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 721 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
621 where
622 Tx: TxDma<T>,
623 Rx: RxDma<T>,
624 {
625 self.transfer_inner(data, data).await 722 self.transfer_inner(data, data).await
626 } 723 }
627
628 /// Blocking write.
629 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
630 T::REGS.cr1().modify(|w| w.set_spe(true));
631 flush_rx_fifo(T::REGS);
632 self.set_word_size(W::CONFIG);
633 for word in words.iter() {
634 let _ = transfer_word(T::REGS, *word)?;
635 }
636 Ok(())
637 }
638
639 /// Blocking read.
640 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
641 T::REGS.cr1().modify(|w| w.set_spe(true));
642 flush_rx_fifo(T::REGS);
643 self.set_word_size(W::CONFIG);
644 for word in words.iter_mut() {
645 *word = transfer_word(T::REGS, W::default())?;
646 }
647 Ok(())
648 }
649
650 /// Blocking in-place bidirectional transfer.
651 ///
652 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
653 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
654 T::REGS.cr1().modify(|w| w.set_spe(true));
655 flush_rx_fifo(T::REGS);
656 self.set_word_size(W::CONFIG);
657 for word in words.iter_mut() {
658 *word = transfer_word(T::REGS, *word)?;
659 }
660 Ok(())
661 }
662
663 /// Blocking bidirectional transfer.
664 ///
665 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
666 ///
667 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
668 /// If `write` is shorter it is padded with zero bytes.
669 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
670 T::REGS.cr1().modify(|w| w.set_spe(true));
671 flush_rx_fifo(T::REGS);
672 self.set_word_size(W::CONFIG);
673 let len = read.len().max(write.len());
674 for i in 0..len {
675 let wb = write.get(i).copied().unwrap_or_default();
676 let rb = transfer_word(T::REGS, wb)?;
677 if let Some(r) = read.get_mut(i) {
678 *r = rb;
679 }
680 }
681 Ok(())
682 }
683} 724}
684 725
685impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 726impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> {
686 fn drop(&mut self) { 727 fn drop(&mut self) {
687 self.sck.as_ref().map(|x| x.set_as_disconnected()); 728 self.sck.as_ref().map(|x| x.set_as_disconnected());
688 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 729 self.mosi.as_ref().map(|x| x.set_as_disconnected());
@@ -819,7 +860,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
819fn flush_rx_fifo(regs: Regs) { 860fn flush_rx_fifo(regs: Regs) {
820 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 861 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
821 while regs.sr().read().rxne() { 862 while regs.sr().read().rxne() {
822 #[cfg(spi_v1)] 863 #[cfg(not(spi_v2))]
823 let _ = regs.dr().read(); 864 let _ = regs.dr().read();
824 #[cfg(spi_v2)] 865 #[cfg(spi_v2)]
825 let _ = regs.dr16().read(); 866 let _ = regs.dr16().read();
@@ -900,7 +941,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
900// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 941// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
901macro_rules! impl_blocking { 942macro_rules! impl_blocking {
902 ($w:ident) => { 943 ($w:ident) => {
903 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> { 944 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> {
904 type Error = Error; 945 type Error = Error;
905 946
906 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 947 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -908,7 +949,7 @@ macro_rules! impl_blocking {
908 } 949 }
909 } 950 }
910 951
911 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> { 952 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> {
912 type Error = Error; 953 type Error = Error;
913 954
914 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 955 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -922,11 +963,11 @@ macro_rules! impl_blocking {
922impl_blocking!(u8); 963impl_blocking!(u8);
923impl_blocking!(u16); 964impl_blocking!(u16);
924 965
925impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> { 966impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
926 type Error = Error; 967 type Error = Error;
927} 968}
928 969
929impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 970impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, M> {
930 fn flush(&mut self) -> Result<(), Self::Error> { 971 fn flush(&mut self) -> Result<(), Self::Error> {
931 Ok(()) 972 Ok(())
932 } 973 }
@@ -959,7 +1000,7 @@ impl embedded_hal_1::spi::Error for Error {
959 } 1000 }
960} 1001}
961 1002
962impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 1003impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Async> {
963 async fn flush(&mut self) -> Result<(), Self::Error> { 1004 async fn flush(&mut self) -> Result<(), Self::Error> {
964 Ok(()) 1005 Ok(())
965 } 1006 }
@@ -1094,7 +1135,7 @@ foreach_peripheral!(
1094 }; 1135 };
1095); 1136);
1096 1137
1097impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { 1138impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> {
1098 type Config = Config; 1139 type Config = Config;
1099 type ConfigError = (); 1140 type ConfigError = ();
1100 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1141 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 7c0523a25..e7fdf4da6 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -13,9 +13,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures::future::{select, Either}; 14use futures::future::{select, Either};
15 15
16use crate::dma::{NoDma, Transfer}; 16use crate::dma::ChannelAndRequest;
17use crate::gpio::AFType; 17use crate::gpio::{AFType, AnyPin, SealedPin};
18use crate::interrupt::typelevel::Interrupt; 18use crate::interrupt::typelevel::Interrupt;
19use crate::mode::{Async, Blocking, Mode};
19#[allow(unused_imports)] 20#[allow(unused_imports)]
20#[cfg(not(any(usart_v1, usart_v2)))] 21#[cfg(not(any(usart_v1, usart_v2)))]
21use crate::pac::usart::regs::Isr as Sr; 22use crate::pac::usart::regs::Isr as Sr;
@@ -162,6 +163,26 @@ pub struct Config {
162 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle). 163 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
163 #[cfg(any(usart_v3, usart_v4))] 164 #[cfg(any(usart_v3, usart_v4))]
164 pub invert_rx: bool, 165 pub invert_rx: bool,
166
167 // private: set by new_half_duplex, not by the user.
168 half_duplex: bool,
169}
170
171impl Config {
172 fn tx_af(&self) -> AFType {
173 #[cfg(any(usart_v3, usart_v4))]
174 if self.swap_rx_tx {
175 return AFType::Input;
176 };
177 AFType::OutputPushPull
178 }
179 fn rx_af(&self) -> AFType {
180 #[cfg(any(usart_v3, usart_v4))]
181 if self.swap_rx_tx {
182 return AFType::OutputPushPull;
183 };
184 AFType::Input
185 }
165} 186}
166 187
167impl Default for Config { 188impl Default for Config {
@@ -181,6 +202,7 @@ impl Default for Config {
181 invert_tx: false, 202 invert_tx: false,
182 #[cfg(any(usart_v3, usart_v4))] 203 #[cfg(any(usart_v3, usart_v4))]
183 invert_rx: false, 204 invert_rx: false,
205 half_duplex: false,
184 } 206 }
185 } 207 }
186} 208}
@@ -217,12 +239,12 @@ enum ReadCompletionEvent {
217/// 239///
218/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] 240/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
219/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. 241/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
220pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 242pub struct Uart<'d, T: BasicInstance, M: Mode> {
221 tx: UartTx<'d, T, TxDma>, 243 tx: UartTx<'d, T, M>,
222 rx: UartRx<'d, T, RxDma>, 244 rx: UartRx<'d, T, M>,
223} 245}
224 246
225impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { 247impl<'d, T: BasicInstance, M: Mode> SetConfig for Uart<'d, T, M> {
226 type Config = Config; 248 type Config = Config;
227 type ConfigError = ConfigError; 249 type ConfigError = ConfigError;
228 250
@@ -236,12 +258,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma>
236/// 258///
237/// Can be obtained from [`Uart::split`], or can be constructed independently, 259/// Can be obtained from [`Uart::split`], or can be constructed independently,
238/// if you do not need the receiving half of the driver. 260/// if you do not need the receiving half of the driver.
239pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 261pub struct UartTx<'d, T: BasicInstance, M: Mode> {
240 phantom: PhantomData<&'d mut T>, 262 _phantom: PhantomData<(T, M)>,
241 tx_dma: PeripheralRef<'d, TxDma>, 263 tx: Option<PeripheralRef<'d, AnyPin>>,
264 cts: Option<PeripheralRef<'d, AnyPin>>,
265 de: Option<PeripheralRef<'d, AnyPin>>,
266 tx_dma: Option<ChannelAndRequest<'d>>,
242} 267}
243 268
244impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { 269impl<'d, T: BasicInstance, M: Mode> SetConfig for UartTx<'d, T, M> {
245 type Config = Config; 270 type Config = Config;
246 type ConfigError = ConfigError; 271 type ConfigError = ConfigError;
247 272
@@ -279,15 +304,17 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
279/// store data received between calls. 304/// store data received between calls.
280/// 305///
281/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043). 306/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043).
282pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 307pub struct UartRx<'d, T: BasicInstance, M: Mode> {
283 _peri: PeripheralRef<'d, T>, 308 _phantom: PhantomData<(T, M)>,
284 rx_dma: PeripheralRef<'d, RxDma>, 309 rx: Option<PeripheralRef<'d, AnyPin>>,
310 rts: Option<PeripheralRef<'d, AnyPin>>,
311 rx_dma: Option<ChannelAndRequest<'d>>,
285 detect_previous_overrun: bool, 312 detect_previous_overrun: bool,
286 #[cfg(any(usart_v1, usart_v2))] 313 #[cfg(any(usart_v1, usart_v2))]
287 buffered_sr: stm32_metapac::usart::regs::Sr, 314 buffered_sr: stm32_metapac::usart::regs::Sr,
288} 315}
289 316
290impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { 317impl<'d, T: BasicInstance, M: Mode> SetConfig for UartRx<'d, T, M> {
291 type Config = Config; 318 type Config = Config;
292 type ConfigError = ConfigError; 319 type ConfigError = ConfigError;
293 320
@@ -296,17 +323,21 @@ impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> {
296 } 323 }
297} 324}
298 325
299impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { 326impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
300 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 327 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
301 pub fn new( 328 pub fn new(
302 peri: impl Peripheral<P = T> + 'd, 329 peri: impl Peripheral<P = T> + 'd,
303 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 330 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
304 tx_dma: impl Peripheral<P = TxDma> + 'd, 331 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
305 config: Config, 332 config: Config,
306 ) -> Result<Self, ConfigError> { 333 ) -> Result<Self, ConfigError> {
307 T::enable_and_reset(); 334 Self::new_inner(
308 335 peri,
309 Self::new_inner(peri, tx, tx_dma, config) 336 new_pin!(tx, AFType::OutputPushPull),
337 None,
338 new_dma!(tx_dma),
339 config,
340 )
310 } 341 }
311 342
312 /// Create a new tx-only UART with a clear-to-send pin 343 /// Create a new tx-only UART with a clear-to-send pin
@@ -314,40 +345,86 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
314 peri: impl Peripheral<P = T> + 'd, 345 peri: impl Peripheral<P = T> + 'd,
315 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 346 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
316 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 347 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
317 tx_dma: impl Peripheral<P = TxDma> + 'd, 348 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
318 config: Config, 349 config: Config,
319 ) -> Result<Self, ConfigError> { 350 ) -> Result<Self, ConfigError> {
320 into_ref!(cts); 351 Self::new_inner(
321 352 peri,
322 T::enable_and_reset(); 353 new_pin!(tx, AFType::OutputPushPull),
354 new_pin!(cts, AFType::Input),
355 new_dma!(tx_dma),
356 config,
357 )
358 }
323 359
324 cts.set_as_af(cts.af_num(), AFType::Input); 360 /// Initiate an asynchronous UART write
325 T::regs().cr3().write(|w| { 361 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
326 w.set_ctse(true); 362 let ch = self.tx_dma.as_mut().unwrap();
363 T::regs().cr3().modify(|reg| {
364 reg.set_dmat(true);
327 }); 365 });
328 Self::new_inner(peri, tx, tx_dma, config) 366 // If we don't assign future to a variable, the data register pointer
367 // is held across an await and makes the future non-Send.
368 let transfer = unsafe { ch.write(buffer, tdr(T::regs()), Default::default()) };
369 transfer.await;
370 Ok(())
329 } 371 }
372}
330 373
331 fn new_inner( 374impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
332 _peri: impl Peripheral<P = T> + 'd, 375 /// Create a new blocking tx-only UART with no hardware flow control.
376 ///
377 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
378 pub fn new_blocking(
379 peri: impl Peripheral<P = T> + 'd,
333 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 380 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
334 tx_dma: impl Peripheral<P = TxDma> + 'd,
335 config: Config, 381 config: Config,
336 ) -> Result<Self, ConfigError> { 382 ) -> Result<Self, ConfigError> {
337 into_ref!(_peri, tx, tx_dma); 383 Self::new_inner(peri, new_pin!(tx, AFType::OutputPushPull), None, None, config)
384 }
338 385
339 let r = T::regs(); 386 /// Create a new blocking tx-only UART with a clear-to-send pin
387 pub fn new_blocking_with_cts(
388 peri: impl Peripheral<P = T> + 'd,
389 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
390 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
391 config: Config,
392 ) -> Result<Self, ConfigError> {
393 Self::new_inner(
394 peri,
395 new_pin!(tx, AFType::OutputPushPull),
396 new_pin!(cts, AFType::Input),
397 None,
398 config,
399 )
400 }
401}
340 402
341 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 403impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
404 fn new_inner(
405 _peri: impl Peripheral<P = T> + 'd,
406 tx: Option<PeripheralRef<'d, AnyPin>>,
407 cts: Option<PeripheralRef<'d, AnyPin>>,
408 tx_dma: Option<ChannelAndRequest<'d>>,
409 config: Config,
410 ) -> Result<Self, ConfigError> {
411 T::enable_and_reset();
342 412
413 let r = T::regs();
414 r.cr3().modify(|w| {
415 w.set_ctse(cts.is_some());
416 });
343 configure(r, &config, T::frequency(), T::KIND, false, true)?; 417 configure(r, &config, T::frequency(), T::KIND, false, true)?;
344 418
345 // create state once! 419 // create state once!
346 let _s = T::state(); 420 let _s = T::state();
347 421
348 Ok(Self { 422 Ok(Self {
423 tx,
424 cts,
425 de: None,
349 tx_dma, 426 tx_dma,
350 phantom: PhantomData, 427 _phantom: PhantomData,
351 }) 428 })
352 } 429 }
353 430
@@ -356,23 +433,6 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
356 reconfigure::<T>(config) 433 reconfigure::<T>(config)
357 } 434 }
358 435
359 /// Initiate an asynchronous UART write
360 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
361 where
362 TxDma: crate::usart::TxDma<T>,
363 {
364 let ch = &mut self.tx_dma;
365 let request = ch.request();
366 T::regs().cr3().modify(|reg| {
367 reg.set_dmat(true);
368 });
369 // If we don't assign future to a variable, the data register pointer
370 // is held across an await and makes the future non-Send.
371 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
372 transfer.await;
373 Ok(())
374 }
375
376 /// Perform a blocking UART write 436 /// Perform a blocking UART write
377 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 437 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
378 let r = T::regs(); 438 let r = T::regs();
@@ -391,18 +451,18 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
391 } 451 }
392} 452}
393 453
394impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { 454impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
455 /// Create a new rx-only UART with no hardware flow control.
456 ///
395 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 457 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
396 pub fn new( 458 pub fn new(
397 peri: impl Peripheral<P = T> + 'd, 459 peri: impl Peripheral<P = T> + 'd,
398 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 460 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
399 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 461 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
400 rx_dma: impl Peripheral<P = RxDma> + 'd, 462 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
401 config: Config, 463 config: Config,
402 ) -> Result<Self, ConfigError> { 464 ) -> Result<Self, ConfigError> {
403 T::enable_and_reset(); 465 Self::new_inner(peri, new_pin!(rx, AFType::Input), None, new_dma!(rx_dma), config)
404
405 Self::new_inner(peri, rx, rx_dma, config)
406 } 466 }
407 467
408 /// Create a new rx-only UART with a request-to-send pin 468 /// Create a new rx-only UART with a request-to-send pin
@@ -411,143 +471,27 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
411 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 471 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
412 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 472 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
413 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 473 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
414 rx_dma: impl Peripheral<P = RxDma> + 'd, 474 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
415 config: Config,
416 ) -> Result<Self, ConfigError> {
417 into_ref!(rts);
418
419 T::enable_and_reset();
420
421 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
422 T::regs().cr3().write(|w| {
423 w.set_rtse(true);
424 });
425
426 Self::new_inner(peri, rx, rx_dma, config)
427 }
428
429 fn new_inner(
430 peri: impl Peripheral<P = T> + 'd,
431 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
432 rx_dma: impl Peripheral<P = RxDma> + 'd,
433 config: Config, 475 config: Config,
434 ) -> Result<Self, ConfigError> { 476 ) -> Result<Self, ConfigError> {
435 into_ref!(peri, rx, rx_dma); 477 Self::new_inner(
436 478 peri,
437 let r = T::regs(); 479 new_pin!(rx, AFType::Input),
438 480 new_pin!(rts, AFType::OutputPushPull),
439 rx.set_as_af(rx.af_num(), AFType::Input); 481 new_dma!(rx_dma),
440 482 config,
441 configure(r, &config, T::frequency(), T::KIND, true, false)?; 483 )
442
443 T::Interrupt::unpend();
444 unsafe { T::Interrupt::enable() };
445
446 // create state once!
447 let _s = T::state();
448
449 Ok(Self {
450 _peri: peri,
451 rx_dma,
452 detect_previous_overrun: config.detect_previous_overrun,
453 #[cfg(any(usart_v1, usart_v2))]
454 buffered_sr: stm32_metapac::usart::regs::Sr(0),
455 })
456 }
457
458 /// Reconfigure the driver
459 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
460 reconfigure::<T>(config)
461 }
462
463 #[cfg(any(usart_v1, usart_v2))]
464 fn check_rx_flags(&mut self) -> Result<bool, Error> {
465 let r = T::regs();
466 loop {
467 // Handle all buffered error flags.
468 if self.buffered_sr.pe() {
469 self.buffered_sr.set_pe(false);
470 return Err(Error::Parity);
471 } else if self.buffered_sr.fe() {
472 self.buffered_sr.set_fe(false);
473 return Err(Error::Framing);
474 } else if self.buffered_sr.ne() {
475 self.buffered_sr.set_ne(false);
476 return Err(Error::Noise);
477 } else if self.buffered_sr.ore() {
478 self.buffered_sr.set_ore(false);
479 return Err(Error::Overrun);
480 } else if self.buffered_sr.rxne() {
481 self.buffered_sr.set_rxne(false);
482 return Ok(true);
483 } else {
484 // No error flags from previous iterations were set: Check the actual status register
485 let sr = r.sr().read();
486 if !sr.rxne() {
487 return Ok(false);
488 }
489
490 // Buffer the status register and let the loop handle the error flags.
491 self.buffered_sr = sr;
492 }
493 }
494 }
495
496 #[cfg(any(usart_v3, usart_v4))]
497 fn check_rx_flags(&mut self) -> Result<bool, Error> {
498 let r = T::regs();
499 let sr = r.isr().read();
500 if sr.pe() {
501 r.icr().write(|w| w.set_pe(true));
502 return Err(Error::Parity);
503 } else if sr.fe() {
504 r.icr().write(|w| w.set_fe(true));
505 return Err(Error::Framing);
506 } else if sr.ne() {
507 r.icr().write(|w| w.set_ne(true));
508 return Err(Error::Noise);
509 } else if sr.ore() {
510 r.icr().write(|w| w.set_ore(true));
511 return Err(Error::Overrun);
512 }
513 Ok(sr.rxne())
514 } 484 }
515 485
516 /// Initiate an asynchronous UART read 486 /// Initiate an asynchronous UART read
517 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 487 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
518 where
519 RxDma: crate::usart::RxDma<T>,
520 {
521 self.inner_read(buffer, false).await?; 488 self.inner_read(buffer, false).await?;
522 489
523 Ok(()) 490 Ok(())
524 } 491 }
525 492
526 /// Read a single u8 if there is one available, otherwise return WouldBlock
527 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
528 let r = T::regs();
529 if self.check_rx_flags()? {
530 Ok(unsafe { rdr(r).read_volatile() })
531 } else {
532 Err(nb::Error::WouldBlock)
533 }
534 }
535
536 /// Perform a blocking read into `buffer`
537 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
538 let r = T::regs();
539 for b in buffer {
540 while !self.check_rx_flags()? {}
541 unsafe { *b = rdr(r).read_volatile() }
542 }
543 Ok(())
544 }
545
546 /// Initiate an asynchronous read with idle line detection enabled 493 /// Initiate an asynchronous read with idle line detection enabled
547 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 494 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
548 where
549 RxDma: crate::usart::RxDma<T>,
550 {
551 self.inner_read(buffer, true).await 495 self.inner_read(buffer, true).await
552 } 496 }
553 497
@@ -555,10 +499,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
555 &mut self, 499 &mut self,
556 buffer: &mut [u8], 500 buffer: &mut [u8],
557 enable_idle_line_detection: bool, 501 enable_idle_line_detection: bool,
558 ) -> Result<ReadCompletionEvent, Error> 502 ) -> Result<ReadCompletionEvent, Error> {
559 where
560 RxDma: crate::usart::RxDma<T>,
561 {
562 let r = T::regs(); 503 let r = T::regs();
563 504
564 // make sure USART state is restored to neutral state when this future is dropped 505 // make sure USART state is restored to neutral state when this future is dropped
@@ -581,15 +522,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
581 }); 522 });
582 }); 523 });
583 524
584 let ch = &mut self.rx_dma; 525 let ch = self.rx_dma.as_mut().unwrap();
585 let request = ch.request();
586 526
587 let buffer_len = buffer.len(); 527 let buffer_len = buffer.len();
588 528
589 // Start USART DMA 529 // Start USART DMA
590 // will not do anything yet because DMAR is not yet set 530 // will not do anything yet because DMAR is not yet set
591 // future which will complete when DMA Read request completes 531 // future which will complete when DMA Read request completes
592 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; 532 let transfer = unsafe { ch.read(rdr(T::regs()), buffer, Default::default()) };
593 533
594 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer 534 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
595 if !self.detect_previous_overrun { 535 if !self.detect_previous_overrun {
@@ -732,10 +672,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
732 r 672 r
733 } 673 }
734 674
735 async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> 675 async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> {
736 where
737 RxDma: crate::usart::RxDma<T>,
738 {
739 if buffer.is_empty() { 676 if buffer.is_empty() {
740 return Ok(0); 677 return Ok(0);
741 } else if buffer.len() > 0xFFFF { 678 } else if buffer.len() > 0xFFFF {
@@ -755,34 +692,186 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
755 } 692 }
756} 693}
757 694
758impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { 695impl<'d, T: BasicInstance> UartRx<'d, T, Blocking> {
696 /// Create a new rx-only UART with no hardware flow control.
697 ///
698 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
699 pub fn new_blocking(
700 peri: impl Peripheral<P = T> + 'd,
701 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
702 config: Config,
703 ) -> Result<Self, ConfigError> {
704 Self::new_inner(peri, new_pin!(rx, AFType::Input), None, None, config)
705 }
706
707 /// Create a new rx-only UART with a request-to-send pin
708 pub fn new_blocking_with_rts(
709 peri: impl Peripheral<P = T> + 'd,
710 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
711 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
712 config: Config,
713 ) -> Result<Self, ConfigError> {
714 Self::new_inner(
715 peri,
716 new_pin!(rx, AFType::Input),
717 new_pin!(rts, AFType::OutputPushPull),
718 None,
719 config,
720 )
721 }
722}
723
724impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
725 fn new_inner(
726 _peri: impl Peripheral<P = T> + 'd,
727 rx: Option<PeripheralRef<'d, AnyPin>>,
728 rts: Option<PeripheralRef<'d, AnyPin>>,
729 rx_dma: Option<ChannelAndRequest<'d>>,
730 config: Config,
731 ) -> Result<Self, ConfigError> {
732 T::enable_and_reset();
733
734 let r = T::regs();
735 r.cr3().write(|w| {
736 w.set_rtse(rts.is_some());
737 });
738 configure(r, &config, T::frequency(), T::KIND, true, false)?;
739
740 T::Interrupt::unpend();
741 unsafe { T::Interrupt::enable() };
742
743 // create state once!
744 let _s = T::state();
745
746 Ok(Self {
747 _phantom: PhantomData,
748 rx,
749 rts,
750 rx_dma,
751 detect_previous_overrun: config.detect_previous_overrun,
752 #[cfg(any(usart_v1, usart_v2))]
753 buffered_sr: stm32_metapac::usart::regs::Sr(0),
754 })
755 }
756
757 /// Reconfigure the driver
758 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
759 reconfigure::<T>(config)
760 }
761
762 #[cfg(any(usart_v1, usart_v2))]
763 fn check_rx_flags(&mut self) -> Result<bool, Error> {
764 let r = T::regs();
765 loop {
766 // Handle all buffered error flags.
767 if self.buffered_sr.pe() {
768 self.buffered_sr.set_pe(false);
769 return Err(Error::Parity);
770 } else if self.buffered_sr.fe() {
771 self.buffered_sr.set_fe(false);
772 return Err(Error::Framing);
773 } else if self.buffered_sr.ne() {
774 self.buffered_sr.set_ne(false);
775 return Err(Error::Noise);
776 } else if self.buffered_sr.ore() {
777 self.buffered_sr.set_ore(false);
778 return Err(Error::Overrun);
779 } else if self.buffered_sr.rxne() {
780 self.buffered_sr.set_rxne(false);
781 return Ok(true);
782 } else {
783 // No error flags from previous iterations were set: Check the actual status register
784 let sr = r.sr().read();
785 if !sr.rxne() {
786 return Ok(false);
787 }
788
789 // Buffer the status register and let the loop handle the error flags.
790 self.buffered_sr = sr;
791 }
792 }
793 }
794
795 #[cfg(any(usart_v3, usart_v4))]
796 fn check_rx_flags(&mut self) -> Result<bool, Error> {
797 let r = T::regs();
798 let sr = r.isr().read();
799 if sr.pe() {
800 r.icr().write(|w| w.set_pe(true));
801 return Err(Error::Parity);
802 } else if sr.fe() {
803 r.icr().write(|w| w.set_fe(true));
804 return Err(Error::Framing);
805 } else if sr.ne() {
806 r.icr().write(|w| w.set_ne(true));
807 return Err(Error::Noise);
808 } else if sr.ore() {
809 r.icr().write(|w| w.set_ore(true));
810 return Err(Error::Overrun);
811 }
812 Ok(sr.rxne())
813 }
814
815 /// Read a single u8 if there is one available, otherwise return WouldBlock
816 pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
817 let r = T::regs();
818 if self.check_rx_flags()? {
819 Ok(unsafe { rdr(r).read_volatile() })
820 } else {
821 Err(nb::Error::WouldBlock)
822 }
823 }
824
825 /// Perform a blocking read into `buffer`
826 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
827 let r = T::regs();
828 for b in buffer {
829 while !self.check_rx_flags()? {}
830 unsafe { *b = rdr(r).read_volatile() }
831 }
832 Ok(())
833 }
834}
835
836impl<'d, T: BasicInstance, M: Mode> Drop for UartTx<'d, T, M> {
759 fn drop(&mut self) { 837 fn drop(&mut self) {
838 self.tx.as_ref().map(|x| x.set_as_disconnected());
839 self.cts.as_ref().map(|x| x.set_as_disconnected());
840 self.de.as_ref().map(|x| x.set_as_disconnected());
760 T::disable(); 841 T::disable();
761 } 842 }
762} 843}
763 844
764impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { 845impl<'d, T: BasicInstance, M: Mode> Drop for UartRx<'d, T, M> {
765 fn drop(&mut self) { 846 fn drop(&mut self) {
847 self.rx.as_ref().map(|x| x.set_as_disconnected());
848 self.rts.as_ref().map(|x| x.set_as_disconnected());
766 T::disable(); 849 T::disable();
767 } 850 }
768} 851}
769 852
770impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { 853impl<'d, T: BasicInstance> Uart<'d, T, Async> {
771 /// Create a new bidirectional UART 854 /// Create a new bidirectional UART
772 pub fn new( 855 pub fn new(
773 peri: impl Peripheral<P = T> + 'd, 856 peri: impl Peripheral<P = T> + 'd,
774 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 857 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
775 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 858 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
776 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 859 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
777 tx_dma: impl Peripheral<P = TxDma> + 'd, 860 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
778 rx_dma: impl Peripheral<P = RxDma> + 'd, 861 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
779 config: Config, 862 config: Config,
780 ) -> Result<Self, ConfigError> { 863 ) -> Result<Self, ConfigError> {
781 // UartRx and UartTx have one refcount ea. 864 Self::new_inner(
782 T::enable_and_reset(); 865 peri,
783 T::enable_and_reset(); 866 new_pin!(rx, config.rx_af()),
784 867 new_pin!(tx, config.tx_af()),
785 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) 868 None,
869 None,
870 None,
871 new_dma!(tx_dma),
872 new_dma!(rx_dma),
873 config,
874 )
786 } 875 }
787 876
788 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 877 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
@@ -793,23 +882,21 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
793 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 882 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
794 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 883 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
795 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 884 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
796 tx_dma: impl Peripheral<P = TxDma> + 'd, 885 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
797 rx_dma: impl Peripheral<P = RxDma> + 'd, 886 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
798 config: Config, 887 config: Config,
799 ) -> Result<Self, ConfigError> { 888 ) -> Result<Self, ConfigError> {
800 into_ref!(cts, rts); 889 Self::new_inner(
801 890 peri,
802 // UartRx and UartTx have one refcount ea. 891 new_pin!(rx, config.rx_af()),
803 T::enable_and_reset(); 892 new_pin!(tx, config.tx_af()),
804 T::enable_and_reset(); 893 new_pin!(rts, AFType::OutputPushPull),
805 894 new_pin!(cts, AFType::Input),
806 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 895 None,
807 cts.set_as_af(cts.af_num(), AFType::Input); 896 new_dma!(tx_dma),
808 T::regs().cr3().write(|w| { 897 new_dma!(rx_dma),
809 w.set_rtse(true); 898 config,
810 w.set_ctse(true); 899 )
811 });
812 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
813 } 900 }
814 901
815 #[cfg(not(any(usart_v1, usart_v2)))] 902 #[cfg(not(any(usart_v1, usart_v2)))]
@@ -820,21 +907,21 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
820 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 907 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
821 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 908 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
822 de: impl Peripheral<P = impl DePin<T>> + 'd, 909 de: impl Peripheral<P = impl DePin<T>> + 'd,
823 tx_dma: impl Peripheral<P = TxDma> + 'd, 910 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
824 rx_dma: impl Peripheral<P = RxDma> + 'd, 911 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
825 config: Config, 912 config: Config,
826 ) -> Result<Self, ConfigError> { 913 ) -> Result<Self, ConfigError> {
827 into_ref!(de); 914 Self::new_inner(
828 915 peri,
829 // UartRx and UartTx have one refcount ea. 916 new_pin!(rx, config.rx_af()),
830 T::enable_and_reset(); 917 new_pin!(tx, config.tx_af()),
831 T::enable_and_reset(); 918 None,
832 919 None,
833 de.set_as_af(de.af_num(), AFType::OutputPushPull); 920 new_pin!(de, AFType::OutputPushPull),
834 T::regs().cr3().write(|w| { 921 new_dma!(tx_dma),
835 w.set_dem(true); 922 new_dma!(rx_dma),
836 }); 923 config,
837 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config) 924 )
838 } 925 }
839 926
840 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin. 927 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
@@ -852,22 +939,24 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
852 peri: impl Peripheral<P = T> + 'd, 939 peri: impl Peripheral<P = T> + 'd,
853 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 940 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
854 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 941 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
855 tx_dma: impl Peripheral<P = TxDma> + 'd, 942 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
856 rx_dma: impl Peripheral<P = RxDma> + 'd, 943 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
857 mut config: Config, 944 mut config: Config,
858 ) -> Result<Self, ConfigError> { 945 ) -> Result<Self, ConfigError> {
859 // UartRx and UartTx have one refcount ea.
860 T::enable_and_reset();
861 T::enable_and_reset();
862
863 config.swap_rx_tx = false; 946 config.swap_rx_tx = false;
947 config.half_duplex = true;
864 948
865 into_ref!(peri, tx, tx_dma, rx_dma); 949 Self::new_inner(
866 950 peri,
867 T::regs().cr3().write(|w| w.set_hdsel(true)); 951 None,
868 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 952 new_pin!(tx, AFType::OutputPushPull),
869 953 None,
870 Self::new_inner(peri, tx_dma, rx_dma, config) 954 None,
955 None,
956 new_dma!(tx_dma),
957 new_dma!(rx_dma),
958 config,
959 )
871 } 960 }
872 961
873 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin. 962 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
@@ -885,62 +974,196 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
885 peri: impl Peripheral<P = T> + 'd, 974 peri: impl Peripheral<P = T> + 'd,
886 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 975 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
887 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 976 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
888 tx_dma: impl Peripheral<P = TxDma> + 'd, 977 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
889 rx_dma: impl Peripheral<P = RxDma> + 'd, 978 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
890 mut config: Config, 979 mut config: Config,
891 ) -> Result<Self, ConfigError> { 980 ) -> Result<Self, ConfigError> {
892 // UartRx and UartTx have one refcount ea.
893 T::enable_and_reset();
894 T::enable_and_reset();
895
896 config.swap_rx_tx = true; 981 config.swap_rx_tx = true;
982 config.half_duplex = true;
983
984 Self::new_inner(
985 peri,
986 None,
987 None,
988 new_pin!(rx, AFType::OutputPushPull),
989 None,
990 None,
991 new_dma!(tx_dma),
992 new_dma!(rx_dma),
993 config,
994 )
995 }
996
997 /// Perform an asynchronous write
998 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
999 self.tx.write(buffer).await
1000 }
1001
1002 /// Perform an asynchronous read into `buffer`
1003 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
1004 self.rx.read(buffer).await
1005 }
897 1006
898 into_ref!(peri, rx, tx_dma, rx_dma); 1007 /// Perform an an asynchronous read with idle line detection enabled
1008 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1009 self.rx.read_until_idle(buffer).await
1010 }
1011}
899 1012
900 T::regs().cr3().write(|w| w.set_hdsel(true)); 1013impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
901 rx.set_as_af(rx.af_num(), AFType::OutputPushPull); 1014 /// Create a new blocking bidirectional UART.
1015 pub fn new_blocking(
1016 peri: impl Peripheral<P = T> + 'd,
1017 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1018 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1019 config: Config,
1020 ) -> Result<Self, ConfigError> {
1021 Self::new_inner(
1022 peri,
1023 new_pin!(rx, config.rx_af()),
1024 new_pin!(tx, config.tx_af()),
1025 None,
1026 None,
1027 None,
1028 None,
1029 None,
1030 config,
1031 )
1032 }
902 1033
903 Self::new_inner(peri, tx_dma, rx_dma, config) 1034 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
1035 pub fn new_blocking_with_rtscts(
1036 peri: impl Peripheral<P = T> + 'd,
1037 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1038 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1039 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
1040 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
1041 config: Config,
1042 ) -> Result<Self, ConfigError> {
1043 Self::new_inner(
1044 peri,
1045 new_pin!(rx, config.rx_af()),
1046 new_pin!(tx, config.tx_af()),
1047 new_pin!(rts, AFType::OutputPushPull),
1048 new_pin!(cts, AFType::Input),
1049 None,
1050 None,
1051 None,
1052 config,
1053 )
904 } 1054 }
905 1055
906 fn new_inner_configure( 1056 #[cfg(not(any(usart_v1, usart_v2)))]
1057 /// Create a new bidirectional UART with a driver-enable pin
1058 pub fn new_blocking_with_de(
907 peri: impl Peripheral<P = T> + 'd, 1059 peri: impl Peripheral<P = T> + 'd,
908 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1060 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
909 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1061 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
910 tx_dma: impl Peripheral<P = TxDma> + 'd, 1062 de: impl Peripheral<P = impl DePin<T>> + 'd,
911 rx_dma: impl Peripheral<P = RxDma> + 'd,
912 config: Config, 1063 config: Config,
913 ) -> Result<Self, ConfigError> { 1064 ) -> Result<Self, ConfigError> {
914 into_ref!(peri, rx, tx, tx_dma, rx_dma); 1065 Self::new_inner(
915 1066 peri,
916 // Some chips do not have swap_rx_tx bit 1067 new_pin!(rx, config.rx_af()),
917 cfg_if::cfg_if! { 1068 new_pin!(tx, config.tx_af()),
918 if #[cfg(any(usart_v3, usart_v4))] { 1069 None,
919 if config.swap_rx_tx { 1070 None,
920 let (rx, tx) = (tx, rx); 1071 new_pin!(de, AFType::OutputPushPull),
921 rx.set_as_af(rx.af_num(), AFType::Input); 1072 None,
922 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1073 None,
923 } else { 1074 config,
924 rx.set_as_af(rx.af_num(), AFType::Input); 1075 )
925 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1076 }
926 } 1077
927 } else { 1078 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
928 rx.set_as_af(rx.af_num(), AFType::Input); 1079 ///
929 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 1080 /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin.
930 } 1081 /// There is no functional difference between these methods, as both allow bidirectional communication.
931 } 1082 ///
1083 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
1084 /// I/O in idle or in reception.
1085 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1086 /// on the line must be managed by software (for instance by using a centralized arbiter).
1087 #[cfg(not(any(usart_v1, usart_v2)))]
1088 #[doc(alias("HDSEL"))]
1089 pub fn new_blocking_half_duplex(
1090 peri: impl Peripheral<P = T> + 'd,
1091 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1092 mut config: Config,
1093 ) -> Result<Self, ConfigError> {
1094 config.swap_rx_tx = false;
1095 config.half_duplex = true;
1096
1097 Self::new_inner(
1098 peri,
1099 None,
1100 new_pin!(tx, AFType::OutputPushPull),
1101 None,
1102 None,
1103 None,
1104 None,
1105 None,
1106 config,
1107 )
1108 }
932 1109
933 Self::new_inner(peri, tx_dma, rx_dma, config) 1110 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
1111 ///
1112 /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
1113 /// There is no functional difference between these methods, as both allow bidirectional communication.
1114 ///
1115 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
1116 /// I/O in idle or in reception.
1117 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1118 /// on the line must be managed by software (for instance by using a centralized arbiter).
1119 #[cfg(not(any(usart_v1, usart_v2)))]
1120 #[doc(alias("HDSEL"))]
1121 pub fn new_blocking_half_duplex_on_rx(
1122 peri: impl Peripheral<P = T> + 'd,
1123 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1124 mut config: Config,
1125 ) -> Result<Self, ConfigError> {
1126 config.swap_rx_tx = true;
1127 config.half_duplex = true;
1128
1129 Self::new_inner(
1130 peri,
1131 None,
1132 None,
1133 new_pin!(rx, AFType::OutputPushPull),
1134 None,
1135 None,
1136 None,
1137 None,
1138 config,
1139 )
934 } 1140 }
1141}
935 1142
1143impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
936 fn new_inner( 1144 fn new_inner(
937 peri: PeripheralRef<'d, T>, 1145 _peri: impl Peripheral<P = T> + 'd,
938 tx_dma: PeripheralRef<'d, TxDma>, 1146 rx: Option<PeripheralRef<'d, AnyPin>>,
939 rx_dma: PeripheralRef<'d, RxDma>, 1147 tx: Option<PeripheralRef<'d, AnyPin>>,
1148 rts: Option<PeripheralRef<'d, AnyPin>>,
1149 cts: Option<PeripheralRef<'d, AnyPin>>,
1150 de: Option<PeripheralRef<'d, AnyPin>>,
1151 tx_dma: Option<ChannelAndRequest<'d>>,
1152 rx_dma: Option<ChannelAndRequest<'d>>,
940 config: Config, 1153 config: Config,
941 ) -> Result<Self, ConfigError> { 1154 ) -> Result<Self, ConfigError> {
1155 // UartRx and UartTx have one refcount each.
1156 T::enable_and_reset();
1157 T::enable_and_reset();
1158
942 let r = T::regs(); 1159 let r = T::regs();
943 1160
1161 r.cr3().write(|w| {
1162 w.set_rtse(rts.is_some());
1163 w.set_ctse(cts.is_some());
1164 #[cfg(not(any(usart_v1, usart_v2)))]
1165 w.set_dem(de.is_some());
1166 });
944 configure(r, &config, T::frequency(), T::KIND, true, true)?; 1167 configure(r, &config, T::frequency(), T::KIND, true, true)?;
945 1168
946 T::Interrupt::unpend(); 1169 T::Interrupt::unpend();
@@ -951,11 +1174,16 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
951 1174
952 Ok(Self { 1175 Ok(Self {
953 tx: UartTx { 1176 tx: UartTx {
1177 _phantom: PhantomData,
1178 tx,
1179 cts,
1180 de,
954 tx_dma, 1181 tx_dma,
955 phantom: PhantomData,
956 }, 1182 },
957 rx: UartRx { 1183 rx: UartRx {
958 _peri: peri, 1184 _phantom: PhantomData,
1185 rx,
1186 rts,
959 rx_dma, 1187 rx_dma,
960 detect_previous_overrun: config.detect_previous_overrun, 1188 detect_previous_overrun: config.detect_previous_overrun,
961 #[cfg(any(usart_v1, usart_v2))] 1189 #[cfg(any(usart_v1, usart_v2))]
@@ -964,14 +1192,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
964 }) 1192 })
965 } 1193 }
966 1194
967 /// Initiate an asynchronous write
968 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
969 where
970 TxDma: crate::usart::TxDma<T>,
971 {
972 self.tx.write(buffer).await
973 }
974
975 /// Perform a blocking write 1195 /// Perform a blocking write
976 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1196 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
977 self.tx.blocking_write(buffer) 1197 self.tx.blocking_write(buffer)
@@ -982,16 +1202,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
982 self.tx.blocking_flush() 1202 self.tx.blocking_flush()
983 } 1203 }
984 1204
985 /// Initiate an asynchronous read into `buffer`
986 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
987 where
988 RxDma: crate::usart::RxDma<T>,
989 {
990 self.rx.read(buffer).await
991 }
992
993 /// Read a single `u8` or return `WouldBlock` 1205 /// Read a single `u8` or return `WouldBlock`
994 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 1206 pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
995 self.rx.nb_read() 1207 self.rx.nb_read()
996 } 1208 }
997 1209
@@ -1000,18 +1212,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
1000 self.rx.blocking_read(buffer) 1212 self.rx.blocking_read(buffer)
1001 } 1213 }
1002 1214
1003 /// Initiate an an asynchronous read with idle line detection enabled
1004 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
1005 where
1006 RxDma: crate::usart::RxDma<T>,
1007 {
1008 self.rx.read_until_idle(buffer).await
1009 }
1010
1011 /// Split the Uart into a transmitter and receiver, which is 1215 /// Split the Uart into a transmitter and receiver, which is
1012 /// particularly useful when having two tasks correlating to 1216 /// particularly useful when having two tasks correlating to
1013 /// transmitting and receiving. 1217 /// transmitting and receiving.
1014 pub fn split(self) -> (UartTx<'d, T, TxDma>, UartRx<'d, T, RxDma>) { 1218 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
1015 (self.tx, self.rx) 1219 (self.tx, self.rx)
1016 } 1220 }
1017} 1221}
@@ -1153,6 +1357,8 @@ fn configure(
1153 #[cfg(not(usart_v1))] 1357 #[cfg(not(usart_v1))]
1154 r.cr3().modify(|w| { 1358 r.cr3().modify(|w| {
1155 w.set_onebit(config.assume_noise_free); 1359 w.set_onebit(config.assume_noise_free);
1360 #[cfg(any(usart_v3, usart_v4))]
1361 w.set_hdsel(config.half_duplex);
1156 }); 1362 });
1157 1363
1158 r.cr1().write(|w| { 1364 r.cr1().write(|w| {
@@ -1185,14 +1391,14 @@ fn configure(
1185 Ok(()) 1391 Ok(())
1186} 1392}
1187 1393
1188impl<'d, T: BasicInstance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> { 1394impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
1189 type Error = Error; 1395 type Error = Error;
1190 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1396 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1191 self.nb_read() 1397 self.nb_read()
1192 } 1398 }
1193} 1399}
1194 1400
1195impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> { 1401impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
1196 type Error = Error; 1402 type Error = Error;
1197 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1403 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1198 self.blocking_write(buffer) 1404 self.blocking_write(buffer)
@@ -1202,14 +1408,14 @@ impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> f
1202 } 1408 }
1203} 1409}
1204 1410
1205impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> { 1411impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
1206 type Error = Error; 1412 type Error = Error;
1207 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1413 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1208 self.nb_read() 1414 self.nb_read()
1209 } 1415 }
1210} 1416}
1211 1417
1212impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> { 1418impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
1213 type Error = Error; 1419 type Error = Error;
1214 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1420 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1215 self.blocking_write(buffer) 1421 self.blocking_write(buffer)
@@ -1231,25 +1437,25 @@ impl embedded_hal_nb::serial::Error for Error {
1231 } 1437 }
1232} 1438}
1233 1439
1234impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { 1440impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
1235 type Error = Error; 1441 type Error = Error;
1236} 1442}
1237 1443
1238impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> { 1444impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
1239 type Error = Error; 1445 type Error = Error;
1240} 1446}
1241 1447
1242impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> { 1448impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
1243 type Error = Error; 1449 type Error = Error;
1244} 1450}
1245 1451
1246impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::Read for UartRx<'d, T, RxDma> { 1452impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
1247 fn read(&mut self) -> nb::Result<u8, Self::Error> { 1453 fn read(&mut self) -> nb::Result<u8, Self::Error> {
1248 self.nb_read() 1454 self.nb_read()
1249 } 1455 }
1250} 1456}
1251 1457
1252impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { 1458impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
1253 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1459 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1254 self.blocking_write(&[char]).map_err(nb::Error::Other) 1460 self.blocking_write(&[char]).map_err(nb::Error::Other)
1255 } 1461 }
@@ -1259,13 +1465,13 @@ impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d,
1259 } 1465 }
1260} 1466}
1261 1467
1262impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Read for Uart<'d, T, TxDma, RxDma> { 1468impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
1263 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1469 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1264 self.nb_read() 1470 self.nb_read()
1265 } 1471 }
1266} 1472}
1267 1473
1268impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { 1474impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
1269 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1475 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1270 self.blocking_write(&[char]).map_err(nb::Error::Other) 1476 self.blocking_write(&[char]).map_err(nb::Error::Other)
1271 } 1477 }
@@ -1281,21 +1487,21 @@ impl embedded_io::Error for Error {
1281 } 1487 }
1282} 1488}
1283 1489
1284impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> 1490impl<T, M: Mode> embedded_io::ErrorType for Uart<'_, T, M>
1285where 1491where
1286 T: BasicInstance, 1492 T: BasicInstance,
1287{ 1493{
1288 type Error = Error; 1494 type Error = Error;
1289} 1495}
1290 1496
1291impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma> 1497impl<T, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M>
1292where 1498where
1293 T: BasicInstance, 1499 T: BasicInstance,
1294{ 1500{
1295 type Error = Error; 1501 type Error = Error;
1296} 1502}
1297 1503
1298impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> 1504impl<T, M: Mode> embedded_io::Write for Uart<'_, T, M>
1299where 1505where
1300 T: BasicInstance, 1506 T: BasicInstance,
1301{ 1507{
@@ -1309,7 +1515,7 @@ where
1309 } 1515 }
1310} 1516}
1311 1517
1312impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> 1518impl<T, M: Mode> embedded_io::Write for UartTx<'_, T, M>
1313where 1519where
1314 T: BasicInstance, 1520 T: BasicInstance,
1315{ 1521{
@@ -1323,10 +1529,9 @@ where
1323 } 1529 }
1324} 1530}
1325 1531
1326impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> 1532impl<T> embedded_io_async::Write for Uart<'_, T, Async>
1327where 1533where
1328 T: BasicInstance, 1534 T: BasicInstance,
1329 TxDma: self::TxDma<T>,
1330{ 1535{
1331 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1536 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1332 self.write(buf).await?; 1537 self.write(buf).await?;
@@ -1338,10 +1543,9 @@ where
1338 } 1543 }
1339} 1544}
1340 1545
1341impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma> 1546impl<T> embedded_io_async::Write for UartTx<'_, T, Async>
1342where 1547where
1343 T: BasicInstance, 1548 T: BasicInstance,
1344 TxDma: self::TxDma<T>,
1345{ 1549{
1346 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1550 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1347 self.write(buf).await?; 1551 self.write(buf).await?;
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b852f0176..8eb18fe5b 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,21 +1,22 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData;
2use core::mem; 3use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralRef;
8use futures::future::{select, Either}; 8use futures::future::{select, Either};
9 9
10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; 10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
11use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::mode::Async;
12use crate::usart::{Regs, Sr}; 13use crate::usart::{Regs, Sr};
13 14
14/// Rx-only Ring-buffered UART Driver 15/// Rx-only Ring-buffered UART Driver
15/// 16///
16/// Created with [UartRx::into_ring_buffered] 17/// Created with [UartRx::into_ring_buffered]
17pub struct RingBufferedUartRx<'d, T: BasicInstance> { 18pub struct RingBufferedUartRx<'d, T: BasicInstance> {
18 _peri: PeripheralRef<'d, T>, 19 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u8>, 20 ring_buf: ReadableRingBuffer<'d, u8>,
20} 21}
21 22
@@ -28,26 +29,29 @@ impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
28 } 29 }
29} 30}
30 31
31impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { 32impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
32 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 33 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
33 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the 34 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
34 /// DMA controller, and must be large enough to prevent overflows. 35 /// DMA controller, and must be large enough to prevent overflows.
35 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> { 36 pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
36 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 37 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
37 38
38 let request = self.rx_dma.request();
39 let opts = Default::default(); 39 let opts = Default::default();
40 40
41 // Safety: we forget the struct before this function returns. 41 // Safety: we forget the struct before this function returns.
42 let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; 42 let rx_dma = self.rx_dma.as_mut().unwrap();
43 let _peri = unsafe { self._peri.clone_unchecked() }; 43 let request = rx_dma.request;
44 let rx_dma = unsafe { rx_dma.channel.clone_unchecked() };
44 45
45 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 46 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
46 47
47 // Don't disable the clock 48 // Don't disable the clock
48 mem::forget(self); 49 mem::forget(self);
49 50
50 RingBufferedUartRx { _peri, ring_buf } 51 RingBufferedUartRx {
52 _phantom: PhantomData,
53 ring_buf,
54 }
51 } 55 }
52} 56}
53 57
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 72459d660..b48a408c4 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -3,6 +3,7 @@
3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks. 3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
4use core::cell::{RefCell, UnsafeCell}; 4use core::cell::{RefCell, UnsafeCell};
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::mem;
6use core::ops::{Deref, DerefMut}; 7use core::ops::{Deref, DerefMut};
7use core::task::Poll; 8use core::task::Poll;
8 9
@@ -134,6 +135,7 @@ where
134/// successfully locked the mutex, and grants access to the contents. 135/// successfully locked the mutex, and grants access to the contents.
135/// 136///
136/// Dropping it unlocks the mutex. 137/// Dropping it unlocks the mutex.
138#[clippy::has_significant_drop]
137pub struct MutexGuard<'a, M, T> 139pub struct MutexGuard<'a, M, T>
138where 140where
139 M: RawMutex, 141 M: RawMutex,
@@ -142,6 +144,25 @@ where
142 mutex: &'a Mutex<M, T>, 144 mutex: &'a Mutex<M, T>,
143} 145}
144 146
147impl<'a, M, T> MutexGuard<'a, M, T>
148where
149 M: RawMutex,
150 T: ?Sized,
151{
152 /// Returns a locked view over a portion of the locked data.
153 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
154 let mutex = this.mutex;
155 let value = fun(unsafe { &mut *this.mutex.inner.get() });
156 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
157 // locked state is being moved to the returned MappedMutexGuard.
158 mem::forget(this);
159 MappedMutexGuard {
160 state: &mutex.state,
161 value,
162 }
163 }
164}
165
145impl<'a, M, T> Drop for MutexGuard<'a, M, T> 166impl<'a, M, T> Drop for MutexGuard<'a, M, T>
146where 167where
147 M: RawMutex, 168 M: RawMutex,
@@ -180,3 +201,115 @@ where
180 unsafe { &mut *(self.mutex.inner.get()) } 201 unsafe { &mut *(self.mutex.inner.get()) }
181 } 202 }
182} 203}
204
205/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or
206/// [`MappedMutexGuard::map`].
207///
208/// This can be used to hold a subfield of the protected data.
209#[clippy::has_significant_drop]
210pub struct MappedMutexGuard<'a, M, T>
211where
212 M: RawMutex,
213 T: ?Sized,
214{
215 state: &'a BlockingMutex<M, RefCell<State>>,
216 value: *mut T,
217}
218
219impl<'a, M, T> MappedMutexGuard<'a, M, T>
220where
221 M: RawMutex,
222 T: ?Sized,
223{
224 /// Returns a locked view over a portion of the locked data.
225 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
226 let state = this.state;
227 let value = fun(unsafe { &mut *this.value });
228 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
229 // locked state is being moved to the returned MappedMutexGuard.
230 mem::forget(this);
231 MappedMutexGuard { state, value }
232 }
233}
234
235impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T>
236where
237 M: RawMutex,
238 T: ?Sized,
239{
240 type Target = T;
241 fn deref(&self) -> &Self::Target {
242 // Safety: the MutexGuard represents exclusive access to the contents
243 // of the mutex, so it's OK to get it.
244 unsafe { &*self.value }
245 }
246}
247
248impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T>
249where
250 M: RawMutex,
251 T: ?Sized,
252{
253 fn deref_mut(&mut self) -> &mut Self::Target {
254 // Safety: the MutexGuard represents exclusive access to the contents
255 // of the mutex, so it's OK to get it.
256 unsafe { &mut *self.value }
257 }
258}
259
260impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T>
261where
262 M: RawMutex,
263 T: ?Sized,
264{
265 fn drop(&mut self) {
266 self.state.lock(|s| {
267 let mut s = unwrap!(s.try_borrow_mut());
268 s.locked = false;
269 s.waker.wake();
270 })
271 }
272}
273
274unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T>
275where
276 M: RawMutex + Sync,
277 T: Send + ?Sized,
278{
279}
280
281unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T>
282where
283 M: RawMutex + Sync,
284 T: Sync + ?Sized,
285{
286}
287
288#[cfg(test)]
289mod tests {
290 use crate::blocking_mutex::raw::NoopRawMutex;
291 use crate::mutex::{Mutex, MutexGuard};
292
293 #[futures_test::test]
294 async fn mapped_guard_releases_lock_when_dropped() {
295 let mutex: Mutex<NoopRawMutex, [i32; 2]> = Mutex::new([0, 1]);
296
297 {
298 let guard = mutex.lock().await;
299 assert_eq!(*guard, [0, 1]);
300 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
301 assert_eq!(*mapped, 1);
302 *mapped = 2;
303 }
304
305 {
306 let guard = mutex.lock().await;
307 assert_eq!(*guard, [0, 2]);
308 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
309 assert_eq!(*mapped, 2);
310 *mapped = 3;
311 }
312
313 assert_eq!(*mutex.lock().await, [0, 3]);
314 }
315}
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 5234e53b9..573a49f19 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
index 4b5da774d..4a96357a4 100644
--- a/examples/stm32f4/src/bin/i2c.rs
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -3,35 +3,19 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::{Error, I2c}; 6use embassy_stm32::i2c::{Error, I2c};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 info!("Hello world!"); 15 info!("Hello world!");
23 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
24 17
25 let mut i2c = I2c::new( 18 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 19
36 let mut data = [0u8; 1]; 20 let mut data = [0u8; 1];
37 21
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index dc9141c62..970d819fc 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let mut spi_config = Config::default(); 17 let mut spi_config = Config::default();
19 spi_config.frequency = Hertz(1_000_000); 18 spi_config.frequency = Hertz(1_000_000);
20 19
21 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 20 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
22 21
23 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
24 23
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 40d9d70f1..991bf6673 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::usart::{Config, Uart}; 6use embassy_stm32::usart::{Config, Uart};
8use embassy_stm32::{bind_interrupts, peripherals, usart}; 7use embassy_stm32::{bind_interrupts, peripherals, usart};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +18,7 @@ fn main() -> ! {
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
20 19
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); 21 let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap();
23 22
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 24 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index dd6de599c..aaf8d6c4f 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
index 56ccb67b8..e00d14327 100644
--- a/examples/stm32f4/src/bin/ws2812_spi.rs
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -13,8 +13,8 @@
13#![no_std] 13#![no_std]
14#![no_main] 14#![no_main]
15 15
16use embassy_stm32::spi;
16use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
17use embassy_stm32::{dma, spi};
18use embassy_time::{Duration, Ticker, Timer}; 18use embassy_time::{Duration, Ticker, Timer};
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
@@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
78 spi_config.frequency = khz(12_800); 78 spi_config.frequency = khz(12_800);
79 79
80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered 80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered
81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); 81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config);
82 82
83 // flip color at 2 Hz 83 // flip color at 2 Hz
84 let mut ticker = Ticker::every(Duration::from_millis(500)); 84 let mut ticker = Ticker::every(Duration::from_millis(500));
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index fb604b34f..47456adf2 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs {
19async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
21 let config = Config::default(); 20 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); 21 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap();
23 22
24 for n in 0u32.. { 23 for n in 0u32.. {
25 let mut s: String<128> = String::new(); 24 let mut s: String<128> = String::new();
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index c5ea51721..2deee271d 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::word::U5; 6use embassy_stm32::dma::word::U5;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
77 76
78 let mut config = Config::default(); 77 let mut config = Config::default();
79 config.frequency = Hertz(4_000_000); 78 config.frequency = Hertz(4_000_000);
80 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); 79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config);
81 80
82 let mut neopixels = Ws2812::new(); 81 let mut neopixels = Ws2812::new();
83 82
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h5/src/bin/usart.rs
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
index caae0dd18..c644e84bd 100644
--- a/examples/stm32h5/src/bin/usart_dma.rs
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index 92047de8d..77b4caa9e 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; 7use embassy_stm32::peripherals::UART7;
8use embassy_stm32::usart::{Config, Uart, UartRx}; 8use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 16});
17 17
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 18static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 19
32#[embassy_executor::main] 20#[embassy_executor::main]
@@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
50} 38}
51 39
52#[embassy_executor::task] 40#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { 41async fn reader(mut rx: UartRx<'static, UART7, Async>) {
54 let mut buf = [0; 8]; 42 let mut buf = [0; 8];
55 loop { 43 loop {
56 info!("reading..."); 44 info!("reading...");
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index aed27723a..aaebdc346 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -7,7 +7,7 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3; 11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
13use embassy_stm32::{spi, Config}; 13use embassy_stm32::{spi, Config};
@@ -16,7 +16,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18#[embassy_executor::task] 18#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { 19async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) {
20 for n in 0u32.. { 20 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 21 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
@@ -62,7 +62,7 @@ fn main() -> ! {
62 let mut spi_config = spi::Config::default(); 62 let mut spi_config = spi::Config::default();
63 spi_config.frequency = mhz(1); 63 spi_config.frequency = mhz(1);
64 64
65 let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); 65 let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
66 66
67 let executor = EXECUTOR.init(Executor::new()); 67 let executor = EXECUTOR.init(Executor::new());
68 68
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 54d4d7656..3d3c724eb 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -7,15 +7,15 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config}; 12use embassy_stm32::{peripherals, spi, Config};
13use heapless::String; 13use heapless::String;
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { 18async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index f9cbad6af..cc49c2fdb 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -4,22 +4,16 @@
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Executor; 6use embassy_executor::Executor;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 8use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
13bind_interrupts!(struct Irqs {
14 UART7 => usart::InterruptHandler<peripherals::UART7>;
15});
16
17#[embassy_executor::task] 11#[embassy_executor::task]
18async fn main_task() { 12async fn main_task() {
19 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
20 14
21 let config = Config::default(); 15 let config = Config::default();
22 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); 16 let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
23 17
24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 18 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
25 info!("wrote Hello, starting echo"); 19 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index ae1f3a2e9..6f340d40a 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -6,7 +6,6 @@ use core::fmt::Write;
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart}; 10use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 11use heapless::String;
@@ -22,7 +21,7 @@ async fn main_task() {
22 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
23 22
24 let config = Config::default(); 23 let config = Config::default();
25 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); 24 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap();
26 25
27 for n in 0u32.. { 26 for n in 0u32.. {
28 let mut s: String<128> = String::new(); 27 let mut s: String<128> = String::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index b98c40877..4ad8e77ce 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::mode::Async;
7use embassy_stm32::peripherals::{DMA1_CH1, UART7}; 7use embassy_stm32::peripherals::UART7;
8use embassy_stm32::usart::{Config, Uart, UartRx}; 8use embassy_stm32::usart::{Config, Uart, UartRx};
9use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>; 15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16}); 16});
17 17
18#[embassy_executor::task]
19async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo");
22
23 let mut buf = [0u8; 1];
24 loop {
25 unwrap!(usart.blocking_read(&mut buf));
26 unwrap!(usart.blocking_write(&buf));
27 }
28}
29
30static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 18static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
31 19
32#[embassy_executor::main] 20#[embassy_executor::main]
@@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
50} 38}
51 39
52#[embassy_executor::task] 40#[embassy_executor::task]
53async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { 41async fn reader(mut rx: UartRx<'static, UART7, Async>) {
54 let mut buf = [0; 8]; 42 let mut buf = [0; 8];
55 loop { 43 loop {
56 info!("reading..."); 44 info!("reading...");
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index f23a537b8..8e0cfdedb 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs
index 8be686c5a..eabf1bac2 100644
--- a/examples/stm32l1/src/bin/spi.rs
+++ b/examples/stm32l1/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index f553deb82..2861bc091 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -3,33 +3,17 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c; 6use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const ADDRESS: u8 = 0x5F; 10const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new( 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
24 p.I2C2,
25 p.PB10,
26 p.PB11,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33 17
34 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index 1b8652bcc..a014b23e0 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -4,34 +4,18 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::I2c; 7use embassy_stm32::i2c::I2c;
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_stm32::{bind_interrupts, i2c, peripherals};
11use embedded_hal_async::i2c::I2c as I2cTrait; 9use embedded_hal_async::i2c::I2c as I2cTrait;
12use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
13 11
14const ADDRESS: u8 = 0x5F; 12const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
16 14
17bind_interrupts!(struct Irqs {
18 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
19 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
20});
21
22#[embassy_executor::main] 15#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
24 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
25 let i2c = I2c::new( 18 let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 NoDma,
31 NoDma,
32 Hertz(100_000),
33 Default::default(),
34 );
35 let mut i2c = BlockingAsync::new(i2c); 19 let mut i2c = BlockingAsync::new(i2c);
36 20
37 let mut data = [0u8; 1]; 21 let mut data = [0u8; 1];
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 77aa929ab..694629ede 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
23use embassy_futures::yield_now; 23use embassy_futures::yield_now;
24use embassy_net::tcp::TcpSocket; 24use embassy_net::tcp::TcpSocket;
25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; 25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
26use embassy_net_adin1110::{Device, Runner, ADIN1110};
27use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
26use embassy_time::{Delay, Duration, Ticker, Timer}; 34use embassy_time::{Delay, Duration, Ticker, Timer};
27use embedded_hal_async::i2c::I2c as I2cBus; 35use embedded_hal_async::i2c::I2c as I2cBus;
36use embedded_hal_bus::spi::ExclusiveDevice;
28use embedded_io::Write as bWrite; 37use embedded_io::Write as bWrite;
29use embedded_io_async::Write; 38use embedded_io_async::Write;
30use hal::gpio::{Input, Level, Output, Speed};
31use hal::i2c::{self, I2c};
32use hal::rng::{self, Rng};
33use hal::{bind_interrupts, exti, pac, peripherals};
34use heapless::Vec; 39use heapless::Vec;
40use panic_probe as _;
35use rand::RngCore; 41use rand::RngCore;
36use static_cell::StaticCell; 42use static_cell::StaticCell;
37use {embassy_stm32 as hal, panic_probe as _};
38 43
39bind_interrupts!(struct Irqs { 44bind_interrupts!(struct Irqs {
40 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; 45 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
@@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
42 RNG => rng::InterruptHandler<peripherals::RNG>; 47 RNG => rng::InterruptHandler<peripherals::RNG>;
43}); 48});
44 49
45use embassy_net_adin1110::{Device, Runner, ADIN1110};
46use embedded_hal_bus::spi::ExclusiveDevice;
47use hal::gpio::Pull;
48use hal::i2c::Config as I2C_Config;
49use hal::spi::{Config as SPI_Config, Spi};
50use hal::time::Hertz;
51
52// Basic settings 50// Basic settings
53// MAC-address used by the adin1110 51// MAC-address used by the adin1110
54const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; 52const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
@@ -57,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
57// Listen port for the webserver 55// Listen port for the webserver
58const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
59 57
60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; 58pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>;
61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
62pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
63pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
64pub type Adin1110T = ADIN1110<SpeSpiCs>; 62pub type Adin1110T = ADIN1110<SpeSpiCs>;
65pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; 63pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>;
66 64
67static TEMP: AtomicI32 = AtomicI32::new(0); 65static TEMP: AtomicI32 = AtomicI32::new(0);
68 66
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 6653e4516..5693a3765 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::gpio::{Level, Output, Speed}; 5use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::spi::{Config, Spi}; 6use embassy_stm32::spi::{Config, Spi};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ fn main() -> ! {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
21 20
22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
index 68dbb70ad..1f1089101 100644
--- a/examples/stm32l4/src/bin/spi_blocking_async.rs
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 7use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::spi::{Config, Spi}; 8use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
19 let mut spi_config = Config::default(); 18 let mut spi_config = Config::default();
20 spi_config.frequency = Hertz(1_000_000); 19 spi_config.frequency = Hertz(1_000_000);
21 20
22 let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 21 let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
23 22
24 let mut spi = BlockingAsync::new(spi); 23 let mut spi = BlockingAsync::new(spi);
25 24
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 7bab23950..d9b388026 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::usart::{Config, Uart}; 5use embassy_stm32::usart::{Config, Uart};
7use embassy_stm32::{bind_interrupts, peripherals, usart}; 6use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
19 18
20 let config = Config::default(); 19 let config = Config::default();
21 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); 20 let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap();
22 21
23 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
24 info!("wrote Hello, starting echo"); 23 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 031888f70..b4f7a1643 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -5,7 +5,6 @@ use core::fmt::Write;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart}; 9use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 10use heapless::String;
@@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 20 info!("Hello World!");
22 21
23 let config = Config::default(); 22 let config = Config::default();
24 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); 23 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap();
25 24
26 for n in 0u32.. { 25 for n in 0u32.. {
27 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml
index 28b8af96e..688347084 100644
--- a/examples/stm32u0/.cargo/config.toml
+++ b/examples/stm32u0/.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# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` 2# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32u083rctx" 3runner = "probe-rs run --chip stm32u083rctx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
index 8219cb038..64fd837a2 100644
--- a/examples/stm32u0/Cargo.toml
+++ b/examples/stm32u0/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 03294339d..01320b88d 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -24,5 +24,9 @@ heapless = { version = "0.8", default-features = false }
24 24
25micromath = "2.0.0" 25micromath = "2.0.0"
26 26
27[features]
28## Use secure registers when TrustZone is enabled
29trustzone-secure = ["embassy-stm32/trustzone-secure"]
30
27[profile.release] 31[profile.release]
28debug = 2 32debug = 2
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
index e376c6bc8..19a78eac9 100644
--- a/examples/stm32u5/src/bin/i2c.rs
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -3,33 +3,17 @@
3 3
4use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c; 6use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
11 9
12const HTS221_ADDRESS: u8 = 0x5F; 10const HTS221_ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 11const WHOAMI: u8 = 0x0F;
14 12
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main] 13#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new( 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default());
24 p.I2C2,
25 p.PH4,
26 p.PH5,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33 17
34 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index 98696fd2b..ac160b995 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2024-03-20" 2channel = "nightly-2024-04-14"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index b0bdd477f..59cb0cfd3 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -6,7 +6,6 @@ mod common;
6use common::*; 6use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::spi::{self, Spi}; 9use embassy_stm32::spi::{self, Spi};
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
12 11
@@ -23,11 +22,11 @@ async fn main(_spawner: Spawner) {
23 let mut spi_config = spi::Config::default(); 22 let mut spi_config = spi::Config::default();
24 spi_config.frequency = Hertz(1_000_000); 23 spi_config.frequency = Hertz(1_000_000);
25 24
26 let mut spi = Spi::new( 25 let mut spi = Spi::new_blocking(
27 spi, sck, // Arduino D13 26 spi, sck, // Arduino D13
28 mosi, // Arduino D11 27 mosi, // Arduino D11
29 miso, // Arduino D12 28 miso, // Arduino D12
30 NoDma, NoDma, spi_config, 29 spi_config,
31 ); 30 );
32 31
33 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 32 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 9b20eb784..a6e34674d 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -6,7 +6,6 @@ mod common;
6use common::*; 6use common::*;
7use defmt::{assert, assert_eq, unreachable}; 7use defmt::{assert, assert_eq, unreachable};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; 9use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
11use embassy_time::{block_for, Duration, Instant}; 10use embassy_time::{block_for, Duration, Instant};
12 11
@@ -20,11 +19,10 @@ async fn main(_spawner: Spawner) {
20 let mut usart = peri!(p, UART); 19 let mut usart = peri!(p, UART);
21 let mut rx = peri!(p, UART_RX); 20 let mut rx = peri!(p, UART_RX);
22 let mut tx = peri!(p, UART_TX); 21 let mut tx = peri!(p, UART_TX);
23 let irq = irqs!(UART);
24 22
25 { 23 {
26 let config = Config::default(); 24 let config = Config::default();
27 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); 25 let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
28 26
29 // We can't send too many bytes, they have to fit in the FIFO. 27 // We can't send too many bytes, they have to fit in the FIFO.
30 // This is because we aren't sending+receiving at the same time. 28 // This is because we aren't sending+receiving at the same time.
@@ -40,7 +38,7 @@ async fn main(_spawner: Spawner) {
40 // Test error handling with with an overflow error 38 // Test error handling with with an overflow error
41 { 39 {
42 let config = Config::default(); 40 let config = Config::default();
43 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); 41 let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
44 42
45 // Send enough bytes to fill the RX FIFOs off all USART versions. 43 // Send enough bytes to fill the RX FIFOs off all USART versions.
46 let data = [0; 64]; 44 let data = [0; 64];
@@ -70,7 +68,7 @@ async fn main(_spawner: Spawner) {
70 68
71 let mut config = Config::default(); 69 let mut config = Config::default();
72 config.baudrate = baudrate; 70 config.baudrate = baudrate;
73 let mut usart = match Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config) { 71 let mut usart = match Uart::new_blocking(&mut usart, &mut rx, &mut tx, config) {
74 Ok(x) => x, 72 Ok(x) => x,
75 Err(ConfigError::BaudrateTooHigh) => { 73 Err(ConfigError::BaudrateTooHigh) => {
76 info!("baudrate too high"); 74 info!("baudrate too high");
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index 0c110421d..908452eaf 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -8,6 +8,7 @@ mod common;
8use common::*; 8use common::*;
9use defmt::{assert_eq, panic}; 9use defmt::{assert_eq, panic};
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_stm32::mode::Async;
11use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; 12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
12use embassy_time::Timer; 13use embassy_time::Timer;
13use rand_chacha::ChaCha8Rng; 14use rand_chacha::ChaCha8Rng;
@@ -51,7 +52,7 @@ async fn main(spawner: Spawner) {
51} 52}
52 53
53#[embassy_executor::task] 54#[embassy_executor::task]
54async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) { 55async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
55 // workaround https://github.com/embassy-rs/embassy/issues/1426 56 // workaround https://github.com/embassy-rs/embassy/issues/1426
56 Timer::after_millis(100).await; 57 Timer::after_millis(100).await;
57 58