aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authoreverdrone <[email protected]>2025-11-11 15:48:56 +0100
committereverdrone <[email protected]>2025-11-11 15:48:56 +0100
commitcede7216861a82b0db55f5a88afb3acf2ace6c4b (patch)
treed92fb578897c77f51317318c5b180931b7b25c63 /embassy-stm32
parentcf55b39f9a54cf3ed01f52c0565a36a444174235 (diff)
parent3d1f09597335d3681699ba09a77da4b39ed984fd (diff)
Merge branch main into n6
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/CHANGELOG.md37
-rw-r--r--embassy-stm32/Cargo.toml30
-rw-r--r--embassy-stm32/build.rs33
-rw-r--r--embassy-stm32/src/adc/adc4.rs27
-rw-r--r--embassy-stm32/src/adc/c0.rs56
-rw-r--r--embassy-stm32/src/adc/f1.rs39
-rw-r--r--embassy-stm32/src/adc/f3.rs46
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs7
-rw-r--r--embassy-stm32/src/adc/g4.rs514
-rw-r--r--embassy-stm32/src/adc/injected.rs44
-rw-r--r--embassy-stm32/src/adc/mod.rs73
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs182
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs432
-rw-r--r--embassy-stm32/src/adc/v1.rs59
-rw-r--r--embassy-stm32/src/adc/v2.rs226
-rw-r--r--embassy-stm32/src/adc/v3.rs306
-rw-r--r--embassy-stm32/src/adc/v4.rs91
-rw-r--r--embassy-stm32/src/adc/watchdog_v1.rs6
-rw-r--r--embassy-stm32/src/backup_sram.rs28
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs12
-rw-r--r--embassy-stm32/src/can/fd/config.rs15
-rw-r--r--embassy-stm32/src/can/fdcan.rs27
-rw-r--r--embassy-stm32/src/can/util.rs2
-rw-r--r--embassy-stm32/src/crc/v1.rs2
-rw-r--r--embassy-stm32/src/crc/v2v3.rs4
-rw-r--r--embassy-stm32/src/cryp/mod.rs10
-rw-r--r--embassy-stm32/src/dac/mod.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs2
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs4
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs2
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs4
-rw-r--r--embassy-stm32/src/dma/mod.rs2
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs2
-rw-r--r--embassy-stm32/src/dsihost.rs14
-rw-r--r--embassy-stm32/src/dts/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs8
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v1/tx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs6
-rw-r--r--embassy-stm32/src/exti.rs2
-rw-r--r--embassy-stm32/src/flash/asynch.rs8
-rw-r--r--embassy-stm32/src/flash/common.rs8
-rw-r--r--embassy-stm32/src/flash/eeprom.rs2
-rw-r--r--embassy-stm32/src/flash/f0.rs2
-rw-r--r--embassy-stm32/src/flash/f1f3.rs2
-rw-r--r--embassy-stm32/src/flash/f2.rs4
-rw-r--r--embassy-stm32/src/flash/f4.rs24
-rw-r--r--embassy-stm32/src/flash/f7.rs12
-rw-r--r--embassy-stm32/src/flash/g.rs18
-rw-r--r--embassy-stm32/src/flash/h5.rs2
-rw-r--r--embassy-stm32/src/flash/h50.rs2
-rw-r--r--embassy-stm32/src/flash/h7.rs4
-rw-r--r--embassy-stm32/src/flash/l.rs30
-rw-r--r--embassy-stm32/src/flash/u0.rs2
-rw-r--r--embassy-stm32/src/flash/u5.rs2
-rw-r--r--embassy-stm32/src/fmc.rs38
-rw-r--r--embassy-stm32/src/gpio.rs2
-rw-r--r--embassy-stm32/src/hash/mod.rs8
-rw-r--r--embassy-stm32/src/hrtim/mod.rs87
-rw-r--r--embassy-stm32/src/hsem/mod.rs4
-rw-r--r--embassy-stm32/src/hspi/mod.rs2
-rw-r--r--embassy-stm32/src/i2c/config.rs8
-rw-r--r--embassy-stm32/src/i2c/mod.rs106
-rw-r--r--embassy-stm32/src/i2c/v1.rs1088
-rw-r--r--embassy-stm32/src/i2c/v2.rs30
-rw-r--r--embassy-stm32/src/i2s.rs7
-rw-r--r--embassy-stm32/src/ipcc.rs2
-rw-r--r--embassy-stm32/src/lib.rs25
-rw-r--r--embassy-stm32/src/low_power.rs143
-rw-r--r--embassy-stm32/src/lptim/pwm.rs6
-rw-r--r--embassy-stm32/src/ltdc.rs2
-rw-r--r--embassy-stm32/src/opamp.rs2
-rw-r--r--embassy-stm32/src/ospi/mod.rs6
-rw-r--r--embassy-stm32/src/qspi/mod.rs2
-rw-r--r--embassy-stm32/src/rcc/bd.rs40
-rw-r--r--embassy-stm32/src/rcc/c0.rs14
-rw-r--r--embassy-stm32/src/rcc/f247.rs4
-rw-r--r--embassy-stm32/src/rcc/h.rs5
-rw-r--r--embassy-stm32/src/rcc/l.rs51
-rw-r--r--embassy-stm32/src/rcc/mco.rs27
-rw-r--r--embassy-stm32/src/rcc/mod.rs7
-rw-r--r--embassy-stm32/src/rcc/u5.rs9
-rw-r--r--embassy-stm32/src/rcc/wba.rs9
-rw-r--r--embassy-stm32/src/rng.rs2
-rw-r--r--embassy-stm32/src/rtc/low_power.rs53
-rw-r--r--embassy-stm32/src/rtc/mod.rs139
-rw-r--r--embassy-stm32/src/rtc/v2.rs10
-rw-r--r--embassy-stm32/src/rtc/v3.rs8
-rw-r--r--embassy-stm32/src/sai/mod.rs6
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs16
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs155
-rw-r--r--embassy-stm32/src/time_driver.rs84
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs18
-rw-r--r--embassy-stm32/src/timer/input_capture.rs2
-rw-r--r--embassy-stm32/src/timer/low_level.rs86
-rw-r--r--embassy-stm32/src/timer/mod.rs4
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs2
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs2
-rw-r--r--embassy-stm32/src/timer/qei.rs102
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs37
-rw-r--r--embassy-stm32/src/tsc/acquisition_banks.rs4
-rw-r--r--embassy-stm32/src/tsc/pin_groups.rs4
-rw-r--r--embassy-stm32/src/ucpd.rs4
-rw-r--r--embassy-stm32/src/uid.rs4
-rw-r--r--embassy-stm32/src/usart/buffered.rs73
-rw-r--r--embassy-stm32/src/usart/mod.rs77
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs158
-rw-r--r--embassy-stm32/src/usb/otg.rs10
-rw-r--r--embassy-stm32/src/usb/usb.rs4
-rw-r--r--embassy-stm32/src/vrefbuf/mod.rs11
-rw-r--r--embassy-stm32/src/wdg/mod.rs2
-rw-r--r--embassy-stm32/src/xspi/mod.rs6
114 files changed, 3752 insertions, 1553 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 190e68d6d..33c7b5da5 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -5,9 +5,14 @@ All notable changes to this project will be documented in this file.
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8<!-- next-header -->
9## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
10 9
10- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717))
11- feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840))
12- feat: Implement into_ring_buffered for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840))
13- feat: Add support for 13-bit address and 16-bit data SDRAM chips
14- feat: stm32/hrtim add new_chx_with_config to provide pin configuration
15- fix flash erase on L4 & L5
11- fix: Fixed STM32H5 builds requiring time feature 16- fix: Fixed STM32H5 builds requiring time feature
12- feat: Derive Clone, Copy for QSPI Config 17- feat: Derive Clone, Copy for QSPI Config
13- fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received 18- fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received
@@ -22,10 +27,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
22- fix: handle address and data-length errors in OSPI 27- fix: handle address and data-length errors in OSPI
23- feat: Allow OSPI DMA writes larger than 64kB using chunking 28- feat: Allow OSPI DMA writes larger than 64kB using chunking
24- feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times 29- feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times
30- feat: Add USB CRS sync support for STM32C071
31- fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map.
32- fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt.
33- fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode.
34- feat: stm32/rcc/mco: Added support for IO driver strength when using Master Clock Out IO. This changes signature on Mco::new taking a McoConfig struct ([#4679](https://github.com/embassy-rs/embassy/pull/4679))
35- feat: derive Clone, Copy and defmt::Format for all SPI-related configs
36- feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668))
37- feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options
38- change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer
39- fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696)
40- change: timer: added output compare values
41- feat: timer: add ability to set master mode
42- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723)
43- fix: usart: fix race condition in ringbuffered usart
44- feat: Add backup_sram::init() for H5 devices to access BKPSRAM
45- feat: Add I2C MultiMaster (Slave) support for I2C v1
46- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821))
47- low-power: update rtc api to allow reconfig
48- adc: consolidate ringbuffer
49- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716))
50- fix: Correct STM32WBA VREFBUFTRIM values
51- low_power: remove stop_with rtc and initialize in init if low-power feature enabled.
52- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847))
53- feat: stm32/spi: added support for slave mode ([#4388](https://github.com/embassy-rs/embassy/pull/4388))
54- chore: Updated stm32-metapac and stm32-data dependencies
55- adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion
56- fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written
25 57
26## 0.4.0 - 2025-08-26 58## 0.4.0 - 2025-08-26
27 59
28- feat: stm32/sai: make NODIV independent of MCKDIV 60- feat: stm32/sai: make NODIV independent of MCKDIV
29- fix: stm32/sai: fix WB MCKDIV 61- fix: stm32/sai: fix WB MCKDIV
30- fix: stm32/i2c: pull-down was enabled instead of pull-none when no internal pull-up was needed. 62- fix: stm32/i2c: pull-down was enabled instead of pull-none when no internal pull-up was needed.
31- feat: Improve blocking hash speed 63- feat: Improve blocking hash speed
@@ -34,6 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
34- chore: Updated stm32-metapac and stm32-data dependencies 66- chore: Updated stm32-metapac and stm32-data dependencies
35- feat: stm32/adc/v3: allow DMA reads to loop through enable channels 67- feat: stm32/adc/v3: allow DMA reads to loop through enable channels
36- fix: Fix XSPI not disabling alternate bytes when they were previously enabled 68- fix: Fix XSPI not disabling alternate bytes when they were previously enabled
69- feat: stm32/adc/v3: added support for Continuous DMA configuration
37- fix: Fix stm32h7rs init when using external flash via XSPI 70- fix: Fix stm32h7rs init when using external flash via XSPI
38- feat: Add Adc::new_with_clock() to configure analog clock 71- feat: Add Adc::new_with_clock() to configure analog clock
39- feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923)) 72- feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923))
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index fabfa8342..0a1854dab 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2name = "embassy-stm32" 2name = "embassy-stm32"
3version = "0.4.0" 3version = "0.4.0"
4edition = "2021" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" 6description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers"
7keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"] 7keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"]
@@ -66,6 +66,10 @@ build = [
66 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l431cb", "time", "time-driver-any"]}, 66 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l431cb", "time", "time-driver-any"]},
67 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l476vg", "time", "time-driver-any"]}, 67 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l476vg", "time", "time-driver-any"]},
68 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l422cb", "time", "time-driver-any"]}, 68 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l422cb", "time", "time-driver-any"]},
69 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4p5ae", "time", "time-driver-any", "single-bank"]},
70 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4q5zg", "time", "time-driver-any", "single-bank"]},
71 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4r9vi", "time", "time-driver-any", "dual-bank"]},
72 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4s7vi", "time", "time-driver-any", "dual-bank"]},
69 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb15cc", "time", "time-driver-any"]}, 73 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb15cc", "time", "time-driver-any"]},
70 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l072cz", "time", "time-driver-any"]}, 74 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l072cz", "time", "time-driver-any"]},
71 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l041f6", "time", "time-driver-any"]}, 75 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l041f6", "time", "time-driver-any"]},
@@ -174,11 +178,10 @@ cortex-m = "0.7.6"
174futures-util = { version = "0.3.30", default-features = false } 178futures-util = { version = "0.3.30", default-features = false }
175sdio-host = "0.9.0" 179sdio-host = "0.9.0"
176critical-section = "1.1" 180critical-section = "1.1"
177stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" }
178 181
179vcell = "0.1.3" 182vcell = "0.1.3"
180nb = "1.0.0" 183nb = "1.0.0"
181stm32-fmc = "0.3.0" 184stm32-fmc = "0.4.0"
182cfg-if = "1.0.0" 185cfg-if = "1.0.0"
183embedded-io = { version = "0.6.0" } 186embedded-io = { version = "0.6.0" }
184embedded-io-async = { version = "0.6.1" } 187embedded-io-async = { version = "0.6.1" }
@@ -194,16 +197,22 @@ block-device-driver = { version = "0.2" }
194aligned = "0.4.1" 197aligned = "0.4.1"
195heapless = "0.9.1" 198heapless = "0.9.1"
196 199
197[dev-dependencies] 200#stm32-metapac = { version = "18" }
198critical-section = { version = "1.1", features = ["std"] } 201stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e" }
199proptest = "1.5.0"
200proptest-state-machine = "0.3.0"
201 202
202[build-dependencies] 203[build-dependencies]
204#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
205stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e", default-features = false, features = ["metadata"] }
206
203proc-macro2 = "1.0.36" 207proc-macro2 = "1.0.36"
204quote = "1.0.15" 208quote = "1.0.15"
205 209
206stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } 210
211[dev-dependencies]
212critical-section = { version = "1.1", features = ["std"] }
213proptest = "1.5.0"
214proptest-state-machine = "0.3.0"
215
207 216
208[features] 217[features]
209default = ["rt"] 218default = ["rt"]
@@ -224,6 +233,10 @@ defmt = [
224 "embassy-usb-synopsys-otg/defmt", 233 "embassy-usb-synopsys-otg/defmt",
225 "stm32-metapac/defmt" 234 "stm32-metapac/defmt"
226] 235]
236## Use log for logging
237log = ["dep:log"]
238## Enable chrono support
239chrono = ["dep:chrono"]
227 240
228exti = [] 241exti = []
229low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 242low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ]
@@ -304,6 +317,7 @@ single-bank = []
304 317
305## internal use only 318## internal use only
306_split-pins-enabled = [] 319_split-pins-enabled = []
320_allow-disable-rtc = []
307 321
308## internal use only 322## internal use only
309_dual-core = [] 323_dual-core = []
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 861f3fcee..09a05ce68 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -9,8 +9,8 @@ use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
10use stm32_metapac::metadata::ir::BitOffset; 10use stm32_metapac::metadata::ir::BitOffset;
11use stm32_metapac::metadata::{ 11use stm32_metapac::metadata::{
12 MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, 12 ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock,
13 ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, 13 PeripheralRccRegister, PeripheralRegisters, StopMode,
14}; 14};
15 15
16#[path = "./build_common.rs"] 16#[path = "./build_common.rs"]
@@ -105,13 +105,17 @@ fn main() {
105 } 105 }
106 (false, false) => { 106 (false, false) => {
107 if METADATA.memory.len() != 1 { 107 if METADATA.memory.len() != 1 {
108 panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection") 108 panic!(
109 "Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection"
110 )
109 } 111 }
110 METADATA.memory[0] 112 METADATA.memory[0]
111 } 113 }
112 } 114 }
113 }; 115 };
114 116
117 let has_bkpsram = memory.iter().any(|m| m.name == "BKPSRAM");
118
115 // ======== 119 // ========
116 // Generate singletons 120 // Generate singletons
117 121
@@ -122,6 +126,13 @@ fn main() {
122 singletons.push(p.name.to_string()); 126 singletons.push(p.name.to_string());
123 } 127 }
124 128
129 cfgs.declare("backup_sram");
130
131 if has_bkpsram {
132 singletons.push("BKPSRAM".to_string());
133 cfgs.enable("backup_sram")
134 }
135
125 // generate one singleton per peripheral (with many exceptions...) 136 // generate one singleton per peripheral (with many exceptions...)
126 for p in METADATA.peripherals { 137 for p in METADATA.peripherals {
127 if let Some(r) = &p.registers { 138 if let Some(r) = &p.registers {
@@ -1995,6 +2006,18 @@ fn main() {
1995 )); 2006 ));
1996 2007
1997 // ======== 2008 // ========
2009 // Generate backup sram constants
2010 if let Some(m) = memory.iter().find(|m| m.name == "BKPSRAM") {
2011 let bkpsram_base = m.address as usize;
2012 let bkpsram_size = m.size as usize;
2013
2014 g.extend(quote!(
2015 pub const BKPSRAM_BASE: usize = #bkpsram_base;
2016 pub const BKPSRAM_SIZE: usize = #bkpsram_size;
2017 ));
2018 }
2019
2020 // ========
1998 // Generate flash constants 2021 // Generate flash constants
1999 2022
2000 if has_flash { 2023 if has_flash {
@@ -2323,6 +2346,10 @@ fn mem_filter(chip: &str, region: &str) -> bool {
2323 return false; 2346 return false;
2324 } 2347 }
2325 2348
2349 if region.starts_with("SDRAM_") || region.starts_with("FMC_") || region.starts_with("OCTOSPI_") {
2350 return false;
2351 }
2352
2326 true 2353 true
2327} 2354}
2328 2355
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 255dc7956..befa8ed4a 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,7 +4,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR
4#[cfg(stm32wba)] 4#[cfg(stm32wba)]
5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; 5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
6 6
7use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; 7use super::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us};
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
@@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S
15#[cfg(stm32wba)] 15#[cfg(stm32wba)]
16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; 16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19 19
20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
21 21
@@ -208,7 +208,10 @@ impl<'d, T: Instance> Adc4<'d, T> {
208 info!("ADC4 frequency set to {}", frequency); 208 info!("ADC4 frequency set to {}", frequency);
209 209
210 if frequency > MAX_ADC_CLK_FREQ { 210 if frequency > MAX_ADC_CLK_FREQ {
211 panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 211 panic!(
212 "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.",
213 MAX_ADC_CLK_FREQ.0 / 1_000_000
214 );
212 } 215 }
213 216
214 let mut s = Self { adc }; 217 let mut s = Self { adc };
@@ -324,18 +327,6 @@ impl<'d, T: Instance> Adc4<'d, T> {
324 Dac {} 327 Dac {}
325 } 328 }
326 329
327 /// Set the ADC sample time.
328 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
329 T::regs().smpr().modify(|w| {
330 w.set_smp(0, sample_time);
331 });
332 }
333
334 /// Get the ADC sample time.
335 pub fn sample_time(&self) -> SampleTime {
336 T::regs().smpr().read().smp(0)
337 }
338
339 /// Set the ADC resolution. 330 /// Set the ADC resolution.
340 pub fn set_resolution(&mut self, resolution: Resolution) { 331 pub fn set_resolution(&mut self, resolution: Resolution) {
341 T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); 332 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
@@ -384,7 +375,11 @@ impl<'d, T: Instance> Adc4<'d, T> {
384 } 375 }
385 376
386 /// Read an ADC channel. 377 /// Read an ADC channel.
387 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 378 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
379 T::regs().smpr().modify(|w| {
380 w.set_smp(0, sample_time);
381 });
382
388 channel.setup(); 383 channel.setup();
389 384
390 // Select channel 385 // Select channel
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f2837a8f1..1869993a5 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -4,11 +4,11 @@ use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 4use pac::adccommon::vals::Presc;
5 5
6use super::{ 6use super::{
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us,
8}; 8};
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::time::Hertz; 10use crate::time::Hertz;
11use crate::{pac, rcc, Peri}; 11use crate::{Peri, pac, rcc};
12 12
13/// Default VREF voltage used for sample conversion to millivolts. 13/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300; 14pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -19,33 +19,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19 19
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; 20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21 21
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22; 22const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8; 23const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 24const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 25const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29 26
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, 27impl<T: Instance> super::VrefConverter for T {
31// this currently cannot be modeled with stm32-data, 28 const CHANNEL: u8 = 10;
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40} 29}
41 30
42/// Internal temperature channel. 31impl<T: Instance> super::TemperatureConverter for T {
43pub struct Temperature; 32 const CHANNEL: u8 = 9;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49} 33}
50 34
51#[derive(Copy, Clone, Debug)] 35#[derive(Copy, Clone, Debug)]
@@ -156,7 +140,7 @@ pub enum Averaging {
156 140
157impl<'d, T: Instance> Adc<'d, T> { 141impl<'d, T: Instance> Adc<'d, T> {
158 /// Create a new ADC driver. 142 /// Create a new ADC driver.
159 pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { 143 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
160 rcc::enable_and_reset::<T>(); 144 rcc::enable_and_reset::<T>();
161 145
162 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 146 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
@@ -168,13 +152,13 @@ impl<'d, T: Instance> Adc<'d, T> {
168 debug!("ADC frequency set to {}", frequency); 152 debug!("ADC frequency set to {}", frequency);
169 153
170 if frequency > MAX_ADC_CLK_FREQ { 154 if frequency > MAX_ADC_CLK_FREQ {
171 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 155 panic!(
156 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
157 MAX_ADC_CLK_FREQ.0 / 1_000_000
158 );
172 } 159 }
173 160
174 let mut s = Self { 161 let mut s = Self { adc };
175 adc,
176 sample_time: SampleTime::from_bits(0),
177 };
178 162
179 s.power_up(); 163 s.power_up();
180 164
@@ -186,8 +170,6 @@ impl<'d, T: Instance> Adc<'d, T> {
186 170
187 s.configure_default(); 171 s.configure_default();
188 172
189 s.set_sample_time_all_channels(sample_time);
190
191 s 173 s
192 } 174 }
193 175
@@ -234,29 +216,27 @@ impl<'d, T: Instance> Adc<'d, T> {
234 } 216 }
235 217
236 /// Enable reading the voltage reference internal channel. 218 /// Enable reading the voltage reference internal channel.
237 pub fn enable_vrefint(&self) -> VrefInt { 219 pub fn enable_vrefint(&self) -> super::VrefInt {
238 T::common_regs().ccr().modify(|reg| { 220 T::common_regs().ccr().modify(|reg| {
239 reg.set_vrefen(true); 221 reg.set_vrefen(true);
240 }); 222 });
241 223
242 VrefInt {} 224 super::VrefInt {}
243 } 225 }
244 226
245 /// Enable reading the temperature internal channel. 227 /// Enable reading the temperature internal channel.
246 pub fn enable_temperature(&self) -> Temperature { 228 pub fn enable_temperature(&self) -> super::Temperature {
247 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); 229 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
248 T::common_regs().ccr().modify(|reg| { 230 T::common_regs().ccr().modify(|reg| {
249 reg.set_tsen(true); 231 reg.set_tsen(true);
250 }); 232 });
251 233
252 Temperature {} 234 super::Temperature {}
253 } 235 }
254 236
255 /// Set the ADC sample time. 237 /// Set the ADC sample time.
256 /// Shall only be called when ADC is not converting. 238 /// Shall only be called when ADC is not converting.
257 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { 239 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
258 self.sample_time = sample_time;
259
260 // Set all channels to use SMP1 field as source. 240 // Set all channels to use SMP1 field as source.
261 T::regs().smpr().modify(|w| { 241 T::regs().smpr().modify(|w| {
262 w.smpsel(0); 242 w.smpsel(0);
@@ -285,7 +265,9 @@ impl<'d, T: Instance> Adc<'d, T> {
285 T::regs().dr().read().data() as u16 265 T::regs().dr().read().data() as u16
286 } 266 }
287 267
288 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 268 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
269 self.set_sample_time_all_channels(sample_time);
270
289 Self::configure_channel(channel); 271 Self::configure_channel(channel);
290 T::regs().cfgr1().write(|reg| { 272 T::regs().cfgr1().write(|reg| {
291 reg.set_chselrmod(false); 273 reg.set_chselrmod(false);
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 3cdc9d8fb..835cc8c63 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -7,7 +7,7 @@ use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::interrupt::{self}; 8use crate::interrupt::{self};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{rcc, Peri}; 10use crate::{Peri, rcc};
11 11
12pub const VDDA_CALIB_MV: u32 = 3300; 12pub const VDDA_CALIB_MV: u32 = 3300;
13pub const ADC_MAX: u32 = (1 << 12) - 1; 13pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -28,20 +28,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
28 } 28 }
29} 29}
30 30
31pub struct Vref; 31impl<T: Instance> super::VrefConverter for T {
32impl<T: Instance> AdcChannel<T> for Vref {} 32 const CHANNEL: u8 = 17;
33impl<T: Instance> super::SealedAdcChannel<T> for Vref {
34 fn channel(&self) -> u8 {
35 17
36 }
37} 33}
38 34
39pub struct Temperature; 35impl<T: Instance> super::TemperatureConverter for T {
40impl<T: Instance> AdcChannel<T> for Temperature {} 36 const CHANNEL: u8 = 16;
41impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
42 fn channel(&self) -> u8 {
43 16
44 }
45} 37}
46 38
47impl<'d, T: Instance> Adc<'d, T> { 39impl<'d, T: Instance> Adc<'d, T> {
@@ -71,10 +63,7 @@ impl<'d, T: Instance> Adc<'d, T> {
71 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
72 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
73 65
74 Self { 66 Self { adc }
75 adc,
76 sample_time: SampleTime::from_bits(0),
77 }
78 } 67 }
79 68
80 fn freq() -> Hertz { 69 fn freq() -> Hertz {
@@ -94,22 +83,18 @@ impl<'d, T: Instance> Adc<'d, T> {
94 } 83 }
95 } 84 }
96 85
97 pub fn enable_vref(&self) -> Vref { 86 pub fn enable_vref(&self) -> super::VrefInt {
98 T::regs().cr2().modify(|reg| { 87 T::regs().cr2().modify(|reg| {
99 reg.set_tsvrefe(true); 88 reg.set_tsvrefe(true);
100 }); 89 });
101 Vref {} 90 super::VrefInt {}
102 } 91 }
103 92
104 pub fn enable_temperature(&self) -> Temperature { 93 pub fn enable_temperature(&self) -> super::Temperature {
105 T::regs().cr2().modify(|reg| { 94 T::regs().cr2().modify(|reg| {
106 reg.set_tsvrefe(true); 95 reg.set_tsvrefe(true);
107 }); 96 });
108 Temperature {} 97 super::Temperature {}
109 }
110
111 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
112 self.sample_time = sample_time;
113 } 98 }
114 99
115 /// Perform a single conversion. 100 /// Perform a single conversion.
@@ -134,8 +119,8 @@ impl<'d, T: Instance> Adc<'d, T> {
134 T::regs().dr().read().0 as u16 119 T::regs().dr().read().0 as u16
135 } 120 }
136 121
137 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 122 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
138 Self::set_channel_sample_time(channel.channel(), self.sample_time); 123 Self::set_channel_sample_time(channel.channel(), sample_time);
139 T::regs().cr1().modify(|reg| { 124 T::regs().cr1().modify(|reg| {
140 reg.set_scan(false); 125 reg.set_scan(false);
141 reg.set_discen(false); 126 reg.set_discen(false);
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 3aeb6f2c7..f6a4e1209 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -6,7 +6,7 @@ use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::time::Hertz; 8use crate::time::Hertz;
9use crate::{interrupt, rcc, Peri}; 9use crate::{Peri, interrupt, rcc};
10 10
11pub const VDDA_CALIB_MV: u32 = 3300; 11pub const VDDA_CALIB_MV: u32 = 3300;
12pub const ADC_MAX: u32 = (1 << 12) - 1; 12pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -29,27 +29,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
29 } 29 }
30} 30}
31 31
32pub struct Vref; 32impl<T: Instance> super::VrefConverter for T {
33impl<T: Instance> AdcChannel<T> for Vref {} 33 const CHANNEL: u8 = 18;
34impl<T: Instance> super::SealedAdcChannel<T> for Vref {
35 fn channel(&self) -> u8 {
36 18
37 }
38}
39
40impl Vref {
41 /// The value that vref would be if vdda was at 3300mv
42 pub fn value(&self) -> u16 {
43 crate::pac::VREFINTCAL.data().read()
44 }
45} 34}
46 35
47pub struct Temperature; 36impl<T: Instance> super::TemperatureConverter for T {
48impl<T: Instance> AdcChannel<T> for Temperature {} 37 const CHANNEL: u8 = 16;
49impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
50 fn channel(&self) -> u8 {
51 16
52 }
53} 38}
54 39
55impl<'d, T: Instance> Adc<'d, T> { 40impl<'d, T: Instance> Adc<'d, T> {
@@ -90,10 +75,7 @@ impl<'d, T: Instance> Adc<'d, T> {
90 T::Interrupt::enable(); 75 T::Interrupt::enable();
91 } 76 }
92 77
93 Self { 78 Self { adc }
94 adc,
95 sample_time: SampleTime::from_bits(0),
96 }
97 } 79 }
98 80
99 fn freq() -> Hertz { 81 fn freq() -> Hertz {
@@ -112,20 +94,16 @@ impl<'d, T: Instance> Adc<'d, T> {
112 } 94 }
113 } 95 }
114 96
115 pub fn enable_vref(&self) -> Vref { 97 pub fn enable_vref(&self) -> super::VrefInt {
116 T::common_regs().ccr().modify(|w| w.set_vrefen(true)); 98 T::common_regs().ccr().modify(|w| w.set_vrefen(true));
117 99
118 Vref {} 100 super::VrefInt {}
119 } 101 }
120 102
121 pub fn enable_temperature(&self) -> Temperature { 103 pub fn enable_temperature(&self) -> super::Temperature {
122 T::common_regs().ccr().modify(|w| w.set_tsen(true)); 104 T::common_regs().ccr().modify(|w| w.set_tsen(true));
123 105
124 Temperature {} 106 super::Temperature {}
125 }
126
127 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
128 self.sample_time = sample_time;
129 } 107 }
130 108
131 /// Perform a single conversion. 109 /// Perform a single conversion.
@@ -150,8 +128,8 @@ impl<'d, T: Instance> Adc<'d, T> {
150 T::regs().dr().read().rdata() 128 T::regs().dr().read().rdata()
151 } 129 }
152 130
153 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 131 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
154 Self::set_channel_sample_time(channel.channel(), self.sample_time); 132 Self::set_channel_sample_time(channel.channel(), sample_time);
155 133
156 // Configure the channel to sample 134 // Configure the channel to sample
157 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel())); 135 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel()));
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 84613078c..919ac3cc0 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -9,7 +9,7 @@ use super::Resolution;
9use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 9use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; 14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
15 15
@@ -79,7 +79,7 @@ impl<T: Instance> Vref<T> {
79 } 79 }
80 80
81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { 81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
82 let vref_val = adc.read(self).await; 82 let vref_val = adc.read(self, SampleTime::from(0)).await;
83 Calibration { 83 Calibration {
84 vref_cal: self.calibrated_value(), 84 vref_cal: self.calibrated_value(),
85 vref_val, 85 vref_val,
@@ -270,7 +270,8 @@ impl<'d, T: Instance> Adc<'d, T> {
270 } 270 }
271 } 271 }
272 272
273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
274 self.set_sample_time(channel, sample_time).await;
274 self.set_sample_sequence(&[channel.channel()]).await; 275 self.set_sample_sequence(&[channel.channel()]).await;
275 self.convert().await 276 self.convert().await
276 } 277 }
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 43498966f..5d9c6ff74 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,57 +1,40 @@
1use core::mem;
2
1#[allow(unused)] 3#[allow(unused)]
2#[cfg(stm32h7)] 4#[cfg(stm32h7)]
3use pac::adc::vals::{Adcaldif, Difsel, Exten}; 5use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)] 6#[allow(unused)]
5#[cfg(stm32g4)] 7#[cfg(stm32g4)]
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; 8pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
7use pac::adccommon::vals::Presc; 9pub use pac::adccommon::vals::Presc;
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
11pub use stm32_metapac::adccommon::vals::Dual;
9 12
10use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; 13use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us};
11use crate::adc::SealedAdcChannel; 14use crate::adc::SealedAdcChannel;
12use crate::dma::Transfer; 15use crate::dma::Transfer;
13use crate::time::Hertz; 16use crate::time::Hertz;
14use crate::{pac, rcc, Peri}; 17use crate::{Peri, pac, rcc};
18
19mod ringbuffered;
20pub use ringbuffered::RingBufferedAdc;
21
22mod injected;
23pub use injected::InjectedAdc;
15 24
16/// Default VREF voltage used for sample conversion to millivolts. 25/// Default VREF voltage used for sample conversion to millivolts.
17pub const VREF_DEFAULT_MV: u32 = 3300; 26pub const VREF_DEFAULT_MV: u32 = 3300;
18/// VREF voltage used for factory calibration of VREFINTCAL register. 27/// VREF voltage used for factory calibration of VREFINTCAL register.
19pub const VREF_CALIB_MV: u32 = 3300; 28pub const VREF_CALIB_MV: u32 = 3300;
20 29
30const NR_INJECTED_RANKS: usize = 4;
31
21/// Max single ADC operation clock frequency 32/// Max single ADC operation clock frequency
22#[cfg(stm32g4)] 33#[cfg(stm32g4)]
23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 34const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
24#[cfg(stm32h7)] 35#[cfg(stm32h7)]
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 36const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26 37
27// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
28/// Internal voltage reference channel.
29pub struct VrefInt;
30impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {}
31impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt {
32 fn channel(&self) -> u8 {
33 T::CHANNEL
34 }
35}
36
37/// Internal temperature channel.
38pub struct Temperature;
39impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {}
40impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature {
41 fn channel(&self) -> u8 {
42 T::CHANNEL
43 }
44}
45
46/// Internal battery voltage channel.
47pub struct Vbat;
48impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {}
49impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat {
50 fn channel(&self) -> u8 {
51 T::CHANNEL
52 }
53}
54
55// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 38// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
56// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 39// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
57#[allow(unused)] 40#[allow(unused)]
@@ -120,6 +103,24 @@ impl Prescaler {
120 } 103 }
121} 104}
122 105
106// Trigger source for ADC conversions¨
107#[derive(Copy, Clone)]
108pub struct ConversionTrigger {
109 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
110 // Note that Injected and Regular channels uses different mappings
111 pub channel: u8,
112 pub edge: Exten,
113}
114
115// Conversion mode for regular ADC channels
116#[derive(Copy, Clone)]
117pub enum RegularConversionMode {
118 // Samples as fast as possible
119 Continuous,
120 // Sample at rate determined by external trigger
121 Triggered(ConversionTrigger),
122}
123
123impl<'d, T: Instance> Adc<'d, T> { 124impl<'d, T: Instance> Adc<'d, T> {
124 /// Create a new ADC driver. 125 /// Create a new ADC driver.
125 pub fn new(adc: Peri<'d, T>) -> Self { 126 pub fn new(adc: Peri<'d, T>) -> Self {
@@ -133,20 +134,20 @@ impl<'d, T: Instance> Adc<'d, T> {
133 trace!("ADC frequency set to {}", frequency); 134 trace!("ADC frequency set to {}", frequency);
134 135
135 if frequency > MAX_ADC_CLK_FREQ { 136 if frequency > MAX_ADC_CLK_FREQ {
136 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 137 panic!(
138 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
139 MAX_ADC_CLK_FREQ.0 / 1_000_000
140 );
137 } 141 }
138 142
139 let mut s = Self { 143 let mut s = Self { adc };
140 adc,
141 sample_time: SampleTime::from_bits(0),
142 };
143 s.power_up(); 144 s.power_up();
144 s.configure_differential_inputs(); 145 s.configure_differential_inputs();
145 146
146 s.calibrate(); 147 s.calibrate();
147 blocking_delay_us(1); 148 blocking_delay_us(1);
148 149
149 s.enable(); 150 Self::enable();
150 s.configure(); 151 s.configure();
151 152
152 s 153 s
@@ -191,7 +192,7 @@ impl<'d, T: Instance> Adc<'d, T> {
191 blocking_delay_us(20); 192 blocking_delay_us(20);
192 } 193 }
193 194
194 fn enable(&mut self) { 195 fn enable() {
195 // Make sure bits are off 196 // Make sure bits are off
196 while T::regs().cr().read().addis() { 197 while T::regs().cr().read().addis() {
197 // spin 198 // spin
@@ -221,39 +222,39 @@ impl<'d, T: Instance> Adc<'d, T> {
221 } 222 }
222 223
223 /// Enable reading the voltage reference internal channel. 224 /// Enable reading the voltage reference internal channel.
224 pub fn enable_vrefint(&self) -> VrefInt 225 pub fn enable_vrefint(&self) -> super::VrefInt
225 where 226 where
226 T: VrefChannel, 227 T: super::VrefConverter,
227 { 228 {
228 T::common_regs().ccr().modify(|reg| { 229 T::common_regs().ccr().modify(|reg| {
229 reg.set_vrefen(true); 230 reg.set_vrefen(true);
230 }); 231 });
231 232
232 VrefInt {} 233 super::VrefInt {}
233 } 234 }
234 235
235 /// Enable reading the temperature internal channel. 236 /// Enable reading the temperature internal channel.
236 pub fn enable_temperature(&self) -> Temperature 237 pub fn enable_temperature(&self) -> super::Temperature
237 where 238 where
238 T: TemperatureChannel, 239 T: super::TemperatureConverter,
239 { 240 {
240 T::common_regs().ccr().modify(|reg| { 241 T::common_regs().ccr().modify(|reg| {
241 reg.set_vsenseen(true); 242 reg.set_vsenseen(true);
242 }); 243 });
243 244
244 Temperature {} 245 super::Temperature {}
245 } 246 }
246 247
247 /// Enable reading the vbat internal channel. 248 /// Enable reading the vbat internal channel.
248 pub fn enable_vbat(&self) -> Vbat 249 pub fn enable_vbat(&self) -> super::Vbat
249 where 250 where
250 T: VBatChannel, 251 T: super::VBatConverter,
251 { 252 {
252 T::common_regs().ccr().modify(|reg| { 253 T::common_regs().ccr().modify(|reg| {
253 reg.set_vbaten(true); 254 reg.set_vbaten(true);
254 }); 255 });
255 256
256 Vbat {} 257 super::Vbat {}
257 } 258 }
258 259
259 /// Enable differential channel. 260 /// Enable differential channel.
@@ -265,7 +266,7 @@ impl<'d, T: Instance> Adc<'d, T> {
265 /// channel on the other ADC unusable. The only exception is when ADC master and the slave 266 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
266 /// operate in interleaved mode. 267 /// operate in interleaved mode.
267 #[cfg(stm32g4)] 268 #[cfg(stm32g4)]
268 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) { 269 fn set_differential_channel(&mut self, ch: usize, enable: bool) {
269 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc 270 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
270 T::regs().difsel().modify(|w| { 271 T::regs().difsel().modify(|w| {
271 w.set_difsel( 272 w.set_difsel(
@@ -318,11 +319,6 @@ impl<'d, T: Instance> Adc<'d, T> {
318 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); 319 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
319 // } 320 // }
320 321
321 /// Set the ADC sample time.
322 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
323 self.sample_time = sample_time;
324 }
325
326 /// Set the ADC resolution. 322 /// Set the ADC resolution.
327 pub fn set_resolution(&mut self, resolution: Resolution) { 323 pub fn set_resolution(&mut self, resolution: Resolution) {
328 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 324 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
@@ -348,13 +344,35 @@ impl<'d, T: Instance> Adc<'d, T> {
348 } 344 }
349 345
350 /// Read an ADC pin. 346 /// Read an ADC pin.
351 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 347 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
352 channel.setup(); 348 channel.setup();
353 349
354 self.read_channel(channel) 350 self.read_channel(channel, sample_time)
355 } 351 }
356 352
357 /// Read one or multiple ADC channels using DMA. 353 /// Start regular adc conversion
354 pub(super) fn start() {
355 T::regs().cr().modify(|reg| {
356 reg.set_adstart(true);
357 });
358 }
359
360 /// Stop regular conversions
361 pub(super) fn stop() {
362 Self::stop_regular_conversions();
363 }
364
365 /// Teardown method for stopping regular ADC conversions
366 pub(super) fn teardown_dma() {
367 Self::stop_regular_conversions();
368
369 // Disable dma control
370 T::regs().cfgr().modify(|reg| {
371 reg.set_dmaen(Dmaen::DISABLE);
372 });
373 }
374
375 /// Read one or multiple ADC regular channels using DMA.
358 /// 376 ///
359 /// `sequence` iterator and `readings` must have the same length. 377 /// `sequence` iterator and `readings` must have the same length.
360 /// 378 ///
@@ -379,6 +397,9 @@ impl<'d, T: Instance> Adc<'d, T> {
379 /// .await; 397 /// .await;
380 /// defmt::info!("measurements: {}", measurements); 398 /// defmt::info!("measurements: {}", measurements);
381 /// ``` 399 /// ```
400 ///
401 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
402 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
382 pub async fn read( 403 pub async fn read(
383 &mut self, 404 &mut self,
384 rx_dma: Peri<'_, impl RxDma<T>>, 405 rx_dma: Peri<'_, impl RxDma<T>>,
@@ -396,91 +417,345 @@ impl<'d, T: Instance> Adc<'d, T> {
396 ); 417 );
397 418
398 // Ensure no conversions are ongoing and ADC is enabled. 419 // Ensure no conversions are ongoing and ADC is enabled.
399 Self::cancel_conversions(); 420 Self::stop_regular_conversions();
400 self.enable(); 421 Self::enable();
422
423 Self::configure_sequence(sequence.map(|(channel, sample_time)| {
424 channel.setup();
425
426 (channel.channel, sample_time)
427 }));
428
429 // Set continuous mode with oneshot dma.
430 // Clear overrun flag before starting transfer.
431 T::regs().isr().modify(|reg| {
432 reg.set_ovr(true);
433 });
401 434
435 T::regs().cfgr().modify(|reg| {
436 reg.set_discen(false);
437 reg.set_cont(true);
438 reg.set_dmacfg(Dmacfg::ONE_SHOT);
439 reg.set_dmaen(Dmaen::ENABLE);
440 });
441
442 let request = rx_dma.request();
443 let transfer = unsafe {
444 Transfer::new_read(
445 rx_dma,
446 request,
447 T::regs().dr().as_ptr() as *mut u16,
448 readings,
449 Default::default(),
450 )
451 };
452
453 // Start conversion
454 T::regs().cr().modify(|reg| {
455 reg.set_adstart(true);
456 });
457
458 // Wait for conversion sequence to finish.
459 transfer.await;
460
461 // Ensure conversions are finished.
462 Self::stop_regular_conversions();
463
464 // Reset configuration.
465 T::regs().cfgr().modify(|reg| {
466 reg.set_cont(false);
467 });
468 }
469
470 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) {
402 // Set sequence length 471 // Set sequence length
403 T::regs().sqr1().modify(|w| { 472 T::regs().sqr1().modify(|w| {
404 w.set_l(sequence.len() as u8 - 1); 473 w.set_l(sequence.len() as u8 - 1);
405 }); 474 });
406 475
407 // Configure channels and ranks 476 // Configure channels and ranks
408 for (_i, (channel, sample_time)) in sequence.enumerate() { 477 for (_i, (ch, sample_time)) in sequence.enumerate() {
409 Self::configure_channel(channel, sample_time); 478 let sample_time = sample_time.into();
479 if ch <= 9 {
480 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
481 } else {
482 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
483 }
410 484
411 match _i { 485 match _i {
412 0..=3 => { 486 0..=3 => {
413 T::regs().sqr1().modify(|w| { 487 T::regs().sqr1().modify(|w| {
414 w.set_sq(_i, channel.channel()); 488 w.set_sq(_i, ch);
415 }); 489 });
416 } 490 }
417 4..=8 => { 491 4..=8 => {
418 T::regs().sqr2().modify(|w| { 492 T::regs().sqr2().modify(|w| {
419 w.set_sq(_i - 4, channel.channel()); 493 w.set_sq(_i - 4, ch);
420 }); 494 });
421 } 495 }
422 9..=13 => { 496 9..=13 => {
423 T::regs().sqr3().modify(|w| { 497 T::regs().sqr3().modify(|w| {
424 w.set_sq(_i - 9, channel.channel()); 498 w.set_sq(_i - 9, ch);
425 }); 499 });
426 } 500 }
427 14..=15 => { 501 14..=15 => {
428 T::regs().sqr4().modify(|w| { 502 T::regs().sqr4().modify(|w| {
429 w.set_sq(_i - 14, channel.channel()); 503 w.set_sq(_i - 14, ch);
430 }); 504 });
431 } 505 }
432 _ => unreachable!(), 506 _ => unreachable!(),
433 } 507 }
434 } 508 }
509 }
510
511 /// Set external trigger for regular conversion sequence
512 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) {
513 T::regs().cfgr().modify(|r| {
514 r.set_extsel(trigger.channel);
515 r.set_exten(trigger.edge);
516 });
517 // Regular conversions uses DMA so no need to generate interrupt
518 T::regs().ier().modify(|r| r.set_eosie(false));
519 }
520
521 // Dual ADC mode selection
522 pub fn configure_dual_mode(&mut self, val: Dual) {
523 T::common_regs().ccr().modify(|reg| {
524 reg.set_dual(val);
525 })
526 }
527
528 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
529 ///
530 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
531 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
532 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
533 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
534 /// defines the period at which the buffer should be read.
535 ///
536 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
537 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
538 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
539 /// the buffer length should be `3 * 40 = 120`.
540 ///
541 /// # Parameters
542 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
543 /// - `dma_buf`: The buffer where DMA stores ADC samples.
544 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
545 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
546 ///
547 /// # Returns
548 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
549 pub fn into_ring_buffered<'a>(
550 mut self,
551 dma: Peri<'a, impl RxDma<T>>,
552 dma_buf: &'a mut [u16],
553 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
554 mode: RegularConversionMode,
555 ) -> RingBufferedAdc<'a, T> {
556 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
557 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
558 assert!(
559 sequence.len() <= 16,
560 "Asynchronous read sequence cannot be more than 16 in length"
561 );
562 // reset conversions and enable the adc
563 Self::stop_regular_conversions();
564 Self::enable();
565
566 //adc side setup
567
568 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| {
569 channel.setup();
570
571 (channel.channel, sample_time)
572 }));
435 573
436 // Set continuous mode with oneshot dma.
437 // Clear overrun flag before starting transfer. 574 // Clear overrun flag before starting transfer.
438 T::regs().isr().modify(|reg| { 575 T::regs().isr().modify(|reg| {
439 reg.set_ovr(true); 576 reg.set_ovr(true);
440 }); 577 });
441 578
442 T::regs().cfgr().modify(|reg| { 579 T::regs().cfgr().modify(|reg| {
443 reg.set_discen(false); 580 reg.set_discen(false); // Convert all channels for each trigger
444 reg.set_cont(true); 581 reg.set_dmacfg(Dmacfg::CIRCULAR);
445 reg.set_dmacfg(Dmacfg::ONE_SHOT);
446 reg.set_dmaen(Dmaen::ENABLE); 582 reg.set_dmaen(Dmaen::ENABLE);
447 }); 583 });
448 584
449 let request = rx_dma.request(); 585 match mode {
450 let transfer = unsafe { 586 RegularConversionMode::Continuous => {
451 Transfer::new_read( 587 T::regs().cfgr().modify(|reg| {
452 rx_dma, 588 reg.set_cont(true);
453 request, 589 });
454 T::regs().dr().as_ptr() as *mut u16, 590 }
455 readings, 591 RegularConversionMode::Triggered(trigger) => {
456 Default::default(), 592 T::regs().cfgr().modify(|r| {
593 r.set_cont(false); // New trigger is neede for each sample to be read
594 });
595 self.set_regular_conversion_trigger(trigger);
596 }
597 }
598
599 mem::forget(self);
600
601 RingBufferedAdc::new(dma, dma_buf)
602 }
603
604 /// Configures the ADC for injected conversions.
605 ///
606 /// Injected conversions are separate from the regular conversion sequence and are typically
607 /// triggered by software or an external event. This method sets up a fixed-length sequence of
608 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
609 /// interrupt should be enabled.
610 ///
611 /// # Parameters
612 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
613 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
614 /// - `trigger`: The trigger source that starts the injected conversion sequence.
615 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
616 ///
617 /// # Returns
618 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
619 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
620 ///
621 /// # Panics
622 /// This function will panic if:
623 /// - `sequence` is empty.
624 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
625 ///
626 /// # Notes
627 /// - Injected conversions can run independently of regular ADC conversions.
628 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
629 /// - Accessing samples beyond `N` will result in a panic; use the returned type
630 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
631 pub fn setup_injected_conversions<'a, const N: usize>(
632 mut self,
633 sequence: [(AnyAdcChannel<T>, SampleTime); N],
634 trigger: ConversionTrigger,
635 interrupt: bool,
636 ) -> InjectedAdc<T, N> {
637 assert!(N != 0, "Read sequence cannot be empty");
638 assert!(
639 N <= NR_INJECTED_RANKS,
640 "Read sequence cannot be more than {} in length",
641 NR_INJECTED_RANKS
642 );
643
644 Self::stop_regular_conversions();
645 Self::enable();
646
647 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
648
649 for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() {
650 Self::configure_channel(&mut channel, sample_time);
651
652 let idx = match n {
653 0..=3 => n,
654 4..=8 => n - 4,
655 9..=13 => n - 9,
656 14..=15 => n - 14,
657 _ => unreachable!(),
658 };
659
660 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
661 }
662
663 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
664
665 self.set_injected_conversion_trigger(trigger);
666 self.enable_injected_eos_interrupt(interrupt);
667 Self::start_injected_conversions();
668
669 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
670 }
671
672 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
673 ///
674 /// # Parameters
675 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
676 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
677 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
678 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
679 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
680 /// - `injected_trigger`: The trigger source for injected conversions.
681 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
682 ///
683 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
684 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
685 ///
686 /// # Returns
687 /// A tuple containing:
688 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
689 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
690 ///
691 /// # Safety
692 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
693 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
694 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
695 pub fn into_ring_buffered_and_injected<'a, const N: usize>(
696 self,
697 dma: Peri<'a, impl RxDma<T>>,
698 dma_buf: &'a mut [u16],
699 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
700 regular_conversion_mode: RegularConversionMode,
701 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
702 injected_trigger: ConversionTrigger,
703 injected_interrupt: bool,
704 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
705 unsafe {
706 (
707 Self {
708 adc: self.adc.clone_unchecked(),
709 }
710 .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode),
711 Self {
712 adc: self.adc.clone_unchecked(),
713 }
714 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
457 ) 715 )
458 }; 716 }
717 }
459 718
460 // Start conversion 719 /// Stop injected conversions
720 pub(super) fn stop_injected_conversions() {
721 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
722 T::regs().cr().modify(|reg| {
723 reg.set_jadstp(Adstp::STOP);
724 });
725 // The software must poll JADSTART until the bit is reset before assuming the
726 // ADC is completely stopped
727 while T::regs().cr().read().jadstart() {}
728 }
729 }
730
731 /// Start injected ADC conversion
732 pub(super) fn start_injected_conversions() {
461 T::regs().cr().modify(|reg| { 733 T::regs().cr().modify(|reg| {
462 reg.set_adstart(true); 734 reg.set_jadstart(true);
463 }); 735 });
736 }
464 737
465 // Wait for conversion sequence to finish. 738 /// Set external trigger for injected conversion sequence
466 transfer.await; 739 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9
467 740 fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) {
468 // Ensure conversions are finished. 741 T::regs().jsqr().modify(|r| {
469 Self::cancel_conversions(); 742 r.set_jextsel(trigger.channel);
470 743 r.set_jexten(trigger.edge);
471 // Reset configuration.
472 T::regs().cfgr().modify(|reg| {
473 reg.set_cont(false);
474 }); 744 });
475 } 745 }
476 746
747 /// Enable end of injected sequence interrupt
748 fn enable_injected_eos_interrupt(&mut self, enable: bool) {
749 T::regs().ier().modify(|r| r.set_jeosie(enable));
750 }
751
477 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 752 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
478 // Configure channel 753 // Configure channel
479 Self::set_channel_sample_time(channel.channel(), sample_time); 754 Self::set_channel_sample_time(channel.channel(), sample_time);
480 } 755 }
481 756
482 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 757 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
483 Self::configure_channel(channel, self.sample_time); 758 Self::configure_channel(channel, sample_time);
484 #[cfg(stm32h7)] 759 #[cfg(stm32h7)]
485 { 760 {
486 T::regs().cfgr2().modify(|w| w.set_lshift(0)); 761 T::regs().cfgr2().modify(|w| w.set_lshift(0));
@@ -506,72 +781,77 @@ impl<'d, T: Instance> Adc<'d, T> {
506 } 781 }
507 } 782 }
508 783
509 fn cancel_conversions() { 784 // Stop regular conversions
785 fn stop_regular_conversions() {
510 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 786 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
511 T::regs().cr().modify(|reg| { 787 T::regs().cr().modify(|reg| {
512 reg.set_adstp(Adstp::STOP); 788 reg.set_adstp(Adstp::STOP);
513 }); 789 });
790 // The software must poll ADSTART until the bit is reset before assuming the
791 // ADC is completely stopped
514 while T::regs().cr().read().adstart() {} 792 while T::regs().cr().read().adstart() {}
515 } 793 }
516 } 794 }
517} 795}
518 796
519/// Implemented for ADCs that have a Temperature channel 797impl<T: Instance, const N: usize> InjectedAdc<T, N> {
520pub trait TemperatureChannel { 798 /// Read sampled data from all injected ADC injected ranks
521 const CHANNEL: u8; 799 /// Clear the JEOS flag to allow a new injected sequence
522} 800 pub(super) fn read_injected_data() -> [u16; N] {
523/// Implemented for ADCs that have a Vref channel 801 let mut data = [0u16; N];
524pub trait VrefChannel { 802 for i in 0..N {
525 const CHANNEL: u8; 803 data[i] = T::regs().jdr(i).read().jdata();
526} 804 }
527/// Implemented for ADCs that have a VBat channel 805
528pub trait VBatChannel { 806 // Clear JEOS by writing 1
529 const CHANNEL: u8; 807 T::regs().isr().modify(|r| r.set_jeos(true));
808 data
809 }
530} 810}
531 811
532#[cfg(stm32g4)] 812#[cfg(stm32g4)]
533mod g4 { 813mod g4 {
534 pub use super::*; 814 use crate::adc::{TemperatureConverter, VBatConverter, VrefConverter};
535 815
536 impl TemperatureChannel for crate::peripherals::ADC1 { 816 impl TemperatureConverter for crate::peripherals::ADC1 {
537 const CHANNEL: u8 = 16; 817 const CHANNEL: u8 = 16;
538 } 818 }
539 819
540 impl VrefChannel for crate::peripherals::ADC1 { 820 impl VrefConverter for crate::peripherals::ADC1 {
541 const CHANNEL: u8 = 18; 821 const CHANNEL: u8 = 18;
542 } 822 }
543 823
544 impl VBatChannel for crate::peripherals::ADC1 { 824 impl VBatConverter for crate::peripherals::ADC1 {
545 const CHANNEL: u8 = 17; 825 const CHANNEL: u8 = 17;
546 } 826 }
547 827
548 #[cfg(peri_adc3_common)] 828 #[cfg(peri_adc3_common)]
549 impl VrefChannel for crate::peripherals::ADC3 { 829 impl VrefConverter for crate::peripherals::ADC3 {
550 const CHANNEL: u8 = 18; 830 const CHANNEL: u8 = 18;
551 } 831 }
552 832
553 #[cfg(peri_adc3_common)] 833 #[cfg(peri_adc3_common)]
554 impl VBatChannel for crate::peripherals::ADC3 { 834 impl VBatConverter for crate::peripherals::ADC3 {
555 const CHANNEL: u8 = 17; 835 const CHANNEL: u8 = 17;
556 } 836 }
557 837
558 #[cfg(not(stm32g4x1))] 838 #[cfg(not(stm32g4x1))]
559 impl VrefChannel for crate::peripherals::ADC4 { 839 impl VrefConverter for crate::peripherals::ADC4 {
560 const CHANNEL: u8 = 18; 840 const CHANNEL: u8 = 18;
561 } 841 }
562 842
563 #[cfg(not(stm32g4x1))] 843 #[cfg(not(stm32g4x1))]
564 impl TemperatureChannel for crate::peripherals::ADC5 { 844 impl TemperatureConverter for crate::peripherals::ADC5 {
565 const CHANNEL: u8 = 4; 845 const CHANNEL: u8 = 4;
566 } 846 }
567 847
568 #[cfg(not(stm32g4x1))] 848 #[cfg(not(stm32g4x1))]
569 impl VrefChannel for crate::peripherals::ADC5 { 849 impl VrefConverter for crate::peripherals::ADC5 {
570 const CHANNEL: u8 = 18; 850 const CHANNEL: u8 = 18;
571 } 851 }
572 852
573 #[cfg(not(stm32g4x1))] 853 #[cfg(not(stm32g4x1))]
574 impl VBatChannel for crate::peripherals::ADC5 { 854 impl VBatConverter for crate::peripherals::ADC5 {
575 const CHANNEL: u8 = 17; 855 const CHANNEL: u8 = 17;
576 } 856 }
577} 857}
@@ -579,13 +859,13 @@ mod g4 {
579// TODO this should look at each ADC individually and impl the correct channels 859// TODO this should look at each ADC individually and impl the correct channels
580#[cfg(stm32h7)] 860#[cfg(stm32h7)]
581mod h7 { 861mod h7 {
582 impl<T: Instance> TemperatureChannel for T { 862 impl<T: Instance> TemperatureConverter for T {
583 const CHANNEL: u8 = 18; 863 const CHANNEL: u8 = 18;
584 } 864 }
585 impl<T: Instance> VrefChannel for T { 865 impl<T: Instance> VrefConverter for T {
586 const CHANNEL: u8 = 19; 866 const CHANNEL: u8 = 19;
587 } 867 }
588 impl<T: Instance> VBatChannel for T { 868 impl<T: Instance> VBatConverter for T {
589 // TODO this should be 14 for H7a/b/35 869 // TODO this should be 14 for H7a/b/35
590 const CHANNEL: u8 = 17; 870 const CHANNEL: u8 = 17;
591 } 871 }
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
new file mode 100644
index 000000000..f9f1bba2a
--- /dev/null
+++ b/embassy-stm32/src/adc/injected.rs
@@ -0,0 +1,44 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::{AnyAdcChannel, SampleTime};
8use crate::adc::Adc;
9#[allow(unused_imports)]
10use crate::adc::Instance;
11
12/// Injected ADC sequence with owned channels.
13pub struct InjectedAdc<T: Instance, const N: usize> {
14 _channels: [(AnyAdcChannel<T>, SampleTime); N],
15 _phantom: PhantomData<T>,
16}
17
18impl<T: Instance, const N: usize> InjectedAdc<T, N> {
19 pub(crate) fn new(channels: [(AnyAdcChannel<T>, SampleTime); N]) -> Self {
20 Self {
21 _channels: channels,
22 _phantom: PhantomData,
23 }
24 }
25
26 pub fn stop_injected_conversions(&mut self) {
27 Adc::<T>::stop_injected_conversions()
28 }
29
30 pub fn start_injected_conversions(&mut self) {
31 Adc::<T>::start_injected_conversions()
32 }
33
34 pub fn read_injected_samples(&mut self) -> [u16; N] {
35 InjectedAdc::<T, N>::read_injected_data()
36 }
37}
38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) {
41 Adc::<T>::teardown_dma();
42 compiler_fence(Ordering::SeqCst);
43 }
44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ea986f4cf..3bf893a35 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -22,7 +22,7 @@ use core::marker::PhantomData;
22#[allow(unused)] 22#[allow(unused)]
23#[cfg(not(any(adc_f3v3, adc_wba)))] 23#[cfg(not(any(adc_f3v3, adc_wba)))]
24pub use _version::*; 24pub use _version::*;
25use embassy_hal_internal::{impl_peripheral, PeripheralType}; 25use embassy_hal_internal::{PeripheralType, impl_peripheral};
26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
27use embassy_sync::waitqueue::AtomicWaker; 27use embassy_sync::waitqueue::AtomicWaker;
28 28
@@ -47,8 +47,6 @@ dma_trait!(RxDma4, adc4::Instance);
47pub struct Adc<'d, T: Instance> { 47pub struct Adc<'d, T: Instance> {
48 #[allow(unused)] 48 #[allow(unused)]
49 adc: crate::Peri<'d, T>, 49 adc: crate::Peri<'d, T>,
50 #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))]
51 sample_time: SampleTime,
52} 50}
53 51
54#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 52#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
@@ -87,14 +85,67 @@ pub(crate) trait SealedAdcChannel<T> {
87/// Performs a busy-wait delay for a specified number of microseconds. 85/// Performs a busy-wait delay for a specified number of microseconds.
88#[allow(unused)] 86#[allow(unused)]
89pub(crate) fn blocking_delay_us(us: u32) { 87pub(crate) fn blocking_delay_us(us: u32) {
90 #[cfg(feature = "time")] 88 cfg_if::cfg_if! {
91 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); 89 // this does strange things on stm32wlx in low power mode depending on exactly when it's called
92 #[cfg(not(feature = "time"))] 90 // as in sometimes 15 us (1 tick) would take > 20 seconds.
93 { 91 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] {
94 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 92 let duration = embassy_time::Duration::from_micros(us as u64);
95 let us = us as u64; 93 embassy_time::block_for(duration);
96 let cycles = freq * us / 1_000_000; 94 } else {
97 cortex_m::asm::delay(cycles as u32); 95 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
96 let us = us as u64;
97 let cycles = freq * us / 1_000_000;
98 cortex_m::asm::delay(cycles as u32);
99 }
100 }
101}
102
103/// Implemented for ADCs that have a Temperature channel
104pub trait TemperatureConverter {
105 const CHANNEL: u8;
106}
107/// Implemented for ADCs that have a Vref channel
108pub trait VrefConverter {
109 const CHANNEL: u8;
110}
111/// Implemented for ADCs that have a VBat channel
112pub trait VBatConverter {
113 const CHANNEL: u8;
114}
115
116// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
117/// Internal voltage reference channel.
118pub struct VrefInt;
119impl<T: Instance + VrefConverter> AdcChannel<T> for VrefInt {}
120impl<T: Instance + VrefConverter> SealedAdcChannel<T> for VrefInt {
121 fn channel(&self) -> u8 {
122 T::CHANNEL
123 }
124}
125
126impl VrefInt {
127 #[cfg(any(adc_f3v1, adc_f3v2))]
128 /// The value that vref would be if vdda was at 3300mv
129 pub fn calibrated_value(&self) -> u16 {
130 crate::pac::VREFINTCAL.data().read()
131 }
132}
133
134/// Internal temperature channel.
135pub struct Temperature;
136impl<T: Instance + TemperatureConverter> AdcChannel<T> for Temperature {}
137impl<T: Instance + TemperatureConverter> SealedAdcChannel<T> for Temperature {
138 fn channel(&self) -> u8 {
139 T::CHANNEL
140 }
141}
142
143/// Internal battery voltage channel.
144pub struct Vbat;
145impl<T: Instance + VBatConverter> AdcChannel<T> for Vbat {}
146impl<T: Instance + VBatConverter> SealedAdcChannel<T> for Vbat {
147 fn channel(&self) -> u8 {
148 T::CHANNEL
98 } 149 }
99} 150}
100 151
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
new file mode 100644
index 000000000..024c6acdc
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -0,0 +1,182 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use crate::adc::Adc;
8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)]
11use crate::dma::{ReadableRingBuffer, TransferOptions};
12use crate::rcc;
13
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct OverrunError;
16
17pub struct RingBufferedAdc<'d, T: Instance> {
18 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u16>,
20}
21
22impl<'d, T: Instance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup
25 let opts = TransferOptions {
26 half_transfer_ir: true,
27 circular: true,
28 ..Default::default()
29 };
30
31 // Safety: we forget the struct before this function returns.
32 let request = dma.request();
33
34 let ring_buf =
35 unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) };
36
37 Self {
38 _phantom: PhantomData,
39 ring_buf,
40 }
41 }
42
43 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
44 pub fn start(&mut self) {
45 compiler_fence(Ordering::SeqCst);
46 self.ring_buf.start();
47
48 Adc::<T>::start();
49 }
50
51 pub fn stop(&mut self) {
52 Adc::<T>::stop();
53
54 self.ring_buf.request_pause();
55
56 compiler_fence(Ordering::SeqCst);
57 }
58
59 pub fn clear(&mut self) {
60 self.ring_buf.clear();
61 }
62
63 /// Reads measurements from the DMA ring buffer.
64 ///
65 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
66 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
67 /// Because interrupts are only generated if half or full DMA transfer completes.
68 ///
69 /// Each call to `read` will populate the `measurements` array in the same order as the channels
70 /// defined with `sequence`. There will be many sequences worth of measurements in this array
71 /// because it only returns if at least half of the DMA buffer is filled. For example if 2
72 /// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
73 ///
74 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
75 /// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
76 /// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
77 /// Example:
78 /// ```rust,ignore
79 /// const DMA_BUF_LEN: usize = 120;
80 /// use embassy_stm32::adc::{Adc, AdcChannel}
81 ///
82 /// let mut adc = Adc::new(p.ADC1);
83 /// let mut adc_pin0 = p.PA0.degrade_adc();
84 /// let mut adc_pin1 = p.PA1.degrade_adc();
85 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
86 ///
87 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
88 /// p.DMA2_CH0,
89 /// adc_dma_buf, [
90 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
91 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
92 /// ].into_iter());
93 ///
94 ///
95 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
96 /// loop {
97 /// match ring_buffered_adc.read(&mut measurements).await {
98 /// Ok(_) => {
99 /// defmt::info!("adc1: {}", measurements);
100 /// }
101 /// Err(e) => {
102 /// defmt::warn!("Error: {:?}", e);
103 /// }
104 /// }
105 /// }
106 /// ```
107 ///
108 ///
109 /// [`teardown_adc`]: #method.teardown_adc
110 /// [`start_continuous_sampling`]: #method.start_continuous_sampling
111 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
112 assert_eq!(
113 self.ring_buf.capacity() / 2,
114 measurements.len(),
115 "Buffer size must be half the size of the ring buffer"
116 );
117
118 if !self.ring_buf.is_running() {
119 self.start();
120 }
121
122 #[cfg(adc_v2)]
123 {
124 // Clear overrun flag if set.
125 if T::regs().sr().read().ovr() {
126 self.stop();
127
128 return Err(OverrunError);
129 }
130 }
131
132 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
133 }
134
135 /// Read bytes that are readily available in the ring buffer.
136 /// If no bytes are currently available in the buffer the call waits until the some
137 /// bytes are available (at least one byte and at most half the buffer size)
138 ///
139 /// Background receive is started if `start_continuous_sampling()` has not been previously called.
140 ///
141 /// Receive in the background is terminated if an error is returned.
142 /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
143 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
144 if !self.ring_buf.is_running() {
145 self.start();
146 }
147
148 #[cfg(adc_v2)]
149 {
150 // Clear overrun flag if set.
151 if T::regs().sr().read().ovr() {
152 self.stop();
153
154 return Err(OverrunError);
155 }
156 }
157 loop {
158 match self.ring_buf.read(buf) {
159 Ok((0, _)) => {}
160 Ok((len, _)) => {
161 return Ok(len);
162 }
163 Err(_) => {
164 self.stop();
165
166 return Err(OverrunError);
167 }
168 }
169 }
170 }
171}
172
173impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
174 fn drop(&mut self) {
175 Adc::<T>::teardown_dma();
176
177 compiler_fence(Ordering::SeqCst);
178
179 self.ring_buf.request_pause();
180 rcc::disable::<T>();
181 }
182}
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
deleted file mode 100644
index 6f69e8486..000000000
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ /dev/null
@@ -1,432 +0,0 @@
1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
4
5use stm32_metapac::adc::vals::SampleTime;
6
7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
9use crate::pac::adc::vals;
10use crate::{rcc, Peri};
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError;
14
15fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
16 r.sr().modify(|regs| {
17 regs.set_eoc(false);
18 regs.set_ovr(false);
19 });
20}
21
22#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
23pub enum Sequence {
24 One,
25 Two,
26 Three,
27 Four,
28 Five,
29 Six,
30 Seven,
31 Eight,
32 Nine,
33 Ten,
34 Eleven,
35 Twelve,
36 Thirteen,
37 Fourteen,
38 Fifteen,
39 Sixteen,
40}
41
42impl From<Sequence> for u8 {
43 fn from(s: Sequence) -> u8 {
44 match s {
45 Sequence::One => 0,
46 Sequence::Two => 1,
47 Sequence::Three => 2,
48 Sequence::Four => 3,
49 Sequence::Five => 4,
50 Sequence::Six => 5,
51 Sequence::Seven => 6,
52 Sequence::Eight => 7,
53 Sequence::Nine => 8,
54 Sequence::Ten => 9,
55 Sequence::Eleven => 10,
56 Sequence::Twelve => 11,
57 Sequence::Thirteen => 12,
58 Sequence::Fourteen => 13,
59 Sequence::Fifteen => 14,
60 Sequence::Sixteen => 15,
61 }
62 }
63}
64
65impl From<u8> for Sequence {
66 fn from(val: u8) -> Self {
67 match val {
68 0 => Sequence::One,
69 1 => Sequence::Two,
70 2 => Sequence::Three,
71 3 => Sequence::Four,
72 4 => Sequence::Five,
73 5 => Sequence::Six,
74 6 => Sequence::Seven,
75 7 => Sequence::Eight,
76 8 => Sequence::Nine,
77 9 => Sequence::Ten,
78 10 => Sequence::Eleven,
79 11 => Sequence::Twelve,
80 12 => Sequence::Thirteen,
81 13 => Sequence::Fourteen,
82 14 => Sequence::Fifteen,
83 15 => Sequence::Sixteen,
84 _ => panic!("Invalid sequence number"),
85 }
86 }
87}
88
89pub struct RingBufferedAdc<'d, T: Instance> {
90 _phantom: PhantomData<T>,
91 ring_buf: ReadableRingBuffer<'d, u16>,
92}
93
94impl<'d, T: Instance> Adc<'d, T> {
95 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
96 ///
97 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
98 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
99 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
100 ///
101 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
103 ///
104 /// [`read`]: #method.read
105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
107
108 let opts: crate::dma::TransferOptions = TransferOptions {
109 half_transfer_ir: true,
110 priority: Priority::VeryHigh,
111 ..Default::default()
112 };
113
114 // Safety: we forget the struct before this function returns.
115 let rx_src = T::regs().dr().as_ptr() as *mut u16;
116 let request = dma.request();
117
118 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
119
120 // Don't disable the clock
121 mem::forget(self);
122
123 RingBufferedAdc {
124 _phantom: PhantomData,
125 ring_buf,
126 }
127 }
128}
129
130impl<'d, T: Instance> RingBufferedAdc<'d, T> {
131 fn is_on() -> bool {
132 T::regs().cr2().read().adon()
133 }
134
135 fn stop_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(false);
138 });
139 }
140
141 fn start_adc() {
142 T::regs().cr2().modify(|reg| {
143 reg.set_adon(true);
144 });
145 }
146
147 /// Sets the channel sample time
148 ///
149 /// ## SAFETY:
150 /// - ADON == 0 i.e ADC must not be enabled when this is called.
151 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
152 if ch <= 9 {
153 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
154 } else {
155 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
156 }
157 }
158
159 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
160 let ch_iter = ch.iter();
161 for idx in ch_iter {
162 unsafe {
163 Self::set_channel_sample_time(*idx, sample_time);
164 }
165 }
166 }
167
168 pub fn set_sample_sequence(
169 &mut self,
170 sequence: Sequence,
171 channel: &mut impl AdcChannel<T>,
172 sample_time: SampleTime,
173 ) {
174 let was_on = Self::is_on();
175 if !was_on {
176 Self::start_adc();
177 }
178
179 // Check the sequence is long enough
180 T::regs().sqr1().modify(|r| {
181 let prev: Sequence = r.l().into();
182 if prev < sequence {
183 let new_l: Sequence = sequence;
184 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
185 r.set_l(sequence.into())
186 } else {
187 r.set_l(prev.into())
188 }
189 });
190
191 // Set this GPIO as an analog input.
192 channel.setup();
193
194 // Set the channel in the right sequence field.
195 match sequence {
196 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
197 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
198 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
212 };
213
214 if !was_on {
215 Self::stop_adc();
216 }
217
218 self.set_channels_sample_time(&[channel.channel()], sample_time);
219
220 Self::start_adc();
221 }
222
223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
224 pub fn start(&mut self) -> Result<(), OverrunError> {
225 self.setup_adc();
226 self.ring_buf.clear();
227
228 Ok(())
229 }
230
231 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
232 self.teardown_adc();
233 Err(err)
234 }
235
236 /// Stops DMA transfer.
237 /// It does not turn off ADC.
238 /// Calling `start` restarts continuous DMA transfer.
239 ///
240 /// [`start`]: #method.start
241 pub fn teardown_adc(&mut self) {
242 // Stop the DMA transfer
243 self.ring_buf.request_pause();
244
245 let r = T::regs();
246
247 // Stop ADC
248 r.cr2().modify(|reg| {
249 // Stop ADC
250 reg.set_swstart(false);
251 // Stop DMA
252 reg.set_dma(false);
253 });
254
255 r.cr1().modify(|w| {
256 // Disable interrupt for end of conversion
257 w.set_eocie(false);
258 // Disable interrupt for overrun
259 w.set_ovrie(false);
260 });
261
262 clear_interrupt_flags(r);
263
264 compiler_fence(Ordering::SeqCst);
265 }
266
267 fn setup_adc(&mut self) {
268 compiler_fence(Ordering::SeqCst);
269
270 self.ring_buf.start();
271
272 let r = T::regs();
273
274 // Enable ADC
275 let was_on = Self::is_on();
276 if !was_on {
277 r.cr2().modify(|reg| {
278 reg.set_adon(false);
279 reg.set_swstart(false);
280 });
281 }
282
283 // Clear all interrupts
284 r.sr().modify(|regs| {
285 regs.set_eoc(false);
286 regs.set_ovr(false);
287 regs.set_strt(false);
288 });
289
290 r.cr1().modify(|w| {
291 // Enable interrupt for end of conversion
292 w.set_eocie(true);
293 // Enable interrupt for overrun
294 w.set_ovrie(true);
295 // Scanning converisons of multiple channels
296 w.set_scan(true);
297 // Continuous conversion mode
298 w.set_discen(false);
299 });
300
301 r.cr2().modify(|w| {
302 // Enable DMA mode
303 w.set_dma(true);
304 // Enable continuous conversions
305 w.set_cont(true);
306 // DMA requests are issues as long as DMA=1 and data are converted.
307 w.set_dds(vals::Dds::CONTINUOUS);
308 // EOC flag is set at the end of each conversion.
309 w.set_eocs(vals::Eocs::EACH_CONVERSION);
310 });
311
312 // Begin ADC conversions
313 T::regs().cr2().modify(|reg| {
314 reg.set_adon(true);
315 reg.set_swstart(true);
316 });
317
318 super::blocking_delay_us(3);
319 }
320
321 /// Read bytes that are readily available in the ring buffer.
322 /// If no bytes are currently available in the buffer the call waits until the some
323 /// bytes are available (at least one byte and at most half the buffer size)
324 ///
325 /// Background receive is started if `start()` has not been previously called.
326 ///
327 /// Receive in the background is terminated if an error is returned.
328 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
329 pub fn blocking_read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
330 let r = T::regs();
331
332 // Start background receive if it was not already started
333 if !r.cr2().read().dma() {
334 self.start()?;
335 }
336
337 // Clear overrun flag if set.
338 if r.sr().read().ovr() {
339 return self.stop(OverrunError);
340 }
341
342 loop {
343 match self.ring_buf.read(buf) {
344 Ok((0, _)) => {}
345 Ok((len, _)) => {
346 return Ok(len);
347 }
348 Err(_) => {
349 return self.stop(OverrunError);
350 }
351 }
352 }
353 }
354
355 /// Reads measurements from the DMA ring buffer.
356 ///
357 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
358 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
359 ///
360 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
361 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
362 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
363 ///
364 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
365 ///
366 /// By default, the ADC fills the DMA buffer as quickly as possible. To control the sample rate, call `teardown_adc` after each readout, and then start the DMA again at the desired interval.
367 /// Note that even if using `teardown_adc` to control the sample rate, with each call to `read`, measurements equivalent to half the size of the DMA buffer are still collected.
368 ///
369 /// Example:
370 /// ```rust,ignore
371 /// const DMA_BUF_LEN: usize = 120;
372 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
373 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
374 ///
375 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
376 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
377 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
378 ///
379 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
380 /// loop {
381 /// match adc.read(&mut measurements).await {
382 /// Ok(_) => {
383 /// defmt::info!("adc1: {}", measurements);
384 /// // Only needed to manually control sample rate.
385 /// adc.teardown_adc();
386 /// }
387 /// Err(e) => {
388 /// defmt::warn!("Error: {:?}", e);
389 /// // DMA overrun, next call to `read` restarts ADC.
390 /// }
391 /// }
392 ///
393 /// // Manually control sample rate.
394 /// Timer::after_millis(100).await;
395 /// }
396 /// ```
397 ///
398 ///
399 /// [`set_sample_sequence`]: #method.set_sample_sequence
400 /// [`teardown_adc`]: #method.teardown_adc
401 /// [`start`]: #method.start
402 pub async fn read<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
403 assert_eq!(
404 self.ring_buf.capacity() / 2,
405 N,
406 "Buffer size must be half the size of the ring buffer"
407 );
408
409 let r = T::regs();
410
411 // Start background receive if it was not already started
412 if !r.cr2().read().dma() {
413 self.start()?;
414 }
415
416 // Clear overrun flag if set.
417 if r.sr().read().ovr() {
418 return self.stop(OverrunError);
419 }
420 match self.ring_buf.read_exact(measurements).await {
421 Ok(len) => Ok(len),
422 Err(_) => self.stop(OverrunError),
423 }
424 }
425}
426
427impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
428 fn drop(&mut self) {
429 self.teardown_adc();
430 rcc::disable::<T>();
431 }
432}
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index d09374876..97557ee8a 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -5,11 +5,12 @@ use core::task::Poll;
5#[cfg(adc_l0)] 5#[cfg(adc_l0)]
6use stm32_metapac::adc::vals::Ckmode; 6use stm32_metapac::adc::vals::Ckmode;
7 7
8use super::blocking_delay_us; 8#[cfg(not(adc_l0))]
9use super::Vbat;
10use super::{Temperature, VrefInt, blocking_delay_us};
9use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 11use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
11use crate::peripherals::ADC1; 13use crate::{Peri, interrupt, rcc};
12use crate::{interrupt, rcc, Peri};
13 14
14mod watchdog_v1; 15mod watchdog_v1;
15pub use watchdog_v1::WatchdogChannels; 16pub use watchdog_v1::WatchdogChannels;
@@ -42,36 +43,23 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
42} 43}
43 44
44#[cfg(not(adc_l0))] 45#[cfg(not(adc_l0))]
45pub struct Vbat; 46impl super::VBatConverter for crate::peripherals::ADC1 {
46 47 const CHANNEL: u8 = 18;
47#[cfg(not(adc_l0))] 48}
48impl AdcChannel<ADC1> for Vbat {}
49 49
50#[cfg(not(adc_l0))] 50#[cfg(not(adc_l0))]
51impl super::SealedAdcChannel<ADC1> for Vbat { 51impl super::VrefConverter for crate::peripherals::ADC1 {
52 fn channel(&self) -> u8 { 52 const CHANNEL: u8 = 17;
53 18
54 }
55} 53}
56 54
57pub struct Vref; 55#[cfg(adc_l0)]
58impl AdcChannel<ADC1> for Vref {} 56impl super::VrefConverter for crate::peripherals::ADC1 {
59impl super::SealedAdcChannel<ADC1> for Vref { 57 const CHANNEL: u8 = 18;
60 fn channel(&self) -> u8 {
61 17
62 }
63} 58}
64 59
65pub struct Temperature; 60#[cfg(not(adc_l0))]
66impl AdcChannel<ADC1> for Temperature {} 61impl super::TemperatureConverter for crate::peripherals::ADC1 {
67impl super::SealedAdcChannel<ADC1> for Temperature { 62 const CHANNEL: u8 = 16;
68 fn channel(&self) -> u8 {
69 if cfg!(adc_l0) {
70 18
71 } else {
72 16
73 }
74 }
75} 63}
76 64
77impl<'d, T: Instance> Adc<'d, T> { 65impl<'d, T: Instance> Adc<'d, T> {
@@ -118,10 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> {
118 T::Interrupt::enable(); 106 T::Interrupt::enable();
119 } 107 }
120 108
121 Self { 109 Self { adc }
122 adc,
123 sample_time: SampleTime::from_bits(0),
124 }
125 } 110 }
126 111
127 #[cfg(not(adc_l0))] 112 #[cfg(not(adc_l0))]
@@ -134,12 +119,12 @@ impl<'d, T: Instance> Adc<'d, T> {
134 Vbat 119 Vbat
135 } 120 }
136 121
137 pub fn enable_vref(&self) -> Vref { 122 pub fn enable_vref(&self) -> VrefInt {
138 // Table 28. Embedded internal reference voltage 123 // Table 28. Embedded internal reference voltage
139 // tstart = 10μs 124 // tstart = 10μs
140 T::regs().ccr().modify(|reg| reg.set_vrefen(true)); 125 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
141 blocking_delay_us(10); 126 blocking_delay_us(10);
142 Vref 127 VrefInt
143 } 128 }
144 129
145 pub fn enable_temperature(&self) -> Temperature { 130 pub fn enable_temperature(&self) -> Temperature {
@@ -153,10 +138,6 @@ impl<'d, T: Instance> Adc<'d, T> {
153 Temperature 138 Temperature
154 } 139 }
155 140
156 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
157 self.sample_time = sample_time;
158 }
159
160 pub fn set_resolution(&mut self, resolution: Resolution) { 141 pub fn set_resolution(&mut self, resolution: Resolution) {
161 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 142 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
162 } 143 }
@@ -167,12 +148,13 @@ impl<'d, T: Instance> Adc<'d, T> {
167 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); 148 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
168 } 149 }
169 150
170 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 151 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
171 let ch_num = channel.channel(); 152 let ch_num = channel.channel();
172 channel.setup(); 153 channel.setup();
173 154
174 // A.7.5 Single conversion sequence code example - Software trigger 155 // A.7.5 Single conversion sequence code example - Software trigger
175 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true)); 156 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true));
157 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
176 158
177 self.convert().await 159 self.convert().await
178 } 160 }
@@ -183,7 +165,6 @@ impl<'d, T: Instance> Adc<'d, T> {
183 reg.set_eosmp(true); 165 reg.set_eosmp(true);
184 }); 166 });
185 167
186 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
187 T::regs().ier().modify(|w| w.set_eocie(true)); 168 T::regs().ier().modify(|w| w.set_eocie(true));
188 T::regs().cr().modify(|reg| reg.set_adstart(true)); 169 T::regs().cr().modify(|reg| reg.set_adstart(true));
189 170
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index e94a25b24..88a8b96ed 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,23 +1,43 @@
1use super::blocking_delay_us; 1use core::mem;
2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 2use core::sync::atomic::{Ordering, compiler_fence};
3use crate::peripherals::ADC1; 3
4use super::{Temperature, Vbat, VrefInt, blocking_delay_us};
5use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel};
6use crate::pac::adc::vals;
4use crate::time::Hertz; 7use crate::time::Hertz;
5use crate::{rcc, Peri}; 8use crate::{Peri, rcc};
9
10mod ringbuffered;
11pub use ringbuffered::RingBufferedAdc;
6 12
7mod ringbuffered_v2; 13fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
8pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 14 r.sr().modify(|regs| {
15 regs.set_eoc(false);
16 regs.set_ovr(false);
17 });
18}
9 19
10/// Default VREF voltage used for sample conversion to millivolts. 20/// Default VREF voltage used for sample conversion to millivolts.
11pub const VREF_DEFAULT_MV: u32 = 3300; 21pub const VREF_DEFAULT_MV: u32 = 3300;
12/// VREF voltage used for factory calibration of VREFINTCAL register. 22/// VREF voltage used for factory calibration of VREFINTCAL register.
13pub const VREF_CALIB_MV: u32 = 3300; 23pub const VREF_CALIB_MV: u32 = 3300;
14 24
15pub struct VrefInt; 25impl super::VrefConverter for crate::peripherals::ADC1 {
16impl AdcChannel<ADC1> for VrefInt {} 26 const CHANNEL: u8 = 17;
17impl super::SealedAdcChannel<ADC1> for VrefInt { 27}
18 fn channel(&self) -> u8 { 28
19 17 29#[cfg(any(stm32f2, stm32f40x, stm32f41x))]
20 } 30impl super::TemperatureConverter for crate::peripherals::ADC1 {
31 const CHANNEL: u8 = 16;
32}
33
34#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))]
35impl super::TemperatureConverter for crate::peripherals::ADC1 {
36 const CHANNEL: u8 = 18;
37}
38
39impl super::VBatConverter for crate::peripherals::ADC1 {
40 const CHANNEL: u8 = 18;
21} 41}
22 42
23impl VrefInt { 43impl VrefInt {
@@ -27,20 +47,6 @@ impl VrefInt {
27 } 47 }
28} 48}
29 49
30pub struct Temperature;
31impl AdcChannel<ADC1> for Temperature {}
32impl super::SealedAdcChannel<ADC1> for Temperature {
33 fn channel(&self) -> u8 {
34 cfg_if::cfg_if! {
35 if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] {
36 16
37 } else {
38 18
39 }
40 }
41 }
42}
43
44impl Temperature { 50impl Temperature {
45 /// Time needed for temperature sensor readings to stabilize 51 /// Time needed for temperature sensor readings to stabilize
46 pub fn start_time_us() -> u32 { 52 pub fn start_time_us() -> u32 {
@@ -48,14 +54,6 @@ impl Temperature {
48 } 54 }
49} 55}
50 56
51pub struct Vbat;
52impl AdcChannel<ADC1> for Vbat {}
53impl super::SealedAdcChannel<ADC1> for Vbat {
54 fn channel(&self) -> u8 {
55 18
56 }
57}
58
59enum Prescaler { 57enum Prescaler {
60 Div2, 58 Div2,
61 Div4, 59 Div4,
@@ -106,18 +104,50 @@ where
106 104
107 blocking_delay_us(3); 105 blocking_delay_us(3);
108 106
109 Self { 107 Self { adc }
110 adc,
111 sample_time: SampleTime::from_bits(0),
112 }
113 } 108 }
114 109
115 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 110 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
116 self.sample_time = sample_time; 111 ///
112 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
113 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
114 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
115 ///
116 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
117 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
118 ///
119 /// [`read`]: #method.read
120 pub fn into_ring_buffered<'a>(
121 self,
122 dma: Peri<'d, impl RxDma<T>>,
123 dma_buf: &'d mut [u16],
124 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
125 ) -> RingBufferedAdc<'d, T> {
126 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
127
128 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| {
129 channel.setup();
130
131 (channel.channel, sample_time)
132 }));
133 compiler_fence(Ordering::SeqCst);
134
135 Self::setup_dma();
136
137 // Don't disable the clock
138 mem::forget(self);
139
140 RingBufferedAdc::new(dma, dma_buf)
117 } 141 }
118 142
119 pub fn set_resolution(&mut self, resolution: Resolution) { 143 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
120 T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); 144 channel.setup();
145
146 // Configure ADC
147 let channel = channel.channel();
148
149 Self::configure_sequence([(channel, sample_time)].into_iter());
150 Self::blocking_convert()
121 } 151 }
122 152
123 /// Enables internal voltage reference and returns [VrefInt], which can be used in 153 /// Enables internal voltage reference and returns [VrefInt], which can be used in
@@ -153,8 +183,27 @@ where
153 Vbat {} 183 Vbat {}
154 } 184 }
155 185
156 /// Perform a single conversion. 186 pub(super) fn start() {
157 fn convert(&mut self) -> u16 { 187 // Begin ADC conversions
188 T::regs().cr2().modify(|reg| {
189 reg.set_adon(true);
190 reg.set_swstart(true);
191 });
192 }
193
194 pub(super) fn stop() {
195 // Stop ADC
196 T::regs().cr2().modify(|reg| {
197 // Stop ADC
198 reg.set_swstart(false);
199 });
200 }
201
202 pub fn set_resolution(&mut self, resolution: Resolution) {
203 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
204 }
205
206 pub(super) fn blocking_convert() -> u16 {
158 // clear end of conversion flag 207 // clear end of conversion flag
159 T::regs().sr().modify(|reg| { 208 T::regs().sr().modify(|reg| {
160 reg.set_eoc(false); 209 reg.set_eoc(false);
@@ -175,28 +224,85 @@ where
175 T::regs().dr().read().0 as u16 224 T::regs().dr().read().0 as u16
176 } 225 }
177 226
178 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 227 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) {
179 channel.setup(); 228 T::regs().cr2().modify(|reg| {
229 reg.set_adon(true);
230 });
180 231
181 // Configure ADC 232 // Check the sequence is long enough
182 let channel = channel.channel(); 233 T::regs().sqr1().modify(|r| {
234 r.set_l((sequence.len() - 1).try_into().unwrap());
235 });
183 236
184 // Select channel 237 for (i, (ch, sample_time)) in sequence.enumerate() {
185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); 238 // Set the channel in the right sequence field.
239 T::regs().sqr3().modify(|w| w.set_sq(i, ch));
186 240
187 // Configure channel 241 let sample_time = sample_time.into();
188 Self::set_channel_sample_time(channel, self.sample_time); 242 if ch <= 9 {
243 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
244 } else {
245 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
246 }
247 }
248 }
249
250 pub(super) fn setup_dma() {
251 let r = T::regs();
252
253 // Clear all interrupts
254 r.sr().modify(|regs| {
255 regs.set_eoc(false);
256 regs.set_ovr(false);
257 regs.set_strt(false);
258 });
259
260 r.cr1().modify(|w| {
261 // Enable interrupt for end of conversion
262 w.set_eocie(true);
263 // Enable interrupt for overrun
264 w.set_ovrie(true);
265 // Scanning converisons of multiple channels
266 w.set_scan(true);
267 // Continuous conversion mode
268 w.set_discen(false);
269 });
189 270
190 self.convert() 271 r.cr2().modify(|w| {
272 // Enable DMA mode
273 w.set_dma(true);
274 // Enable continuous conversions
275 w.set_cont(true);
276 // DMA requests are issues as long as DMA=1 and data are converted.
277 w.set_dds(vals::Dds::CONTINUOUS);
278 // EOC flag is set at the end of each conversion.
279 w.set_eocs(vals::Eocs::EACH_CONVERSION);
280 });
191 } 281 }
192 282
193 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 283 pub(super) fn teardown_dma() {
194 let sample_time = sample_time.into(); 284 let r = T::regs();
195 if ch <= 9 { 285
196 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); 286 // Stop ADC
197 } else { 287 r.cr2().modify(|reg| {
198 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 288 // Stop ADC
199 } 289 reg.set_swstart(false);
290 // Stop ADC
291 reg.set_adon(false);
292 // Stop DMA
293 reg.set_dma(false);
294 });
295
296 r.cr1().modify(|w| {
297 // Disable interrupt for end of conversion
298 w.set_eocie(false);
299 // Disable interrupt for overrun
300 w.set_ovrie(false);
301 });
302
303 clear_interrupt_flags(r);
304
305 compiler_fence(Ordering::SeqCst);
200 } 306 }
201} 307}
202 308
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 16063ce4d..e816907d1 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -9,11 +9,21 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
9#[cfg(adc_g0)] 9#[cfg(adc_g0)]
10pub use pac::adc::vals::{Ovsr, Ovss, Presc}; 10pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12#[allow(unused_imports)]
13use super::SealedAdcChannel;
12use super::{ 14use super::{
13 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 15 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, Temperature, Vbat, VrefInt,
16 blocking_delay_us,
14}; 17};
18
19#[cfg(any(adc_v3, adc_g0, adc_u0))]
20mod ringbuffered;
21
22#[cfg(any(adc_v3, adc_g0, adc_u0))]
23use ringbuffered::RingBufferedAdc;
24
15use crate::dma::Transfer; 25use crate::dma::Transfer;
16use crate::{pac, rcc, Peri}; 26use crate::{Peri, pac, rcc};
17 27
18/// Default VREF voltage used for sample conversion to millivolts. 28/// Default VREF voltage used for sample conversion to millivolts.
19pub const VREF_DEFAULT_MV: u32 = 3300; 29pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,61 +35,55 @@ pub const VREF_CALIB_MV: u32 = 3000;
25// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable 35// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable
26const SAMPLE_TIMES_CAPACITY: usize = 2; 36const SAMPLE_TIMES_CAPACITY: usize = 2;
27 37
28pub struct VrefInt; 38#[cfg(adc_g0)]
29impl<T: Instance> AdcChannel<T> for VrefInt {} 39impl<T: Instance> super::VrefConverter for T {
30impl<T: Instance> SealedAdcChannel<T> for VrefInt { 40 const CHANNEL: u8 = 13;
31 fn channel(&self) -> u8 { 41}
32 cfg_if! { 42#[cfg(any(adc_h5, adc_h7rs))]
33 if #[cfg(adc_g0)] { 43impl<T: Instance> super::VrefConverter for T {
34 let val = 13; 44 const CHANNEL: u8 = 17;
35 } else if #[cfg(any(adc_h5, adc_h7rs))] { 45}
36 let val = 17; 46#[cfg(adc_u0)]
37 } else if #[cfg(adc_u0)] { 47impl<T: Instance> super::VrefConverter for T {
38 let val = 12; 48 const CHANNEL: u8 = 12;
39 } else { 49}
40 let val = 0; 50#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
41 } 51impl<T: Instance> super::VrefConverter for T {
42 } 52 const CHANNEL: u8 = 0;
43 val
44 }
45} 53}
46 54
47pub struct Temperature; 55#[cfg(adc_g0)]
48impl<T: Instance> AdcChannel<T> for Temperature {} 56impl<T: Instance> super::TemperatureConverter for T {
49impl<T: Instance> SealedAdcChannel<T> for Temperature { 57 const CHANNEL: u8 = 12;
50 fn channel(&self) -> u8 { 58}
51 cfg_if! { 59#[cfg(any(adc_h5, adc_h7rs))]
52 if #[cfg(adc_g0)] { 60impl<T: Instance> super::TemperatureConverter for T {
53 let val = 12; 61 const CHANNEL: u8 = 16;
54 } else if #[cfg(any(adc_h5, adc_h7rs))] { 62}
55 let val = 16; 63#[cfg(adc_u0)]
56 } else if #[cfg(adc_u0)] { 64impl<T: Instance> super::TemperatureConverter for T {
57 let val = 11; 65 const CHANNEL: u8 = 11;
58 } else { 66}
59 let val = 17; 67#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
60 } 68impl<T: Instance> super::TemperatureConverter for T {
61 } 69 const CHANNEL: u8 = 17;
62 val
63 }
64} 70}
65 71
66pub struct Vbat; 72#[cfg(adc_g0)]
67impl<T: Instance> AdcChannel<T> for Vbat {} 73impl<T: Instance> super::VBatConverter for T {
68impl<T: Instance> SealedAdcChannel<T> for Vbat { 74 const CHANNEL: u8 = 14;
69 fn channel(&self) -> u8 { 75}
70 cfg_if! { 76#[cfg(any(adc_h5, adc_h7rs))]
71 if #[cfg(adc_g0)] { 77impl<T: Instance> super::VBatConverter for T {
72 let val = 14; 78 const CHANNEL: u8 = 2;
73 } else if #[cfg(any(adc_h5, adc_h7rs))] { 79}
74 let val = 2; 80#[cfg(adc_u0)]
75 } else if #[cfg(any(adc_h5, adc_h7rs))] { 81impl<T: Instance> super::VBatConverter for T {
76 let val = 13; 82 const CHANNEL: u8 = 13;
77 } else { 83}
78 let val = 18; 84#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
79 } 85impl<T: Instance> super::VBatConverter for T {
80 } 86 const CHANNEL: u8 = 18;
81 val
82 }
83} 87}
84 88
85cfg_if! { 89cfg_if! {
@@ -174,15 +178,44 @@ impl<'d, T: Instance> Adc<'d, T> {
174 blocking_delay_us(1); 178 blocking_delay_us(1);
175 } 179 }
176 180
181 #[cfg(any(adc_v3, adc_g0, adc_u0))]
182 pub(super) fn start() {
183 // Start adc conversion
184 T::regs().cr().modify(|reg| {
185 reg.set_adstart(true);
186 });
187 }
188
189 #[cfg(any(adc_v3, adc_g0, adc_u0))]
190 pub(super) fn stop() {
191 // Stop adc conversion
192 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
193 T::regs().cr().modify(|reg| {
194 reg.set_adstp(true);
195 });
196 while T::regs().cr().read().adstart() {}
197 }
198 }
199
200 #[cfg(any(adc_v3, adc_g0, adc_u0))]
201 pub(super) fn teardown_dma() {
202 //disable dma control
203 #[cfg(not(any(adc_g0, adc_u0)))]
204 T::regs().cfgr().modify(|reg| {
205 reg.set_dmaen(false);
206 });
207 #[cfg(any(adc_g0, adc_u0))]
208 T::regs().cfgr1().modify(|reg| {
209 reg.set_dmaen(false);
210 });
211 }
212
177 /// Initialize the ADC leaving any analog clock at reset value. 213 /// Initialize the ADC leaving any analog clock at reset value.
178 /// For G0 and WL, this is the async clock without prescaler. 214 /// For G0 and WL, this is the async clock without prescaler.
179 pub fn new(adc: Peri<'d, T>) -> Self { 215 pub fn new(adc: Peri<'d, T>) -> Self {
180 Self::init_regulator(); 216 Self::init_regulator();
181 Self::init_calibrate(); 217 Self::init_calibrate();
182 Self { 218 Self { adc }
183 adc,
184 sample_time: SampleTime::from_bits(0),
185 }
186 } 219 }
187 220
188 #[cfg(adc_g0)] 221 #[cfg(adc_g0)]
@@ -218,10 +251,7 @@ impl<'d, T: Instance> Adc<'d, T> {
218 251
219 Self::init_calibrate(); 252 Self::init_calibrate();
220 253
221 Self { 254 Self { adc }
222 adc,
223 sample_time: SampleTime::from_bits(0),
224 }
225 } 255 }
226 256
227 // Enable ADC only when it is not already running. 257 // Enable ADC only when it is not already running.
@@ -303,16 +333,6 @@ impl<'d, T: Instance> Adc<'d, T> {
303 Vbat {} 333 Vbat {}
304 } 334 }
305 335
306 /// Set the ADC sample time.
307 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
308 self.sample_time = sample_time;
309 }
310
311 /// Get the ADC sample time.
312 pub fn sample_time(&self) -> SampleTime {
313 self.sample_time
314 }
315
316 /// Set the ADC resolution. 336 /// Set the ADC resolution.
317 pub fn set_resolution(&mut self, resolution: Resolution) { 337 pub fn set_resolution(&mut self, resolution: Resolution) {
318 #[cfg(not(any(adc_g0, adc_u0)))] 338 #[cfg(not(any(adc_g0, adc_u0)))]
@@ -374,8 +394,8 @@ impl<'d, T: Instance> Adc<'d, T> {
374 } 394 }
375 395
376 /// Read an ADC channel. 396 /// Read an ADC channel.
377 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 397 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
378 self.read_channel(channel) 398 self.read_channel(channel, sample_time)
379 } 399 }
380 400
381 /// Read one or multiple ADC channels using DMA. 401 /// Read one or multiple ADC channels using DMA.
@@ -423,6 +443,9 @@ impl<'d, T: Instance> Adc<'d, T> {
423 "Asynchronous read sequence cannot be more than 16 in length" 443 "Asynchronous read sequence cannot be more than 16 in length"
424 ); 444 );
425 445
446 #[cfg(all(feature = "low-power", stm32wlex))]
447 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
448
426 // Ensure no conversions are ongoing and ADC is enabled. 449 // Ensure no conversions are ongoing and ADC is enabled.
427 Self::cancel_conversions(); 450 Self::cancel_conversions();
428 self.enable(); 451 self.enable();
@@ -559,6 +582,137 @@ impl<'d, T: Instance> Adc<'d, T> {
559 }); 582 });
560 } 583 }
561 584
585 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
586 ///
587 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
588 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
589 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
590 ///
591 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
592 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
593 ///
594 /// [`read`]: #method.read
595 #[cfg(any(adc_v3, adc_g0, adc_u0))]
596 pub fn into_ring_buffered<'a>(
597 &mut self,
598 dma: Peri<'a, impl RxDma<T>>,
599 dma_buf: &'a mut [u16],
600 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
601 ) -> RingBufferedAdc<'a, T> {
602 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
603 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
604 assert!(
605 sequence.len() <= 16,
606 "Asynchronous read sequence cannot be more than 16 in length"
607 );
608 // reset conversions and enable the adc
609 Self::cancel_conversions();
610 self.enable();
611
612 //adc side setup
613
614 // Set sequence length
615 #[cfg(not(any(adc_g0, adc_u0)))]
616 T::regs().sqr1().modify(|w| {
617 w.set_l(sequence.len() as u8 - 1);
618 });
619
620 #[cfg(adc_g0)]
621 {
622 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new();
623
624 T::regs().chselr().write(|chselr| {
625 T::regs().smpr().write(|smpr| {
626 for (channel, sample_time) in sequence {
627 chselr.set_chsel(channel.channel.into(), true);
628 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
629 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
630 } else {
631 smpr.set_sample_time(sample_times.len(), sample_time);
632 if let Err(_) = sample_times.push(sample_time) {
633 panic!(
634 "Implementation is limited to {} unique sample times among all channels.",
635 SAMPLE_TIMES_CAPACITY
636 );
637 }
638 }
639 }
640 })
641 });
642 }
643 #[cfg(not(adc_g0))]
644 {
645 #[cfg(adc_u0)]
646 let mut channel_mask = 0;
647
648 // Configure channels and ranks
649 for (_i, (mut channel, sample_time)) in sequence.enumerate() {
650 Self::configure_channel(&mut channel, sample_time);
651
652 // Each channel is sampled according to sequence
653 #[cfg(not(any(adc_g0, adc_u0)))]
654 match _i {
655 0..=3 => {
656 T::regs().sqr1().modify(|w| {
657 w.set_sq(_i, channel.channel());
658 });
659 }
660 4..=8 => {
661 T::regs().sqr2().modify(|w| {
662 w.set_sq(_i - 4, channel.channel());
663 });
664 }
665 9..=13 => {
666 T::regs().sqr3().modify(|w| {
667 w.set_sq(_i - 9, channel.channel());
668 });
669 }
670 14..=15 => {
671 T::regs().sqr4().modify(|w| {
672 w.set_sq(_i - 14, channel.channel());
673 });
674 }
675 _ => unreachable!(),
676 }
677
678 #[cfg(adc_u0)]
679 {
680 channel_mask |= 1 << channel.channel();
681 }
682 }
683
684 // On G0 and U0 enabled channels are sampled from 0 to last channel.
685 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
686 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
687 #[cfg(adc_u0)]
688 T::regs().chselr().modify(|reg| {
689 reg.set_chsel(channel_mask);
690 });
691 }
692 // Set continuous mode with Circular dma.
693 // Clear overrun flag before starting transfer.
694 T::regs().isr().modify(|reg| {
695 reg.set_ovr(true);
696 });
697
698 #[cfg(not(any(adc_g0, adc_u0)))]
699 T::regs().cfgr().modify(|reg| {
700 reg.set_discen(false);
701 reg.set_cont(true);
702 reg.set_dmacfg(Dmacfg::CIRCULAR);
703 reg.set_dmaen(true);
704 });
705 #[cfg(any(adc_g0, adc_u0))]
706 T::regs().cfgr1().modify(|reg| {
707 reg.set_discen(false);
708 reg.set_cont(true);
709 reg.set_dmacfg(Dmacfg::CIRCULAR);
710 reg.set_dmaen(true);
711 });
712
713 RingBufferedAdc::new(dma, dma_buf)
714 }
715
562 #[cfg(not(adc_g0))] 716 #[cfg(not(adc_g0))]
563 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 717 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
564 // RM0492, RM0481, etc. 718 // RM0492, RM0481, etc.
@@ -572,13 +726,13 @@ impl<'d, T: Instance> Adc<'d, T> {
572 Self::set_channel_sample_time(channel.channel(), sample_time); 726 Self::set_channel_sample_time(channel.channel(), sample_time);
573 } 727 }
574 728
575 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 729 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
576 self.enable(); 730 self.enable();
577 #[cfg(not(adc_g0))] 731 #[cfg(not(adc_g0))]
578 Self::configure_channel(channel, self.sample_time); 732 Self::configure_channel(channel, sample_time);
579 #[cfg(adc_g0)] 733 #[cfg(adc_g0)]
580 T::regs().smpr().write(|reg| { 734 T::regs().smpr().write(|reg| {
581 reg.set_sample_time(0, self.sample_time); 735 reg.set_sample_time(0, sample_time);
582 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); 736 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1);
583 }); 737 });
584 // Select channel 738 // Select channel
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index b66437e6e..2f7baf3bf 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -5,11 +5,12 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{ 7use super::{
8 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 8 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, Temperature, Vbat,
9 VrefInt, blocking_delay_us,
9}; 10};
10use crate::dma::Transfer; 11use crate::dma::Transfer;
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::{pac, rcc, Peri}; 13use crate::{Peri, pac, rcc};
13 14
14/// Default VREF voltage used for sample conversion to millivolts. 15/// Default VREF voltage used for sample conversion to millivolts.
15pub const VREF_DEFAULT_MV: u32 = 3300; 16pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,52 +26,40 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 26const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
26 27
27#[cfg(stm32g4)] 28#[cfg(stm32g4)]
28const VREF_CHANNEL: u8 = 18; 29impl<T: Instance> super::VrefConverter for T {
30 const CHANNEL: u8 = 18;
31}
29#[cfg(stm32g4)] 32#[cfg(stm32g4)]
30const TEMP_CHANNEL: u8 = 16; 33impl<T: Instance> super::TemperatureConverter for T {
34 const CHANNEL: u8 = 16;
35}
31 36
32#[cfg(stm32h7)] 37#[cfg(stm32h7)]
33const VREF_CHANNEL: u8 = 19; 38impl<T: Instance> super::VrefConverter for T {
39 const CHANNEL: u8 = 19;
40}
34#[cfg(stm32h7)] 41#[cfg(stm32h7)]
35const TEMP_CHANNEL: u8 = 18; 42impl<T: Instance> super::TemperatureConverter for T {
43 const CHANNEL: u8 = 18;
44}
36 45
37// TODO this should be 14 for H7a/b/35 46// TODO this should be 14 for H7a/b/35
38#[cfg(not(stm32u5))] 47#[cfg(not(stm32u5))]
39const VBAT_CHANNEL: u8 = 17; 48impl<T: Instance> super::VBatConverter for T {
49 const CHANNEL: u8 = 17;
50}
40 51
41#[cfg(stm32u5)] 52#[cfg(stm32u5)]
42const VREF_CHANNEL: u8 = 0; 53impl<T: Instance> super::VrefConverter for T {
43#[cfg(stm32u5)] 54 const CHANNEL: u8 = 0;
44const TEMP_CHANNEL: u8 = 19;
45#[cfg(stm32u5)]
46const VBAT_CHANNEL: u8 = 18;
47
48// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
49/// Internal voltage reference channel.
50pub struct VrefInt;
51impl<T: Instance> AdcChannel<T> for VrefInt {}
52impl<T: Instance> SealedAdcChannel<T> for VrefInt {
53 fn channel(&self) -> u8 {
54 VREF_CHANNEL
55 }
56} 55}
57 56#[cfg(stm32u5)]
58/// Internal temperature channel. 57impl<T: Instance> super::TemperatureConverter for T {
59pub struct Temperature; 58 const CHANNEL: u8 = 19;
60impl<T: Instance> AdcChannel<T> for Temperature {}
61impl<T: Instance> SealedAdcChannel<T> for Temperature {
62 fn channel(&self) -> u8 {
63 TEMP_CHANNEL
64 }
65} 59}
66 60#[cfg(stm32u5)]
67/// Internal battery voltage channel. 61impl<T: Instance> super::VBatConverter for T {
68pub struct Vbat; 62 const CHANNEL: u8 = 18;
69impl<T: Instance> AdcChannel<T> for Vbat {}
70impl<T: Instance> SealedAdcChannel<T> for Vbat {
71 fn channel(&self) -> u8 {
72 VBAT_CHANNEL
73 }
74} 63}
75 64
76// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 65// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
@@ -171,7 +160,10 @@ impl<'d, T: Instance> Adc<'d, T> {
171 info!("ADC frequency set to {}", frequency); 160 info!("ADC frequency set to {}", frequency);
172 161
173 if frequency > MAX_ADC_CLK_FREQ { 162 if frequency > MAX_ADC_CLK_FREQ {
174 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 163 panic!(
164 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
165 MAX_ADC_CLK_FREQ.0 / 1_000_000
166 );
175 } 167 }
176 168
177 #[cfg(stm32h7)] 169 #[cfg(stm32h7)]
@@ -187,10 +179,7 @@ impl<'d, T: Instance> Adc<'d, T> {
187 }; 179 };
188 T::regs().cr().modify(|w| w.set_boost(boost)); 180 T::regs().cr().modify(|w| w.set_boost(boost));
189 } 181 }
190 let mut s = Self { 182 let mut s = Self { adc };
191 adc,
192 sample_time: SampleTime::from_bits(0),
193 };
194 s.power_up(); 183 s.power_up();
195 s.configure_differential_inputs(); 184 s.configure_differential_inputs();
196 185
@@ -274,16 +263,6 @@ impl<'d, T: Instance> Adc<'d, T> {
274 Vbat {} 263 Vbat {}
275 } 264 }
276 265
277 /// Set the ADC sample time.
278 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
279 self.sample_time = sample_time;
280 }
281
282 /// Get the ADC sample time.
283 pub fn sample_time(&self) -> SampleTime {
284 self.sample_time
285 }
286
287 /// Set the ADC resolution. 266 /// Set the ADC resolution.
288 pub fn set_resolution(&mut self, resolution: Resolution) { 267 pub fn set_resolution(&mut self, resolution: Resolution) {
289 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 268 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
@@ -332,8 +311,8 @@ impl<'d, T: Instance> Adc<'d, T> {
332 } 311 }
333 312
334 /// Read an ADC channel. 313 /// Read an ADC channel.
335 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 314 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
336 self.read_channel(channel) 315 self.read_channel(channel, sample_time)
337 } 316 }
338 317
339 /// Read one or multiple ADC channels using DMA. 318 /// Read one or multiple ADC channels using DMA.
@@ -469,8 +448,8 @@ impl<'d, T: Instance> Adc<'d, T> {
469 } 448 }
470 } 449 }
471 450
472 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 451 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
473 Self::configure_channel(channel, self.sample_time); 452 Self::configure_channel(channel, sample_time);
474 453
475 T::regs().sqr1().modify(|reg| { 454 T::regs().sqr1().modify(|reg| {
476 reg.set_sq(0, channel.channel()); 455 reg.set_sq(0, channel.channel());
diff --git a/embassy-stm32/src/adc/watchdog_v1.rs b/embassy-stm32/src/adc/watchdog_v1.rs
index bbe8e1971..b12e0d333 100644
--- a/embassy-stm32/src/adc/watchdog_v1.rs
+++ b/embassy-stm32/src/adc/watchdog_v1.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::task::Poll; 2use core::task::Poll;
3 3
4use stm32_metapac::adc::vals::{Align, Awdsgl, Res}; 4use stm32_metapac::adc::vals::{Align, Awdsgl, Res, SampleTime};
5 5
6use crate::adc::{Adc, AdcChannel, Instance}; 6use crate::adc::{Adc, AdcChannel, Instance};
7 7
@@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
67 /// let v_high = adc.monitor_watchdog().await; 67 /// let v_high = adc.monitor_watchdog().await;
68 /// info!("ADC sample is high {}", v_high); 68 /// info!("ADC sample is high {}", v_high);
69 /// ``` 69 /// ```
70 pub async fn monitor_watchdog(&mut self) -> u16 { 70 pub async fn monitor_watchdog(&mut self, sample_time: SampleTime) -> u16 {
71 assert!( 71 assert!(
72 match T::regs().cfgr1().read().awdsgl() { 72 match T::regs().cfgr1().read().awdsgl() {
73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0, 73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0,
@@ -76,7 +76,7 @@ impl<'d, T: Instance> Adc<'d, T> {
76 "`set_channel` should be called before `monitor`", 76 "`set_channel` should be called before `monitor`",
77 ); 77 );
78 assert!(T::regs().chselr().read().0 != 0); 78 assert!(T::regs().chselr().read().0 != 0);
79 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); 79 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
80 Self::start_awd(); 80 Self::start_awd();
81 81
82 let sample = poll_fn(|cx| { 82 let sample = poll_fn(|cx| {
diff --git a/embassy-stm32/src/backup_sram.rs b/embassy-stm32/src/backup_sram.rs
new file mode 100644
index 000000000..31b373c6c
--- /dev/null
+++ b/embassy-stm32/src/backup_sram.rs
@@ -0,0 +1,28 @@
1//! Battary backed SRAM
2
3use core::slice;
4
5use embassy_hal_internal::Peri;
6
7use crate::_generated::{BKPSRAM_BASE, BKPSRAM_SIZE};
8use crate::peripherals::BKPSRAM;
9
10/// Struct used to initilize backup sram
11pub struct BackupMemory {}
12
13impl BackupMemory {
14 /// Setup battery backed sram
15 ///
16 /// Returns slice to sram and whether the sram was retained
17 pub fn new(_backup_sram: Peri<'static, BKPSRAM>) -> (&'static mut [u8], bool) {
18 // Assert bksram has been enabled in rcc
19 assert!(crate::pac::PWR.bdcr().read().bren() == crate::pac::pwr::vals::Retention::PRESERVED);
20
21 unsafe {
22 (
23 slice::from_raw_parts_mut(BKPSRAM_BASE as *mut u8, BKPSRAM_SIZE),
24 critical_section::with(|_| crate::rcc::BKSRAM_RETAINED),
25 )
26 }
27 }
28}
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 8eb188560..507350c42 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -5,8 +5,8 @@ use core::future::poll_fn;
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::PeripheralType; 8use embassy_hal_internal::PeripheralType;
9use embassy_hal_internal::interrupt::InterruptExt;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -22,7 +22,7 @@ use crate::can::enums::{BusError, RefCountOp, TryReadError};
22use crate::gpio::{AfType, OutputType, Pull, Speed}; 22use crate::gpio::{AfType, OutputType, Pull, Speed};
23use crate::interrupt::typelevel::Interrupt; 23use crate::interrupt::typelevel::Interrupt;
24use crate::rcc::{self, RccPeripheral}; 24use crate::rcc::{self, RccPeripheral};
25use crate::{interrupt, peripherals, Peri}; 25use crate::{Peri, interrupt, peripherals};
26 26
27/// Interrupt handler. 27/// Interrupt handler.
28pub struct TxInterruptHandler<T: Instance> { 28pub struct TxInterruptHandler<T: Instance> {
@@ -186,10 +186,10 @@ impl<'d> Can<'d> {
186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>, 186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>, 187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> 190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> 191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
192 + 'd, 192 + 'd,
193 ) -> Self { 193 ) -> Self {
194 let info = T::info(); 194 let info = T::info();
195 let regs = &T::info().regs; 195 let regs = &T::info().regs;
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index c6a66b469..4fe634ce4 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -1,7 +1,7 @@
1//! Configuration for FDCAN Module 1//! Configuration for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows 2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3 3
4use core::num::{NonZeroU16, NonZeroU8}; 4use core::num::{NonZeroU8, NonZeroU16};
5 5
6/// Configures the bit timings. 6/// Configures the bit timings.
7/// 7///
@@ -360,6 +360,8 @@ pub struct FdCanConfig {
360 pub global_filter: GlobalFilter, 360 pub global_filter: GlobalFilter,
361 /// TX buffer mode (FIFO or priority queue) 361 /// TX buffer mode (FIFO or priority queue)
362 pub tx_buffer_mode: TxBufferMode, 362 pub tx_buffer_mode: TxBufferMode,
363 /// Automatic recovery from bus off state
364 pub automatic_bus_off_recovery: bool,
363} 365}
364 366
365impl FdCanConfig { 367impl FdCanConfig {
@@ -456,6 +458,16 @@ impl FdCanConfig {
456 self.tx_buffer_mode = txbm; 458 self.tx_buffer_mode = txbm;
457 self 459 self
458 } 460 }
461
462 /// Enables or disables automatic recovery from bus off state
463 ///
464 /// Automatic recovery is performed by clearing the INIT bit in the CCCR register if
465 /// the BO bit is active in the IR register in the IT0 interrupt.
466 #[inline]
467 pub const fn set_automatic_bus_off_recovery(mut self, enabled: bool) -> Self {
468 self.automatic_bus_off_recovery = enabled;
469 self
470 }
459} 471}
460 472
461impl Default for FdCanConfig { 473impl Default for FdCanConfig {
@@ -474,6 +486,7 @@ impl Default for FdCanConfig {
474 timestamp_source: TimestampSource::None, 486 timestamp_source: TimestampSource::None,
475 global_filter: GlobalFilter::default(), 487 global_filter: GlobalFilter::default(),
476 tx_buffer_mode: TxBufferMode::Priority, 488 tx_buffer_mode: TxBufferMode::Priority,
489 automatic_bus_off_recovery: true,
477 } 490 }
478 } 491 }
479} 492}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index d8f71e03e..9883aff57 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -3,8 +3,8 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::interrupt::InterruptExt;
7use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::channel::Channel; 9use embassy_sync::channel::Channel;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
@@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers;
13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18pub(crate) mod fd; 18pub(crate) mod fd;
19 19
@@ -53,7 +53,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
53 regs.ir().write(|w| w.set_tefn(true)); 53 regs.ir().write(|w| w.set_tefn(true));
54 } 54 }
55 55
56 T::info().state.lock(|s| { 56 let recover_from_bo = T::info().state.lock(|s| {
57 let state = s.borrow_mut(); 57 let state = s.borrow_mut();
58 match &state.tx_mode { 58 match &state.tx_mode {
59 TxMode::NonBuffered(waker) => waker.wake(), 59 TxMode::NonBuffered(waker) => waker.wake(),
@@ -85,11 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
85 if ir.rfn(1) { 85 if ir.rfn(1) {
86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick); 86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
87 } 87 }
88
89 state.automatic_bus_off_recovery
88 }); 90 });
89 91
90 if ir.bo() { 92 if ir.bo() {
91 regs.ir().write(|w| w.set_bo(true)); 93 regs.ir().write(|w| w.set_bo(true));
92 if regs.psr().read().bo() { 94 if let Some(true) = recover_from_bo
95 && regs.psr().read().bo()
96 {
93 // Initiate bus-off recovery sequence by resetting CCCR.INIT 97 // Initiate bus-off recovery sequence by resetting CCCR.INIT
94 regs.cccr().modify(|w| w.set_init(false)); 98 regs.cccr().modify(|w| w.set_init(false));
95 } 99 }
@@ -182,8 +186,8 @@ impl<'d> CanConfigurator<'d> {
182 rx: Peri<'d, impl RxPin<T>>, 186 rx: Peri<'d, impl RxPin<T>>,
183 tx: Peri<'d, impl TxPin<T>>, 187 tx: Peri<'d, impl TxPin<T>>,
184 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
185 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
186 + 'd, 190 + 'd,
187 ) -> CanConfigurator<'d> { 191 ) -> CanConfigurator<'d> {
188 set_as_af!(rx, AfType::input(Pull::None)); 192 set_as_af!(rx, AfType::input(Pull::None));
189 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 193 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
@@ -263,7 +267,9 @@ impl<'d> CanConfigurator<'d> {
263 pub fn start(self, mode: OperatingMode) -> Can<'d> { 267 pub fn start(self, mode: OperatingMode) -> Can<'d> {
264 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); 268 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit);
265 self.info.state.lock(|s| { 269 self.info.state.lock(|s| {
266 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; 270 let mut state = s.borrow_mut();
271 state.ns_per_timer_tick = ns_per_timer_tick;
272 state.automatic_bus_off_recovery = Some(self.config.automatic_bus_off_recovery);
267 }); 273 });
268 self.info.regs.into_mode(self.config, mode); 274 self.info.regs.into_mode(self.config, mode);
269 Can { 275 Can {
@@ -459,7 +465,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
459 pub async fn write(&mut self, frame: Frame) { 465 pub async fn write(&mut self, frame: Frame) {
460 self.tx_buf.send(frame).await; 466 self.tx_buf.send(frame).await;
461 self.info.interrupt0.pend(); // Wake for Tx 467 self.info.interrupt0.pend(); // Wake for Tx
462 //T::IT0Interrupt::pend(); // Wake for Tx 468 //T::IT0Interrupt::pend(); // Wake for Tx
463 } 469 }
464 470
465 /// Async read frame from RX buffer. 471 /// Async read frame from RX buffer.
@@ -548,7 +554,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
548 pub async fn write(&mut self, frame: FdFrame) { 554 pub async fn write(&mut self, frame: FdFrame) {
549 self.tx_buf.send(frame).await; 555 self.tx_buf.send(frame).await;
550 self.info.interrupt0.pend(); // Wake for Tx 556 self.info.interrupt0.pend(); // Wake for Tx
551 //T::IT0Interrupt::pend(); // Wake for Tx 557 //T::IT0Interrupt::pend(); // Wake for Tx
552 } 558 }
553 559
554 /// Async read frame from RX buffer. 560 /// Async read frame from RX buffer.
@@ -861,7 +867,7 @@ struct State {
861 sender_instance_count: usize, 867 sender_instance_count: usize,
862 tx_pin_port: Option<u8>, 868 tx_pin_port: Option<u8>,
863 rx_pin_port: Option<u8>, 869 rx_pin_port: Option<u8>,
864 870 automatic_bus_off_recovery: Option<bool>, // controlled by CanConfigurator::start()
865 pub err_waker: AtomicWaker, 871 pub err_waker: AtomicWaker,
866} 872}
867 873
@@ -876,6 +882,7 @@ impl State {
876 sender_instance_count: 0, 882 sender_instance_count: 0,
877 tx_pin_port: None, 883 tx_pin_port: None,
878 rx_pin_port: None, 884 rx_pin_port: None,
885 automatic_bus_off_recovery: None,
879 } 886 }
880 } 887 }
881} 888}
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs
index fcdbbad62..6d7f0c16a 100644
--- a/embassy-stm32/src/can/util.rs
+++ b/embassy-stm32/src/can/util.rs
@@ -1,6 +1,6 @@
1//! Utility functions shared between CAN controller types. 1//! Utility functions shared between CAN controller types.
2 2
3use core::num::{NonZeroU16, NonZeroU8}; 3use core::num::{NonZeroU8, NonZeroU16};
4 4
5/// Shared struct to represent bit timings used by calc_can_timings. 5/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)] 6#[derive(Clone, Copy, Debug)]
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index 13e5263de..836228599 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -1,6 +1,6 @@
1use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::peripherals::CRC; 2use crate::peripherals::CRC;
3use crate::{rcc, Peri}; 3use crate::{Peri, rcc};
4 4
5/// CRC driver. 5/// CRC driver.
6pub struct Crc<'d> { 6pub struct Crc<'d> {
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index d834d0971..a566a2e04 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -1,7 +1,7 @@
1use crate::pac::crc::vals;
2use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::pac::crc::vals;
3use crate::peripherals::CRC; 3use crate::peripherals::CRC;
4use crate::{rcc, Peri}; 4use crate::{Peri, rcc};
5 5
6/// CRC driver. 6/// CRC driver.
7pub struct Crc<'d> { 7pub struct Crc<'d> {
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 0173b2b5d..4f1115fb7 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1236,7 +1236,10 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> {
1236 } 1236 }
1237 if C::REQUIRES_PADDING { 1237 if C::REQUIRES_PADDING {
1238 if last_block_remainder != 0 { 1238 if last_block_remainder != 0 {
1239 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1239 panic!(
1240 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1241 C::BLOCK_SIZE
1242 );
1240 } 1243 }
1241 } 1244 }
1242 if last_block { 1245 if last_block {
@@ -1703,7 +1706,10 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
1703 } 1706 }
1704 if C::REQUIRES_PADDING { 1707 if C::REQUIRES_PADDING {
1705 if last_block_remainder != 0 { 1708 if last_block_remainder != 0 {
1706 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1709 panic!(
1710 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1711 C::BLOCK_SIZE
1712 );
1707 } 1713 }
1708 } 1714 }
1709 if last_block { 1715 if last_block {
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 08e001337..d74d4a4be 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -8,7 +8,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode};
8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] 8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
9use crate::pac::dac; 9use crate::pac::dac;
10use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
11use crate::{peripherals, Peri}; 11use crate::{Peri, peripherals};
12 12
13mod tsel; 13mod tsel;
14use embassy_hal_internal::PeripheralType; 14use embassy_hal_internal::PeripheralType;
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index bd03f1e00..dcae9f298 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::{AfType, Pull}; 10use crate::gpio::{AfType, Pull};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
15pub struct InterruptHandler<T: Instance> { 15pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 73ecab070..90dbf4f09 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -1,6 +1,6 @@
1use core::future::{poll_fn, Future}; 1use core::future::{Future, poll_fn};
2use core::pin::Pin; 2use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering}; 3use core::sync::atomic::{AtomicUsize, Ordering, fence};
4use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
5 5
6use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 4a14c2a8e..3e117c331 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -2,7 +2,7 @@
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
5use core::sync::atomic::{fence, AtomicUsize, Ordering}; 5use core::sync::atomic::{AtomicUsize, Ordering, fence};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index 9ee52193b..94c597e0d 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -3,12 +3,12 @@
3//! FIXME: Add request_pause functionality? 3//! FIXME: Add request_pause functionality?
4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically). 4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically).
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::sync::atomic::{fence, Ordering}; 6use core::sync::atomic::{Ordering, fence};
7use core::task::Waker; 7use core::task::Waker;
8 8
9use embassy_hal_internal::Peri; 9use embassy_hal_internal::Peri;
10 10
11use super::{AnyChannel, TransferOptions, STATE}; 11use super::{AnyChannel, STATE, TransferOptions};
12use crate::dma::gpdma::linked_list::{RunMode, Table}; 12use crate::dma::gpdma::linked_list::{RunMode, Table};
13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
14use crate::dma::word::Word; 14use crate::dma::word::Word;
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 5989bfd7c..297fa3674 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -24,7 +24,7 @@ pub(crate) use util::*;
24pub(crate) mod ringbuffer; 24pub(crate) mod ringbuffer;
25pub mod word; 25pub mod word;
26 26
27use embassy_hal_internal::{impl_peripheral, PeripheralType}; 27use embassy_hal_internal::{PeripheralType, impl_peripheral};
28 28
29use crate::interrupt; 29use crate::interrupt;
30 30
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
index 661fb1728..eff5b4058 100644
--- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
@@ -2,7 +2,7 @@ use std::task::Waker;
2 2
3use proptest::prop_oneof; 3use proptest::prop_oneof;
4use proptest::strategy::{self, BoxedStrategy, Strategy as _}; 4use proptest::strategy::{self, BoxedStrategy, Strategy as _};
5use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; 5use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine};
6 6
7use super::*; 7use super::*;
8 8
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index deda956af..59a2cbcdb 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -7,7 +7,7 @@ use embassy_hal_internal::PeripheralType;
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral}; 9use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peri}; 10use crate::{Peri, peripherals};
11 11
12/// Performs a busy-wait delay for a specified number of microseconds. 12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) { 13pub fn blocking_delay_ms(ms: u32) {
@@ -121,17 +121,15 @@ impl<'d, T: Instance> DsiHost<'d, T> {
121 121
122 /// DCS or Generic short/long write command 122 /// DCS or Generic short/long write command
123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { 123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
124 assert!(data.len() > 0); 124 match data.len() {
125 125 0 => self.short_write(channel_id, PacketType::DcsShortPktWriteP0, address, 0),
126 if data.len() == 1 { 126 1 => self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]),
127 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) 127 _ => self.long_write(
128 } else {
129 self.long_write(
130 channel_id, 128 channel_id,
131 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... 129 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
132 address, 130 address,
133 data, 131 data,
134 ) 132 ),
135 } 133 }
136 } 134 }
137 135
diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs
index 1f39c8db5..a75ae0560 100644
--- a/embassy-stm32/src/dts/mod.rs
+++ b/embassy-stm32/src/dts/mod.rs
@@ -1,7 +1,7 @@
1//! Digital Temperature Sensor (DTS) 1//! Digital Temperature Sensor (DTS)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_hal_internal::Peri; 7use embassy_hal_internal::Peri;
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 5be1c9739..a77eb8719 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -4,7 +4,7 @@ mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{fence, Ordering}; 7use core::sync::atomic::{Ordering, fence};
8 8
9use embassy_hal_internal::Peri; 9use embassy_hal_internal::Peri;
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
@@ -190,7 +190,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
190 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping 190 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
191 w.set_fes(Fes::FES100); // fast ethernet speed 191 w.set_fes(Fes::FES100); // fast ethernet speed
192 w.set_dm(Dm::FULL_DUPLEX); // full duplex 192 w.set_dm(Dm::FULL_DUPLEX); // full duplex
193 // TODO: Carrier sense ? ECRSFD 193 // TODO: Carrier sense ? ECRSFD
194 }); 194 });
195 195
196 // Set the mac to pass all multicast packets 196 // Set the mac to pass all multicast packets
@@ -350,7 +350,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
350 } 350 }
351 351
352 #[cfg(any(eth_v1b, eth_v1c))] 352 #[cfg(any(eth_v1b, eth_v1c))]
353 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 353 config_pins!(
354 rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
355 );
354 356
355 let pins = Pins::Mii([ 357 let pins = Pins::Mii([
356 rx_clk.into(), 358 rx_clk.into(),
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 2a46c1895..6ade1f29c 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use stm32_metapac::eth::vals::{Rpd, Rps}; 3use stm32_metapac::eth::vals::{Rpd, Rps};
4use vcell::VolatileCell; 4use vcell::VolatileCell;
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs
index 1317d20f4..ba99b66cb 100644
--- a/embassy-stm32/src/eth/v1/tx_desc.rs
+++ b/embassy-stm32/src/eth/v1/tx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 645bfdb14..e335ed8f3 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{fence, Ordering}; 1use core::sync::atomic::{Ordering, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index cf7a9901b..39a6e8b0f 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,7 +1,7 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{Ordering, fence};
5 5
6use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 7use stm32_metapac::syscfg::vals::EthSelPhy;
@@ -144,7 +144,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); 144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII));
145 }); 145 });
146 146
147 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 147 config_pins!(
148 rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
149 );
148 150
149 let pins = Pins::Mii([ 151 let pins = Pins::Mii([
150 rx_clk.into(), 152 rx_clk.into(),
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index bc4ecd1cc..83e0ecf88 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -71,7 +71,7 @@ unsafe fn on_irq() {
71 } 71 }
72 72
73 #[cfg(feature = "low-power")] 73 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 74 crate::low_power::Executor::on_wakeup_irq();
75} 75}
76 76
77struct BitIter(u32); 77struct BitIter(u32);
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 006dcddeb..a131217b7 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,17 +1,17 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::mutex::Mutex; 6use embassy_sync::mutex::Mutex;
7 7
8use super::{ 8use super::{
9 blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, 9 Async, Error, FLASH_BASE, FLASH_SIZE, Flash, FlashLayout, WRITE_SIZE, blocking_read, ensure_sector_aligned, family,
10 FLASH_BASE, FLASH_SIZE, WRITE_SIZE, 10 get_flash_regions, get_sector,
11}; 11};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::peripherals::FLASH; 13use crate::peripherals::FLASH;
14use crate::{interrupt, Peri}; 14use crate::{Peri, interrupt};
15 15
16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
17 17
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 10023e637..b595938a6 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,14 +1,14 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5 5
6use super::{ 6use super::{
7 family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, 7 Async, Blocking, Error, FLASH_SIZE, FlashBank, FlashLayout, FlashRegion, FlashSector, MAX_ERASE_SIZE, READ_SIZE,
8 MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, 8 WRITE_SIZE, family, get_flash_regions,
9}; 9};
10use crate::Peri;
11use crate::_generated::FLASH_BASE; 10use crate::_generated::FLASH_BASE;
11use crate::Peri;
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13 13
14/// Internal flash memory driver. 14/// Internal flash memory driver.
diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs
index cc3529eb9..39c497e3f 100644
--- a/embassy-stm32/src/flash/eeprom.rs
+++ b/embassy-stm32/src/flash/eeprom.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::drop::OnDrop; 1use embassy_hal_internal::drop::OnDrop;
2 2
3use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; 3use super::{Blocking, EEPROM_BASE, EEPROM_SIZE, Error, Flash, family};
4 4
5#[cfg(eeprom)] 5#[cfg(eeprom)]
6impl<'d> Flash<'d, Blocking> { 6impl<'d> Flash<'d, Blocking> {
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 3f9dbe945..5c01fce9c 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index bf9ad2893..9e469ffbc 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
index 67e380619..b48ab3b76 100644
--- a/embassy-stm32/src/flash/f2.rs
+++ b/embassy-stm32/src/flash/f2.rs
@@ -1,9 +1,9 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use pac::flash::regs::Sr; 4use pac::flash::regs::Sr;
5 5
6use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 6use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 62e0492b5..9c5051492 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -1,10 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use embassy_sync::waitqueue::AtomicWaker; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr; 5use pac::flash::regs::Sr;
6 6
7use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 7use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
8use crate::_generated::FLASH_SIZE; 8use crate::_generated::FLASH_SIZE;
9use crate::flash::Error; 9use crate::flash::Error;
10use crate::pac; 10use crate::pac;
@@ -246,7 +246,9 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
246 feature = "stm32f439zi", 246 feature = "stm32f439zi",
247 ))] 247 ))]
248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
249 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); 249 panic!(
250 "Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"
251 );
250 } 252 }
251 253
252 #[cfg(any( 254 #[cfg(any(
@@ -270,14 +272,16 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
270 feature = "stm32f439zg", 272 feature = "stm32f439zg",
271 ))] 273 ))]
272 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 274 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
273 panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); 275 panic!(
276 "Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"
277 );
274 } 278 }
275} 279}
276 280
277#[allow(unused)] 281#[allow(unused)]
278fn pa12_is_output_pull_low() -> bool { 282fn pa12_is_output_pull_low() -> bool {
279 use pac::gpio::vals;
280 use pac::GPIOA; 283 use pac::GPIOA;
284 use pac::gpio::vals;
281 const PIN: usize = 12; 285 const PIN: usize = 12;
282 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 286 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
283 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN 287 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN
@@ -287,7 +291,7 @@ fn pa12_is_output_pull_low() -> bool {
287#[cfg(test)] 291#[cfg(test)]
288mod tests { 292mod tests {
289 use super::*; 293 use super::*;
290 use crate::flash::{get_sector, FlashBank}; 294 use crate::flash::{FlashBank, get_sector};
291 295
292 #[test] 296 #[test]
293 #[cfg(stm32f429)] 297 #[cfg(stm32f429)]
@@ -370,9 +374,13 @@ mod tests {
370#[cfg(all(bank_setup_configurable))] 374#[cfg(all(bank_setup_configurable))]
371pub(crate) fn check_bank_setup() { 375pub(crate) fn check_bank_setup() {
372 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { 376 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() {
373 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); 377 panic!(
378 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"
379 );
374 } 380 }
375 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { 381 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() {
376 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); 382 panic!(
383 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"
384 );
377 } 385 }
378} 386}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 0547c747a..09389c417 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -99,7 +99,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> {
99#[cfg(test)] 99#[cfg(test)]
100mod tests { 100mod tests {
101 use super::*; 101 use super::*;
102 use crate::flash::{get_sector, FlashBank}; 102 use crate::flash::{FlashBank, get_sector};
103 103
104 #[test] 104 #[test]
105 #[cfg(stm32f732)] 105 #[cfg(stm32f732)]
@@ -218,9 +218,13 @@ mod tests {
218#[cfg(all(bank_setup_configurable))] 218#[cfg(all(bank_setup_configurable))]
219pub(crate) fn check_bank_setup() { 219pub(crate) fn check_bank_setup() {
220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { 220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() {
221 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); 221 panic!(
222 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"
223 );
222 } 224 }
223 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { 225 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() {
224 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); 226 panic!(
227 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"
228 );
225 } 229 }
226} 230}
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index bc1fd360c..d026541a4 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
@@ -105,19 +105,27 @@ fn wait_busy() {
105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] 105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))]
106pub(crate) fn check_bank_setup() { 106pub(crate) fn check_bank_setup() {
107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
108 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 108 panic!(
109 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
110 );
109 } 111 }
110 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 112 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
111 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 113 panic!(
114 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
115 );
112 } 116 }
113} 117}
114 118
115#[cfg(all(bank_setup_configurable, flash_g0x1))] 119#[cfg(all(bank_setup_configurable, flash_g0x1))]
116pub(crate) fn check_bank_setup() { 120pub(crate) fn check_bank_setup() {
117 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { 121 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() {
118 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); 122 panic!(
123 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"
124 );
119 } 125 }
120 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { 126 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() {
121 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); 127 panic!(
128 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"
129 );
122 } 130 }
123} 131}
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
index fd9bfcc75..88f247879 100644
--- a/embassy-stm32/src/flash/h5.rs
+++ b/embassy-stm32/src/flash/h5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index f8e210556..91d5da4d6 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -1,7 +1,7 @@
1/// STM32H50 series flash impl. See RM0492 1/// STM32H50 series flash impl. See RM0492
2use core::{ 2use core::{
3 ptr::write_volatile, 3 ptr::write_volatile,
4 sync::atomic::{fence, Ordering}, 4 sync::atomic::{Ordering, fence},
5}; 5};
6 6
7use cortex_m::interrupt; 7use cortex_m::interrupt;
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index f1d84101c..8a43cce3f 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,7 +1,7 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 4use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 1b82704ec..b3281f2d5 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] 96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))]
97 { 97 {
98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
99 #[cfg(any(flash_l4, flash_l5))]
100 let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32;
99 101
100 #[cfg(flash_l4)] 102 #[cfg(flash_l4)]
101 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 103 let (idx, bank) = if idx > (pgn - 1) {
104 (idx - pgn, true)
105 } else {
106 (idx, false)
107 };
102 108
103 #[cfg(flash_l5)] 109 #[cfg(flash_l5)]
104 let (idx, bank) = if pac::FLASH.optr().read().dbank() { 110 let (idx, bank) = if pac::FLASH.optr().read().dbank() {
105 if idx > 255 { 111 if idx > (pgn - 1) {
106 (idx - 256, Some(true)) 112 (idx - pgn, Some(true))
107 } else { 113 } else {
108 (idx, Some(false)) 114 (idx, Some(false))
109 } 115 }
@@ -234,19 +240,27 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
234#[cfg(all(bank_setup_configurable, flash_l5))] 240#[cfg(all(bank_setup_configurable, flash_l5))]
235pub(crate) fn check_bank_setup() { 241pub(crate) fn check_bank_setup() {
236 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 242 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
237 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 243 panic!(
244 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
245 );
238 } 246 }
239 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 247 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
240 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 248 panic!(
249 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
250 );
241 } 251 }
242} 252}
243 253
244#[cfg(all(bank_setup_configurable, flash_l4))] 254#[cfg(all(bank_setup_configurable, flash_l4))]
245pub(crate) fn check_bank_setup() { 255pub(crate) fn check_bank_setup() {
246 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { 256 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() {
247 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); 257 panic!(
258 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"
259 );
248 } 260 }
249 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { 261 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() {
250 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); 262 panic!(
263 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"
264 );
251 } 265 }
252} 266}
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
index 68d847eca..a64f6c492 100644
--- a/embassy-stm32/src/flash/u0.rs
+++ b/embassy-stm32/src/flash/u0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 6c3d4b422..5f1f562c0 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashBank, FlashSector, WRITE_SIZE}; 4use super::{FlashBank, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index ff18a8bee..a7c6c90bb 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::gpio::{AfType, OutputType, Pull, Speed}; 6use crate::gpio::{AfType, OutputType, Pull, Speed};
7use crate::{rcc, Peri}; 7use crate::{Peri, rcc};
8 8
9/// FMC driver 9/// FMC driver
10pub struct Fmc<'d, T: Instance> { 10pub struct Fmc<'d, T: Instance> {
@@ -236,6 +236,42 @@ impl<'d, T: Instance> Fmc<'d, T> {
236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) 236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
237 ] 237 ]
238 )); 238 ));
239
240 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank1: (
241 bank: stm32_fmc::SdramTargetBank::Bank1,
242 addr: [
243 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
244 ],
245 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
246 d: [
247 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
248 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
249 ],
250 nbl: [
251 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
252 ],
253 ctrl: [
254 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
255 ]
256 ));
257
258 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank2: (
259 bank: stm32_fmc::SdramTargetBank::Bank2,
260 addr: [
261 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
262 ],
263 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
264 d: [
265 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
266 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
267 ],
268 nbl: [
269 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
270 ],
271 ctrl: [
272 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
273 ]
274 ));
239} 275}
240 276
241trait SealedInstance: crate::rcc::RccPeripheral { 277trait SealedInstance: crate::rcc::RccPeripheral {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 5645f71cb..1813a887b 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -4,7 +4,7 @@
4use core::convert::Infallible; 4use core::convert::Infallible;
5 5
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; 7use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral};
8 8
9use crate::pac::gpio::{self, vals}; 9use crate::pac::gpio::{self, vals};
10use crate::peripherals; 10use crate::peripherals;
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 90c06c0d8..ba573267c 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt;
19use crate::mode::Async; 19use crate::mode::Async;
20use crate::mode::{Blocking, Mode}; 20use crate::mode::{Blocking, Mode};
21use crate::peripherals::HASH; 21use crate::peripherals::HASH;
22use crate::{interrupt, pac, peripherals, rcc, Peri}; 22use crate::{Peri, interrupt, pac, peripherals, rcc};
23 23
24#[cfg(hash_v1)] 24#[cfg(hash_v1)]
25const NUM_CONTEXT_REGS: usize = 51; 25const NUM_CONTEXT_REGS: usize = 51;
@@ -514,11 +514,7 @@ impl<'d, T: Instance> Hash<'d, T, Async> {
514 T::regs().imr().modify(|reg| reg.set_dcie(true)); 514 T::regs().imr().modify(|reg| reg.set_dcie(true));
515 // Check for completion. 515 // Check for completion.
516 let bits = T::regs().sr().read(); 516 let bits = T::regs().sr().read();
517 if bits.dcis() { 517 if bits.dcis() { Poll::Ready(()) } else { Poll::Pending }
518 Poll::Ready(())
519 } else {
520 Poll::Pending
521 }
522 }) 518 })
523 .await; 519 .await;
524 520
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6fece5eb2..6c6807479 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,6 +10,7 @@ pub use traits::Instance;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc; 11use crate::rcc;
12use crate::time::Hertz; 12use crate::time::Hertz;
13pub use crate::timer::simple_pwm::PwmPinConfig;
13 14
14/// HRTIM burst controller instance. 15/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 16pub struct BurstController<T: Instance> {
@@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
73} 74}
74 75
75macro_rules! advanced_channel_impl { 76macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 77 ($new_chx:ident, $new_chx_with_config:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 78 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 79 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 80 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
@@ -86,6 +87,21 @@ macro_rules! advanced_channel_impl {
86 phantom: PhantomData, 87 phantom: PhantomData,
87 } 88 }
88 } 89 }
90
91 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with a specific configuration.")]
92 pub fn $new_chx_with_config(
93 pin: Peri<'d, impl $pin_trait<T>>,
94 pin_config: PwmPinConfig,
95 ) -> Self {
96 critical_section::with(|_| {
97 pin.set_low();
98 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
99 });
100 PwmPin {
101 _pin: pin.into(),
102 phantom: PhantomData,
103 }
104 }
89 } 105 }
90 106
91 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 107 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
@@ -100,6 +116,21 @@ macro_rules! advanced_channel_impl {
100 phantom: PhantomData, 116 phantom: PhantomData,
101 } 117 }
102 } 118 }
119
120 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance with a specific configuration.")]
121 pub fn $new_chx_with_config(
122 pin: Peri<'d, impl $complementary_pin_trait<T>>,
123 pin_config: PwmPinConfig,
124 ) -> Self {
125 critical_section::with(|_| {
126 pin.set_low();
127 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
128 });
129 ComplementaryPwmPin {
130 _pin: pin.into(),
131 phantom: PhantomData,
132 }
133 }
103 } 134 }
104 135
105 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { 136 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> {
@@ -111,13 +142,55 @@ macro_rules! advanced_channel_impl {
111 }; 142 };
112} 143}
113 144
114advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); 145advanced_channel_impl!(
115advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); 146 new_cha,
116advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); 147 new_cha_with_config,
117advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); 148 ChA,
118advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); 149 0,
150 ChannelAPin,
151 ChannelAComplementaryPin
152);
153advanced_channel_impl!(
154 new_chb,
155 new_chb_with_config,
156 ChB,
157 1,
158 ChannelBPin,
159 ChannelBComplementaryPin
160);
161advanced_channel_impl!(
162 new_chc,
163 new_chc_with_config,
164 ChC,
165 2,
166 ChannelCPin,
167 ChannelCComplementaryPin
168);
169advanced_channel_impl!(
170 new_chd,
171 new_chd_with_config,
172 ChD,
173 3,
174 ChannelDPin,
175 ChannelDComplementaryPin
176);
177advanced_channel_impl!(
178 new_che,
179 new_che_with_config,
180 ChE,
181 4,
182 ChannelEPin,
183 ChannelEComplementaryPin
184);
119#[cfg(hrtim_v2)] 185#[cfg(hrtim_v2)]
120advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); 186advanced_channel_impl!(
187 new_chf,
188 new_chf_with_config,
189 ChF,
190 5,
191 ChannelFPin,
192 ChannelFComplementaryPin
193);
121 194
122/// Struct used to divide a high resolution timer into multiple channels 195/// Struct used to divide a high resolution timer into multiple channels
123pub struct AdvancedPwm<'d, T: Instance> { 196pub struct AdvancedPwm<'d, T: Instance> {
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index 573a1851d..4d3a5d68d 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -2,13 +2,13 @@
2 2
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::pac;
6use crate::rcc::{self, RccPeripheral};
7// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. 5// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs.
8// Those MCUs have a different HSEM implementation (Secure semaphore lock support, 6// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
9// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), 7// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
10// which is not yet supported by this code. 8// which is not yet supported by this code.
11use crate::Peri; 9use crate::Peri;
10use crate::pac;
11use crate::rcc::{self, RccPeripheral};
12 12
13/// HSEM error. 13/// HSEM error.
14#[derive(Debug)] 14#[derive(Debug)]
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 95d9e5099..69baa708e 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -16,7 +16,7 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
16use embassy_hal_internal::{Peri, PeripheralType}; 16use embassy_hal_internal::{Peri, PeripheralType};
17pub use enums::*; 17pub use enums::*;
18 18
19use crate::dma::{word, ChannelAndRequest}; 19use crate::dma::{ChannelAndRequest, word};
20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
21use crate::mode::{Async, Blocking, Mode as PeriMode}; 21use crate::mode::{Async, Blocking, Mode as PeriMode};
22use crate::pac::hspi::Hspi as Regs; 22use crate::pac::hspi::Hspi as Regs;
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs
index 4e3b736c7..74fac14b2 100644
--- a/embassy-stm32/src/i2c/config.rs
+++ b/embassy-stm32/src/i2c/config.rs
@@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz; 4use crate::time::Hertz;
5 5
6#[repr(u8)] 6#[repr(u8)]
7#[derive(Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out. 9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask { 10pub enum AddrMask {
@@ -60,7 +60,7 @@ impl Address {
60 } 60 }
61} 61}
62 62
63#[derive(Copy, Clone)] 63#[derive(Debug, Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register. 65/// The second Own Address register.
66pub struct OA2 { 66pub struct OA2 {
@@ -70,7 +70,7 @@ pub struct OA2 {
70 pub mask: AddrMask, 70 pub mask: AddrMask,
71} 71}
72 72
73#[derive(Copy, Clone)] 73#[derive(Debug, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral. 75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses { 76pub enum OwnAddresses {
@@ -88,7 +88,7 @@ pub enum OwnAddresses {
88} 88}
89 89
90/// Slave Configuration 90/// Slave Configuration
91#[derive(Copy, Clone)] 91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))] 92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig { 93pub struct SlaveAddrConfig {
94 /// Target Address(es) 94 /// Target Address(es)
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 249bac41c..ee60c3f44 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> {
154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>, 154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>, 155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
158 + 'd, 158 + 'd,
159 tx_dma: Peri<'d, impl TxDma<T>>, 159 tx_dma: Peri<'d, impl TxDma<T>>,
160 rx_dma: Peri<'d, impl RxDma<T>>, 160 rx_dma: Peri<'d, impl RxDma<T>>,
161 config: Config, 161 config: Config,
@@ -219,6 +219,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 081eb1191..128a58db7 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -8,7 +8,7 @@ use core::future::poll_fn;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{Either, select};
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation; 13use embedded_hal_1::i2c::Operation;
14use mode::Master; 14use mode::Master;
@@ -30,6 +30,7 @@ use crate::pac::i2c;
30// hit a case like this! 30// hit a case like this!
31pub unsafe fn on_interrupt<T: Instance>() { 31pub unsafe fn on_interrupt<T: Instance>() {
32 let regs = T::info().regs; 32 let regs = T::info().regs;
33 trace!("I2C interrupt triggered");
33 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 34 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
34 // other stuff, so we wake the task on every interrupt. 35 // other stuff, so we wake the task on every interrupt.
35 T::state().waker.wake(); 36 T::state().waker.wake();
@@ -92,6 +93,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
92 self.info.regs.cr1().modify(|reg| { 93 self.info.regs.cr1().modify(|reg| {
93 reg.set_pe(true); 94 reg.set_pe(true);
94 }); 95 });
96 trace!("i2c v1 init complete");
95 } 97 }
96 98
97 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> { 99 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
@@ -151,7 +153,13 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
151 Ok(sr1) 153 Ok(sr1)
152 } 154 }
153 155
154 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { 156 fn write_bytes(
157 &mut self,
158 address: u8,
159 write_buffer: &[u8],
160 timeout: Timeout,
161 frame: FrameOptions,
162 ) -> Result<(), Error> {
155 if frame.send_start() { 163 if frame.send_start() {
156 // Send a START condition 164 // Send a START condition
157 165
@@ -170,7 +178,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
170 } 178 }
171 179
172 // Set up current address we're trying to talk to 180 // Set up current address we're trying to talk to
173 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); 181 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
174 182
175 // Wait until address was sent 183 // Wait until address was sent
176 // Wait for the address to be acknowledged 184 // Wait for the address to be acknowledged
@@ -184,7 +192,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
184 } 192 }
185 193
186 // Send bytes 194 // Send bytes
187 for c in bytes { 195 for c in write_buffer {
188 self.send_byte(*c, timeout)?; 196 self.send_byte(*c, timeout)?;
189 } 197 }
190 198
@@ -236,12 +244,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
236 244
237 fn blocking_read_timeout( 245 fn blocking_read_timeout(
238 &mut self, 246 &mut self,
239 addr: u8, 247 address: u8,
240 buffer: &mut [u8], 248 read_buffer: &mut [u8],
241 timeout: Timeout, 249 timeout: Timeout,
242 frame: FrameOptions, 250 frame: FrameOptions,
243 ) -> Result<(), Error> { 251 ) -> Result<(), Error> {
244 let Some((last, buffer)) = buffer.split_last_mut() else { 252 let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else {
245 return Err(Error::Overrun); 253 return Err(Error::Overrun);
246 }; 254 };
247 255
@@ -263,7 +271,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
263 } 271 }
264 272
265 // Set up current address we're trying to talk to 273 // Set up current address we're trying to talk to
266 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); 274 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
267 275
268 // Wait until address was sent 276 // Wait until address was sent
269 // Wait for the address to be acknowledged 277 // Wait for the address to be acknowledged
@@ -276,7 +284,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
276 } 284 }
277 285
278 // Receive bytes into buffer 286 // Receive bytes into buffer
279 for c in buffer { 287 for c in read_buffer {
280 *c = self.recv_byte(timeout)?; 288 *c = self.recv_byte(timeout)?;
281 } 289 }
282 290
@@ -291,37 +299,42 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
291 }); 299 });
292 300
293 // Receive last byte 301 // Receive last byte
294 *last = self.recv_byte(timeout)?; 302 *last_byte = self.recv_byte(timeout)?;
295 303
296 // Fallthrough is success 304 // Fallthrough is success
297 Ok(()) 305 Ok(())
298 } 306 }
299 307
300 /// Blocking read. 308 /// Blocking read.
301 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 309 pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
302 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) 310 self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)
303 } 311 }
304 312
305 /// Blocking write. 313 /// Blocking write.
306 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 314 pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
307 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; 315 self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?;
308 316
309 // Fallthrough is success 317 // Fallthrough is success
310 Ok(()) 318 Ok(())
311 } 319 }
312 320
313 /// Blocking write, restart, read. 321 /// Blocking write, restart, read.
314 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write_read(
323 &mut self,
324 address: u8,
325 write_buffer: &[u8],
326 read_buffer: &mut [u8],
327 ) -> Result<(), Error> {
315 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 328 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
316 // stop condition below. 329 // stop condition below.
317 if read.is_empty() { 330 if read_buffer.is_empty() {
318 return Err(Error::Overrun); 331 return Err(Error::Overrun);
319 } 332 }
320 333
321 let timeout = self.timeout(); 334 let timeout = self.timeout();
322 335
323 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; 336 self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?;
324 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; 337 self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?;
325 338
326 Ok(()) 339 Ok(())
327 } 340 }
@@ -331,32 +344,43 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
331 /// Consecutive operations of same type are merged. See [transaction contract] for details. 344 /// Consecutive operations of same type are merged. See [transaction contract] for details.
332 /// 345 ///
333 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 346 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
334 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 347 pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
335 let timeout = self.timeout(); 348 let timeout = self.timeout();
336 349
337 for (op, frame) in operation_frames(operations)? { 350 for (op, frame) in operation_frames(operations)? {
338 match op { 351 match op {
339 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 352 Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?,
340 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 353 Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?,
341 } 354 }
342 } 355 }
343 356
344 Ok(()) 357 Ok(())
345 } 358 }
346 359
347 // Async 360 /// Can be used by both blocking and async implementations
348
349 #[inline] // pretty sure this should always be inlined 361 #[inline] // pretty sure this should always be inlined
350 fn enable_interrupts(info: &'static Info) -> () { 362 fn enable_interrupts(info: &'static Info) {
351 info.regs.cr2().modify(|w| { 363 // The interrupt handler disables interrupts globally, so we need to re-enable them
352 w.set_iterren(true); 364 // This must be done in a critical section to avoid races
353 w.set_itevten(true); 365 critical_section::with(|_| {
366 info.regs.cr2().modify(|w| {
367 w.set_iterren(true);
368 w.set_itevten(true);
369 });
354 }); 370 });
355 } 371 }
372
373 /// Can be used by both blocking and async implementations
374 fn clear_stop_flag(info: &'static Info) {
375 trace!("I2C slave: clearing STOPF flag (v1 sequence)");
376 // v1 requires: READ SR1 then WRITE CR1 to clear STOPF
377 let _ = info.regs.sr1().read();
378 info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF
379 }
356} 380}
357 381
358impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 382impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
359 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 383 async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> {
360 self.info.regs.cr2().modify(|w| { 384 self.info.regs.cr2().modify(|w| {
361 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 385 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
362 // reception. 386 // reception.
@@ -439,7 +463,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
439 // this address from the memory after each TxE event. 463 // this address from the memory after each TxE event.
440 let dst = self.info.regs.dr().as_ptr() as *mut u8; 464 let dst = self.info.regs.dr().as_ptr() as *mut u8;
441 465
442 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 466 self.tx_dma
467 .as_mut()
468 .unwrap()
469 .write(write_buffer, dst, Default::default())
443 }; 470 };
444 471
445 // Wait for bytes to be sent, or an error to occur. 472 // Wait for bytes to be sent, or an error to occur.
@@ -501,28 +528,28 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
501 } 528 }
502 529
503 /// Write. 530 /// Write.
504 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 531 pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
505 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 532 self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame)
506 .await?; 533 .await?;
507 534
508 Ok(()) 535 Ok(())
509 } 536 }
510 537
511 /// Read. 538 /// Read.
512 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 539 pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
513 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 540 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
514 .await?; 541 .await?;
515 542
516 Ok(()) 543 Ok(())
517 } 544 }
518 545
519 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { 546 async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
520 if buffer.is_empty() { 547 if read_buffer.is_empty() {
521 return Err(Error::Overrun); 548 return Err(Error::Overrun);
522 } 549 }
523 550
524 // Some branches below depend on whether the buffer contains only a single byte. 551 // Some branches below depend on whether the buffer contains only a single byte.
525 let single_byte = buffer.len() == 1; 552 let single_byte = read_buffer.len() == 1;
526 553
527 self.info.regs.cr2().modify(|w| { 554 self.info.regs.cr2().modify(|w| {
528 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 555 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
@@ -612,7 +639,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
612 self.info.regs.sr2().read(); 639 self.info.regs.sr2().read();
613 } else { 640 } else {
614 // Before starting reception of single byte (but without START condition, i.e. in case 641 // Before starting reception of single byte (but without START condition, i.e. in case
615 // of continued frame), program NACK to emit at end of this byte. 642 // of merged operations), program NACK to emit at end of this byte.
616 if frame.send_nack() && single_byte { 643 if frame.send_nack() && single_byte {
617 self.info.regs.cr1().modify(|w| { 644 self.info.regs.cr1().modify(|w| {
618 w.set_ack(false); 645 w.set_ack(false);
@@ -634,7 +661,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
634 // from this address from the memory after each RxE event. 661 // from this address from the memory after each RxE event.
635 let src = self.info.regs.dr().as_ptr() as *mut u8; 662 let src = self.info.regs.dr().as_ptr() as *mut u8;
636 663
637 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 664 self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default())
638 }; 665 };
639 666
640 // Wait for bytes to be received, or an error to occur. 667 // Wait for bytes to be received, or an error to occur.
@@ -673,15 +700,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
673 } 700 }
674 701
675 /// Write, restart, read. 702 /// Write, restart, read.
676 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 703 pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> {
677 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 704 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
678 // stop condition below. 705 // stop condition below.
679 if read.is_empty() { 706 if read_buffer.is_empty() {
680 return Err(Error::Overrun); 707 return Err(Error::Overrun);
681 } 708 }
682 709
683 self.write_frame(address, write, FrameOptions::FirstFrame).await?; 710 self.write_frame(address, write_buffer, FrameOptions::FirstFrame)
684 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await 711 .await?;
712 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
713 .await
685 } 714 }
686 715
687 /// Transaction with operations. 716 /// Transaction with operations.
@@ -689,11 +718,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
689 /// Consecutive operations of same type are merged. See [transaction contract] for details. 718 /// Consecutive operations of same type are merged. See [transaction contract] for details.
690 /// 719 ///
691 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 720 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
692 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 721 pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
693 for (op, frame) in operation_frames(operations)? { 722 for (op, frame) in operation_frames(operations)? {
694 match op { 723 match op {
695 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 724 Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?,
696 Operation::Write(write) => self.write_frame(addr, write, frame).await?, 725 Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?,
697 } 726 }
698 } 727 }
699 728
@@ -729,12 +758,956 @@ impl Duty {
729 } 758 }
730} 759}
731 760
761/// Result of attempting to send a byte in slave transmitter mode
762#[derive(Debug, PartialEq)]
763enum TransmitResult {
764 /// Byte sent and ACKed by master - continue transmission
765 Acknowledged,
766 /// Byte sent but NACKed by master - normal end of read transaction
767 NotAcknowledged,
768 /// STOP condition detected - master terminated transaction
769 Stopped,
770 /// RESTART condition detected - master starting new transaction
771 Restarted,
772}
773
774/// Result of attempting to receive a byte in slave receiver mode
775#[derive(Debug, PartialEq)]
776enum ReceiveResult {
777 /// Data byte successfully received
778 Data(u8),
779 /// STOP condition detected - end of write transaction
780 Stopped,
781 /// RESTART condition detected - master starting new transaction
782 Restarted,
783}
784
785/// Enumeration of slave transaction termination conditions
786#[derive(Debug, Clone, Copy, PartialEq)]
787#[cfg_attr(feature = "defmt", derive(defmt::Format))]
788enum SlaveTermination {
789 /// STOP condition received - normal end of transaction
790 Stop,
791 /// RESTART condition received - master starting new transaction
792 Restart,
793 /// NACK received - normal end of read transaction
794 Nack,
795}
796
797impl<'d, M: PeriMode> I2c<'d, M, Master> {
798 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
799 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
800 let mut slave = I2c {
801 info: self.info,
802 state: self.state,
803 kernel_clock: self.kernel_clock,
804 tx_dma: self.tx_dma.take(), // Use take() to move ownership
805 rx_dma: self.rx_dma.take(), // Use take() to move ownership
806 #[cfg(feature = "time")]
807 timeout: self.timeout,
808 _phantom: PhantomData,
809 _phantom2: PhantomData,
810 _drop_guard: self._drop_guard, // Move the drop guard
811 };
812 slave.init_slave(slave_addr_config);
813 slave
814 }
815}
816
817// Address configuration methods
818impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
819 /// Initialize slave mode with address configuration
820 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
821 trace!("I2C slave: initializing with config={:?}", config);
822
823 // Disable peripheral for configuration
824 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
825
826 // Configure slave addresses
827 self.apply_address_configuration(config);
828
829 // Enable peripheral with slave settings
830 self.info.regs.cr1().modify(|reg| {
831 reg.set_pe(true);
832 reg.set_ack(true); // Enable acknowledgment for slave mode
833 reg.set_nostretch(false); // Allow clock stretching for processing time
834 });
835
836 trace!("I2C slave: initialization complete");
837 }
838
839 /// Apply the complete address configuration for slave mode
840 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
841 match config.addr {
842 OwnAddresses::OA1(addr) => {
843 self.configure_primary_address(addr);
844 self.disable_secondary_address();
845 }
846 OwnAddresses::OA2(oa2) => {
847 self.configure_default_primary_address();
848 self.configure_secondary_address(oa2.addr); // v1 ignores mask
849 }
850 OwnAddresses::Both { oa1, oa2 } => {
851 self.configure_primary_address(oa1);
852 self.configure_secondary_address(oa2.addr); // v1 ignores mask
853 }
854 }
855
856 // Configure general call detection
857 if config.general_call {
858 self.info.regs.cr1().modify(|w| w.set_engc(true));
859 }
860 }
861
862 /// Configure the primary address (OA1) register
863 fn configure_primary_address(&mut self, addr: Address) {
864 match addr {
865 Address::SevenBit(addr) => {
866 self.info.regs.oar1().write(|reg| {
867 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
868 reg.set_add(hw_addr);
869 reg.set_addmode(i2c::vals::Addmode::BIT7);
870 });
871 }
872 Address::TenBit(addr) => {
873 self.info.regs.oar1().write(|reg| {
874 reg.set_add(addr);
875 reg.set_addmode(i2c::vals::Addmode::BIT10);
876 });
877 }
878 }
879
880 // Set required bit 14 as per reference manual
881 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
882 }
883
884 /// Configure the secondary address (OA2) register
885 fn configure_secondary_address(&mut self, addr: u8) {
886 self.info.regs.oar2().write(|reg| {
887 reg.set_add2(addr);
888 reg.set_endual(i2c::vals::Endual::DUAL);
889 });
890 }
891
892 /// Set a default primary address when using OA2-only mode
893 fn configure_default_primary_address(&mut self) {
894 self.info.regs.oar1().write(|reg| {
895 reg.set_add(0); // Reserved address, safe to use
896 reg.set_addmode(i2c::vals::Addmode::BIT7);
897 });
898 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
899 }
900
901 /// Disable secondary address when not needed
902 fn disable_secondary_address(&mut self) {
903 self.info.regs.oar2().write(|reg| {
904 reg.set_endual(i2c::vals::Endual::SINGLE);
905 });
906 }
907}
908
909impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> {
910 /// Listen for incoming I2C address match and return the command type
911 ///
912 /// This method blocks until the slave address is matched by a master.
913 /// Returns the command type (Read/Write) and the matched address.
914 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
915 trace!("I2C slave: starting blocking listen for address match");
916 let result = self.blocking_listen_with_timeout(self.timeout());
917 trace!("I2C slave: blocking listen complete, result={:?}", result);
918 result
919 }
920
921 /// Respond to a master read request by transmitting data
922 ///
923 /// Sends the provided data to the master. If the master requests more bytes
924 /// than available, padding bytes (0x00) are sent until the master terminates
925 /// the transaction with NACK.
926 ///
927 /// Returns the total number of bytes transmitted (including padding).
928 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
929 trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len());
930
931 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
932 trace!("I2C slave: zero-length read detected");
933 return Ok(zero_length_result);
934 }
935
936 let result = self.transmit_to_master(data, self.timeout());
937 trace!("I2C slave: blocking respond_to_read complete, result={:?}", result);
938 result
939 }
940
941 /// Respond to a master write request by receiving data
942 ///
943 /// Receives data from the master into the provided buffer. If the master
944 /// sends more bytes than the buffer can hold, excess bytes are acknowledged
945 /// but discarded.
946 ///
947 /// Returns the number of bytes stored in the buffer (not total received).
948 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
949 trace!(
950 "I2C slave: starting blocking respond_to_write, buffer_len={}",
951 buffer.len()
952 );
953 let result = self.receive_from_master(buffer, self.timeout());
954 trace!("I2C slave: blocking respond_to_write complete, result={:?}", result);
955 result
956 }
957
958 // Private implementation methods
959
960 /// Wait for address match and determine transaction type
961 fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
962 // Ensure interrupts are disabled for blocking operation
963 self.disable_i2c_interrupts();
964
965 // Wait for address match (ADDR flag)
966 loop {
967 let sr1 = Self::read_status_and_handle_errors(self.info)?;
968
969 if sr1.addr() {
970 // Address matched - read SR2 to get direction and clear ADDR flag
971 let sr2 = self.info.regs.sr2().read();
972 let direction = if sr2.tra() {
973 SlaveCommandKind::Read
974 } else {
975 SlaveCommandKind::Write
976 };
977
978 // Use the static method instead of the instance method
979 let matched_address = Self::decode_matched_address(sr2, self.info)?;
980 trace!(
981 "I2C slave: address matched, direction={:?}, addr={:?}",
982 direction, matched_address
983 );
984
985 return Ok(SlaveCommand {
986 kind: direction,
987 address: matched_address,
988 });
989 }
990
991 timeout.check()?;
992 }
993 }
994
995 /// Transmit data to master in response to read request
996 fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
997 let mut bytes_transmitted = 0;
998 let mut padding_count = 0;
999
1000 loop {
1001 let byte_to_send = if bytes_transmitted < data.len() {
1002 data[bytes_transmitted]
1003 } else {
1004 padding_count += 1;
1005 0x00 // Send padding bytes when data is exhausted
1006 };
1007
1008 match self.transmit_byte(byte_to_send, timeout)? {
1009 TransmitResult::Acknowledged => {
1010 bytes_transmitted += 1;
1011 }
1012 TransmitResult::NotAcknowledged => {
1013 bytes_transmitted += 1; // Count the NACKed byte
1014 break;
1015 }
1016 TransmitResult::Stopped | TransmitResult::Restarted => {
1017 break;
1018 }
1019 }
1020 }
1021
1022 if padding_count > 0 {
1023 trace!(
1024 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1025 data.len(),
1026 padding_count,
1027 bytes_transmitted
1028 );
1029 }
1030
1031 Ok(bytes_transmitted)
1032 }
1033
1034 /// Receive data from master during write request
1035 fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
1036 let mut bytes_stored = 0;
1037
1038 // Receive bytes that fit in buffer
1039 while bytes_stored < buffer.len() {
1040 match self.receive_byte(timeout)? {
1041 ReceiveResult::Data(byte) => {
1042 buffer[bytes_stored] = byte;
1043 bytes_stored += 1;
1044 }
1045 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1046 return Ok(bytes_stored);
1047 }
1048 }
1049 }
1050
1051 // Handle buffer overflow by discarding excess bytes
1052 if bytes_stored == buffer.len() {
1053 trace!("I2C slave: buffer full, discarding excess bytes");
1054 self.discard_excess_bytes(timeout)?;
1055 }
1056
1057 Ok(bytes_stored)
1058 }
1059
1060 /// Detect zero-length read pattern early
1061 ///
1062 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
1063 /// by NACK+STOP without wanting any data. This must be detected before attempting
1064 /// to transmit any bytes to avoid SDA line issues.
1065 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
1066 // Quick check for immediate termination signals
1067 let sr1 = self.info.regs.sr1().read();
1068
1069 // Check for immediate NACK (fastest zero-length pattern)
1070 if sr1.af() {
1071 self.clear_acknowledge_failure();
1072 return Ok(Some(0));
1073 }
1074
1075 // Check for immediate STOP (alternative zero-length pattern)
1076 if sr1.stopf() {
1077 Self::clear_stop_flag(self.info);
1078 return Ok(Some(0));
1079 }
1080
1081 // Give a brief window for master to send termination signals
1082 // This handles masters that have slight delays between address ACK and NACK
1083 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window
1084
1085 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
1086 let sr1 = self.info.regs.sr1().read();
1087
1088 // Immediate NACK indicates zero-length read
1089 if sr1.af() {
1090 self.clear_acknowledge_failure();
1091 return Ok(Some(0));
1092 }
1093
1094 // Immediate STOP indicates zero-length read
1095 if sr1.stopf() {
1096 Self::clear_stop_flag(self.info);
1097 return Ok(Some(0));
1098 }
1099
1100 // If TXE becomes ready, master is waiting for data - not zero-length
1101 if sr1.txe() {
1102 return Ok(None); // Proceed with normal transmission
1103 }
1104
1105 // If RESTART detected, handle as zero-length
1106 if sr1.addr() {
1107 return Ok(Some(0));
1108 }
1109 }
1110
1111 // No zero-length pattern detected within the window
1112 Ok(None)
1113 }
1114
1115 /// Discard excess bytes when buffer is full
1116 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {
1117 let mut discarded_count = 0;
1118
1119 loop {
1120 match self.receive_byte(timeout)? {
1121 ReceiveResult::Data(_) => {
1122 discarded_count += 1;
1123 continue;
1124 }
1125 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1126 if discarded_count > 0 {
1127 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1128 }
1129 break;
1130 }
1131 }
1132 }
1133 Ok(())
1134 }
1135
1136 /// Send a single byte and wait for master's response
1137 fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result<TransmitResult, Error> {
1138 // Wait for transmit buffer ready
1139 self.wait_for_transmit_ready(timeout)?;
1140
1141 // Send the byte
1142 self.info.regs.dr().write(|w| w.set_dr(byte));
1143
1144 // Wait for transmission completion or master response
1145 self.wait_for_transmit_completion(timeout)
1146 }
1147
1148 /// Wait until transmit buffer is ready (TXE flag set)
1149 fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> {
1150 loop {
1151 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1152
1153 // Check for early termination conditions
1154 if let Some(result) = Self::check_early_termination(sr1) {
1155 return Err(self.handle_early_termination(result));
1156 }
1157
1158 if sr1.txe() {
1159 return Ok(()); // Ready to transmit
1160 }
1161
1162 timeout.check()?;
1163 }
1164 }
1165
1166 /// Wait for byte transmission completion or master response
1167 fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result<TransmitResult, Error> {
1168 loop {
1169 let sr1 = self.info.regs.sr1().read();
1170
1171 // Check flags in priority order
1172 if sr1.af() {
1173 self.clear_acknowledge_failure();
1174 return Ok(TransmitResult::NotAcknowledged);
1175 }
1176
1177 if sr1.btf() {
1178 return Ok(TransmitResult::Acknowledged);
1179 }
1180
1181 if sr1.stopf() {
1182 Self::clear_stop_flag(self.info);
1183 return Ok(TransmitResult::Stopped);
1184 }
1185
1186 if sr1.addr() {
1187 return Ok(TransmitResult::Restarted);
1188 }
1189
1190 // Check for other error conditions
1191 self.check_for_hardware_errors(sr1)?;
1192
1193 timeout.check()?;
1194 }
1195 }
1196
1197 /// Receive a single byte or detect transaction termination
1198 fn receive_byte(&mut self, timeout: Timeout) -> Result<ReceiveResult, Error> {
1199 loop {
1200 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1201
1202 // Check for received data first (prioritize data over control signals)
1203 if sr1.rxne() {
1204 let byte = self.info.regs.dr().read().dr();
1205 return Ok(ReceiveResult::Data(byte));
1206 }
1207
1208 // Check for transaction termination
1209 if sr1.addr() {
1210 return Ok(ReceiveResult::Restarted);
1211 }
1212
1213 if sr1.stopf() {
1214 Self::clear_stop_flag(self.info);
1215 return Ok(ReceiveResult::Stopped);
1216 }
1217
1218 timeout.check()?;
1219 }
1220 }
1221
1222 /// Determine which slave address was matched based on SR2 flags
1223 fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> {
1224 if sr2.gencall() {
1225 Ok(Address::SevenBit(0x00)) // General call address
1226 } else if sr2.dualf() {
1227 // OA2 (secondary address) was matched
1228 let oar2 = info.regs.oar2().read();
1229 if oar2.endual() != i2c::vals::Endual::DUAL {
1230 return Err(Error::Bus); // Hardware inconsistency
1231 }
1232 Ok(Address::SevenBit(oar2.add2()))
1233 } else {
1234 // OA1 (primary address) was matched
1235 let oar1 = info.regs.oar1().read();
1236 match oar1.addmode() {
1237 i2c::vals::Addmode::BIT7 => {
1238 let addr = (oar1.add() >> 1) as u8;
1239 Ok(Address::SevenBit(addr))
1240 }
1241 i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())),
1242 }
1243 }
1244 }
1245
1246 // Helper methods for hardware interaction
1247
1248 /// Read status register and handle I2C errors (except NACK in slave mode)
1249 fn read_status_and_handle_errors(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
1250 match Self::check_and_clear_error_flags(info) {
1251 Ok(sr1) => Ok(sr1),
1252 Err(Error::Nack) => {
1253 // In slave mode, NACK is normal protocol behavior, not an error
1254 Ok(info.regs.sr1().read())
1255 }
1256 Err(other_error) => Err(other_error),
1257 }
1258 }
1259
1260 /// Check for conditions that cause early termination of operations
1261 fn check_early_termination(sr1: i2c::regs::Sr1) -> Option<TransmitResult> {
1262 if sr1.stopf() {
1263 Some(TransmitResult::Stopped)
1264 } else if sr1.addr() {
1265 Some(TransmitResult::Restarted)
1266 } else if sr1.af() {
1267 Some(TransmitResult::NotAcknowledged)
1268 } else {
1269 None
1270 }
1271 }
1272
1273 /// Convert early termination to appropriate error
1274 fn handle_early_termination(&mut self, result: TransmitResult) -> Error {
1275 match result {
1276 TransmitResult::Stopped => {
1277 Self::clear_stop_flag(self.info);
1278 Error::Bus // Unexpected STOP during setup
1279 }
1280 TransmitResult::Restarted => {
1281 Error::Bus // Unexpected RESTART during setup
1282 }
1283 TransmitResult::NotAcknowledged => {
1284 self.clear_acknowledge_failure();
1285 Error::Bus // Unexpected NACK during setup
1286 }
1287 TransmitResult::Acknowledged => {
1288 unreachable!() // This should never be passed to this function
1289 }
1290 }
1291 }
1292
1293 /// Check for hardware-level I2C errors during transmission
1294 fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> {
1295 if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() {
1296 // Delegate to existing error handling
1297 Self::check_and_clear_error_flags(self.info)?;
1298 }
1299 Ok(())
1300 }
1301
1302 /// Disable I2C event and error interrupts for blocking operations
1303 fn disable_i2c_interrupts(&mut self) {
1304 self.info.regs.cr2().modify(|w| {
1305 w.set_itevten(false);
1306 w.set_iterren(false);
1307 });
1308 }
1309
1310 /// Clear the acknowledge failure flag
1311 fn clear_acknowledge_failure(&mut self) {
1312 self.info.regs.sr1().write(|reg| {
1313 reg.0 = !0;
1314 reg.set_af(false);
1315 });
1316 }
1317
1318 /// Configure DMA settings for slave operations (shared between read/write)
1319 fn setup_slave_dma_base(&mut self) {
1320 self.info.regs.cr2().modify(|w| {
1321 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1322 w.set_dmaen(true); // Enable DMA requests
1323 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1324 });
1325 }
1326
1327 /// Disable DMA and interrupts in a critical section
1328 fn disable_dma_and_interrupts(info: &'static Info) {
1329 critical_section::with(|_| {
1330 info.regs.cr2().modify(|w| {
1331 w.set_dmaen(false);
1332 w.set_iterren(false);
1333 w.set_itevten(false);
1334 });
1335 });
1336 }
1337
1338 /// Check for early termination conditions during slave operations
1339 /// Returns Some(result) if termination detected, None to continue
1340 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1341 if sr1.stopf() {
1342 Some(SlaveTermination::Stop)
1343 } else if sr1.addr() {
1344 Some(SlaveTermination::Restart)
1345 } else if sr1.af() {
1346 Some(SlaveTermination::Nack)
1347 } else {
1348 None
1349 }
1350 }
1351}
1352
1353impl<'d> I2c<'d, Async, MultiMaster> {
1354 /// Async listen for incoming I2C messages using interrupts
1355 ///
1356 /// Waits for a master to address this slave and returns the command type
1357 /// (Read/Write) and the matched address. This method will suspend until
1358 /// an address match occurs.
1359 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1360 trace!("I2C slave: starting async listen for address match");
1361 let state = self.state;
1362 let info = self.info;
1363
1364 Self::enable_interrupts(info);
1365
1366 let on_drop = OnDrop::new(|| {
1367 Self::disable_dma_and_interrupts(info);
1368 });
1369
1370 let result = poll_fn(|cx| {
1371 state.waker.register(cx.waker());
1372
1373 match Self::check_and_clear_error_flags(info) {
1374 Err(e) => {
1375 error!("I2C slave: error during listen: {:?}", e);
1376 Poll::Ready(Err(e))
1377 }
1378 Ok(sr1) => {
1379 if sr1.addr() {
1380 let sr2 = info.regs.sr2().read();
1381 let direction = if sr2.tra() {
1382 SlaveCommandKind::Read
1383 } else {
1384 SlaveCommandKind::Write
1385 };
1386
1387 let matched_address = match Self::decode_matched_address(sr2, info) {
1388 Ok(addr) => {
1389 trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr);
1390 addr
1391 }
1392 Err(e) => {
1393 error!("I2C slave: failed to decode matched address: {:?}", e);
1394 return Poll::Ready(Err(e));
1395 }
1396 };
1397
1398 Poll::Ready(Ok(SlaveCommand {
1399 kind: direction,
1400 address: matched_address,
1401 }))
1402 } else {
1403 Self::enable_interrupts(info);
1404 Poll::Pending
1405 }
1406 }
1407 }
1408 })
1409 .await;
1410
1411 drop(on_drop);
1412 trace!("I2C slave: listen complete, result={:?}", result);
1413 result
1414 }
1415
1416 /// Async respond to write command using RX DMA
1417 ///
1418 /// Receives data from the master into the provided buffer using DMA.
1419 /// If the master sends more bytes than the buffer can hold, excess bytes
1420 /// are acknowledged but discarded to prevent interrupt flooding.
1421 ///
1422 /// Returns the number of bytes stored in the buffer (not total received).
1423 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1424 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1425
1426 if buffer.is_empty() {
1427 warn!("I2C slave: respond_to_write called with empty buffer");
1428 return Err(Error::Overrun);
1429 }
1430
1431 let state = self.state;
1432 let info = self.info;
1433
1434 self.setup_slave_dma_base();
1435
1436 let on_drop = OnDrop::new(|| {
1437 Self::disable_dma_and_interrupts(info);
1438 });
1439
1440 info.regs.sr2().read();
1441
1442 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1443
1444 drop(on_drop);
1445 trace!("I2C slave: respond_to_write complete, result={:?}", result);
1446 result
1447 }
1448
1449 /// Async respond to read command using TX DMA
1450 ///
1451 /// Transmits data to the master using DMA. If the master requests more bytes
1452 /// than available in the data buffer, padding bytes (0x00) are sent until
1453 /// the master terminates the transaction with NACK, STOP, or RESTART.
1454 ///
1455 /// Returns the total number of bytes transmitted (data + padding).
1456 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1457 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1458
1459 if data.is_empty() {
1460 warn!("I2C slave: respond_to_read called with empty data");
1461 return Err(Error::Overrun);
1462 }
1463
1464 let state = self.state;
1465 let info = self.info;
1466
1467 self.setup_slave_dma_base();
1468
1469 let on_drop = OnDrop::new(|| {
1470 Self::disable_dma_and_interrupts(info);
1471 });
1472
1473 info.regs.sr2().read();
1474
1475 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1476
1477 drop(on_drop);
1478 trace!("I2C slave: respond_to_read complete, result={:?}", result);
1479 result
1480 }
1481
1482 // === Private Transfer Execution Methods ===
1483
1484 /// Execute complete slave receive transfer with excess byte handling
1485 async fn execute_slave_receive_transfer(
1486 &mut self,
1487 buffer: &mut [u8],
1488 state: &'static State,
1489 info: &'static Info,
1490 ) -> Result<usize, Error> {
1491 let dma_transfer = unsafe {
1492 let src = info.regs.dr().as_ptr() as *mut u8;
1493 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1494 };
1495
1496 let i2c_monitor =
1497 Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1498
1499 match select(dma_transfer, i2c_monitor).await {
1500 Either::Second(Err(e)) => {
1501 error!("I2C slave: error during receive transfer: {:?}", e);
1502 Self::disable_dma_and_interrupts(info);
1503 Err(e)
1504 }
1505 Either::First(_) => {
1506 trace!("I2C slave: DMA receive completed, handling excess bytes");
1507 Self::disable_dma_and_interrupts(info);
1508 self.handle_excess_bytes(state, info).await?;
1509 Ok(buffer.len())
1510 }
1511 Either::Second(Ok(termination)) => {
1512 trace!("I2C slave: receive terminated by I2C event: {:?}", termination);
1513 Self::disable_dma_and_interrupts(info);
1514 Ok(buffer.len())
1515 }
1516 }
1517 }
1518
1519 /// Execute complete slave transmit transfer with padding byte handling
1520 async fn execute_slave_transmit_transfer(
1521 &mut self,
1522 data: &[u8],
1523 state: &'static State,
1524 info: &'static Info,
1525 ) -> Result<usize, Error> {
1526 let dma_transfer = unsafe {
1527 let dst = info.regs.dr().as_ptr() as *mut u8;
1528 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1529 };
1530
1531 let i2c_monitor = Self::create_termination_monitor(
1532 state,
1533 info,
1534 &[
1535 SlaveTermination::Stop,
1536 SlaveTermination::Restart,
1537 SlaveTermination::Nack,
1538 ],
1539 );
1540
1541 match select(dma_transfer, i2c_monitor).await {
1542 Either::Second(Err(e)) => {
1543 error!("I2C slave: error during transmit transfer: {:?}", e);
1544 Self::disable_dma_and_interrupts(info);
1545 Err(e)
1546 }
1547 Either::First(_) => {
1548 trace!("I2C slave: DMA transmit completed, handling padding bytes");
1549 Self::disable_dma_and_interrupts(info);
1550 let padding_count = self.handle_padding_bytes(state, info).await?;
1551 let total_bytes = data.len() + padding_count;
1552 trace!(
1553 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1554 data.len(),
1555 padding_count,
1556 total_bytes
1557 );
1558 Ok(total_bytes)
1559 }
1560 Either::Second(Ok(termination)) => {
1561 trace!("I2C slave: transmit terminated by I2C event: {:?}", termination);
1562 Self::disable_dma_and_interrupts(info);
1563 Ok(data.len())
1564 }
1565 }
1566 }
1567
1568 /// Create a future that monitors for specific slave termination conditions
1569 fn create_termination_monitor(
1570 state: &'static State,
1571 info: &'static Info,
1572 allowed_terminations: &'static [SlaveTermination],
1573 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1574 poll_fn(move |cx| {
1575 state.waker.register(cx.waker());
1576
1577 match Self::check_and_clear_error_flags(info) {
1578 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1579 Poll::Ready(Ok(SlaveTermination::Nack))
1580 }
1581 Err(e) => Poll::Ready(Err(e)),
1582 Ok(sr1) => {
1583 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1584 if allowed_terminations.contains(&termination) {
1585 // Handle the specific termination condition
1586 match termination {
1587 SlaveTermination::Stop => Self::clear_stop_flag(info),
1588 SlaveTermination::Nack => {
1589 info.regs.sr1().write(|reg| {
1590 reg.0 = !0;
1591 reg.set_af(false);
1592 });
1593 }
1594 SlaveTermination::Restart => {
1595 // ADDR flag will be handled by next listen() call
1596 }
1597 }
1598 Poll::Ready(Ok(termination))
1599 } else {
1600 // Unexpected termination condition
1601 Poll::Ready(Err(Error::Bus))
1602 }
1603 } else {
1604 Self::enable_interrupts(info);
1605 Poll::Pending
1606 }
1607 }
1608 }
1609 })
1610 }
1611
1612 /// Handle excess bytes after DMA buffer is full
1613 ///
1614 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1615 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1616 let mut discarded_count = 0;
1617
1618 poll_fn(|cx| {
1619 state.waker.register(cx.waker());
1620
1621 match Self::check_and_clear_error_flags(info) {
1622 Err(e) => {
1623 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1624 Poll::Ready(Err(e))
1625 }
1626 Ok(sr1) => {
1627 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1628 match termination {
1629 SlaveTermination::Stop => Self::clear_stop_flag(info),
1630 SlaveTermination::Restart => {}
1631 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1632 }
1633 if discarded_count > 0 {
1634 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1635 }
1636 return Poll::Ready(Ok(()));
1637 }
1638
1639 if sr1.rxne() {
1640 let _discarded_byte = info.regs.dr().read().dr();
1641 discarded_count += 1;
1642 Self::enable_interrupts(info);
1643 return Poll::Pending;
1644 }
1645
1646 Self::enable_interrupts(info);
1647 Poll::Pending
1648 }
1649 }
1650 })
1651 .await
1652 }
1653
1654 /// Handle padding bytes after DMA data is exhausted
1655 ///
1656 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1657 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1658 let mut padding_count = 0;
1659
1660 poll_fn(|cx| {
1661 state.waker.register(cx.waker());
1662
1663 match Self::check_and_clear_error_flags(info) {
1664 Err(Error::Nack) => Poll::Ready(Ok(padding_count)),
1665 Err(e) => {
1666 error!("I2C slave: error while sending padding bytes: {:?}", e);
1667 Poll::Ready(Err(e))
1668 }
1669 Ok(sr1) => {
1670 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1671 match termination {
1672 SlaveTermination::Stop => Self::clear_stop_flag(info),
1673 SlaveTermination::Restart => {}
1674 SlaveTermination::Nack => {
1675 info.regs.sr1().write(|reg| {
1676 reg.0 = !0;
1677 reg.set_af(false);
1678 });
1679 }
1680 }
1681 return Poll::Ready(Ok(padding_count));
1682 }
1683
1684 if sr1.txe() {
1685 info.regs.dr().write(|w| w.set_dr(0x00));
1686 padding_count += 1;
1687 Self::enable_interrupts(info);
1688 return Poll::Pending;
1689 }
1690
1691 Self::enable_interrupts(info);
1692 Poll::Pending
1693 }
1694 }
1695 })
1696 .await
1697 }
1698}
1699
1700/// Timing configuration for I2C v1 hardware
1701///
1702/// This struct encapsulates the complex timing calculations required for STM32 I2C v1
1703/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of
1704/// the unified TIMINGR register found in v2 hardware.
732struct Timings { 1705struct Timings {
733 freq: u8, 1706 freq: u8, // APB frequency in MHz for CR2.FREQ register
734 mode: Mode, 1707 mode: Mode, // Standard or Fast mode selection
735 trise: u8, 1708 trise: u8, // Rise time compensation value
736 ccr: u16, 1709 ccr: u16, // Clock control register value
737 duty: Duty, 1710 duty: Duty, // Fast mode duty cycle selection
738} 1711}
739 1712
740impl Timings { 1713impl Timings {
@@ -762,11 +1735,7 @@ impl Timings {
762 mode = Mode::Standard; 1735 mode = Mode::Standard;
763 ccr = { 1736 ccr = {
764 let ccr = clock / (frequency * 2); 1737 let ccr = clock / (frequency * 2);
765 if ccr < 4 { 1738 if ccr < 4 { 4 } else { ccr }
766 4
767 } else {
768 ccr
769 }
770 }; 1739 };
771 } else { 1740 } else {
772 const DUTYCYCLE: u8 = 0; 1741 const DUTYCYCLE: u8 = 0;
@@ -775,14 +1744,10 @@ impl Timings {
775 duty = Duty::Duty2_1; 1744 duty = Duty::Duty2_1;
776 ccr = clock / (frequency * 3); 1745 ccr = clock / (frequency * 3);
777 ccr = if ccr < 1 { 1 } else { ccr }; 1746 ccr = if ccr < 1 { 1 } else { ccr };
778
779 // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
780 } else { 1747 } else {
781 duty = Duty::Duty16_9; 1748 duty = Duty::Duty16_9;
782 ccr = clock / (frequency * 25); 1749 ccr = clock / (frequency * 25);
783 ccr = if ccr < 1 { 1 } else { ccr }; 1750 ccr = if ccr < 1 { 1 } else { ccr };
784
785 // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
786 } 1751 }
787 } 1752 }
788 1753
@@ -792,11 +1757,6 @@ impl Timings {
792 ccr: ccr as u16, 1757 ccr: ccr as u16,
793 duty, 1758 duty,
794 mode, 1759 mode,
795 //prescale: presc_reg,
796 //scll,
797 //sclh,
798 //sdadel,
799 //scldel,
800 } 1760 }
801 } 1761 }
802} 1762}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 0bfc795ac..4527e55b9 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -2,7 +2,7 @@ use core::cmp;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use config::{Address, OwnAddresses, OA2}; 5use config::{Address, OA2, OwnAddresses};
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::drop::OnDrop; 7use embassy_hal_internal::drop::OnDrop;
8use embedded_hal_1::i2c::Operation; 8use embedded_hal_1::i2c::Operation;
@@ -70,6 +70,11 @@ fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
70} 70}
71 71
72pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
73 // restore the clocks to their last configured state as
74 // much is lost in STOP modes
75 #[cfg(all(feature = "low-power", stm32wlex))]
76 crate::low_power::Executor::on_wakeup_irq();
77
73 let regs = T::info().regs; 78 let regs = T::info().regs;
74 let isr = regs.isr().read(); 79 let isr = regs.isr().read();
75 80
@@ -814,6 +819,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
814 819
815 /// Write. 820 /// Write.
816 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 821 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
822 #[cfg(all(feature = "low-power", stm32wlex))]
823 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
817 let timeout = self.timeout(); 824 let timeout = self.timeout();
818 if write.is_empty() { 825 if write.is_empty() {
819 self.write_internal(address.into(), write, true, timeout) 826 self.write_internal(address.into(), write, true, timeout)
@@ -828,6 +835,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
828 /// 835 ///
829 /// The buffers are concatenated in a single write transaction. 836 /// The buffers are concatenated in a single write transaction.
830 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 837 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
838 #[cfg(all(feature = "low-power", stm32wlex))]
839 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
831 let timeout = self.timeout(); 840 let timeout = self.timeout();
832 841
833 if write.is_empty() { 842 if write.is_empty() {
@@ -851,6 +860,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
851 860
852 /// Read. 861 /// Read.
853 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 862 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
863 #[cfg(all(feature = "low-power", stm32wlex))]
864 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
854 let timeout = self.timeout(); 865 let timeout = self.timeout();
855 866
856 if buffer.is_empty() { 867 if buffer.is_empty() {
@@ -863,6 +874,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
863 874
864 /// Write, restart, read. 875 /// Write, restart, read.
865 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 876 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
877 #[cfg(all(feature = "low-power", stm32wlex))]
878 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
866 let timeout = self.timeout(); 879 let timeout = self.timeout();
867 880
868 if write.is_empty() { 881 if write.is_empty() {
@@ -888,6 +901,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
888 /// 901 ///
889 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 902 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
890 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))]
905 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
891 let _ = addr; 906 let _ = addr;
892 let _ = operations; 907 let _ = operations;
893 todo!() 908 todo!()
@@ -1181,7 +1196,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1181 1196
1182 let regs = self.info.regs; 1197 let regs = self.info.regs;
1183 1198
1184 let dma_transfer = unsafe { 1199 let mut dma_transfer = unsafe {
1185 regs.cr1().modify(|w| { 1200 regs.cr1().modify(|w| {
1186 w.set_rxdmaen(true); 1201 w.set_rxdmaen(true);
1187 w.set_stopie(true); 1202 w.set_stopie(true);
@@ -1220,6 +1235,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1220 regs.cr1().modify(|w| w.set_tcie(true)); 1235 regs.cr1().modify(|w| w.set_tcie(true));
1221 Poll::Pending 1236 Poll::Pending
1222 } else if isr.stopf() { 1237 } else if isr.stopf() {
1238 remaining_len = remaining_len.saturating_add(dma_transfer.get_remaining_transfers() as usize);
1223 regs.icr().write(|reg| reg.set_stopcf(true)); 1239 regs.icr().write(|reg| reg.set_stopcf(true));
1224 let poll = Poll::Ready(Ok(total_len - remaining_len)); 1240 let poll = Poll::Ready(Ok(total_len - remaining_len));
1225 poll 1241 poll
@@ -1229,6 +1245,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1229 }) 1245 })
1230 .await?; 1246 .await?;
1231 1247
1248 dma_transfer.request_pause();
1232 dma_transfer.await; 1249 dma_transfer.await;
1233 1250
1234 drop(on_drop); 1251 drop(on_drop);
@@ -1258,7 +1275,8 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1258 w.set_txdmaen(false); 1275 w.set_txdmaen(false);
1259 w.set_stopie(false); 1276 w.set_stopie(false);
1260 w.set_tcie(false); 1277 w.set_tcie(false);
1261 }) 1278 });
1279 regs.isr().write(|w| w.set_txe(true));
1262 }); 1280 });
1263 1281
1264 let state = self.state; 1282 let state = self.state;
@@ -1281,6 +1299,11 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1281 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1299 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1282 Poll::Pending 1300 Poll::Pending
1283 } else if isr.stopf() { 1301 } else if isr.stopf() {
1302 let mut leftover_bytes = dma_transfer.get_remaining_transfers();
1303 if !self.info.regs.isr().read().txe() {
1304 leftover_bytes = leftover_bytes.saturating_add(1);
1305 }
1306 remaining_len = remaining_len.saturating_add(leftover_bytes as usize);
1284 self.info.regs.icr().write(|reg| reg.set_stopcf(true)); 1307 self.info.regs.icr().write(|reg| reg.set_stopcf(true));
1285 if remaining_len > 0 { 1308 if remaining_len > 0 {
1286 dma_transfer.request_pause(); 1309 dma_transfer.request_pause();
@@ -1294,6 +1317,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1294 }) 1317 })
1295 .await?; 1318 .await?;
1296 1319
1320 dma_transfer.request_pause();
1297 dma_transfer.await; 1321 dma_transfer.await;
1298 1322
1299 drop(on_drop); 1323 drop(on_drop);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index b6d3daf54..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -3,12 +3,13 @@
3use embassy_futures::join::join; 3use embassy_futures::join::join;
4use stm32_metapac::spi::vals; 4use stm32_metapac::spi::vals;
5 5
6use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; 6use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
8use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
9use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
10use crate::time::Hertz; 12use crate::time::Hertz;
11use crate::Peri;
12 13
13/// I2S mode 14/// I2S mode
14#[derive(Copy, Clone)] 15#[derive(Copy, Clone)]
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 670d8332c..e1d8b1c2a 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,7 +1,7 @@
1//! Inter-Process Communication Controller (IPCC) 1//! Inter-Process Communication Controller (IPCC)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 4ea38b414..5b338a28b 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(test), no_std)] 1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
3#![cfg_attr( 4#![cfg_attr(
4 docsrs, 5 docsrs,
5 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n" 6 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n"
@@ -53,6 +54,8 @@ pub mod timer;
53 54
54#[cfg(adc)] 55#[cfg(adc)]
55pub mod adc; 56pub mod adc;
57#[cfg(backup_sram)]
58pub mod backup_sram;
56#[cfg(can)] 59#[cfg(can)]
57pub mod can; 60pub mod can;
58// FIXME: Cordic driver cause stm32u5a5zj crash 61// FIXME: Cordic driver cause stm32u5a5zj crash
@@ -194,7 +197,7 @@ macro_rules! bind_interrupts {
194 197
195 $( 198 $(
196 #[allow(non_snake_case)] 199 #[allow(non_snake_case)]
197 #[no_mangle] 200 #[unsafe(no_mangle)]
198 $(#[cfg($cond_irq)])? 201 $(#[cfg($cond_irq)])?
199 $(#[doc = $doc])* 202 $(#[doc = $doc])*
200 unsafe extern "C" fn $irq() { 203 unsafe extern "C" fn $irq() {
@@ -222,7 +225,7 @@ macro_rules! bind_interrupts {
222} 225}
223 226
224// Reexports 227// Reexports
225pub use _generated::{peripherals, Peripherals}; 228pub use _generated::{Peripherals, peripherals};
226pub use embassy_hal_internal::{Peri, PeripheralType}; 229pub use embassy_hal_internal::{Peri, PeripheralType};
227#[cfg(feature = "unstable-pac")] 230#[cfg(feature = "unstable-pac")]
228pub use stm32_metapac as pac; 231pub use stm32_metapac as pac;
@@ -240,6 +243,14 @@ pub struct Config {
240 /// RCC config. 243 /// RCC config.
241 pub rcc: rcc::Config, 244 pub rcc: rcc::Config,
242 245
246 #[cfg(feature = "low-power")]
247 /// RTC config
248 pub rtc: rtc::RtcConfig,
249
250 #[cfg(feature = "low-power")]
251 /// Minimum time to stop
252 pub min_stop_pause: embassy_time::Duration,
253
243 /// Enable debug during sleep and stop. 254 /// Enable debug during sleep and stop.
244 /// 255 ///
245 /// May increase power consumption. Defaults to true. 256 /// May increase power consumption. Defaults to true.
@@ -293,6 +304,10 @@ impl Default for Config {
293 fn default() -> Self { 304 fn default() -> Self {
294 Self { 305 Self {
295 rcc: Default::default(), 306 rcc: Default::default(),
307 #[cfg(feature = "low-power")]
308 rtc: Default::default(),
309 #[cfg(feature = "low-power")]
310 min_stop_pause: embassy_time::Duration::from_millis(250),
296 #[cfg(dbgmcu)] 311 #[cfg(dbgmcu)]
297 enable_debug_during_sleep: true, 312 enable_debug_during_sleep: true,
298 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] 313 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
@@ -632,6 +647,12 @@ fn init_hw(config: Config) -> Peripherals {
632 exti::init(cs); 647 exti::init(cs);
633 648
634 rcc::init_rcc(cs, config.rcc); 649 rcc::init_rcc(cs, config.rcc);
650
651 #[cfg(feature = "low-power")]
652 crate::rtc::init_rtc(cs, config.rtc);
653
654 #[cfg(feature = "low-power")]
655 crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause);
635 } 656 }
636 657
637 p 658 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 342f73bc8..696dfe83f 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -41,12 +41,6 @@
41//! config.enable_debug_during_sleep = false; 41//! config.enable_debug_during_sleep = false;
42//! let p = embassy_stm32::init(config); 42//! let p = embassy_stm32::init(config);
43//! 43//!
44//! // give the RTC to the executor...
45//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
46//! static RTC: StaticCell<Rtc> = StaticCell::new();
47//! let rtc = RTC.init(rtc);
48//! embassy_stm32::low_power::stop_with_rtc(rtc);
49//!
50//! // your application here... 44//! // your application here...
51//! } 45//! }
52//! ``` 46//! ```
@@ -56,27 +50,72 @@
56 50
57use core::arch::asm; 51use core::arch::asm;
58use core::marker::PhantomData; 52use core::marker::PhantomData;
59use core::sync::atomic::{compiler_fence, Ordering}; 53use core::sync::atomic::{Ordering, compiler_fence};
60 54
61use cortex_m::peripheral::SCB; 55use cortex_m::peripheral::SCB;
56use critical_section::CriticalSection;
62use embassy_executor::*; 57use embassy_executor::*;
63 58
64use crate::interrupt; 59use crate::interrupt;
65use crate::time_driver::{get_driver, RtcDriver}; 60use crate::time_driver::get_driver;
66 61
67const THREAD_PENDER: usize = usize::MAX; 62const THREAD_PENDER: usize = usize::MAX;
68 63
69use crate::rtc::Rtc;
70
71static mut EXECUTOR: Option<Executor> = None; 64static mut EXECUTOR: Option<Executor> = None;
72 65
66/// Prevent the device from going into the stop mode if held
67pub struct DeviceBusy(StopMode);
68
69impl DeviceBusy {
70 /// Create a new DeviceBusy with stop1.
71 pub fn new_stop1() -> Self {
72 Self::new(StopMode::Stop1)
73 }
74
75 /// Create a new DeviceBusy with stop2.
76 pub fn new_stop2() -> Self {
77 Self::new(StopMode::Stop2)
78 }
79
80 /// Create a new DeviceBusy.
81 pub fn new(stop_mode: StopMode) -> Self {
82 critical_section::with(|_| unsafe {
83 match stop_mode {
84 StopMode::Stop1 => {
85 crate::rcc::REFCOUNT_STOP1 += 1;
86 }
87 StopMode::Stop2 => {
88 crate::rcc::REFCOUNT_STOP2 += 1;
89 }
90 }
91 });
92
93 Self(stop_mode)
94 }
95}
96
97impl Drop for DeviceBusy {
98 fn drop(&mut self) {
99 critical_section::with(|_| unsafe {
100 match self.0 {
101 StopMode::Stop1 => {
102 crate::rcc::REFCOUNT_STOP1 -= 1;
103 }
104 StopMode::Stop2 => {
105 crate::rcc::REFCOUNT_STOP2 -= 1;
106 }
107 }
108 });
109 }
110}
111
73#[cfg(not(stm32u0))] 112#[cfg(not(stm32u0))]
74foreach_interrupt! { 113foreach_interrupt! {
75 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 114 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
76 #[interrupt] 115 #[interrupt]
77 #[allow(non_snake_case)] 116 #[allow(non_snake_case)]
78 unsafe fn $irq() { 117 unsafe fn $irq() {
79 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 118 Executor::on_wakeup_irq();
80 } 119 }
81 }; 120 };
82} 121}
@@ -87,31 +126,21 @@ foreach_interrupt! {
87 #[interrupt] 126 #[interrupt]
88 #[allow(non_snake_case)] 127 #[allow(non_snake_case)]
89 unsafe fn $irq() { 128 unsafe fn $irq() {
90 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 129 Executor::on_wakeup_irq();
91 } 130 }
92 }; 131 };
93} 132}
94 133
95#[allow(dead_code)]
96pub(crate) unsafe fn on_wakeup_irq() {
97 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
98}
99
100/// Configure STOP mode with RTC.
101pub fn stop_with_rtc(rtc: &'static Rtc) {
102 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
103}
104
105/// Get whether the core is ready to enter the given stop mode. 134/// Get whether the core is ready to enter the given stop mode.
106/// 135///
107/// This will return false if some peripheral driver is in use that 136/// This will return false if some peripheral driver is in use that
108/// prevents entering the given stop mode. 137/// prevents entering the given stop mode.
109pub fn stop_ready(stop_mode: StopMode) -> bool { 138pub fn stop_ready(stop_mode: StopMode) -> bool {
110 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 139 critical_section::with(|cs| match Executor::stop_mode(cs) {
111 Some(StopMode::Stop2) => true, 140 Some(StopMode::Stop2) => true,
112 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 141 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
113 None => false, 142 None => false,
114 } 143 })
115} 144}
116 145
117/// Available Stop modes. 146/// Available Stop modes.
@@ -124,10 +153,10 @@ pub enum StopMode {
124 Stop2, 153 Stop2,
125} 154}
126 155
127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 156#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
128use stm32_metapac::pwr::vals::Lpms; 157use stm32_metapac::pwr::vals::Lpms;
129 158
130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 159#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
131impl Into<Lpms> for StopMode { 160impl Into<Lpms> for StopMode {
132 fn into(self) -> Lpms { 161 fn into(self) -> Lpms {
133 match self { 162 match self {
@@ -154,7 +183,6 @@ pub struct Executor {
154 inner: raw::Executor, 183 inner: raw::Executor,
155 not_send: PhantomData<*mut ()>, 184 not_send: PhantomData<*mut ()>,
156 scb: SCB, 185 scb: SCB,
157 time_driver: &'static RtcDriver,
158} 186}
159 187
160impl Executor { 188impl Executor {
@@ -167,7 +195,6 @@ impl Executor {
167 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 195 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
168 not_send: PhantomData, 196 not_send: PhantomData,
169 scb: cortex_m::Peripherals::steal().SCB, 197 scb: cortex_m::Peripherals::steal().SCB,
170 time_driver: get_driver(),
171 }); 198 });
172 199
173 let executor = EXECUTOR.as_mut().unwrap(); 200 let executor = EXECUTOR.as_mut().unwrap();
@@ -176,21 +203,31 @@ impl Executor {
176 }) 203 })
177 } 204 }
178 205
179 unsafe fn on_wakeup_irq(&mut self) { 206 pub(crate) unsafe fn on_wakeup_irq() {
180 self.time_driver.resume_time(); 207 critical_section::with(|cs| {
181 trace!("low power: resume"); 208 #[cfg(stm32wlex)]
182 } 209 {
183 210 let extscr = crate::pac::PWR.extscr().read();
184 pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { 211 if extscr.c1stop2f() || extscr.c1stopf() {
185 self.time_driver.set_rtc(rtc); 212 // when we wake from any stop mode we need to re-initialize the rcc
186 213 crate::rcc::apply_resume_config();
187 rtc.enable_wakeup_line(); 214 if extscr.c1stop2f() {
188 215 // when we wake from STOP2, we need to re-initialize the time driver
189 trace!("low power: stop with rtc configured"); 216 crate::time_driver::init_timer(cs);
217 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
218 // and given that we just woke from STOP2, we can reset them
219 crate::rcc::REFCOUNT_STOP2 = 0;
220 crate::rcc::REFCOUNT_STOP1 = 0;
221 }
222 }
223 }
224 get_driver().resume_time(cs);
225 trace!("low power: resume");
226 });
190 } 227 }
191 228
192 fn stop_mode(&self) -> Option<StopMode> { 229 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
193 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 230 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } {
194 Some(StopMode::Stop2) 231 Some(StopMode::Stop2)
195 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 232 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
196 Some(StopMode::Stop1) 233 Some(StopMode::Stop1)
@@ -201,7 +238,7 @@ impl Executor {
201 238
202 #[allow(unused_variables)] 239 #[allow(unused_variables)]
203 fn configure_stop(&mut self, stop_mode: StopMode) { 240 fn configure_stop(&mut self, stop_mode: StopMode) {
204 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba))] 241 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))]
205 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 242 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
206 #[cfg(stm32h5)] 243 #[cfg(stm32h5)]
207 crate::pac::PWR.pmcr().modify(|v| { 244 crate::pac::PWR.pmcr().modify(|v| {
@@ -213,17 +250,22 @@ impl Executor {
213 250
214 fn configure_pwr(&mut self) { 251 fn configure_pwr(&mut self) {
215 self.scb.clear_sleepdeep(); 252 self.scb.clear_sleepdeep();
253 // Clear any previous stop flags
254 #[cfg(stm32wlex)]
255 crate::pac::PWR.extscr().modify(|w| {
256 w.set_c1cssf(true);
257 });
216 258
217 compiler_fence(Ordering::SeqCst); 259 compiler_fence(Ordering::SeqCst);
218 260
219 let stop_mode = self.stop_mode(); 261 let stop_mode = critical_section::with(|cs| Self::stop_mode(cs));
220 262
221 if stop_mode.is_none() { 263 if stop_mode.is_none() {
222 trace!("low power: not ready to stop"); 264 trace!("low power: not ready to stop");
223 return; 265 return;
224 } 266 }
225 267
226 if self.time_driver.pause_time().is_err() { 268 if get_driver().pause_time().is_err() {
227 trace!("low power: failed to pause time"); 269 trace!("low power: failed to pause time");
228 return; 270 return;
229 } 271 }
@@ -266,6 +308,19 @@ impl Executor {
266 executor.inner.poll(); 308 executor.inner.poll();
267 self.configure_pwr(); 309 self.configure_pwr();
268 asm!("wfe"); 310 asm!("wfe");
311 #[cfg(stm32wlex)]
312 {
313 let es = crate::pac::PWR.extscr().read();
314 match (es.c1stopf(), es.c1stop2f()) {
315 (true, false) => debug!("low power: wake from STOP1"),
316 (false, true) => debug!("low power: wake from STOP2"),
317 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"),
318 (false, false) => trace!("low power: stop mode not entered"),
319 };
320 crate::pac::PWR.extscr().modify(|w| {
321 w.set_c1cssf(false);
322 });
323 }
269 }; 324 };
270 } 325 }
271 } 326 }
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
index 96af9f4d9..a69db3caf 100644
--- a/embassy-stm32/src/lptim/pwm.rs
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -4,12 +4,12 @@ use core::marker::PhantomData;
4 4
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6 6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))] 7#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin; 8use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))] 9use super::timer::Timer;
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance}; 10use super::{BasicInstance, Instance};
11#[cfg(any(lptim_v2a, lptim_v2b))]
12use super::{Channel1Pin, Channel2Pin, channel::Channel, timer::ChannelDirection};
13#[cfg(gpio_v2)] 13#[cfg(gpio_v2)]
14use crate::gpio::Pull; 14use crate::gpio::Pull;
15use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Speed};
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 0f6ef569c..de2db9872 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr};
14use crate::gpio::{AfType, OutputType, Speed}; 14use crate::gpio::{AfType, OutputType, Speed};
15use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::{self}; 16use crate::interrupt::{self};
17use crate::{peripherals, rcc, Peri}; 17use crate::{Peri, peripherals, rcc};
18 18
19static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); 19static LTDC_WAKER: AtomicWaker = AtomicWaker::new();
20 20
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index e36719ef3..ac8d5de21 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -3,10 +3,10 @@
3 3
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::Peri;
6use crate::pac::opamp::vals::*; 7use crate::pac::opamp::vals::*;
7#[cfg(not(any(stm32g4, stm32f3)))] 8#[cfg(not(any(stm32g4, stm32f3)))]
8use crate::rcc::RccInfo; 9use crate::rcc::RccInfo;
9use crate::Peri;
10 10
11/// Performs a busy-wait delay for a specified number of microseconds. 11/// Performs a busy-wait delay for a specified number of microseconds.
12#[cfg(opamp_v5)] 12#[cfg(opamp_v5)]
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index d93cecb69..592a8594a 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -12,14 +12,14 @@ use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; 13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
14 14
15use crate::dma::{word, ChannelAndRequest}; 15use crate::dma::{ChannelAndRequest, word};
16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode}; 17use crate::mode::{Async, Blocking, Mode as PeriMode};
18use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{Octospi as Regs, vals};
19#[cfg(octospim_v1)] 19#[cfg(octospim_v1)]
20use crate::pac::octospim::Octospim; 20use crate::pac::octospim::Octospim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// OPSI driver config. 24/// OPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index b03cd9009..bb4f4f1d0 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
16use crate::rcc::{self, RccPeripheral}; 16use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peri}; 17use crate::{Peri, peripherals};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index e5f52c3c7..9cad03227 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,6 +1,8 @@
1use core::sync::atomic::{compiler_fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence};
2 2
3use crate::pac::common::{Reg, RW}; 3use crate::pac::common::{RW, Reg};
4#[cfg(backup_sram)]
5use crate::pac::pwr::vals::Retention;
4pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; 6pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
5use crate::time::Hertz; 7use crate::time::Hertz;
6 8
@@ -52,9 +54,9 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 54 }
53} 55}
54 56
55#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 57#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 58type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2l0, rtc_v2l1))] 59#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 60type Bdcr = crate::pac::rcc::regs::Csr;
59#[cfg(any(stm32c0))] 61#[cfg(any(stm32c0))]
60type Bdcr = crate::pac::rcc::regs::Csr1; 62type Bdcr = crate::pac::rcc::regs::Csr1;
@@ -78,9 +80,9 @@ fn unlock() {
78} 80}
79 81
80fn bdcr() -> Reg<Bdcr, RW> { 82fn bdcr() -> Reg<Bdcr, RW> {
81 #[cfg(any(rtc_v2l0, rtc_v2l1))] 83 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
82 return crate::pac::RCC.csr(); 84 return crate::pac::RCC.csr();
83 #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 85 #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
84 return crate::pac::RCC.bdcr(); 86 return crate::pac::RCC.bdcr();
85 #[cfg(any(stm32c0))] 87 #[cfg(any(stm32c0))]
86 return crate::pac::RCC.csr1(); 88 return crate::pac::RCC.csr1();
@@ -91,6 +93,8 @@ pub struct LsConfig {
91 pub rtc: RtcClockSource, 93 pub rtc: RtcClockSource,
92 pub lsi: bool, 94 pub lsi: bool,
93 pub lse: Option<LseConfig>, 95 pub lse: Option<LseConfig>,
96 #[cfg(backup_sram)]
97 pub enable_backup_sram: bool,
94} 98}
95 99
96impl LsConfig { 100impl LsConfig {
@@ -115,6 +119,8 @@ impl LsConfig {
115 peripherals_clocked: false, 119 peripherals_clocked: false,
116 }), 120 }),
117 lsi: false, 121 lsi: false,
122 #[cfg(backup_sram)]
123 enable_backup_sram: false,
118 } 124 }
119 } 125 }
120 126
@@ -123,6 +129,8 @@ impl LsConfig {
123 rtc: RtcClockSource::LSI, 129 rtc: RtcClockSource::LSI,
124 lsi: true, 130 lsi: true,
125 lse: None, 131 lse: None,
132 #[cfg(backup_sram)]
133 enable_backup_sram: false,
126 } 134 }
127 } 135 }
128 136
@@ -131,6 +139,8 @@ impl LsConfig {
131 rtc: RtcClockSource::DISABLE, 139 rtc: RtcClockSource::DISABLE,
132 lsi: false, 140 lsi: false,
133 lse: None, 141 lse: None,
142 #[cfg(backup_sram)]
143 enable_backup_sram: false,
134 } 144 }
135 } 145 }
136} 146}
@@ -200,6 +210,22 @@ impl LsConfig {
200 while !csr.read().lsi1rdy() {} 210 while !csr.read().lsi1rdy() {}
201 } 211 }
202 212
213 // Enable backup regulator for peristent battery backed sram
214 #[cfg(backup_sram)]
215 {
216 unsafe { super::BKSRAM_RETAINED = crate::pac::PWR.bdcr().read().bren() == Retention::PRESERVED };
217
218 crate::pac::PWR.bdcr().modify(|w| {
219 w.set_bren(match self.enable_backup_sram {
220 true => Retention::PRESERVED,
221 false => Retention::LOST,
222 });
223 });
224
225 // Wait for backup regulator voltage to stabilize
226 while self.enable_backup_sram && !crate::pac::PWR.bdsr().read().brrdy() {}
227 }
228
203 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. 229 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
204 // once set, changing it requires a backup domain reset. 230 // once set, changing it requires a backup domain reset.
205 // first check if the configuration matches what we want. 231 // first check if the configuration matches what we want.
@@ -329,7 +355,7 @@ impl LsConfig {
329 if self.rtc != RtcClockSource::DISABLE { 355 if self.rtc != RtcClockSource::DISABLE {
330 #[cfg(not(rcc_n6))] 356 #[cfg(not(rcc_n6))]
331 bdcr().modify(|w| { 357 bdcr().modify(|w| {
332 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] 358 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
333 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 359 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
334 360
335 #[cfg(not(rcc_wba))] 361 #[cfg(not(rcc_wba))]
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index c2295bab6..99f22273d 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -49,6 +49,10 @@ pub struct Config {
49 /// System Clock Configuration 49 /// System Clock Configuration
50 pub sys: Sysclk, 50 pub sys: Sysclk,
51 51
52 /// HSI48 Configuration
53 #[cfg(crs)]
54 pub hsi48: Option<super::Hsi48Config>,
55
52 pub ahb_pre: AHBPrescaler, 56 pub ahb_pre: AHBPrescaler,
53 pub apb1_pre: APBPrescaler, 57 pub apb1_pre: APBPrescaler,
54 58
@@ -68,6 +72,8 @@ impl Config {
68 }), 72 }),
69 hse: None, 73 hse: None,
70 sys: Sysclk::HSISYS, 74 sys: Sysclk::HSISYS,
75 #[cfg(crs)]
76 hsi48: Some(crate::rcc::Hsi48Config::new()),
71 ahb_pre: AHBPrescaler::DIV1, 77 ahb_pre: AHBPrescaler::DIV1,
72 apb1_pre: APBPrescaler::DIV1, 78 apb1_pre: APBPrescaler::DIV1,
73 ls: crate::rcc::LsConfig::new(), 79 ls: crate::rcc::LsConfig::new(),
@@ -127,6 +133,10 @@ pub(crate) unsafe fn init(config: Config) {
127 } 133 }
128 }; 134 };
129 135
136 // Configure HSI48 if required
137 #[cfg(crs)]
138 let hsi48 = config.hsi48.map(super::init_hsi48);
139
130 let rtc = config.ls.init(); 140 let rtc = config.ls.init();
131 141
132 let sys = match config.sys { 142 let sys = match config.sys {
@@ -185,13 +195,13 @@ pub(crate) unsafe fn init(config: Config) {
185 hsi: hsi, 195 hsi: hsi,
186 hsiker: hsiker, 196 hsiker: hsiker,
187 hse: hse, 197 hse: hse,
198 #[cfg(crs)]
199 hsi48: hsi48,
188 rtc: rtc, 200 rtc: rtc,
189 201
190 // TODO 202 // TODO
191 lsi: None, 203 lsi: None,
192 lse: None, 204 lse: None,
193 #[cfg(crs)]
194 hsi48: None,
195 ); 205 );
196 206
197 RCC.ccipr() 207 RCC.ccipr()
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 8f2e8db5f..d941054cd 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -1,13 +1,13 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3#[cfg(any(stm32f4, stm32f7))]
4use crate::pac::PWR;
3#[cfg(any(stm32f413, stm32f423, stm32f412))] 5#[cfg(any(stm32f413, stm32f423, stm32f412))]
4pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; 6pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource;
5pub use crate::pac::rcc::vals::{ 7pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 8 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 9 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 10};
9#[cfg(any(stm32f4, stm32f7))]
10use crate::pac::PWR;
11use crate::pac::{FLASH, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::time::Hertz; 12use crate::time::Hertz;
13 13
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 331bab7a0..485edd390 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) {
597 Hertz(24_000_000) => Usbrefcksel::MHZ24, 597 Hertz(24_000_000) => Usbrefcksel::MHZ24,
598 Hertz(26_000_000) => Usbrefcksel::MHZ26, 598 Hertz(26_000_000) => Usbrefcksel::MHZ26,
599 Hertz(32_000_000) => Usbrefcksel::MHZ32, 599 Hertz(32_000_000) => Usbrefcksel::MHZ32,
600 _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 600 _ => panic!(
601 "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
602 clk_val
603 ),
601 }, 604 },
602 None => Usbrefcksel::MHZ24, 605 None => Usbrefcksel::MHZ24,
603 }; 606 };
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 81b89046e..584957c6d 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,3 +1,6 @@
1#[cfg(all(feature = "low-power", stm32wlex))]
2use core::mem::MaybeUninit;
3
1#[cfg(any(stm32l0, stm32l1))] 4#[cfg(any(stm32l0, stm32l1))]
2pub use crate::pac::pwr::vals::Vos as VoltageScale; 5pub use crate::pac::pwr::vals::Vos as VoltageScale;
3use crate::pac::rcc::regs::Cfgr; 6use crate::pac::rcc::regs::Cfgr;
@@ -11,6 +14,42 @@ use crate::time::Hertz;
11/// HSI speed 14/// HSI speed
12pub const HSI_FREQ: Hertz = Hertz(16_000_000); 15pub const HSI_FREQ: Hertz = Hertz(16_000_000);
13 16
17/// Saved RCC Config
18///
19/// Used when exiting STOP2 to re-enable clocks to their last configured state
20/// for chips that need it.
21#[cfg(all(feature = "low-power", stm32wlex))]
22static mut RESUME_RCC_CONFIG: MaybeUninit<Config> = MaybeUninit::uninit();
23
24/// Set the rcc config to be restored when exiting STOP2
25///
26/// Safety: Sets a mutable global.
27#[cfg(all(feature = "low-power", stm32wlex))]
28pub(crate) unsafe fn set_resume_config(config: Config) {
29 trace!("rcc set_resume_config()");
30 RESUME_RCC_CONFIG = MaybeUninit::new(config);
31}
32
33/// Get the rcc config to be restored when exiting STOP2
34///
35/// Safety: Reads a mutable global.
36#[cfg(all(feature = "low-power", stm32wlex))]
37pub(crate) unsafe fn get_resume_config() -> Config {
38 *(*core::ptr::addr_of_mut!(RESUME_RCC_CONFIG)).assume_init_ref()
39}
40
41#[cfg(all(feature = "low-power", stm32wlex))]
42/// Safety: should only be called from low power executable just after resuming from STOP2
43pub(crate) unsafe fn apply_resume_config() {
44 trace!("rcc apply_resume_config()");
45
46 while RCC.cfgr().read().sws() != Sysclk::MSI {}
47
48 let config = get_resume_config();
49
50 init(config);
51}
52
14#[derive(Clone, Copy, Eq, PartialEq)] 53#[derive(Clone, Copy, Eq, PartialEq)]
15pub enum HseMode { 54pub enum HseMode {
16 /// crystal/ceramic oscillator (HSEBYP=0) 55 /// crystal/ceramic oscillator (HSEBYP=0)
@@ -154,6 +193,10 @@ fn msi_enable(range: MSIRange) {
154} 193}
155 194
156pub(crate) unsafe fn init(config: Config) { 195pub(crate) unsafe fn init(config: Config) {
196 // save the rcc config because if we enter stop 2 we need to re-apply it on wakeup
197 #[cfg(all(feature = "low-power", stm32wlex))]
198 set_resume_config(config);
199
157 // Switch to MSI to prevent problems with PLL configuration. 200 // Switch to MSI to prevent problems with PLL configuration.
158 if !RCC.cr().read().msion() { 201 if !RCC.cr().read().msion() {
159 // Turn on MSI and configure it to 4MHz. 202 // Turn on MSI and configure it to 4MHz.
@@ -499,9 +542,9 @@ pub use pll::*;
499 542
500#[cfg(any(stm32l0, stm32l1))] 543#[cfg(any(stm32l0, stm32l1))]
501mod pll { 544mod pll {
502 use super::{pll_enable, PllInstance}; 545 use super::{PllInstance, pll_enable};
503 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
504 use crate::pac::RCC; 546 use crate::pac::RCC;
547 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
505 use crate::time::Hertz; 548 use crate::time::Hertz;
506 549
507 #[derive(Clone, Copy)] 550 #[derive(Clone, Copy)]
@@ -563,11 +606,11 @@ mod pll {
563 606
564#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] 607#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
565mod pll { 608mod pll {
566 use super::{pll_enable, PllInstance}; 609 use super::{PllInstance, pll_enable};
610 use crate::pac::RCC;
567 pub use crate::pac::rcc::vals::{ 611 pub use crate::pac::rcc::vals::{
568 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, 612 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource,
569 }; 613 };
570 use crate::pac::RCC;
571 use crate::time::Hertz; 614 use crate::time::Hertz;
572 615
573 #[derive(Clone, Copy)] 616 #[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index a8f8cfcff..0624fdf26 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -3,6 +3,7 @@ use core::marker::PhantomData;
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::gpio::{AfType, OutputType, Speed}; 5use crate::gpio::{AfType, OutputType, Speed};
6use crate::pac::RCC;
6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] 7#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
7pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
8#[cfg(not(any( 9#[cfg(not(any(
@@ -33,8 +34,7 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource;
33 rcc_n6 34 rcc_n6
34))] 35))]
35pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 36pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
36use crate::pac::RCC; 37use crate::{Peri, peripherals};
37use crate::{peripherals, Peri};
38 38
39#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] 39#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
40#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] 40#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
@@ -95,12 +95,29 @@ pub struct Mco<'d, T: McoInstance> {
95 95
96impl<'d, T: McoInstance> Mco<'d, T> { 96impl<'d, T: McoInstance> Mco<'d, T> {
97 /// Create a new MCO instance. 97 /// Create a new MCO instance.
98 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 98 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, config: McoConfig) -> Self {
99 critical_section::with(|_| unsafe { 99 critical_section::with(|_| unsafe {
100 T::_apply_clock_settings(source, prescaler); 100 T::_apply_clock_settings(source, config.prescaler);
101 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 101 set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed));
102 }); 102 });
103 103
104 Self { phantom: PhantomData } 104 Self { phantom: PhantomData }
105 } 105 }
106} 106}
107
108#[non_exhaustive]
109pub struct McoConfig {
110 /// Master Clock Out prescaler
111 pub prescaler: McoPrescaler,
112 /// IO Drive Strength
113 pub speed: Speed,
114}
115
116impl Default for McoConfig {
117 fn default() -> Self {
118 Self {
119 prescaler: McoPrescaler::DIV1,
120 speed: Speed::VeryHigh,
121 }
122 }
123}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 1cd80c17f..592890777 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -34,7 +34,7 @@ mod _version;
34pub use _version::*; 34pub use _version::*;
35use stm32_metapac::RCC; 35use stm32_metapac::RCC;
36 36
37pub use crate::_generated::{mux, Clocks}; 37pub use crate::_generated::{Clocks, mux};
38use crate::time::Hertz; 38use crate::time::Hertz;
39 39
40#[cfg(feature = "low-power")] 40#[cfg(feature = "low-power")]
@@ -49,6 +49,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
49/// May be read without a critical section 49/// May be read without a critical section
50pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 50pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
51 51
52#[cfg(backup_sram)]
53pub(crate) static mut BKSRAM_RETAINED: bool = false;
54
52#[cfg(not(feature = "_dual-core"))] 55#[cfg(not(feature = "_dual-core"))]
53/// Frozen clock frequencies 56/// Frozen clock frequencies
54/// 57///
@@ -391,7 +394,7 @@ pub fn disable<T: RccPeripheral>() {
391/// 394///
392/// This should only be called after `init`. 395/// This should only be called after `init`.
393#[cfg(not(feature = "_dual-core"))] 396#[cfg(not(feature = "_dual-core"))]
394pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { 397pub fn reinit(config: Config, _rcc: &'_ mut crate::Peri<'_, crate::peripherals::RCC>) {
395 critical_section::with(|cs| init_rcc(cs, config)) 398 critical_section::with(|cs| init_rcc(cs, config))
396} 399}
397 400
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 06895a99a..7b0dcb63f 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7}; 7};
8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
12use crate::rcc::LSI_FREQ; 12use crate::rcc::LSI_FREQ;
13use crate::time::Hertz; 13use crate::time::Hertz;
14 14
@@ -442,7 +442,10 @@ pub(crate) unsafe fn init(config: Config) {
442 Hertz(24_000_000) => Usbrefcksel::MHZ24, 442 Hertz(24_000_000) => Usbrefcksel::MHZ24,
443 Hertz(26_000_000) => Usbrefcksel::MHZ26, 443 Hertz(26_000_000) => Usbrefcksel::MHZ26,
444 Hertz(32_000_000) => Usbrefcksel::MHZ32, 444 Hertz(32_000_000) => Usbrefcksel::MHZ32,
445 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 445 _ => panic!(
446 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
447 clk_val
448 ),
446 }, 449 },
447 None => Usbrefcksel::MHZ24, 450 None => Usbrefcksel::MHZ24,
448 }; 451 };
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 481437939..2528996d5 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{
7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, 7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv,
8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, 8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk,
9}; 9};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
12use crate::pac::{FLASH, RCC}; 10use crate::pac::{FLASH, RCC};
11#[cfg(all(peri_usb_otg_hs))]
12pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
13use crate::rcc::LSI_FREQ; 13use crate::rcc::LSI_FREQ;
14use crate::time::Hertz; 14use crate::time::Hertz;
15 15
@@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) {
245 Hertz(24_000_000) => Usbrefcksel::MHZ24, 245 Hertz(24_000_000) => Usbrefcksel::MHZ24,
246 Hertz(26_000_000) => Usbrefcksel::MHZ26, 246 Hertz(26_000_000) => Usbrefcksel::MHZ26,
247 Hertz(32_000_000) => Usbrefcksel::MHZ32, 247 Hertz(32_000_000) => Usbrefcksel::MHZ32,
248 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 248 _ => panic!(
249 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
250 clk_val
251 ),
249 }, 252 },
250 None => Usbrefcksel::MHZ24, 253 None => Usbrefcksel::MHZ24,
251 }; 254 };
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 63654639e..dada9bda1 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -9,7 +9,7 @@ use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, pac, peripherals, rcc, Peri}; 12use crate::{Peri, interrupt, pac, peripherals, rcc};
13 13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 15
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index 78ccd3e6c..e5bf30927 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,6 +1,10 @@
1use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; 1#[cfg(feature = "time")]
2use embassy_time::{Duration, TICK_HZ};
3
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt;
2use crate::peripherals::RTC; 6use crate::peripherals::RTC;
3use crate::rtc::SealedInstance; 7use crate::rtc::{RtcTimeProvider, SealedInstance};
4 8
5/// Represents an instant in time that can be substracted to compute a duration 9/// Represents an instant in time that can be substracted to compute a duration
6pub(super) struct RtcInstant { 10pub(super) struct RtcInstant {
@@ -11,7 +15,7 @@ pub(super) struct RtcInstant {
11} 15}
12 16
13impl RtcInstant { 17impl RtcInstant {
14 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
15 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> { 19 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
16 if second > 59 { 20 if second > 59 {
17 Err(DateTimeError::InvalidSecond) 21 Err(DateTimeError::InvalidSecond)
@@ -38,8 +42,6 @@ impl core::ops::Sub for RtcInstant {
38 type Output = embassy_time::Duration; 42 type Output = embassy_time::Duration;
39 43
40 fn sub(self, rhs: Self) -> Self::Output { 44 fn sub(self, rhs: Self) -> Self::Output {
41 use embassy_time::{Duration, TICK_HZ};
42
43 let second = if self.second < rhs.second { 45 let second = if self.second < rhs.second {
44 self.second + 60 46 self.second + 60
45 } else { 47 } else {
@@ -66,7 +68,7 @@ pub(crate) enum WakeupPrescaler {
66} 68}
67 69
68#[cfg(any( 70#[cfg(any(
69 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba 71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
70))] 72))]
71impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
72 fn from(val: WakeupPrescaler) -> Self { 74 fn from(val: WakeupPrescaler) -> Self {
@@ -82,7 +84,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
82} 84}
83 85
84#[cfg(any( 86#[cfg(any(
85 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba 87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
86))] 88))]
87impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
88 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
@@ -115,7 +117,7 @@ impl WakeupPrescaler {
115impl Rtc { 117impl Rtc {
116 /// Return the current instant. 118 /// Return the current instant.
117 fn instant(&self) -> Result<RtcInstant, RtcError> { 119 fn instant(&self) -> Result<RtcInstant, RtcError> {
118 self.time_provider().read(|_, tr, ss| { 120 RtcTimeProvider::new().read(|_, tr, ss| {
119 let second = bcd2_to_byte((tr.st(), tr.su())); 121 let second = bcd2_to_byte((tr.st(), tr.su()));
120 122
121 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
@@ -125,15 +127,10 @@ impl Rtc {
125 /// start the wakeup alarm and with a duration that is as close to but less than 127 /// start the wakeup alarm and with a duration that is as close to but less than
126 /// the requested duration, and record the instant the wakeup alarm was started 128 /// the requested duration, and record the instant the wakeup alarm was started
127 pub(crate) fn start_wakeup_alarm( 129 pub(crate) fn start_wakeup_alarm(
128 &self, 130 &mut self,
129 requested_duration: embassy_time::Duration, 131 requested_duration: embassy_time::Duration,
130 cs: critical_section::CriticalSection, 132 cs: critical_section::CriticalSection,
131 ) { 133 ) {
132 use embassy_time::{Duration, TICK_HZ};
133
134 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
135 use crate::pac::rtc::vals::Calrf;
136
137 // Panic if the rcc mod knows we're not using low-power rtc 134 // Panic if the rcc mod knows we're not using low-power rtc
138 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 135 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
139 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); 136 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
@@ -150,17 +147,15 @@ impl Rtc {
150 self.write(false, |regs| { 147 self.write(false, |regs| {
151 regs.cr().modify(|w| w.set_wute(false)); 148 regs.cr().modify(|w| w.set_wute(false));
152 149
153 #[cfg(any( 150 #[cfg(rtc_v2)]
154 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
155 ))]
156 { 151 {
157 regs.isr().modify(|w| w.set_wutf(false)); 152 regs.isr().modify(|w| w.set_wutf(false));
158 while !regs.isr().read().wutwf() {} 153 while !regs.isr().read().wutwf() {}
159 } 154 }
160 155
161 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 156 #[cfg(rtc_v3)]
162 { 157 {
163 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 158 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
164 while !regs.icsr().read().wutwf() {} 159 while !regs.icsr().read().wutwf() {}
165 } 160 }
166 161
@@ -184,11 +179,10 @@ impl Rtc {
184 179
185 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
186 /// was called, otherwise none 181 /// was called, otherwise none
187 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 182 pub(crate) fn stop_wakeup_alarm(
188 use crate::interrupt::typelevel::Interrupt; 183 &mut self,
189 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 184 cs: critical_section::CriticalSection,
190 use crate::pac::rtc::vals::Calrf; 185 ) -> Option<embassy_time::Duration> {
191
192 let instant = self.instant().unwrap(); 186 let instant = self.instant().unwrap();
193 if RTC::regs().cr().read().wute() { 187 if RTC::regs().cr().read().wute() {
194 trace!("rtc: stop wakeup alarm at {}", instant); 188 trace!("rtc: stop wakeup alarm at {}", instant);
@@ -197,13 +191,10 @@ impl Rtc {
197 regs.cr().modify(|w| w.set_wutie(false)); 191 regs.cr().modify(|w| w.set_wutie(false));
198 regs.cr().modify(|w| w.set_wute(false)); 192 regs.cr().modify(|w| w.set_wute(false));
199 193
200 #[cfg(any( 194 #[cfg(rtc_v2)]
201 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
202 ))]
203 regs.isr().modify(|w| w.set_wutf(false)); 195 regs.isr().modify(|w| w.set_wutf(false));
204 196 #[cfg(rtc_v3)]
205 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 197 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
206 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
207 198
208 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, 199 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
209 // there is a table for every "Event input" / "EXTI Line". 200 // there is a table for every "Event input" / "EXTI Line".
@@ -222,8 +213,6 @@ impl Rtc {
222 } 213 }
223 214
224 pub(crate) fn enable_wakeup_line(&self) { 215 pub(crate) fn enable_wakeup_line(&self) {
225 use crate::interrupt::typelevel::Interrupt;
226
227 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 216 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
228 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 217 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
229 218
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 449f3008a..116b3c7ed 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,33 +5,32 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::Cell; 8use core::cell::{Cell, RefCell, RefMut};
9#[cfg(feature = "low-power")]
10use core::ops;
9 11
10#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 13use critical_section::CriticalSection;
12#[cfg(feature = "low-power")] 14#[cfg(feature = "low-power")]
13use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
16#[cfg(feature = "low-power")]
17use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14 18
15use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
16pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 19pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
20use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
17use crate::pac::rtc::regs::{Dr, Tr}; 21use crate::pac::rtc::regs::{Dr, Tr};
18use crate::time::Hertz; 22use crate::time::Hertz;
19 23
20/// refer to AN4759 to compare features of RTC2 and RTC3 24/// refer to AN4759 to compare features of RTC2 and RTC3
21#[cfg_attr(any(rtc_v1), path = "v1.rs")] 25#[cfg_attr(rtc_v1, path = "v1.rs")]
22#[cfg_attr( 26#[cfg_attr(rtc_v2, path = "v2.rs")]
23 any( 27#[cfg_attr(rtc_v3, path = "v3.rs")]
24 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
25 ),
26 path = "v2.rs"
27)]
28#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs, rtc_v3c0), path = "v3.rs")]
29mod _version; 28mod _version;
30#[allow(unused_imports)] 29#[allow(unused_imports)]
31pub use _version::*; 30pub use _version::*;
32 31
33use crate::peripherals::RTC;
34use crate::Peri; 32use crate::Peri;
33use crate::peripherals::RTC;
35 34
36/// Errors that can occur on methods on [RtcClock] 35/// Errors that can occur on methods on [RtcClock]
37#[non_exhaustive] 36#[non_exhaustive]
@@ -49,11 +48,17 @@ pub enum RtcError {
49} 48}
50 49
51/// Provides immutable access to the current time of the RTC. 50/// Provides immutable access to the current time of the RTC.
51#[derive(Clone)]
52pub struct RtcTimeProvider { 52pub struct RtcTimeProvider {
53 _private: (), 53 _private: (),
54} 54}
55 55
56impl RtcTimeProvider { 56impl RtcTimeProvider {
57 /// Create a new RTC time provider instance.
58 pub(self) const fn new() -> Self {
59 Self { _private: () }
60 }
61
57 /// Return the current datetime. 62 /// Return the current datetime.
58 /// 63 ///
59 /// # Errors 64 /// # Errors
@@ -72,12 +77,12 @@ impl RtcTimeProvider {
72 77
73 // Calculate second fraction and multiply to microseconds 78 // Calculate second fraction and multiply to microseconds
74 // Formula from RM0410 79 // Formula from RM0410
75 #[cfg(not(rtc_v2f2))] 80 #[cfg(not(rtc_v2_f2))]
76 let us = { 81 let us = {
77 let prediv = RTC::regs().prer().read().prediv_s() as f32; 82 let prediv = RTC::regs().prer().read().prediv_s() as f32;
78 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 83 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32
79 }; 84 };
80 #[cfg(rtc_v2f2)] 85 #[cfg(rtc_v2_f2)]
81 let us = 0; 86 let us = 0;
82 87
83 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) 88 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime)
@@ -87,9 +92,9 @@ impl RtcTimeProvider {
87 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> { 92 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> {
88 let r = RTC::regs(); 93 let r = RTC::regs();
89 94
90 #[cfg(not(rtc_v2f2))] 95 #[cfg(not(rtc_v2_f2))]
91 let read_ss = || r.ssr().read().ss(); 96 let read_ss = || r.ssr().read().ss();
92 #[cfg(rtc_v2f2)] 97 #[cfg(rtc_v2_f2)]
93 let read_ss = || 0; 98 let read_ss = || 0;
94 99
95 let mut ss = read_ss(); 100 let mut ss = read_ss();
@@ -111,6 +116,50 @@ impl RtcTimeProvider {
111 } 116 }
112} 117}
113 118
119#[cfg(feature = "low-power")]
120/// Contains an RTC driver.
121pub struct RtcContainer {
122 pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
123}
124
125#[cfg(feature = "low-power")]
126impl RtcContainer {
127 pub(self) const fn new() -> Self {
128 Self {
129 mutex: &crate::time_driver::get_driver().rtc,
130 }
131 }
132
133 /// Acquire an RTC borrow.
134 pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> {
135 RtcBorrow {
136 ref_mut: self.mutex.borrow(cs).borrow_mut(),
137 }
138 }
139}
140
141#[cfg(feature = "low-power")]
142/// Contains an RTC borrow.
143pub struct RtcBorrow<'a> {
144 pub(self) ref_mut: RefMut<'a, Option<Rtc>>,
145}
146
147#[cfg(feature = "low-power")]
148impl<'a> ops::Deref for RtcBorrow<'a> {
149 type Target = Rtc;
150
151 fn deref(&self) -> &Self::Target {
152 self.ref_mut.as_ref().unwrap()
153 }
154}
155
156#[cfg(feature = "low-power")]
157impl<'a> ops::DerefMut for RtcBorrow<'a> {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 self.ref_mut.as_mut().unwrap()
160 }
161}
162
114/// RTC driver. 163/// RTC driver.
115pub struct Rtc { 164pub struct Rtc {
116 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
@@ -126,13 +175,21 @@ pub struct RtcConfig {
126 /// 175 ///
127 /// A high counter frequency may impact stop power consumption 176 /// A high counter frequency may impact stop power consumption
128 pub frequency: Hertz, 177 pub frequency: Hertz,
178
179 #[cfg(feature = "_allow-disable-rtc")]
180 /// Allow disabling the rtc, even when stop is configured
181 pub _disable_rtc: bool,
129} 182}
130 183
131impl Default for RtcConfig { 184impl Default for RtcConfig {
132 /// LSI with prescalers assuming 32.768 kHz. 185 /// LSI with prescalers assuming 32.768 kHz.
133 /// Raw sub-seconds in 1/256. 186 /// Raw sub-seconds in 1/256.
134 fn default() -> Self { 187 fn default() -> Self {
135 RtcConfig { frequency: Hertz(256) } 188 RtcConfig {
189 frequency: Hertz(256),
190 #[cfg(feature = "_allow-disable-rtc")]
191 _disable_rtc: false,
192 }
136 } 193 }
137} 194}
138 195
@@ -150,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod {
150} 207}
151 208
152impl Rtc { 209impl Rtc {
210 #[cfg(not(feature = "low-power"))]
153 /// Create a new RTC instance. 211 /// Create a new RTC instance.
154 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { 212 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> (Self, RtcTimeProvider) {
213 (Self::new_inner(rtc_config), RtcTimeProvider::new())
214 }
215
216 #[cfg(feature = "low-power")]
217 /// Create a new RTC instance.
218 pub fn new(_rtc: Peri<'static, RTC>) -> (RtcContainer, RtcTimeProvider) {
219 (RtcContainer::new(), RtcTimeProvider::new())
220 }
221
222 pub(self) fn new_inner(rtc_config: RtcConfig) -> Self {
155 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 223 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
156 crate::rcc::enable_and_reset::<RTC>(); 224 crate::rcc::enable_and_reset::<RTC>();
157 225
@@ -168,12 +236,15 @@ impl Rtc {
168 this.configure(async_psc, sync_psc); 236 this.configure(async_psc, sync_psc);
169 237
170 // Wait for the clock to update after initialization 238 // Wait for the clock to update after initialization
171 #[cfg(not(rtc_v2f2))] 239 #[cfg(not(rtc_v2_f2))]
172 { 240 {
173 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 241 let now = RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap();
174 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 242 while now == RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap() {}
175 } 243 }
176 244
245 #[cfg(feature = "low-power")]
246 this.enable_wakeup_line();
247
177 this 248 this
178 } 249 }
179 250
@@ -182,11 +253,6 @@ impl Rtc {
182 freqs.rtc.to_hertz().unwrap() 253 freqs.rtc.to_hertz().unwrap()
183 } 254 }
184 255
185 /// Acquire a [`RtcTimeProvider`] instance.
186 pub const fn time_provider(&self) -> RtcTimeProvider {
187 RtcTimeProvider { _private: () }
188 }
189
190 /// Set the datetime to a new value. 256 /// Set the datetime to a new value.
191 /// 257 ///
192 /// # Errors 258 /// # Errors
@@ -230,15 +296,6 @@ impl Rtc {
230 Ok(()) 296 Ok(())
231 } 297 }
232 298
233 /// Return the current datetime.
234 ///
235 /// # Errors
236 ///
237 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
238 pub fn now(&self) -> Result<DateTime, RtcError> {
239 self.time_provider().now()
240 }
241
242 /// Check if daylight savings time is active. 299 /// Check if daylight savings time is active.
243 pub fn get_daylight_savings(&self) -> bool { 300 pub fn get_daylight_savings(&self) -> bool {
244 let cr = RTC::regs().cr().read(); 301 let cr = RTC::regs().cr().read();
@@ -320,3 +377,15 @@ trait SealedInstance {
320 377
321 // fn apply_config(&mut self, rtc_config: RtcConfig); 378 // fn apply_config(&mut self, rtc_config: RtcConfig);
322} 379}
380
381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) {
383 #[cfg(feature = "_allow-disable-rtc")]
384 if config._disable_rtc {
385 return;
386 }
387
388 crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config));
389
390 trace!("low power: stop with rtc configured");
391}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 28380a3c0..8ac022536 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -11,11 +11,11 @@ impl super::Rtc {
11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { 11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
12 self.write(true, |rtc| { 12 self.write(true, |rtc| {
13 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
14 #[cfg(not(rtc_v2f2))] 14 #[cfg(not(rtc_v2_f2))]
15 w.set_bypshad(true); 15 w.set_bypshad(true);
16 #[cfg(rtc_v2f2)] 16 #[cfg(rtc_v2_f2)]
17 w.set_fmt(false); 17 w.set_fmt(false);
18 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); 19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
20 w.set_osel(Osel::DISABLED); 20 w.set_osel(Osel::DISABLED);
21 w.set_pol(Pol::HIGH); 21 w.set_pol(Pol::HIGH);
@@ -36,7 +36,7 @@ impl super::Rtc {
36 /// 36 ///
37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler` 37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12). 38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
39 #[cfg(not(rtc_v2f2))] 39 #[cfg(not(rtc_v2_f2))]
40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) { 40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) {
41 const RTC_CALR_MIN_PPM: f32 = -487.1; 41 const RTC_CALR_MIN_PPM: f32 = -487.1;
42 const RTC_CALR_MAX_PPM: f32 = 488.5; 42 const RTC_CALR_MAX_PPM: f32 = 488.5;
@@ -93,7 +93,7 @@ impl super::Rtc {
93 }) 93 })
94 } 94 }
95 95
96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 96 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
97 where 97 where
98 F: FnOnce(crate::pac::rtc::Rtc) -> R, 98 F: FnOnce(crate::pac::rtc::Rtc) -> R,
99 { 99 {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index d0b52049e..f7ebea73e 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw8, Calw16, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::RtcCalibrationCyclePeriod; 3use super::RtcCalibrationCyclePeriod;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -95,7 +95,7 @@ impl super::Rtc {
95 }) 95 })
96 } 96 }
97 97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 98 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
99 where 99 where
100 F: FnOnce(crate::pac::rtc::Rtc) -> R, 100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 { 101 {
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] { 134 if #[cfg(any(stm32g4, stm32wlex))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] { 145 if #[cfg(any(stm32g4, stm32wlex))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index fb8b23b79..726d1729a 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -6,12 +6,12 @@ use core::marker::PhantomData;
6use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7 7
8pub use crate::dma::word; 8pub use crate::dma::word;
9use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 9use crate::dma::{Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer, ringbuffer};
10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; 11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider;
12use crate::pac::sai::{vals, Sai as Regs}; 12use crate::pac::sai::{Sai as Regs, vals};
13use crate::rcc::{self, RccPeripheral}; 13use crate::rcc::{self, RccPeripheral};
14use crate::{peripherals, Peri}; 14use crate::{Peri, peripherals};
15 15
16/// SAI error 16/// SAI error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)] 17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ccbd16cbf..e05131040 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -11,9 +11,9 @@ use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::common_cmd::{self, Resp, ResponseLen}; 13use sdio_host::common_cmd::{self, Resp, ResponseLen};
14use sdio_host::emmc::{ExtCSD, EMMC}; 14use sdio_host::emmc::{EMMC, ExtCSD};
15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; 15use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus};
16use sdio_host::{emmc_cmd, sd_cmd, Cmd}; 16use sdio_host::{Cmd, emmc_cmd, sd_cmd};
17 17
18#[cfg(sdmmc_v1)] 18#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest; 19use crate::dma::ChannelAndRequest;
@@ -1032,12 +1032,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1032 1032
1033 /// Wait for a previously started datapath transfer to complete from an interrupt. 1033 /// Wait for a previously started datapath transfer to complete from an interrupt.
1034 #[inline] 1034 #[inline]
1035 #[allow(unused)]
1035 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { 1036 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> {
1036 let regs = T::regs();
1037
1038 let res = poll_fn(|cx| { 1037 let res = poll_fn(|cx| {
1038 // Compiler might not be sufficiently constrained here
1039 // https://github.com/embassy-rs/embassy/issues/4723
1039 T::state().register(cx.waker()); 1040 T::state().register(cx.waker());
1040 let status = regs.star().read(); 1041 let status = T::regs().star().read();
1041 1042
1042 if status.dcrcfail() { 1043 if status.dcrcfail() {
1043 return Poll::Ready(Err(Error::Crc)); 1044 return Poll::Ready(Err(Error::Crc));
@@ -1052,10 +1053,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1052 if status.stbiterr() { 1053 if status.stbiterr() {
1053 return Poll::Ready(Err(Error::StBitErr)); 1054 return Poll::Ready(Err(Error::StBitErr));
1054 } 1055 }
1056 #[cfg(sdmmc_v1)]
1055 let done = match block { 1057 let done = match block {
1056 true => status.dbckend(), 1058 true => status.dbckend(),
1057 false => status.dataend(), 1059 false => status.dataend(),
1058 }; 1060 };
1061 #[cfg(sdmmc_v2)]
1062 let done = status.dataend();
1059 if done { 1063 if done {
1060 return Poll::Ready(Ok(())); 1064 return Poll::Ready(Ok(()));
1061 } 1065 }
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index b0a32d5d1..6f2d24560 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -13,7 +13,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::spdifrx::Spdifrx as Regs; 14use crate::pac::spdifrx::Spdifrx as Regs;
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 15use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18/// Possible S/PDIF preamble types. 18/// Possible S/PDIF preamble types.
19#[allow(dead_code)] 19#[allow(dead_code)]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c5373a54d..abb80ed26 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,15 +6,15 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
10 10
11use crate::dma::{word, ChannelAndRequest}; 11use crate::Peri;
12use crate::dma::{ChannelAndRequest, word};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
14use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{Spi as Regs, regs, vals};
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 16use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::Peri;
18 18
19/// SPI error. 19/// SPI error.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)] 20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -125,26 +125,69 @@ impl Config {
125 ) 125 )
126 } 126 }
127} 127}
128
129/// SPI communication mode
130pub mod mode {
131 use stm32_metapac::spi::vals;
132
133 trait SealedMode {}
134
135 /// Trait for SPI communication mode operations.
136 #[allow(private_bounds)]
137 pub trait CommunicationMode: SealedMode {
138 /// Spi communication mode
139 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
140 const MASTER: vals::Mstr;
141 /// Spi communication mode
142 #[cfg(any(spi_v4, spi_v5, spi_v6))]
143 const MASTER: vals::Master;
144 }
145
146 /// Mode allowing for SPI master operations.
147 pub struct Master;
148 /// Mode allowing for SPI slave operations.
149 pub struct Slave;
150
151 impl SealedMode for Master {}
152 impl CommunicationMode for Master {
153 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
154 const MASTER: vals::Mstr = vals::Mstr::MASTER;
155 #[cfg(any(spi_v4, spi_v5, spi_v6))]
156 const MASTER: vals::Master = vals::Master::MASTER;
157 }
158
159 impl SealedMode for Slave {}
160 impl CommunicationMode for Slave {
161 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
162 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
163 #[cfg(any(spi_v4, spi_v5, spi_v6))]
164 const MASTER: vals::Master = vals::Master::SLAVE;
165 }
166}
167use mode::{CommunicationMode, Master, Slave};
168
128/// SPI driver. 169/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 170pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 171 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 172 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 173 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 174 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 175 miso: Option<Peri<'d, AnyPin>>,
176 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 177 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 178 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 179 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 180 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 181 gpio_speed: Speed,
140} 182}
141 183
142impl<'d, M: PeriMode> Spi<'d, M> { 184impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 185 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 186 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 187 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 188 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 189 miso: Option<Peri<'d, AnyPin>>,
190 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 191 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 192 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 193 config: Config,
@@ -155,6 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 198 sck,
156 mosi, 199 mosi,
157 miso, 200 miso,
201 nss,
158 tx_dma, 202 tx_dma,
159 rx_dma, 203 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 204 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -183,12 +227,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
183 w.set_cpha(cpha); 227 w.set_cpha(cpha);
184 w.set_cpol(cpol); 228 w.set_cpol(cpol);
185 229
186 w.set_mstr(vals::Mstr::MASTER); 230 w.set_mstr(CM::MASTER);
187 w.set_br(br); 231 w.set_br(br);
188 w.set_spe(true); 232 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 233 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 234 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 235 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
192 w.set_crcen(false); 236 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 237 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 238 // we're doing "fake rxonly", by actually writing one
@@ -210,11 +254,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
210 w.set_cpha(cpha); 254 w.set_cpha(cpha);
211 w.set_cpol(cpol); 255 w.set_cpol(cpol);
212 256
213 w.set_mstr(vals::Mstr::MASTER); 257 w.set_mstr(CM::MASTER);
214 w.set_br(br); 258 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 259 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 260 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 261 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
218 w.set_crcen(false); 262 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 263 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 264 w.set_spe(true);
@@ -229,8 +273,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
229 w.set_cpha(cpha); 273 w.set_cpha(cpha);
230 w.set_cpol(cpol); 274 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 275 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 276 w.set_ssm(CM::MASTER == vals::Master::MASTER);
233 w.set_master(vals::Master::MASTER); 277 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 278 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 279 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 280 w.set_midi(0);
@@ -469,7 +513,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 513 }
470} 514}
471 515
472impl<'d> Spi<'d, Blocking> { 516impl<'d> Spi<'d, Blocking, Slave> {
517 /// Create a new blocking SPI slave driver.
518 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
519 peri: Peri<'d, T>,
520 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
521 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
522 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
523 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
524 config: Config,
525 ) -> Self {
526 Self::new_inner(
527 peri,
528 new_pin!(sck, config.sck_af()),
529 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
530 new_pin!(miso, AfType::input(config.miso_pull)),
531 new_pin!(cs, AfType::input(Pull::None)),
532 None,
533 None,
534 config,
535 )
536 }
537}
538
539impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 540 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 541 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 542 peri: Peri<'d, T>,
@@ -485,6 +552,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 552 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 553 None,
487 None, 554 None,
555 None,
488 config, 556 config,
489 ) 557 )
490 } 558 }
@@ -503,6 +571,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 571 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 572 None,
505 None, 573 None,
574 None,
506 config, 575 config,
507 ) 576 )
508 } 577 }
@@ -521,6 +590,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 590 None,
522 None, 591 None,
523 None, 592 None,
593 None,
524 config, 594 config,
525 ) 595 )
526 } 596 }
@@ -540,12 +610,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 610 None,
541 None, 611 None,
542 None, 612 None,
613 None,
543 config, 614 config,
544 ) 615 )
545 } 616 }
546} 617}
547 618
548impl<'d> Spi<'d, Async> { 619impl<'d> Spi<'d, Async, Slave> {
620 /// Create a new SPI slave driver.
621 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
622 peri: Peri<'d, T>,
623 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
624 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
625 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
626 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
627 tx_dma: Peri<'d, impl TxDma<T>>,
628 rx_dma: Peri<'d, impl RxDma<T>>,
629 config: Config,
630 ) -> Self {
631 Self::new_inner(
632 peri,
633 new_pin!(sck, config.sck_af()),
634 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
635 new_pin!(miso, AfType::input(config.miso_pull)),
636 new_pin!(cs, AfType::input(Pull::None)),
637 new_dma!(tx_dma),
638 new_dma!(rx_dma),
639 config,
640 )
641 }
642}
643
644impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 645 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 646 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 647 peri: Peri<'d, T>,
@@ -561,6 +657,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 657 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 658 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 659 new_pin!(miso, AfType::input(config.miso_pull)),
660 None,
564 new_dma!(tx_dma), 661 new_dma!(tx_dma),
565 new_dma!(rx_dma), 662 new_dma!(rx_dma),
566 config, 663 config,
@@ -581,6 +678,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 678 new_pin!(sck, config.sck_af()),
582 None, 679 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 680 new_pin!(miso, AfType::input(config.miso_pull)),
681 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 682 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 683 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 684 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,6 +701,7 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 701 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 702 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 703 None,
704 None,
606 new_dma!(tx_dma), 705 new_dma!(tx_dma),
607 None, 706 None,
608 config, 707 config,
@@ -623,6 +722,7 @@ impl<'d> Spi<'d, Async> {
623 None, 722 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 723 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 724 None,
725 None,
626 new_dma!(tx_dma), 726 new_dma!(tx_dma),
627 None, 727 None,
628 config, 728 config,
@@ -646,7 +746,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 746 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 747 config.frequency = freq;
648 748
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 749 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 750 }
651 751
652 #[allow(dead_code)] 752 #[allow(dead_code)]
@@ -656,9 +756,11 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 756 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 757 config: Config,
658 ) -> Self { 758 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 759 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 760 }
761}
661 762
763impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 764 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 765 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664 if data.is_empty() { 766 if data.is_empty() {
@@ -888,11 +990,12 @@ impl<'d> Spi<'d, Async> {
888 } 990 }
889} 991}
890 992
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 993impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 994 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 995 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 996 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 997 self.miso.as_ref().map(|x| x.set_as_disconnected());
998 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 999
897 self.info.rcc.disable(); 1000 self.info.rcc.disable();
898 } 1001 }
@@ -1127,7 +1230,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1230// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1231macro_rules! impl_blocking {
1129 ($w:ident) => { 1232 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1233 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1234 type Error = Error;
1132 1235
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1236 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1238,7 @@ macro_rules! impl_blocking {
1135 } 1238 }
1136 } 1239 }
1137 1240
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1241 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1242 type Error = Error;
1140 1243
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1244 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1252,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1252impl_blocking!(u8);
1150impl_blocking!(u16); 1253impl_blocking!(u16);
1151 1254
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1255impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1256 type Error = Error;
1154} 1257}
1155 1258
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1259impl<'d, W: Word, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M, CM> {
1157 fn flush(&mut self) -> Result<(), Self::Error> { 1260 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1261 Ok(())
1159 } 1262 }
@@ -1186,7 +1289,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1289 }
1187} 1290}
1188 1291
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1292impl<'d, W: Word, CM: CommunicationMode> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async, CM> {
1190 async fn flush(&mut self) -> Result<(), Self::Error> { 1293 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1294 Ok(())
1192 } 1295 }
@@ -1328,7 +1431,7 @@ foreach_peripheral!(
1328 }; 1431 };
1329); 1432);
1330 1433
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1434impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1435 type Config = Config;
1333 type ConfigError = (); 1436 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1437 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7db74bdf6..7db51d72e 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,14 +1,16 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::{Cell, RefCell}; 3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4#[cfg(all(feature = "low-power", stm32wlex))]
5use core::sync::atomic::AtomicU16;
6use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
5 7
6use critical_section::CriticalSection; 8use critical_section::CriticalSection;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::blocking_mutex::Mutex; 9use embassy_sync::blocking_mutex::Mutex;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_time_driver::{Driver, TICK_HZ}; 11use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_utils::Queue; 12use embassy_time_queue_utils::Queue;
11use stm32_metapac::timer::{regs, TimGp16}; 13use stm32_metapac::timer::{TimGp16, regs};
12 14
13use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals; 16use crate::pac::timer::vals;
@@ -213,7 +215,13 @@ pub(crate) struct RtcDriver {
213 period: AtomicU32, 215 period: AtomicU32,
214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>, 216 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
215 #[cfg(feature = "low-power")] 217 #[cfg(feature = "low-power")]
216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 218 pub(crate) rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
219 #[cfg(feature = "low-power")]
220 /// The minimum pause time beyond which the executor will enter a low-power state.
221 min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>,
222 /// Saved count for the timer (its value is lost when entering STOP2)
223 #[cfg(all(feature = "low-power", stm32wlex))]
224 saved_count: AtomicU16,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 225 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
218} 226}
219 227
@@ -221,12 +229,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
221 period: AtomicU32::new(0), 229 period: AtomicU32::new(0),
222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 230 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
223 #[cfg(feature = "low-power")] 231 #[cfg(feature = "low-power")]
224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 232 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)),
233 #[cfg(feature = "low-power")]
234 min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))),
235 #[cfg(all(feature = "low-power", stm32wlex))]
236 saved_count: AtomicU16::new(0),
225 queue: Mutex::new(RefCell::new(Queue::new())) 237 queue: Mutex::new(RefCell::new(Queue::new()))
226}); 238});
227 239
228impl RtcDriver { 240impl RtcDriver {
229 fn init(&'static self, cs: critical_section::CriticalSection) { 241 /// initialize the timer, but don't start it. Used for chips like stm32wle5
242 /// for low power where the timer config is lost in STOP2.
243 fn init_timer(&'static self, cs: critical_section::CriticalSection) {
230 let r = regs_gp16(); 244 let r = regs_gp16();
231 245
232 rcc::enable_and_reset_with_cs::<T>(cs); 246 rcc::enable_and_reset_with_cs::<T>(cs);
@@ -259,10 +273,16 @@ impl RtcDriver {
259 w.set_ccie(0, true); 273 w.set_ccie(0, true);
260 }); 274 });
261 275
276 #[cfg(all(feature = "low-power", stm32wlex))]
277 r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst)));
278
262 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); 279 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
263 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() }; 280 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() };
281 }
264 282
265 r.cr1().modify(|w| w.set_cen(true)); 283 fn init(&'static self, cs: CriticalSection) {
284 self.init_timer(cs);
285 regs_gp16().cr1().modify(|w| w.set_cen(true));
266 } 286 }
267 287
268 fn on_interrupt(&self) { 288 fn on_interrupt(&self) {
@@ -379,27 +399,26 @@ impl RtcDriver {
379 #[cfg(feature = "low-power")] 399 #[cfg(feature = "low-power")]
380 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 400 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
381 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 401 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
382 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { 402 if let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) {
383 self.add_time(offset, cs); 403 self.add_time(offset, cs);
384 } 404 }
385 } 405 }
386 406
387 /* 407 /*
388 Low-power public functions: all create a critical section 408 Low-power public functions: all create or require a critical section
389 */ 409 */
390 #[cfg(feature = "low-power")] 410 #[cfg(feature = "low-power")]
391 /// Set the rtc but panic if it's already been set 411 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
392 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { 412 self.min_stop_pause.borrow(cs).replace(min_stop_pause);
393 critical_section::with(|cs| {
394 rtc.stop_wakeup_alarm(cs);
395
396 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
397 });
398 } 413 }
399 414
400 #[cfg(feature = "low-power")] 415 #[cfg(feature = "low-power")]
401 /// The minimum pause time beyond which the executor will enter a low-power state. 416 /// Set the rtc but panic if it's already been set
402 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); 417 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
418 rtc.stop_wakeup_alarm(cs);
419
420 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
421 }
403 422
404 #[cfg(feature = "low-power")] 423 #[cfg(feature = "low-power")]
405 /// Pause the timer if ready; return err if not 424 /// Pause the timer if ready; return err if not
@@ -413,17 +432,25 @@ impl RtcDriver {
413 self.stop_wakeup_alarm(cs); 432 self.stop_wakeup_alarm(cs);
414 433
415 let time_until_next_alarm = self.time_until_next_alarm(cs); 434 let time_until_next_alarm = self.time_until_next_alarm(cs);
416 if time_until_next_alarm < Self::MIN_STOP_PAUSE { 435 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
436 trace!(
437 "time_until_next_alarm < self.min_stop_pause ({})",
438 time_until_next_alarm
439 );
417 Err(()) 440 Err(())
418 } else { 441 } else {
419 self.rtc 442 self.rtc
420 .borrow(cs) 443 .borrow(cs)
421 .get() 444 .borrow_mut()
445 .as_mut()
422 .unwrap() 446 .unwrap()
423 .start_wakeup_alarm(time_until_next_alarm, cs); 447 .start_wakeup_alarm(time_until_next_alarm, cs);
424 448
425 regs_gp16().cr1().modify(|w| w.set_cen(false)); 449 regs_gp16().cr1().modify(|w| w.set_cen(false));
426 450 // save the count for the timer as its lost in STOP2 for stm32wlex
451 #[cfg(stm32wlex)]
452 self.saved_count
453 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
427 Ok(()) 454 Ok(())
428 } 455 }
429 }) 456 })
@@ -431,18 +458,16 @@ impl RtcDriver {
431 458
432 #[cfg(feature = "low-power")] 459 #[cfg(feature = "low-power")]
433 /// Resume the timer with the given offset 460 /// Resume the timer with the given offset
434 pub(crate) fn resume_time(&self) { 461 pub(crate) fn resume_time(&self, cs: CriticalSection) {
435 if regs_gp16().cr1().read().cen() { 462 if regs_gp16().cr1().read().cen() {
436 // Time isn't currently stopped 463 // Time isn't currently stopped
437 464
438 return; 465 return;
439 } 466 }
440 467
441 critical_section::with(|cs| { 468 self.stop_wakeup_alarm(cs);
442 self.stop_wakeup_alarm(cs);
443 469
444 regs_gp16().cr1().modify(|w| w.set_cen(true)); 470 regs_gp16().cr1().modify(|w| w.set_cen(true));
445 })
446 } 471 }
447 472
448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 473 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
@@ -514,10 +539,15 @@ impl Driver for RtcDriver {
514} 539}
515 540
516#[cfg(feature = "low-power")] 541#[cfg(feature = "low-power")]
517pub(crate) fn get_driver() -> &'static RtcDriver { 542pub(crate) const fn get_driver() -> &'static RtcDriver {
518 &DRIVER 543 &DRIVER
519} 544}
520 545
521pub(crate) fn init(cs: CriticalSection) { 546pub(crate) fn init(cs: CriticalSection) {
522 DRIVER.init(cs) 547 DRIVER.init(cs)
523} 548}
549
550#[cfg(all(feature = "low-power", stm32wlex))]
551pub(crate) fn init_timer(cs: CriticalSection) {
552 DRIVER.init_timer(cs)
553}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 484aae1d0..9a56a41fb 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,16 +2,16 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; 5pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr};
6 6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 7use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 8use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; 9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::Peri;
10use crate::gpio::{AnyPin, OutputType}; 11use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::timer::low_level::OutputCompareMode;
13use crate::timer::TimerChannel; 13use crate::timer::TimerChannel;
14use crate::Peri; 14use crate::timer::low_level::OutputCompareMode;
15 15
16/// Complementary PWM pin wrapper. 16/// Complementary PWM pin wrapper.
17/// 17///
@@ -136,6 +136,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
136 self.inner.get_moe() 136 self.inner.get_moe()
137 } 137 }
138 138
139 /// Set Master Slave Mode 2
140 pub fn set_mms2(&mut self, mms2: Mms2) {
141 self.inner.set_mms2_selection(mms2);
142 }
143
144 /// Set Repetition Counter
145 pub fn set_repetition_counter(&mut self, val: u16) {
146 self.inner.set_repetition_counter(val);
147 }
148
139 /// Enable the given channel. 149 /// Enable the given channel.
140 pub fn enable(&mut self, channel: Channel) { 150 pub fn enable(&mut self, channel: Channel) {
141 self.inner.enable_channel(channel, true); 151 self.inner.enable_channel(channel, true);
@@ -388,7 +398,7 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
388 398
389#[cfg(test)] 399#[cfg(test)]
390mod tests { 400mod tests {
391 use super::{compute_dead_time_value, Ckd}; 401 use super::{Ckd, compute_dead_time_value};
392 402
393 #[test] 403 #[test]
394 fn test_compute_dead_time_value() { 404 fn test_compute_dead_time_value() {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 7a25e6c21..2a4ec2db0 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -8,11 +8,11 @@ use core::task::{Context, Poll};
8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; 8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; 9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
10pub use super::{Ch1, Ch2, Ch3, Ch4}; 10pub use super::{Ch1, Ch2, Ch3, Ch4};
11use crate::Peri;
11use crate::gpio::{AfType, AnyPin, Pull}; 12use crate::gpio::{AfType, AnyPin, Pull};
12use crate::interrupt::typelevel::{Binding, Interrupt}; 13use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::time::Hertz; 14use crate::time::Hertz;
14use crate::timer::TimerChannel; 15use crate::timer::TimerChannel;
15use crate::Peri;
16 16
17/// Capture pin wrapper. 17/// Capture pin wrapper.
18/// 18///
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index ac039bb0d..0122fe4f7 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,7 +10,7 @@ use core::mem::ManuallyDrop;
10 10
11use embassy_hal_internal::Peri; 11use embassy_hal_internal::Peri;
12// Re-export useful enums 12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
14 14
15use super::*; 15use super::*;
16use crate::pac::timer::vals; 16use crate::pac::timer::vals;
@@ -143,20 +143,69 @@ pub enum OutputCompareMode {
143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as 143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144 /// TIMx_CNT>TIMx_CCRx else inactive. 144 /// TIMx_CNT>TIMx_CCRx else inactive.
145 PwmMode2, 145 PwmMode2,
146 // TODO: there's more modes here depending on the chip family. 146
147 #[cfg(timer_v2)]
148 /// In up-counting mode, the channel is active until a trigger
149 /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
150 /// mode 1 and the channels becomes active again at the next update. In down-counting
151 /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
152 /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
153 /// inactive again at the next update.
154 OnePulseMode1,
155
156 #[cfg(timer_v2)]
157 /// In up-counting mode, the channel is inactive until a
158 /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
159 /// PWM mode 2 and the channels becomes inactive again at the next update. In down
160 /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
161 /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
162 /// becomes active again at the next update.
163 OnePulseMode2,
164
165 #[cfg(timer_v2)]
166 /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
167 /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
168 CombinedPwmMode1,
169
170 #[cfg(timer_v2)]
171 /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
172 /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
173 CombinedPwmMode2,
174
175 #[cfg(timer_v2)]
176 /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
177 /// when the counter is counting up, tim_oc2ref when it is counting down.
178 AsymmetricPwmMode1,
179
180 #[cfg(timer_v2)]
181 /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
182 /// when the counter is counting up, tim_oc2ref when it is counting down.
183 AsymmetricPwmMode2,
147} 184}
148 185
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 186impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
150 fn from(mode: OutputCompareMode) -> Self { 187 fn from(mode: OutputCompareMode) -> Self {
151 match mode { 188 match mode {
152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 189 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, 190 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, 191 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 192 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, 193 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, 194 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, 195 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, 196 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
197 #[cfg(timer_v2)]
198 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
199 #[cfg(timer_v2)]
200 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
201 #[cfg(timer_v2)]
202 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
203 #[cfg(timer_v2)]
204 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
205 #[cfg(timer_v2)]
206 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
207 #[cfg(timer_v2)]
208 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
160 } 209 }
161 } 210 }
162} 211}
@@ -640,6 +689,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
640 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 689 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641 } 690 }
642 691
692 /// Set Timer Master Mode
693 pub fn set_master_mode(&self, mms: MasterMode) {
694 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
695 }
696
643 /// Set Timer Slave Mode 697 /// Set Timer Slave Mode
644 pub fn set_slave_mode(&self, sms: SlaveMode) { 698 pub fn set_slave_mode(&self, sms: SlaveMode) {
645 self.regs_gp16().smcr().modify(|r| r.set_sms(sms)); 699 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
@@ -760,6 +814,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
760 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); 814 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761 } 815 }
762 816
817 /// Set master mode selection 2
818 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
819 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
820 }
821
822 /// Set repetition counter
823 pub fn set_repetition_counter(&self, val: u16) {
824 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
825 }
826
763 /// Trigger software break 1 or 2 827 /// Trigger software break 1 or 2
764 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. 828 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765 pub fn trigger_software_break(&self, n: usize) { 829 pub fn trigger_software_break(&self, n: usize) {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b09bc7166..804d1ef37 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -399,7 +399,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
400 unsafe fn on_interrupt() { 400 unsafe fn on_interrupt() {
401 #[cfg(feature = "low-power")] 401 #[cfg(feature = "low-power")]
402 crate::low_power::on_wakeup_irq(); 402 crate::low_power::Executor::on_wakeup_irq();
403 403
404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
405 405
@@ -429,7 +429,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
429{ 429{
430 unsafe fn on_interrupt() { 430 unsafe fn on_interrupt() {
431 #[cfg(feature = "low-power")] 431 #[cfg(feature = "low-power")]
432 crate::low_power::on_wakeup_irq(); 432 crate::low_power::Executor::on_wakeup_irq();
433 433
434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
435 435
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index a75b41bd7..fe8681356 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -11,12 +11,12 @@ use super::low_level::{
11}; 11};
12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; 12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
13pub use super::{Ch1, Ch2}; 13pub use super::{Ch1, Ch2};
14use crate::Peri;
14use crate::gpio::{AfType, AnyPin, Pull}; 15use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::pac::timer::vals::Etp; 17use crate::pac::timer::vals::Etp;
17use crate::time::Hertz; 18use crate::time::Hertz;
18use crate::timer::TimerChannel; 19use crate::timer::TimerChannel;
19use crate::Peri;
20 20
21/// External input marker type. 21/// External input marker type.
22pub enum Ext {} 22pub enum Ext {}
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 159b5a177..da8a79b09 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -2,9 +2,9 @@
2 2
3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; 3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; 4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin};
5use crate::Peri;
5use crate::gpio::{AfType, Pull}; 6use crate::gpio::{AfType, Pull};
6use crate::time::Hertz; 7use crate::time::Hertz;
7use crate::Peri;
8 8
9/// PWM Input driver. 9/// PWM Input driver.
10/// 10///
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 82b5968b0..a547a2a19 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,45 +1,67 @@
1//! Quadrature decoder using a timer. 1//! Quadrature decoder using a timer.
2 2
3use core::marker::PhantomData; 3use stm32_metapac::timer::vals::{self, Sms};
4
5use stm32_metapac::timer::vals;
6 4
7use super::low_level::Timer; 5use super::low_level::Timer;
8pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
9use super::{GeneralInstance4Channel, TimerPin}; 7use super::{GeneralInstance4Channel, TimerPin};
8use crate::Peri;
10use crate::gpio::{AfType, AnyPin, Pull}; 9use crate::gpio::{AfType, AnyPin, Pull};
11use crate::timer::TimerChannel; 10use crate::timer::TimerChannel;
12use crate::Peri;
13 11
14/// Counting direction 12/// Qei driver config.
15pub enum Direction { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16 /// Counting up. 14#[derive(Clone, Copy)]
17 Upcounting, 15pub struct Config {
18 /// Counting down. 16 /// Configures the internal pull up/down resistor for Qei's channel 1 pin.
19 Downcounting, 17 pub ch1_pull: Pull,
18 /// Configures the internal pull up/down resistor for Qei's channel 2 pin.
19 pub ch2_pull: Pull,
20 /// Specifies the encoder mode to use for the Qei peripheral.
21 pub mode: QeiMode,
20} 22}
21 23
22/// Wrapper for using a pin with QEI. 24impl Default for Config {
23pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> { 25 /// Arbitrary defaults to preserve backwards compatibility
24 #[allow(unused)] 26 fn default() -> Self {
25 pin: Peri<'d, AnyPin>, 27 Self {
26 phantom: PhantomData<if_afio!((T, Channel, A))>, 28 ch1_pull: Pull::None,
29 ch2_pull: Pull::None,
30 mode: QeiMode::Mode3,
31 }
32 }
27} 33}
28 34
29impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) { 35/// See STMicro AN4013 for §2.3 for more information
30 /// Create a new QEI pin instance. 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>) -> Self { 37#[derive(Clone, Copy)]
32 critical_section::with(|_| { 38pub enum QeiMode {
33 pin.set_low(); 39 /// Direct alias for [`Sms::ENCODER_MODE_1`]
34 set_as_af!(pin, AfType::input(Pull::None)); 40 Mode1,
35 }); 41 /// Direct alias for [`Sms::ENCODER_MODE_2`]
36 QeiPin { 42 Mode2,
37 pin: pin.into(), 43 /// Direct alias for [`Sms::ENCODER_MODE_3`]
38 phantom: PhantomData, 44 Mode3,
45}
46
47impl From<QeiMode> for Sms {
48 fn from(mode: QeiMode) -> Self {
49 match mode {
50 QeiMode::Mode1 => Sms::ENCODER_MODE_1,
51 QeiMode::Mode2 => Sms::ENCODER_MODE_2,
52 QeiMode::Mode3 => Sms::ENCODER_MODE_3,
39 } 53 }
40 } 54 }
41} 55}
42 56
57/// Counting direction
58pub enum Direction {
59 /// Counting up.
60 Upcounting,
61 /// Counting down.
62 Downcounting,
63}
64
43trait SealedQeiChannel: TimerChannel {} 65trait SealedQeiChannel: TimerChannel {}
44 66
45/// Marker trait for a timer channel eligible for use with QEI. 67/// Marker trait for a timer channel eligible for use with QEI.
@@ -55,20 +77,28 @@ impl SealedQeiChannel for Ch2 {}
55/// Quadrature decoder driver. 77/// Quadrature decoder driver.
56pub struct Qei<'d, T: GeneralInstance4Channel> { 78pub struct Qei<'d, T: GeneralInstance4Channel> {
57 inner: Timer<'d, T>, 79 inner: Timer<'d, T>,
80 _ch1: Peri<'d, AnyPin>,
81 _ch2: Peri<'d, AnyPin>,
58} 82}
59 83
60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 84impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
61 /// Create a new quadrature decoder driver. 85 /// Create a new quadrature decoder driver, with a given [`Config`].
62 #[allow(unused)] 86 #[allow(unused)]
63 pub fn new<#[cfg(afio)] A>( 87 pub fn new<CH1: QeiChannel, CH2: QeiChannel, #[cfg(afio)] A>(
64 tim: Peri<'d, T>, 88 tim: Peri<'d, T>,
65 ch1: if_afio!(QeiPin<'d, T, Ch1, A>), 89 ch1: Peri<'d, if_afio!(impl TimerPin<T, CH1, A>)>,
66 ch2: if_afio!(QeiPin<'d, T, Ch2, A>), 90 ch2: Peri<'d, if_afio!(impl TimerPin<T, CH2, A>)>,
91 config: Config,
67 ) -> Self { 92 ) -> Self {
68 Self::new_inner(tim) 93 // Configure the pins to be used for the QEI peripheral.
69 } 94 critical_section::with(|_| {
95 ch1.set_low();
96 set_as_af!(ch1, AfType::input(config.ch1_pull));
97
98 ch2.set_low();
99 set_as_af!(ch2, AfType::input(config.ch2_pull));
100 });
70 101
71 fn new_inner(tim: Peri<'d, T>) -> Self {
72 let inner = Timer::new(tim); 102 let inner = Timer::new(tim);
73 let r = inner.regs_gp16(); 103 let r = inner.regs_gp16();
74 104
@@ -88,13 +118,17 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
88 }); 118 });
89 119
90 r.smcr().modify(|w| { 120 r.smcr().modify(|w| {
91 w.set_sms(vals::Sms::ENCODER_MODE_3); 121 w.set_sms(config.mode.into());
92 }); 122 });
93 123
94 r.arr().modify(|w| w.set_arr(u16::MAX)); 124 r.arr().modify(|w| w.set_arr(u16::MAX));
95 r.cr1().modify(|w| w.set_cen(true)); 125 r.cr1().modify(|w| w.set_cen(true));
96 126
97 Self { inner } 127 Self {
128 inner,
129 _ch1: ch1.into(),
130 _ch2: ch2.into(),
131 }
98 } 132 }
99 133
100 /// Get direction. 134 /// Get direction.
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index e6165e42b..36303aeb4 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -5,11 +5,11 @@ use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; 7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin};
8use crate::Peri;
8#[cfg(gpio_v2)] 9#[cfg(gpio_v2)]
9use crate::gpio::Pull; 10use crate::gpio::Pull;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 11use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::Peri;
13 13
14/// PWM pin wrapper. 14/// PWM pin wrapper.
15/// 15///
@@ -339,14 +339,33 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
339 ..Default::default() 339 ..Default::default()
340 }; 340 };
341 341
342 Transfer::new_write( 342 match self.inner.bits() {
343 dma, 343 TimerBits::Bits16 => {
344 req, 344 Transfer::new_write(
345 duty, 345 dma,
346 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, 346 req,
347 dma_transfer_option, 347 duty,
348 ) 348 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
349 .await 349 dma_transfer_option,
350 )
351 .await
352 }
353 #[cfg(not(any(stm32l0)))]
354 TimerBits::Bits32 => {
355 #[cfg(not(any(bdma, gpdma)))]
356 panic!("unsupported timer bits");
357
358 #[cfg(any(bdma, gpdma))]
359 Transfer::new_write(
360 dma,
361 req,
362 duty,
363 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
364 dma_transfer_option,
365 )
366 .await
367 }
368 };
350 }; 369 };
351 370
352 // restore output compare state 371 // restore output compare state
diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs
index 7d6442b48..097cf7942 100644
--- a/embassy-stm32/src/tsc/acquisition_banks.rs
+++ b/embassy-stm32/src/tsc/acquisition_banks.rs
@@ -1,11 +1,11 @@
1use super::TSC_NUM_GROUPS;
1use super::io_pin::*; 2use super::io_pin::*;
2#[cfg(any(tsc_v2, tsc_v3))] 3#[cfg(any(tsc_v2, tsc_v3))]
3use super::pin_groups::G7; 4use super::pin_groups::G7;
4#[cfg(tsc_v3)] 5#[cfg(tsc_v3)]
5use super::pin_groups::G8; 6use super::pin_groups::G8;
6use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; 7use super::pin_groups::{G1, G2, G3, G4, G5, G6, pin_roles};
7use super::types::{Group, GroupStatus}; 8use super::types::{Group, GroupStatus};
8use super::TSC_NUM_GROUPS;
9 9
10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. 10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank.
11/// 11///
diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs
index 84421f7ff..9347e6bc0 100644
--- a/embassy-stm32/src/tsc/pin_groups.rs
+++ b/embassy-stm32/src/tsc/pin_groups.rs
@@ -1,11 +1,11 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::ops::BitOr; 2use core::ops::BitOr;
3 3
4use super::Instance;
4use super::errors::GroupError; 5use super::errors::GroupError;
5use super::io_pin::*; 6use super::io_pin::*;
6use super::Instance;
7use crate::gpio::{AfType, AnyPin, OutputType, Speed};
8use crate::Peri; 7use crate::Peri;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9 9
10/// Pin type definition to control IO parameters 10/// Pin type definition to control IO parameters
11#[derive(PartialEq, Clone, Copy)] 11#[derive(PartialEq, Clone, Copy)]
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 18aff4fbd..8f259a917 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -19,8 +19,8 @@ use core::marker::PhantomData;
19use core::sync::atomic::{AtomicBool, Ordering}; 19use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::PeripheralType; 22use embassy_hal_internal::PeripheralType;
23use embassy_hal_internal::drop::OnDrop;
24use embassy_sync::waitqueue::AtomicWaker; 24use embassy_sync::waitqueue::AtomicWaker;
25 25
26use crate::dma::{ChannelAndRequest, TransferOptions}; 26use crate::dma::{ChannelAndRequest, TransferOptions};
@@ -28,7 +28,7 @@ use crate::interrupt::typelevel::Interrupt;
28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; 29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
30use crate::rcc::{self, RccPeripheral}; 30use crate::rcc::{self, RccPeripheral};
31use crate::{interrupt, Peri}; 31use crate::{Peri, interrupt};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
34 _cs: critical_section::CriticalSection, 34 _cs: critical_section::CriticalSection,
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 5e38532bd..2d3e2b972 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,8 +1,8 @@
1//! Unique ID (UID) 1//! Unique ID (UID)
2 2
3/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
4pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> [u8; 12] {
5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
6} 6}
7 7
8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. 8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c734eed49..69c3a740f 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,20 +1,20 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
9use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin,
15 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, 16 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate,
16 sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, 17 sr, tdr,
17 TxPin,
18}; 18};
19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; 19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
20use crate::interrupt::{self, InterruptExt}; 20use crate::interrupt::{self, InterruptExt};
@@ -68,8 +68,15 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
69 } 69 }
70 70
71 if !state.rx_buf.is_empty() { 71 let eager = state.eager_reads.load(Ordering::Relaxed);
72 state.rx_waker.wake(); 72 if eager > 0 {
73 if state.rx_buf.available() >= eager {
74 state.rx_waker.wake();
75 }
76 } else {
77 if state.rx_buf.is_half_full() {
78 state.rx_waker.wake();
79 }
73 } 80 }
74 } 81 }
75 82
@@ -132,6 +139,7 @@ pub(super) struct State {
132 tx_done: AtomicBool, 139 tx_done: AtomicBool,
133 tx_rx_refcount: AtomicU8, 140 tx_rx_refcount: AtomicU8,
134 half_duplex_readback: AtomicBool, 141 half_duplex_readback: AtomicBool,
142 eager_reads: AtomicUsize,
135} 143}
136 144
137impl State { 145impl State {
@@ -144,6 +152,7 @@ impl State {
144 tx_done: AtomicBool::new(true), 152 tx_done: AtomicBool::new(true),
145 tx_rx_refcount: AtomicU8::new(0), 153 tx_rx_refcount: AtomicU8::new(0),
146 half_duplex_readback: AtomicBool::new(false), 154 half_duplex_readback: AtomicBool::new(false),
155 eager_reads: AtomicUsize::new(0),
147 } 156 }
148 } 157 }
149} 158}
@@ -419,6 +428,9 @@ impl<'d> BufferedUart<'d> {
419 let state = T::buffered_state(); 428 let state = T::buffered_state();
420 let kernel_clock = T::frequency(); 429 let kernel_clock = T::frequency();
421 430
431 state
432 .eager_reads
433 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
422 state.half_duplex_readback.store( 434 state.half_duplex_readback.store(
423 config.duplex == Duplex::Half(HalfDuplexReadback::Readback), 435 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
424 Ordering::Relaxed, 436 Ordering::Relaxed,
@@ -456,6 +468,9 @@ impl<'d> BufferedUart<'d> {
456 let info = self.rx.info; 468 let info = self.rx.info;
457 let state = self.rx.state; 469 let state = self.rx.state;
458 state.tx_rx_refcount.store(2, Ordering::Relaxed); 470 state.tx_rx_refcount.store(2, Ordering::Relaxed);
471 state
472 .eager_reads
473 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
459 474
460 info.rcc.enable_and_reset(); 475 info.rcc.enable_and_reset();
461 476
@@ -527,6 +542,11 @@ impl<'d> BufferedUart<'d> {
527 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 542 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
528 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 543 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
529 544
545 self.rx
546 .state
547 .eager_reads
548 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
549
530 self.rx.info.regs.cr1().modify(|w| { 550 self.rx.info.regs.cr1().modify(|w| {
531 w.set_rxneie(true); 551 w.set_rxneie(true);
532 w.set_idleie(true); 552 w.set_idleie(true);
@@ -553,24 +573,30 @@ impl<'d> BufferedUartRx<'d> {
553 poll_fn(move |cx| { 573 poll_fn(move |cx| {
554 let state = self.state; 574 let state = self.state;
555 let mut rx_reader = unsafe { state.rx_buf.reader() }; 575 let mut rx_reader = unsafe { state.rx_buf.reader() };
556 let data = rx_reader.pop_slice(); 576 let mut buf_len = 0;
577 let mut data = rx_reader.pop_slice();
557 578
558 if !data.is_empty() { 579 while !data.is_empty() && buf_len < buf.len() {
559 let len = data.len().min(buf.len()); 580 let data_len = data.len().min(buf.len() - buf_len);
560 buf[..len].copy_from_slice(&data[..len]); 581 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
582 buf_len += data_len;
561 583
562 let do_pend = state.rx_buf.is_full(); 584 let do_pend = state.rx_buf.is_full();
563 rx_reader.pop_done(len); 585 rx_reader.pop_done(data_len);
564 586
565 if do_pend { 587 if do_pend {
566 self.info.interrupt.pend(); 588 self.info.interrupt.pend();
567 } 589 }
568 590
569 return Poll::Ready(Ok(len)); 591 data = rx_reader.pop_slice();
570 } 592 }
571 593
572 state.rx_waker.register(cx.waker()); 594 if buf_len != 0 {
573 Poll::Pending 595 Poll::Ready(Ok(buf_len))
596 } else {
597 state.rx_waker.register(cx.waker());
598 Poll::Pending
599 }
574 }) 600 })
575 .await 601 .await
576 } 602 }
@@ -579,21 +605,24 @@ impl<'d> BufferedUartRx<'d> {
579 loop { 605 loop {
580 let state = self.state; 606 let state = self.state;
581 let mut rx_reader = unsafe { state.rx_buf.reader() }; 607 let mut rx_reader = unsafe { state.rx_buf.reader() };
582 let data = rx_reader.pop_slice(); 608 let mut buf_len = 0;
609 let mut data = rx_reader.pop_slice();
583 610
584 if !data.is_empty() { 611 while !data.is_empty() && buf_len < buf.len() {
585 let len = data.len().min(buf.len()); 612 let data_len = data.len().min(buf.len() - buf_len);
586 buf[..len].copy_from_slice(&data[..len]); 613 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
614 buf_len += data_len;
587 615
588 let do_pend = state.rx_buf.is_full(); 616 let do_pend = state.rx_buf.is_full();
589 rx_reader.pop_done(len); 617 rx_reader.pop_done(data_len);
590 618
591 if do_pend { 619 if do_pend {
592 self.info.interrupt.pend(); 620 self.info.interrupt.pend();
593 } 621 }
594 622
595 return Ok(len); 623 data = rx_reader.pop_slice();
596 } 624 }
625 return Ok(buf_len);
597 } 626 }
598 } 627 }
599 628
@@ -633,6 +662,10 @@ impl<'d> BufferedUartRx<'d> {
633 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 662 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
634 reconfigure(self.info, self.kernel_clock, config)?; 663 reconfigure(self.info, self.kernel_clock, config)?;
635 664
665 self.state
666 .eager_reads
667 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
668
636 self.info.regs.cr1().modify(|w| { 669 self.info.regs.cr1().modify(|w| {
637 w.set_rxneie(true); 670 w.set_rxneie(true);
638 w.set_idleie(true); 671 w.set_idleie(true);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ff211e0c9..0e7da634d 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,15 +4,16 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; 7use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12use embassy_hal_internal::drop::OnDrop;
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{Either, select};
15 15
16use crate::Peri;
16use crate::dma::ChannelAndRequest; 17use crate::dma::ChannelAndRequest;
17use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
18use crate::interrupt::typelevel::Interrupt as _; 19use crate::interrupt::typelevel::Interrupt as _;
@@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs;
25use crate::pac::usart::{regs, vals}; 26use crate::pac::usart::{regs, vals};
26use crate::rcc::{RccInfo, SealedRccPeripheral}; 27use crate::rcc::{RccInfo, SealedRccPeripheral};
27use crate::time::Hertz; 28use crate::time::Hertz;
28use crate::Peri;
29 29
30/// Interrupt handler. 30/// Interrupt handler.
31pub struct InterruptHandler<T: Instance> { 31pub struct InterruptHandler<T: Instance> {
@@ -185,6 +185,12 @@ pub enum ConfigError {
185 RxOrTxNotEnabled, 185 RxOrTxNotEnabled,
186 /// Data bits and parity combination not supported 186 /// Data bits and parity combination not supported
187 DataParityNotSupported, 187 DataParityNotSupported,
188 /// DE assertion time too high
189 #[cfg(not(any(usart_v1, usart_v2)))]
190 DeAssertionTimeTooHigh,
191 /// DE deassertion time too high
192 #[cfg(not(any(usart_v1, usart_v2)))]
193 DeDeassertionTimeTooHigh,
188} 194}
189 195
190#[non_exhaustive] 196#[non_exhaustive]
@@ -206,6 +212,21 @@ pub struct Config {
206 /// If false: the error is ignored and cleared 212 /// If false: the error is ignored and cleared
207 pub detect_previous_overrun: bool, 213 pub detect_previous_overrun: bool,
208 214
215 /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216 /// typically only wake/return after line idle or after the buffer is at least half full
217 /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions
218 /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances.
219 ///
220 /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
221 /// available in the buffer, in addition to waking/returning when the conditions described
222 /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx`
223 /// will trigger an interrupt for every received word to check the buffer level, which may
224 /// impact performance at high data rates.
225 ///
226 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
227 /// return a single word, a full buffer, or after line idle.
228 pub eager_reads: Option<usize>,
229
209 /// Set this to true if the line is considered noise free. 230 /// Set this to true if the line is considered noise free.
210 /// This will increase the receiver’s tolerance to clock deviations, 231 /// This will increase the receiver’s tolerance to clock deviations,
211 /// but will effectively disable noise detection. 232 /// but will effectively disable noise detection.
@@ -239,6 +260,14 @@ pub struct Config {
239 /// Set the pin configuration for the DE pin. 260 /// Set the pin configuration for the DE pin.
240 pub de_config: OutputConfig, 261 pub de_config: OutputConfig,
241 262
263 /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period.
264 #[cfg(not(any(usart_v1, usart_v2)))]
265 pub de_assertion_time: u8,
266
267 /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period.
268 #[cfg(not(any(usart_v1, usart_v2)))]
269 pub de_deassertion_time: u8,
270
242 // private: set by new_half_duplex, not by the user. 271 // private: set by new_half_duplex, not by the user.
243 duplex: Duplex, 272 duplex: Duplex,
244} 273}
@@ -270,6 +299,7 @@ impl Default for Config {
270 parity: Parity::ParityNone, 299 parity: Parity::ParityNone,
271 // historical behavior 300 // historical behavior
272 detect_previous_overrun: false, 301 detect_previous_overrun: false,
302 eager_reads: None,
273 #[cfg(not(usart_v1))] 303 #[cfg(not(usart_v1))]
274 assume_noise_free: false, 304 assume_noise_free: false,
275 #[cfg(any(usart_v3, usart_v4))] 305 #[cfg(any(usart_v3, usart_v4))]
@@ -283,6 +313,10 @@ impl Default for Config {
283 tx_config: OutputConfig::PushPull, 313 tx_config: OutputConfig::PushPull,
284 rts_config: OutputConfig::PushPull, 314 rts_config: OutputConfig::PushPull,
285 de_config: OutputConfig::PushPull, 315 de_config: OutputConfig::PushPull,
316 #[cfg(not(any(usart_v1, usart_v2)))]
317 de_assertion_time: 0,
318 #[cfg(not(any(usart_v1, usart_v2)))]
319 de_deassertion_time: 0,
286 duplex: Duplex::Full, 320 duplex: Duplex::Full,
287 } 321 }
288 } 322 }
@@ -966,6 +1000,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
966 let info = self.info; 1000 let info = self.info;
967 let state = self.state; 1001 let state = self.state;
968 state.tx_rx_refcount.store(1, Ordering::Relaxed); 1002 state.tx_rx_refcount.store(1, Ordering::Relaxed);
1003 state
1004 .eager_reads
1005 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
969 1006
970 info.rcc.enable_and_reset(); 1007 info.rcc.enable_and_reset();
971 1008
@@ -982,6 +1019,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
982 1019
983 /// Reconfigure the driver 1020 /// Reconfigure the driver
984 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 1021 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1022 self.state
1023 .eager_reads
1024 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
985 reconfigure(self.info, self.kernel_clock, config) 1025 reconfigure(self.info, self.kernel_clock, config)
986 } 1026 }
987 1027
@@ -1462,6 +1502,9 @@ impl<'d, M: Mode> Uart<'d, M> {
1462 let info = self.rx.info; 1502 let info = self.rx.info;
1463 let state = self.rx.state; 1503 let state = self.rx.state;
1464 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1504 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1505 state
1506 .eager_reads
1507 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1465 1508
1466 info.rcc.enable_and_reset(); 1509 info.rcc.enable_and_reset();
1467 1510
@@ -1690,6 +1733,16 @@ fn configure(
1690 return Err(ConfigError::RxOrTxNotEnabled); 1733 return Err(ConfigError::RxOrTxNotEnabled);
1691 } 1734 }
1692 1735
1736 #[cfg(not(any(usart_v1, usart_v2)))]
1737 let dem = r.cr3().read().dem();
1738
1739 #[cfg(not(any(usart_v1, usart_v2)))]
1740 if config.de_assertion_time > 31 {
1741 return Err(ConfigError::DeAssertionTimeTooHigh);
1742 } else if config.de_deassertion_time > 31 {
1743 return Err(ConfigError::DeDeassertionTimeTooHigh);
1744 }
1745
1693 // UART must be disabled during configuration. 1746 // UART must be disabled during configuration.
1694 r.cr1().modify(|w| { 1747 r.cr1().modify(|w| {
1695 w.set_ue(false); 1748 w.set_ue(false);
@@ -1738,6 +1791,20 @@ fn configure(
1738 w.set_re(enable_rx); 1791 w.set_re(enable_rx);
1739 } 1792 }
1740 1793
1794 #[cfg(not(any(usart_v1, usart_v2)))]
1795 if dem {
1796 w.set_deat(if over8 {
1797 config.de_assertion_time / 2
1798 } else {
1799 config.de_assertion_time
1800 });
1801 w.set_dedt(if over8 {
1802 config.de_assertion_time / 2
1803 } else {
1804 config.de_assertion_time
1805 });
1806 }
1807
1741 // configure word size and parity, since the parity bit is inserted into the MSB position, 1808 // configure word size and parity, since the parity bit is inserted into the MSB position,
1742 // it increases the effective word size 1809 // it increases the effective word size
1743 match (config.parity, config.data_bits) { 1810 match (config.parity, config.data_bits) {
@@ -2022,6 +2089,7 @@ struct State {
2022 rx_waker: AtomicWaker, 2089 rx_waker: AtomicWaker,
2023 tx_waker: AtomicWaker, 2090 tx_waker: AtomicWaker,
2024 tx_rx_refcount: AtomicU8, 2091 tx_rx_refcount: AtomicU8,
2092 eager_reads: AtomicUsize,
2025} 2093}
2026 2094
2027impl State { 2095impl State {
@@ -2030,6 +2098,7 @@ impl State {
2030 rx_waker: AtomicWaker::new(), 2098 rx_waker: AtomicWaker::new(),
2031 tx_waker: AtomicWaker::new(), 2099 tx_waker: AtomicWaker::new(),
2032 tx_rx_refcount: AtomicU8::new(0), 2100 tx_rx_refcount: AtomicU8::new(0),
2101 eager_reads: AtomicUsize::new(0),
2033 } 2102 }
2034 } 2103 }
2035} 2104}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 5f4e87834..bac570d27 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,19 +1,21 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{Ordering, compiler_fence};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embedded_io_async::ReadReady; 7use embedded_io_async::ReadReady;
8use futures_util::future::{select, Either}; 8use futures_util::future::{Either, select};
9 9
10use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; 10use super::{
11 Config, ConfigError, Error, Info, State, UartRx, clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr,
12};
13use crate::Peri;
11use crate::dma::ReadableRingBuffer; 14use crate::dma::ReadableRingBuffer;
12use crate::gpio::{AnyPin, SealedPin as _}; 15use crate::gpio::{AnyPin, SealedPin as _};
13use crate::mode::Async; 16use crate::mode::Async;
14use crate::time::Hertz; 17use crate::time::Hertz;
15use crate::usart::Regs; 18use crate::usart::Regs;
16use crate::Peri;
17 19
18/// Rx-only Ring-buffered UART Driver 20/// Rx-only Ring-buffered UART Driver
19/// 21///
@@ -26,9 +28,9 @@ use crate::Peri;
26/// contain enough bytes to fill the buffer passed by the caller of 28/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty. 29/// the function, or is empty.
28/// 30///
29/// Waiting for bytes operates in one of two modes, depending on 31/// Waiting for bytes operates in one of three modes, depending on
30/// the behavior of the sender and the size of the buffer passed 32/// the behavior of the sender, the size of the buffer passed
31/// to the function: 33/// to the function, and the configuration:
32/// 34///
33/// - If the sender sends intermittently, the 'idle line' 35/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any 36/// condition will be detected when the sender stops, and any
@@ -47,7 +49,11 @@ use crate::Peri;
47/// interrupt when those specific buffer addresses have been 49/// interrupt when those specific buffer addresses have been
48/// written. 50/// written.
49/// 51///
50/// In both cases this will result in variable latency due to the 52/// - If `eager_reads` is enabled in `config`, the UART interrupt
53/// is enabled on all data reception and the call will only wait
54/// for at least one byte to be available before returning.
55///
56/// In the first two cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and 57/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit, 58/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is 59/// then a byte will be received every ~4.16ms. If the ring buffer is
@@ -68,15 +74,10 @@ use crate::Peri;
68/// sending, but would be falsely triggered in the worst-case 74/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario. 75/// buffer delay scenario.
70/// 76///
71/// Note: This latency is caused by the limited capabilities of the 77/// Note: Enabling `eager_reads` with `RingBufferedUartRx` will enable
72/// STM32 DMA controller; since it cannot generate an interrupt when 78/// an UART RXNE interrupt, which will cause an interrupt to occur on
73/// it stores a byte into an empty ring buffer, or in any other 79/// every received data byte. The data is still copied using DMA, but
74/// configurable conditions, it is not possible to take notice of the 80/// there is nevertheless additional processing overhead for each byte.
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
80pub struct RingBufferedUartRx<'d> { 81pub struct RingBufferedUartRx<'d> {
81 info: &'static Info, 82 info: &'static Info,
82 state: &'static State, 83 state: &'static State,
@@ -133,6 +134,9 @@ impl<'d> UartRx<'d, Async> {
133impl<'d> RingBufferedUartRx<'d> { 134impl<'d> RingBufferedUartRx<'d> {
134 /// Reconfigure the driver 135 /// Reconfigure the driver
135 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 136 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
137 self.state
138 .eager_reads
139 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
136 reconfigure(self.info, self.kernel_clock, config) 140 reconfigure(self.info, self.kernel_clock, config)
137 } 141 }
138 142
@@ -148,8 +152,8 @@ impl<'d> RingBufferedUartRx<'d> {
148 let r = self.info.regs; 152 let r = self.info.regs;
149 // clear all interrupts and DMA Rx Request 153 // clear all interrupts and DMA Rx Request
150 r.cr1().modify(|w| { 154 r.cr1().modify(|w| {
151 // disable RXNE interrupt 155 // use RXNE only when returning reads early
152 w.set_rxneie(false); 156 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0);
153 // enable parity interrupt if not ParityNone 157 // enable parity interrupt if not ParityNone
154 w.set_peie(w.pce()); 158 w.set_peie(w.pce());
155 // enable idle line interrupt 159 // enable idle line interrupt
@@ -248,39 +252,67 @@ impl<'d> RingBufferedUartRx<'d> {
248 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 252 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
249 compiler_fence(Ordering::SeqCst); 253 compiler_fence(Ordering::SeqCst);
250 254
251 // Future which completes when idle line is detected 255 loop {
252 let s = self.state; 256 // Future which completes when idle line is detected
253 let uart = poll_fn(|cx| { 257 let s = self.state;
254 s.rx_waker.register(cx.waker()); 258 let mut uart_init = false;
255 259 let uart = poll_fn(|cx| {
256 compiler_fence(Ordering::SeqCst); 260 s.rx_waker.register(cx.waker());
257 261
258 if check_idle_and_errors(self.info.regs)? { 262 compiler_fence(Ordering::SeqCst);
259 // Idle line is detected 263
260 Poll::Ready(Ok(())) 264 // We may have been woken by IDLE or, if eager_reads is set, by RXNE.
261 } else { 265 // However, DMA will clear RXNE, so we can't check directly, and because
262 Poll::Pending 266 // the other future borrows `ring_buf`, we can't check `len()` here either.
263 } 267 // Instead, return from this future and we'll check the length afterwards.
264 }); 268 let eager = s.eager_reads.load(Ordering::Relaxed) > 0;
269
270 let idle = check_idle_and_errors(self.info.regs)?;
271 if idle || (eager && uart_init) {
272 // Idle line is detected, or eager reads is set and some data is available.
273 Poll::Ready(Ok(idle))
274 } else {
275 uart_init = true;
276 Poll::Pending
277 }
278 });
265 279
266 let mut dma_init = false; 280 let mut dma_init = false;
267 // Future which completes when the DMA controller indicates it 281 // Future which completes when the DMA controller indicates it
268 // has written to the ring buffer's middle byte, or last byte 282 // has written to the ring buffer's middle byte, or last byte
269 let dma = poll_fn(|cx| { 283 let dma = poll_fn(|cx| {
270 self.ring_buf.set_waker(cx.waker()); 284 self.ring_buf.set_waker(cx.waker());
271 285
272 let status = match dma_init { 286 let status = match dma_init {
273 false => Poll::Pending, 287 false => Poll::Pending,
274 true => Poll::Ready(()), 288 true => Poll::Ready(()),
275 }; 289 };
276 290
277 dma_init = true; 291 dma_init = true;
278 status 292 status
279 }); 293 });
280 294
281 match select(uart, dma).await { 295 match select(uart, dma).await {
282 Either::Left((result, _)) => result, 296 // UART woke with line idle
283 Either::Right(((), _)) => Ok(()), 297 Either::Left((Ok(true), _)) => {
298 return Ok(());
299 }
300 // UART woke without idle or error: word received
301 Either::Left((Ok(false), _)) => {
302 let eager = self.state.eager_reads.load(Ordering::Relaxed);
303 if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager {
304 return Ok(());
305 } else {
306 continue;
307 }
308 }
309 // UART woke with error
310 Either::Left((Err(e), _)) => {
311 return Err(e);
312 }
313 // DMA woke
314 Either::Right(((), _)) => return Ok(()),
315 }
284 } 316 }
285 } 317 }
286 318
@@ -308,26 +340,16 @@ impl Drop for RingBufferedUartRx<'_> {
308/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags 340/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
309/// are cleared by a single read to the RDR register. 341/// are cleared by a single read to the RDR register.
310fn check_idle_and_errors(r: Regs) -> Result<bool, Error> { 342fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
311 // Critical section is required so that the flags aren't set after read and before clear 343 // SAFETY: read only and we only use Rx related flags
312 let sr = critical_section::with(|_| { 344 let sr = sr(r).read();
313 // SAFETY: read only and we only use Rx related flags 345
314 let sr = sr(r).read(); 346 #[cfg(not(any(usart_v3, usart_v4)))]
315 347 unsafe {
316 #[cfg(any(usart_v3, usart_v4))] 348 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
317 r.icr().write(|w| { 349 rdr(r).read_volatile()
318 w.set_idle(true); 350 };
319 w.set_pe(true); 351 clear_interrupt_flags(r, sr);
320 w.set_fe(true); 352
321 w.set_ne(true);
322 w.set_ore(true);
323 });
324 #[cfg(not(any(usart_v3, usart_v4)))]
325 unsafe {
326 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
327 rdr(r).read_volatile()
328 };
329 sr
330 });
331 if sr.pe() { 353 if sr.pe() {
332 Err(Error::Parity) 354 Err(Error::Parity)
333 } else if sr.fe() { 355 } else if sr.fe() {
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 5ce81b131..f6b1a81db 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -2,18 +2,18 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; 4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported};
5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7pub use embassy_usb_synopsys_otg::Config; 5pub use embassy_usb_synopsys_otg::Config;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
8use embassy_usb_synopsys_otg::{ 8use embassy_usb_synopsys_otg::{
9 on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, 9 Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, PhyType, State,
10 PhyType, State, 10 on_interrupt as on_interrupt_impl,
11}; 11};
12 12
13use crate::gpio::{AfType, OutputType, Speed}; 13use crate::gpio::{AfType, OutputType, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, Peri}; 16use crate::{Peri, interrupt};
17 17
18const MAX_EP_COUNT: usize = 9; 18const MAX_EP_COUNT: usize = 9;
19 19
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9e08d99b3..d405e4802 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,11 +12,11 @@ use embassy_usb_driver::{
12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13}; 13};
14 14
15use crate::pac::USBRAM;
15use crate::pac::usb::regs; 16use crate::pac::usb::regs;
16use crate::pac::usb::vals::{EpType, Stat}; 17use crate::pac::usb::vals::{EpType, Stat};
17use crate::pac::USBRAM;
18use crate::rcc::RccPeripheral; 18use crate::rcc::RccPeripheral;
19use crate::{interrupt, Peri}; 19use crate::{Peri, interrupt};
20 20
21/// Interrupt handler. 21/// Interrupt handler.
22pub struct InterruptHandler<T: Instance> { 22pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs
index ccbd748d5..43dd9c800 100644
--- a/embassy-stm32/src/vrefbuf/mod.rs
+++ b/embassy-stm32/src/vrefbuf/mod.rs
@@ -14,10 +14,10 @@ pub struct VoltageReferenceBuffer<'d, T: Instance> {
14#[cfg(rcc_wba)] 14#[cfg(rcc_wba)]
15fn get_refbuf_trim(voltage_scale: Vrs) -> usize { 15fn get_refbuf_trim(voltage_scale: Vrs) -> usize {
16 match voltage_scale { 16 match voltage_scale {
17 Vrs::VREF0 => 0x0BFA_07A8usize, 17 Vrs::VREF0 => 0x0BFA_07ABusize,
18 Vrs::VREF1 => 0x0BFA_07A9usize, 18 Vrs::VREF1 => 0x0BFA_07AAusize,
19 Vrs::VREF2 => 0x0BFA_07AAusize, 19 Vrs::VREF2 => 0x0BFA_07A9usize,
20 Vrs::VREF3 => 0x0BFA_07ABusize, 20 Vrs::VREF3 => 0x0BFA_07A8usize,
21 _ => panic!("Incorrect Vrs setting!"), 21 _ => panic!("Incorrect Vrs setting!"),
22 } 22 }
23} 23}
@@ -62,8 +62,7 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> {
62 } 62 }
63 trace!( 63 trace!(
64 "Vrefbuf configured with voltage scale {} and impedance mode {}", 64 "Vrefbuf configured with voltage scale {} and impedance mode {}",
65 voltage_scale as u8, 65 voltage_scale as u8, impedance_mode as u8,
66 impedance_mode as u8,
67 ); 66 );
68 VoltageReferenceBuffer { vrefbuf: PhantomData } 67 VoltageReferenceBuffer { vrefbuf: PhantomData }
69 } 68 }
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index fb5c3d930..1164739ff 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -4,8 +4,8 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5use stm32_metapac::iwdg::vals::{Key, Pr}; 5use stm32_metapac::iwdg::vals::{Key, Pr};
6 6
7use crate::rcc::LSI_FREQ;
8use crate::Peri; 7use crate::Peri;
8use crate::rcc::LSI_FREQ;
9 9
10/// Independent watchdog (IWDG) driver. 10/// Independent watchdog (IWDG) driver.
11pub struct IndependentWatchdog<'d, T: Instance> { 11pub struct IndependentWatchdog<'d, T: Instance> {
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index 901569f64..a80a2692b 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -11,15 +11,15 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13 13
14use crate::dma::{word, ChannelAndRequest}; 14use crate::dma::{ChannelAndRequest, word};
15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
16use crate::mode::{Async, Blocking, Mode as PeriMode}; 16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::pac::xspi::vals::*;
18use crate::pac::xspi::Xspi as Regs; 17use crate::pac::xspi::Xspi as Regs;
18use crate::pac::xspi::vals::*;
19#[cfg(xspim_v1)] 19#[cfg(xspim_v1)]
20use crate::pac::xspim::Xspim; 20use crate::pac::xspim::Xspim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// XPSI driver config. 24/// XPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]