diff options
| author | Dion Dokter <[email protected]> | 2024-04-16 13:48:18 +0200 |
|---|---|---|
| committer | Dion Dokter <[email protected]> | 2024-04-16 13:48:18 +0200 |
| commit | c8c7c718f39d441492aa37d1404851d08a708098 (patch) | |
| tree | c98b52116524cf39d06c229c6c0857a98ab4262b | |
| parent | e224e6cef4e0508f14bb9ffd1d9d0fc9220c07d8 (diff) | |
| parent | e38f1011d6234fbc51fbbbb2d93365517705e3ac (diff) | |
Merge branch 'master' into u0-dion
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 | ||
| 12 | MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml | 12 | MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml |
| 13 | MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly | 13 | MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly |
| 14 | MIRIFLAGS=-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 | |||
| 8 | export CARGO_HOME=/ci/cache/cargo | 8 | export CARGO_HOME=/ci/cache/cargo |
| 9 | export CARGO_TARGET_DIR=/ci/cache/target | 9 | export CARGO_TARGET_DIR=/ci/cache/target |
| 10 | 10 | ||
| 11 | cargo test --manifest-path ./embassy-futures/Cargo.toml | ||
| 11 | cargo test --manifest-path ./embassy-sync/Cargo.toml | 12 | cargo test --manifest-path ./embassy-sync/Cargo.toml |
| 12 | cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml | 13 | cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml |
| 13 | cargo test --manifest-path ./embassy-hal-internal/Cargo.toml | 14 | cargo 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. |
| @@ -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. |
| 254 | rm out/tests/stm32u5a5zj/usart | 254 | rm out/tests/stm32u5a5zj/usart |
| 255 | 255 | ||
| 256 | # flaky, perhaps bad wire | ||
| 257 | rm out/tests/stm32l152re/usart_rx_ringbuffered | ||
| 258 | |||
| 256 | if [[ -z "${TELEPROBE_TOKEN-}" ]]; then | 259 | if [[ -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 | |||
| 3 | All notable changes to this project will be documented in this file. | ||
| 4 | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| 6 | and 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/) |
| 116 | memory-x = ["stm32-metapac/memory-x"] | 116 | memory-x = ["stm32-metapac/memory-x"] |
| 117 | 117 | ||
| 118 | ## Use secure registers when TrustZone is enabled | ||
| 119 | trustzone-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)] |
| 17 | pub use dmamux::*; | 17 | pub use dmamux::*; |
| 18 | 18 | ||
| 19 | mod util; | ||
| 20 | pub(crate) use util::*; | ||
| 21 | |||
| 19 | pub(crate) mod ringbuffer; | 22 | pub(crate) mod ringbuffer; |
| 20 | pub mod word; | 23 | pub 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 @@ | |||
| 1 | use embassy_hal_internal::PeripheralRef; | ||
| 2 | |||
| 3 | use super::word::Word; | ||
| 4 | use 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. | ||
| 9 | pub(crate) struct ChannelAndRequest<'d> { | ||
| 10 | pub channel: PeripheralRef<'d, AnyChannel>, | ||
| 11 | pub request: Request, | ||
| 12 | } | ||
| 13 | |||
| 14 | impl<'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. | ||
| 121 | pub 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! | ||
| 135 | pub 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 | |||
| 114 | fn sr_busy(sr: Nssr) -> bool { | 158 | fn 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 | ||
| 16 | pub(crate) unsafe fn lock() { | 16 | pub(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 | ||
| 20 | pub(crate) unsafe fn unlock() { | 23 | pub(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 | ||
| 27 | pub(crate) unsafe fn enable_blocking_write() { | 36 | pub(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 | ||
| 35 | pub(crate) unsafe fn disable_blocking_write() { | 49 | pub(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 | ||
| 39 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 56 | pub(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 | ||
| 52 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 69 | pub(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 | |||
| 70 | pub(crate) unsafe fn clear_all_err() { | 103 | pub(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 | ||
| 76 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 112 | unsafe 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")] |
| 15 | use embassy_time::{Duration, Instant}; | 15 | use embassy_time::{Duration, Instant}; |
| 16 | 16 | ||
| 17 | use crate::dma::NoDma; | 17 | use crate::dma::ChannelAndRequest; |
| 18 | use crate::gpio::{AFType, Pull}; | 18 | use crate::gpio::{AFType, Pull}; |
| 19 | use crate::interrupt::typelevel::Interrupt; | 19 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::mode::{Async, Blocking, Mode}; | ||
| 20 | use crate::time::Hertz; | 21 | use crate::time::Hertz; |
| 21 | use crate::{interrupt, peripherals}; | 22 | use crate::{interrupt, peripherals}; |
| 22 | 23 | ||
| @@ -71,17 +72,16 @@ impl Default for Config { | |||
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | /// I2C driver. | 74 | /// I2C driver. |
| 74 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | 75 | pub 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 | ||
| 84 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 84 | impl<'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 | |||
| 102 | impl<'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 | |||
| 115 | impl<'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 | ||
| 252 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | 281 | impl<'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 | ||
| 260 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { | 289 | impl<'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 | ||
| 268 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { | 297 | impl<'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 | ||
| 292 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> { | 321 | impl<'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 | ||
| 296 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { | 325 | impl<'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 | ||
| 318 | impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { | 347 | impl<'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; | |||
| 13 | use embedded_hal_1::i2c::Operation; | 13 | use embedded_hal_1::i2c::Operation; |
| 14 | 14 | ||
| 15 | use super::*; | 15 | use super::*; |
| 16 | use crate::dma::Transfer; | 16 | use crate::mode::Mode as PeriMode; |
| 17 | use crate::pac::i2c; | 17 | use crate::pac::i2c; |
| 18 | 18 | ||
| 19 | // /!\ /!\ | 19 | // /!\ /!\ |
| @@ -41,7 +41,7 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 41 | }); | 41 | }); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 44 | impl<'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> | 331 | impl<'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 | ||
| 703 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | 681 | impl<'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 | ||
| 809 | impl<'d, T: Instance> SetConfig for I2c<'d, T> { | 787 | impl<'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; | |||
| 7 | use embedded_hal_1::i2c::Operation; | 7 | use embedded_hal_1::i2c::Operation; |
| 8 | 8 | ||
| 9 | use super::*; | 9 | use super::*; |
| 10 | use crate::dma::Transfer; | ||
| 11 | use crate::pac::i2c; | 10 | use crate::pac::i2c; |
| 12 | 11 | ||
| 13 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 12 | pub(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 | ||
| 27 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 26 | impl<'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 | |||
| 416 | impl<'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 | ||
| 687 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | 661 | impl<'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 | ||
| 817 | impl<'d, T: Instance> SetConfig for I2c<'d, T> { | 791 | impl<'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 @@ | |||
| 2 | use embassy_hal_internal::into_ref; | 2 | use embassy_hal_internal::into_ref; |
| 3 | 3 | ||
| 4 | use crate::gpio::{AFType, AnyPin, SealedPin}; | 4 | use crate::gpio::{AFType, AnyPin, SealedPin}; |
| 5 | use crate::mode::Async; | ||
| 5 | use crate::pac::spi::vals; | 6 | use crate::pac::spi::vals; |
| 6 | use crate::spi::{Config as SpiConfig, *}; | 7 | use crate::spi::{Config as SpiConfig, *}; |
| 7 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| @@ -152,15 +153,15 @@ impl Default for Config { | |||
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | /// I2S driver. | 155 | /// I2S driver. |
| 155 | pub struct I2S<'d, T: Instance, Tx, Rx> { | 156 | pub 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 | ||
| 163 | impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | 164 | impl<'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 | ||
| 285 | impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { | 279 | impl<'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; | |||
| 15 | include!(concat!(env!("OUT_DIR"), "/_macros.rs")); | 15 | include!(concat!(env!("OUT_DIR"), "/_macros.rs")); |
| 16 | 16 | ||
| 17 | // Utilities | 17 | // Utilities |
| 18 | mod macros; | ||
| 18 | pub mod time; | 19 | pub mod time; |
| 19 | mod traits; | 20 | /// Operating modes for peripherals. |
| 21 | pub 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 |
| 22 | pub mod dma; | 45 | pub 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 | |||
| 73 | macro_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 | |||
| 84 | macro_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 { | |||
| 119 | pub fn frequency<T: RccPeripheral>() -> Hertz { | 119 | pub 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. | ||
| 128 | pub 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. | ||
| 137 | pub 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 | ||
| 4 | use core::marker::PhantomData; | ||
| 4 | use core::ptr; | 5 | use core::ptr; |
| 5 | 6 | ||
| 6 | use embassy_embedded_hal::SetConfig; | 7 | use embassy_embedded_hal::SetConfig; |
| @@ -8,8 +9,9 @@ use embassy_futures::join::join; | |||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 10 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 10 | 11 | ||
| 11 | use crate::dma::{slice_ptr_parts, word, Transfer}; | 12 | use crate::dma::{slice_ptr_parts, word, ChannelAndRequest}; |
| 12 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; | 13 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; |
| 14 | use crate::mode::{Async, Blocking, Mode as PeriMode}; | ||
| 13 | use crate::pac::spi::{regs, vals, Spi as Regs}; | 15 | use crate::pac::spi::{regs, vals, Spi as Regs}; |
| 14 | use crate::rcc::RccPeripheral; | 16 | use crate::rcc::RccPeripheral; |
| 15 | use crate::time::Hertz; | 17 | use 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. |
| 87 | pub struct Spi<'d, T: Instance, Tx, Rx> { | 95 | pub 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 | ||
| 97 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | 106 | impl<'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 | |||
| 399 | impl<'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 | |||
| 475 | impl<'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 | ||
| 685 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | 726 | impl<'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> { | |||
| 819 | fn flush_rx_fifo(regs: Regs) { | 860 | fn 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 |
| 901 | macro_rules! impl_blocking { | 942 | macro_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 { | |||
| 922 | impl_blocking!(u8); | 963 | impl_blocking!(u8); |
| 923 | impl_blocking!(u16); | 964 | impl_blocking!(u16); |
| 924 | 965 | ||
| 925 | impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> { | 966 | impl<'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 | ||
| 929 | impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { | 970 | impl<'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 | ||
| 962 | impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { | 1003 | impl<'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 | ||
| 1097 | impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { | 1138 | impl<'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}; | |||
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | use futures::future::{select, Either}; | 14 | use futures::future::{select, Either}; |
| 15 | 15 | ||
| 16 | use crate::dma::{NoDma, Transfer}; | 16 | use crate::dma::ChannelAndRequest; |
| 17 | use crate::gpio::AFType; | 17 | use crate::gpio::{AFType, AnyPin, SealedPin}; |
| 18 | use crate::interrupt::typelevel::Interrupt; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use 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)))] |
| 21 | use crate::pac::usart::regs::Isr as Sr; | 22 | use 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 | |||
| 171 | impl 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 | ||
| 167 | impl Default for Config { | 188 | impl 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`. |
| 220 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 242 | pub 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 | ||
| 225 | impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { | 247 | impl<'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. |
| 239 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | 261 | pub 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 | ||
| 244 | impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { | 269 | impl<'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). |
| 282 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 307 | pub 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 | ||
| 290 | impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { | 317 | impl<'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 | ||
| 299 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | 326 | impl<'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( | 374 | impl<'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); | 403 | impl<'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 | ||
| 394 | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | 454 | impl<'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 | ||
| 758 | impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { | 695 | impl<'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 | |||
| 724 | impl<'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 | |||
| 836 | impl<'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 | ||
| 764 | impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { | 845 | impl<'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 | ||
| 770 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | 853 | impl<'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)); | 1013 | impl<'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 | ||
| 1143 | impl<'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 | ||
| 1188 | impl<'d, T: BasicInstance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> { | 1394 | impl<'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 | ||
| 1195 | impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> { | 1401 | impl<'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 | ||
| 1205 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> { | 1411 | impl<'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 | ||
| 1212 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> { | 1418 | impl<'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 | ||
| 1234 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { | 1440 | impl<'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 | ||
| 1238 | impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> { | 1444 | impl<'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 | ||
| 1242 | impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> { | 1448 | impl<'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 | ||
| 1246 | impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::Read for UartRx<'d, T, RxDma> { | 1452 | impl<'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 | ||
| 1252 | impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { | 1458 | impl<'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 | ||
| 1262 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Read for Uart<'d, T, TxDma, RxDma> { | 1468 | impl<'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 | ||
| 1268 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { | 1474 | impl<'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 | ||
| 1284 | impl<T, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> | 1490 | impl<T, M: Mode> embedded_io::ErrorType for Uart<'_, T, M> |
| 1285 | where | 1491 | where |
| 1286 | T: BasicInstance, | 1492 | T: BasicInstance, |
| 1287 | { | 1493 | { |
| 1288 | type Error = Error; | 1494 | type Error = Error; |
| 1289 | } | 1495 | } |
| 1290 | 1496 | ||
| 1291 | impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma> | 1497 | impl<T, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M> |
| 1292 | where | 1498 | where |
| 1293 | T: BasicInstance, | 1499 | T: BasicInstance, |
| 1294 | { | 1500 | { |
| 1295 | type Error = Error; | 1501 | type Error = Error; |
| 1296 | } | 1502 | } |
| 1297 | 1503 | ||
| 1298 | impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma> | 1504 | impl<T, M: Mode> embedded_io::Write for Uart<'_, T, M> |
| 1299 | where | 1505 | where |
| 1300 | T: BasicInstance, | 1506 | T: BasicInstance, |
| 1301 | { | 1507 | { |
| @@ -1309,7 +1515,7 @@ where | |||
| 1309 | } | 1515 | } |
| 1310 | } | 1516 | } |
| 1311 | 1517 | ||
| 1312 | impl<T, TxDma> embedded_io::Write for UartTx<'_, T, TxDma> | 1518 | impl<T, M: Mode> embedded_io::Write for UartTx<'_, T, M> |
| 1313 | where | 1519 | where |
| 1314 | T: BasicInstance, | 1520 | T: BasicInstance, |
| 1315 | { | 1521 | { |
| @@ -1323,10 +1529,9 @@ where | |||
| 1323 | } | 1529 | } |
| 1324 | } | 1530 | } |
| 1325 | 1531 | ||
| 1326 | impl<T, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> | 1532 | impl<T> embedded_io_async::Write for Uart<'_, T, Async> |
| 1327 | where | 1533 | where |
| 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 | ||
| 1341 | impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma> | 1546 | impl<T> embedded_io_async::Write for UartTx<'_, T, Async> |
| 1342 | where | 1547 | where |
| 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 @@ | |||
| 1 | use core::future::poll_fn; | 1 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | ||
| 2 | use core::mem; | 3 | use core::mem; |
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 5 | use core::task::Poll; |
| 5 | 6 | ||
| 6 | use embassy_embedded_hal::SetConfig; | 7 | use embassy_embedded_hal::SetConfig; |
| 7 | use embassy_hal_internal::PeripheralRef; | ||
| 8 | use futures::future::{select, Either}; | 8 | use futures::future::{select, Either}; |
| 9 | 9 | ||
| 10 | use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; | 10 | use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; |
| 11 | use crate::dma::ReadableRingBuffer; | 11 | use crate::dma::ReadableRingBuffer; |
| 12 | use crate::mode::Async; | ||
| 12 | use crate::usart::{Regs, Sr}; | 13 | use 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] |
| 17 | pub struct RingBufferedUartRx<'d, T: BasicInstance> { | 18 | pub 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 | ||
| 31 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | 32 | impl<'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. |
| 4 | use core::cell::{RefCell, UnsafeCell}; | 4 | use core::cell::{RefCell, UnsafeCell}; |
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::mem; | ||
| 6 | use core::ops::{Deref, DerefMut}; | 7 | use core::ops::{Deref, DerefMut}; |
| 7 | use core::task::Poll; | 8 | use 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] | ||
| 137 | pub struct MutexGuard<'a, M, T> | 139 | pub struct MutexGuard<'a, M, T> |
| 138 | where | 140 | where |
| 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 | ||
| 147 | impl<'a, M, T> MutexGuard<'a, M, T> | ||
| 148 | where | ||
| 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 | |||
| 145 | impl<'a, M, T> Drop for MutexGuard<'a, M, T> | 166 | impl<'a, M, T> Drop for MutexGuard<'a, M, T> |
| 146 | where | 167 | where |
| 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] | ||
| 210 | pub struct MappedMutexGuard<'a, M, T> | ||
| 211 | where | ||
| 212 | M: RawMutex, | ||
| 213 | T: ?Sized, | ||
| 214 | { | ||
| 215 | state: &'a BlockingMutex<M, RefCell<State>>, | ||
| 216 | value: *mut T, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl<'a, M, T> MappedMutexGuard<'a, M, T> | ||
| 220 | where | ||
| 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 | |||
| 235 | impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T> | ||
| 236 | where | ||
| 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 | |||
| 248 | impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T> | ||
| 249 | where | ||
| 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 | |||
| 260 | impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T> | ||
| 261 | where | ||
| 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 | |||
| 274 | unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T> | ||
| 275 | where | ||
| 276 | M: RawMutex + Sync, | ||
| 277 | T: Send + ?Sized, | ||
| 278 | { | ||
| 279 | } | ||
| 280 | |||
| 281 | unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T> | ||
| 282 | where | ||
| 283 | M: RawMutex + Sync, | ||
| 284 | T: Sync + ?Sized, | ||
| 285 | { | ||
| 286 | } | ||
| 287 | |||
| 288 | #[cfg(test)] | ||
| 289 | mod 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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c}; | 6 | use embassy_stm32::i2c::{Error, I2c}; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 9 | ||
| 12 | const ADDRESS: u8 = 0x5F; | 10 | const ADDRESS: u8 = 0x5F; |
| 13 | const WHOAMI: u8 = 0x0F; | 11 | const WHOAMI: u8 = 0x0F; |
| 14 | 12 | ||
| 15 | bind_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] |
| 21 | async fn main(_spawner: Spawner) { | 14 | async 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 | ||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use 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 | ||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 6 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use 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 | ||
| 16 | use embassy_stm32::spi; | ||
| 16 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 17 | use embassy_stm32::{dma, spi}; | ||
| 18 | use embassy_time::{Duration, Ticker, Timer}; | 18 | use embassy_time::{Duration, Ticker, Timer}; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use heapless::String; |
| @@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs { | |||
| 19 | async fn main(_spawner: Spawner) { | 18 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::word::U5; | 6 | use embassy_stm32::dma::word::U5; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_time::Timer; | 9 | use 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 @@ | |||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Executor; | 6 | use embassy_executor::Executor; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 7 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 10 | use static_cell::StaticCell; | 8 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 10 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::task] | 11 | #[embassy_executor::task] |
| 18 | async fn main_task() { | 12 | async 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; | |||
| 6 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Executor; | 8 | use embassy_executor::Executor; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 12 | use heapless::String; | 11 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::mode::Async; |
| 7 | use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; | 7 | use embassy_stm32::peripherals::UART7; |
| 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 10 | use 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] | ||
| 19 | async 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 | |||
| 30 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 18 | static 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] |
| 53 | async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { | 41 | async 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; | |||
| 7 | use cortex_m_rt::entry; | 7 | use cortex_m_rt::entry; |
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::dma::NoDma; | 10 | use embassy_stm32::mode::Blocking; |
| 11 | use embassy_stm32::peripherals::SPI3; | 11 | use embassy_stm32::peripherals::SPI3; |
| 12 | use embassy_stm32::time::mhz; | 12 | use embassy_stm32::time::mhz; |
| 13 | use embassy_stm32::{spi, Config}; | 13 | use embassy_stm32::{spi, Config}; |
| @@ -16,7 +16,7 @@ use static_cell::StaticCell; | |||
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 17 | ||
| 18 | #[embassy_executor::task] | 18 | #[embassy_executor::task] |
| 19 | async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { | 19 | async 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; | |||
| 7 | use cortex_m_rt::entry; | 7 | use cortex_m_rt::entry; |
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; | 10 | use embassy_stm32::mode::Async; |
| 11 | use embassy_stm32::time::mhz; | 11 | use embassy_stm32::time::mhz; |
| 12 | use embassy_stm32::{spi, Config}; | 12 | use embassy_stm32::{peripherals, spi, Config}; |
| 13 | use heapless::String; | 13 | use heapless::String; |
| 14 | use static_cell::StaticCell; | 14 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { | 18 | async 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 @@ | |||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Executor; | 6 | use embassy_executor::Executor; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 7 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 10 | use static_cell::StaticCell; | 8 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 10 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::task] | 11 | #[embassy_executor::task] |
| 18 | async fn main_task() { | 12 | async 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; | |||
| 6 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Executor; | 8 | use embassy_executor::Executor; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 12 | use heapless::String; | 11 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::mode::Async; |
| 7 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | 7 | use embassy_stm32::peripherals::UART7; |
| 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 10 | use 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] | ||
| 19 | async 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 | |||
| 30 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 18 | static 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] |
| 53 | async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { | 41 | async 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::i2c::I2c; | 6 | use embassy_stm32::i2c::I2c; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 9 | ||
| 12 | const ADDRESS: u8 = 0x5F; | 10 | const ADDRESS: u8 = 0x5F; |
| 13 | const WHOAMI: u8 = 0x0F; | 11 | const WHOAMI: u8 = 0x0F; |
| 14 | 12 | ||
| 15 | bind_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] |
| 21 | async fn main(_spawner: Spawner) { | 14 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_embedded_hal::adapter::BlockingAsync; | 5 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::i2c::I2c; | 7 | use embassy_stm32::i2c::I2c; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 11 | use embedded_hal_async::i2c::I2c as I2cTrait; | 9 | use embedded_hal_async::i2c::I2c as I2cTrait; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 11 | ||
| 14 | const ADDRESS: u8 = 0x5F; | 12 | const ADDRESS: u8 = 0x5F; |
| 15 | const WHOAMI: u8 = 0x0F; | 13 | const WHOAMI: u8 = 0x0F; |
| 16 | 14 | ||
| 17 | bind_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] |
| 23 | async fn main(_spawner: Spawner) { | 16 | async 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}; | |||
| 23 | use embassy_futures::yield_now; | 23 | use embassy_futures::yield_now; |
| 24 | use embassy_net::tcp::TcpSocket; | 24 | use embassy_net::tcp::TcpSocket; |
| 25 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; | 25 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; |
| 26 | use embassy_net_adin1110::{Device, Runner, ADIN1110}; | ||
| 27 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | ||
| 28 | use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; | ||
| 29 | use embassy_stm32::mode::Async; | ||
| 30 | use embassy_stm32::rng::{self, Rng}; | ||
| 31 | use embassy_stm32::spi::{Config as SPI_Config, Spi}; | ||
| 32 | use embassy_stm32::time::Hertz; | ||
| 33 | use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; | ||
| 26 | use embassy_time::{Delay, Duration, Ticker, Timer}; | 34 | use embassy_time::{Delay, Duration, Ticker, Timer}; |
| 27 | use embedded_hal_async::i2c::I2c as I2cBus; | 35 | use embedded_hal_async::i2c::I2c as I2cBus; |
| 36 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 28 | use embedded_io::Write as bWrite; | 37 | use embedded_io::Write as bWrite; |
| 29 | use embedded_io_async::Write; | 38 | use embedded_io_async::Write; |
| 30 | use hal::gpio::{Input, Level, Output, Speed}; | ||
| 31 | use hal::i2c::{self, I2c}; | ||
| 32 | use hal::rng::{self, Rng}; | ||
| 33 | use hal::{bind_interrupts, exti, pac, peripherals}; | ||
| 34 | use heapless::Vec; | 39 | use heapless::Vec; |
| 40 | use panic_probe as _; | ||
| 35 | use rand::RngCore; | 41 | use rand::RngCore; |
| 36 | use static_cell::StaticCell; | 42 | use static_cell::StaticCell; |
| 37 | use {embassy_stm32 as hal, panic_probe as _}; | ||
| 38 | 43 | ||
| 39 | bind_interrupts!(struct Irqs { | 44 | bind_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 | ||
| 45 | use embassy_net_adin1110::{Device, Runner, ADIN1110}; | ||
| 46 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 47 | use hal::gpio::Pull; | ||
| 48 | use hal::i2c::Config as I2C_Config; | ||
| 49 | use hal::spi::{Config as SPI_Config, Spi}; | ||
| 50 | use hal::time::Hertz; | ||
| 51 | |||
| 52 | // Basic settings | 50 | // Basic settings |
| 53 | // MAC-address used by the adin1110 | 51 | // MAC-address used by the adin1110 |
| 54 | const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; | 52 | const 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 |
| 58 | const HTTP_LISTEN_PORT: u16 = 80; | 56 | const HTTP_LISTEN_PORT: u16 = 80; |
| 59 | 57 | ||
| 60 | pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; | 58 | pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>; |
| 61 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; | 59 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; |
| 62 | pub type SpeInt = exti::ExtiInput<'static>; | 60 | pub type SpeInt = exti::ExtiInput<'static>; |
| 63 | pub type SpeRst = Output<'static>; | 61 | pub type SpeRst = Output<'static>; |
| 64 | pub type Adin1110T = ADIN1110<SpeSpiCs>; | 62 | pub type Adin1110T = ADIN1110<SpeSpiCs>; |
| 65 | pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; | 63 | pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>; |
| 66 | 64 | ||
| 67 | static TEMP: AtomicI32 = AtomicI32::new(0); | 65 | static 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::dma::NoDma; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | 5 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 7 | use embassy_stm32::spi::{Config, Spi}; | 6 | use embassy_stm32::spi::{Config, Spi}; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_embedded_hal::adapter::BlockingAsync; | 5 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | 7 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; |
| 9 | use embassy_stm32::spi::{Config, Spi}; | 8 | use embassy_stm32::spi::{Config, Spi}; |
| 10 | use embassy_stm32::time::Hertz; | 9 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::dma::NoDma; | ||
| 6 | use embassy_stm32::usart::{Config, Uart}; | 5 | use embassy_stm32::usart::{Config, Uart}; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 6 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 7 | use {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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use 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` |
| 3 | runner = "probe-rs run --chip STM32u083rctx" | 3 | runner = "probe-rs run --chip stm32u083rctx" |
| 4 | 4 | ||
| 5 | [build] | 5 | [build] |
| 6 | target = "thumbv6m-none-eabi" | 6 | target = "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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-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 | ||
| 25 | micromath = "2.0.0" | 25 | micromath = "2.0.0" |
| 26 | 26 | ||
| 27 | [features] | ||
| 28 | ## Use secure registers when TrustZone is enabled | ||
| 29 | trustzone-secure = ["embassy-stm32/trustzone-secure"] | ||
| 30 | |||
| 27 | [profile.release] | 31 | [profile.release] |
| 28 | debug = 2 | 32 | debug = 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 | ||
| 4 | use defmt::{info, unwrap}; | 4 | use defmt::{info, unwrap}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::i2c::I2c; | 6 | use embassy_stm32::i2c::I2c; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 9 | ||
| 12 | const HTS221_ADDRESS: u8 = 0x5F; | 10 | const HTS221_ADDRESS: u8 = 0x5F; |
| 13 | const WHOAMI: u8 = 0x0F; | 11 | const WHOAMI: u8 = 0x0F; |
| 14 | 12 | ||
| 15 | bind_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] |
| 21 | async fn main(_spawner: Spawner) { | 14 | async 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] |
| 2 | channel = "nightly-2024-03-20" | 2 | channel = "nightly-2024-04-14" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] |
| 4 | targets = [ | 4 | targets = [ |
| 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; | |||
| 6 | use common::*; | 6 | use common::*; |
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::spi::{self, Spi}; | 9 | use embassy_stm32::spi::{self, Spi}; |
| 11 | use embassy_stm32::time::Hertz; | 10 | use 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; | |||
| 6 | use common::*; | 6 | use common::*; |
| 7 | use defmt::{assert, assert_eq, unreachable}; | 7 | use defmt::{assert, assert_eq, unreachable}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; | 9 | use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; |
| 11 | use embassy_time::{block_for, Duration, Instant}; | 10 | use 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; | |||
| 8 | use common::*; | 8 | use common::*; |
| 9 | use defmt::{assert_eq, panic}; | 9 | use defmt::{assert_eq, panic}; |
| 10 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::mode::Async; | ||
| 11 | use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; | 12 | use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; |
| 12 | use embassy_time::Timer; | 13 | use embassy_time::Timer; |
| 13 | use rand_chacha::ChaCha8Rng; | 14 | use rand_chacha::ChaCha8Rng; |
| @@ -51,7 +52,7 @@ async fn main(spawner: Spawner) { | |||
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | #[embassy_executor::task] | 54 | #[embassy_executor::task] |
| 54 | async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) { | 55 | async 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 | ||
