aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-10-26 19:34:43 +0000
committerGitHub <[email protected]>2022-10-26 19:34:43 +0000
commit01e23bf9dd2f7d55a01d5a0ac18bc6f26ca05e30 (patch)
tree549f0565d84360ccb1fd076d31e7a4dfd930bf15
parente5097a8866c071c8b986757543a723b20b67fa03 (diff)
parent52c03cf0a4ae5a7a6374e6acac123670b83860fe (diff)
Merge #1025
1025: Implement I2C timeouts, second attempt r=Dirbaio a=chemicstry This is an alterrnative to #1022 as discussed there. Timeouts are implemented using suggested `check_timeout: impl Fn() -> Result<(), Error>` function, which does not depend on `embassy-time` by default and is a noop for regular I2C. This also adds `time` feature like in `embassy-nrf` to enable `embassy-time` dependencies. While at it, I also gated some other peripherals that depend on `embassy-time`, notably `usb` and (partially) `subghz`. `TimeoutI2c` is currently only implemented for i2cv1, because i2cv2 has additional complications: - Async methods still use a lot of busy waiting code in between DMA transfers, so simple `with_timeout()` will not work and it will have to use both types of timeouts. It could probably be rewritten to replace busy waits with IRQs, but that's outside the scope of this PR. - I2C definition `I2c<'d, T, TXDMA, RXDMA>` is different from i2cv1 `I2c<'d, T>` making it hard to share single `TimeoutI2c` wrapper. A couple of options here: - Duplicate `TimeoutI2c` code - Add dummy `TXDMA`, `RXDMA` types to i2cv1 considering that in the future it should also support DMA Co-authored-by: chemicstry <[email protected]>
-rw-r--r--embassy-stm32/Cargo.toml5
-rw-r--r--embassy-stm32/src/i2c/mod.rs5
-rw-r--r--embassy-stm32/src/i2c/timeout.rs142
-rw-r--r--embassy-stm32/src/i2c/v1.rs123
-rw-r--r--embassy-stm32/src/i2c/v2.rs221
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/subghz/timeout.rs1
-rw-r--r--embassy-stm32/src/subghz/tx_params.rs1
-rw-r--r--examples/stm32f4/src/bin/i2c.rs45
-rw-r--r--examples/stm32h7/src/bin/i2c.rs44
10 files changed, 508 insertions, 81 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 0b88e89c9..6b00518a6 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -82,9 +82,12 @@ memory-x = ["stm32-metapac/memory-x"]
82subghz = [] 82subghz = []
83exti = [] 83exti = []
84 84
85# Enables additional driver features that depend on embassy-time
86time = ["dep:embassy-time"]
87
85# Features starting with `_` are for internal use only. They're not intended 88# Features starting with `_` are for internal use only. They're not intended
86# to be enabled by other crates, and are not covered by semver guarantees. 89# to be enabled by other crates, and are not covered by semver guarantees.
87_time-driver = ["dep:embassy-time"] 90_time-driver = ["time"]
88time-driver-any = ["_time-driver"] 91time-driver-any = ["_time-driver"]
89time-driver-tim2 = ["_time-driver"] 92time-driver-tim2 = ["_time-driver"]
90time-driver-tim3 = ["_time-driver"] 93time-driver-tim3 = ["_time-driver"]
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 9d314f411..f898fcc8b 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -7,6 +7,11 @@ use crate::interrupt::Interrupt;
7mod _version; 7mod _version;
8pub use _version::*; 8pub use _version::*;
9 9
10#[cfg(feature = "time")]
11mod timeout;
12#[cfg(feature = "time")]
13pub use timeout::*;
14
10use crate::peripherals; 15use crate::peripherals;
11 16
12#[derive(Debug)] 17#[derive(Debug)]
diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs
new file mode 100644
index 000000000..4fca1ca2b
--- /dev/null
+++ b/embassy-stm32/src/i2c/timeout.rs
@@ -0,0 +1,142 @@
1use embassy_time::{Duration, Instant};
2
3use super::{Error, I2c, Instance};
4
5/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
6///
7/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
8/// A regular [I2c] would freeze until condition is removed.
9pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> {
10 i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>,
11 timeout: Duration,
12}
13
14fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
15 let deadline = Instant::now() + timeout;
16 move || {
17 if Instant::now() > deadline {
18 Err(Error::Timeout)
19 } else {
20 Ok(())
21 }
22 }
23}
24
25impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
26 pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
27 Self { i2c, timeout }
28 }
29
30 /// Blocking read with a custom timeout
31 pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> {
32 self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout))
33 }
34
35 /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
36 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
37 self.blocking_read_timeout(addr, buffer, self.timeout)
38 }
39
40 /// Blocking write with a custom timeout
41 pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> {
42 self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout))
43 }
44
45 /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
46 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
47 self.blocking_write_timeout(addr, bytes, self.timeout)
48 }
49
50 /// Blocking write-read with a custom timeout
51 pub fn blocking_write_read_timeout(
52 &mut self,
53 addr: u8,
54 bytes: &[u8],
55 buffer: &mut [u8],
56 timeout: Duration,
57 ) -> Result<(), Error> {
58 self.i2c
59 .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout))
60 }
61
62 /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
63 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
64 self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout)
65 }
66}
67
68impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
69 type Error = Error;
70
71 fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
72 self.blocking_read(addr, buffer)
73 }
74}
75
76impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
77 type Error = Error;
78
79 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
80 self.blocking_write(addr, bytes)
81 }
82}
83
84impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
85 type Error = Error;
86
87 fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
88 self.blocking_write_read(addr, bytes, buffer)
89 }
90}
91
92#[cfg(feature = "unstable-traits")]
93mod eh1 {
94 use super::*;
95
96 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> {
97 type Error = Error;
98 }
99
100 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
101 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
102 self.blocking_read(address, buffer)
103 }
104
105 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
106 self.blocking_write(address, buffer)
107 }
108
109 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
110 where
111 B: IntoIterator<Item = u8>,
112 {
113 todo!();
114 }
115
116 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error>
117 where
118 B: IntoIterator<Item = u8>,
119 {
120 todo!();
121 }
122
123 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
124 self.blocking_write_read(address, wr_buffer, rd_buffer)
125 }
126
127 fn transaction<'a>(
128 &mut self,
129 _address: u8,
130 _operations: &mut [embedded_hal_1::i2c::Operation<'a>],
131 ) -> Result<(), Self::Error> {
132 todo!();
133 }
134
135 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
136 where
137 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
138 {
139 todo!();
140 }
141 }
142}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index f39a37df6..f140e2b0d 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1,8 +1,9 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_embedded_hal::SetConfig; 3use embassy_embedded_hal::SetConfig;
4use embassy_hal_common::into_ref; 4use embassy_hal_common::{into_ref, PeripheralRef};
5 5
6use crate::dma::NoDma;
6use crate::gpio::sealed::AFType; 7use crate::gpio::sealed::AFType;
7use crate::gpio::Pull; 8use crate::gpio::Pull;
8use crate::i2c::{Error, Instance, SclPin, SdaPin}; 9use crate::i2c::{Error, Instance, SclPin, SdaPin};
@@ -34,19 +35,26 @@ impl State {
34 } 35 }
35} 36}
36 37
37pub struct I2c<'d, T: Instance> { 38pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
38 phantom: PhantomData<&'d mut T>, 39 phantom: PhantomData<&'d mut T>,
40 #[allow(dead_code)]
41 tx_dma: PeripheralRef<'d, TXDMA>,
42 #[allow(dead_code)]
43 rx_dma: PeripheralRef<'d, RXDMA>,
39} 44}
40 45
41impl<'d, T: Instance> I2c<'d, T> { 46impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
42 pub fn new( 47 pub fn new(
43 _peri: impl Peripheral<P = T> + 'd, 48 _peri: impl Peripheral<P = T> + 'd,
44 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 49 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
45 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 50 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
51 _irq: impl Peripheral<P = T::Interrupt> + 'd,
52 tx_dma: impl Peripheral<P = TXDMA> + 'd,
53 rx_dma: impl Peripheral<P = RXDMA> + 'd,
46 freq: Hertz, 54 freq: Hertz,
47 config: Config, 55 config: Config,
48 ) -> Self { 56 ) -> Self {
49 into_ref!(scl, sda); 57 into_ref!(scl, sda, tx_dma, rx_dma);
50 58
51 T::enable(); 59 T::enable();
52 T::reset(); 60 T::reset();
@@ -99,7 +107,11 @@ impl<'d, T: Instance> I2c<'d, T> {
99 }); 107 });
100 } 108 }
101 109
102 Self { phantom: PhantomData } 110 Self {
111 phantom: PhantomData,
112 tx_dma,
113 rx_dma,
114 }
103 } 115 }
104 116
105 unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { 117 unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
@@ -141,7 +153,12 @@ impl<'d, T: Instance> I2c<'d, T> {
141 Ok(sr1) 153 Ok(sr1)
142 } 154 }
143 155
144 unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 156 unsafe fn write_bytes(
157 &mut self,
158 addr: u8,
159 bytes: &[u8],
160 check_timeout: impl Fn() -> Result<(), Error>,
161 ) -> Result<(), Error> {
145 // Send a START condition 162 // Send a START condition
146 163
147 T::regs().cr1().modify(|reg| { 164 T::regs().cr1().modify(|reg| {
@@ -149,7 +166,9 @@ impl<'d, T: Instance> I2c<'d, T> {
149 }); 166 });
150 167
151 // Wait until START condition was generated 168 // Wait until START condition was generated
152 while !self.check_and_clear_error_flags()?.start() {} 169 while !self.check_and_clear_error_flags()?.start() {
170 check_timeout()?;
171 }
153 172
154 // Also wait until signalled we're master and everything is waiting for us 173 // Also wait until signalled we're master and everything is waiting for us
155 while { 174 while {
@@ -157,7 +176,9 @@ impl<'d, T: Instance> I2c<'d, T> {
157 176
158 let sr2 = T::regs().sr2().read(); 177 let sr2 = T::regs().sr2().read();
159 !sr2.msl() && !sr2.busy() 178 !sr2.msl() && !sr2.busy()
160 } {} 179 } {
180 check_timeout()?;
181 }
161 182
162 // Set up current address, we're trying to talk to 183 // Set up current address, we're trying to talk to
163 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 184 T::regs().dr().write(|reg| reg.set_dr(addr << 1));
@@ -165,26 +186,30 @@ impl<'d, T: Instance> I2c<'d, T> {
165 // Wait until address was sent 186 // Wait until address was sent
166 // Wait for the address to be acknowledged 187 // Wait for the address to be acknowledged
167 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 188 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
168 while !self.check_and_clear_error_flags()?.addr() {} 189 while !self.check_and_clear_error_flags()?.addr() {
190 check_timeout()?;
191 }
169 192
170 // Clear condition by reading SR2 193 // Clear condition by reading SR2
171 let _ = T::regs().sr2().read(); 194 let _ = T::regs().sr2().read();
172 195
173 // Send bytes 196 // Send bytes
174 for c in bytes { 197 for c in bytes {
175 self.send_byte(*c)?; 198 self.send_byte(*c, &check_timeout)?;
176 } 199 }
177 200
178 // Fallthrough is success 201 // Fallthrough is success
179 Ok(()) 202 Ok(())
180 } 203 }
181 204
182 unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> { 205 unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
183 // Wait until we're ready for sending 206 // Wait until we're ready for sending
184 while { 207 while {
185 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 208 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
186 !self.check_and_clear_error_flags()?.txe() 209 !self.check_and_clear_error_flags()?.txe()
187 } {} 210 } {
211 check_timeout()?;
212 }
188 213
189 // Push out a byte of data 214 // Push out a byte of data
190 T::regs().dr().write(|reg| reg.set_dr(byte)); 215 T::regs().dr().write(|reg| reg.set_dr(byte));
@@ -193,24 +218,33 @@ impl<'d, T: Instance> I2c<'d, T> {
193 while { 218 while {
194 // Check for any potential error conditions. 219 // Check for any potential error conditions.
195 !self.check_and_clear_error_flags()?.btf() 220 !self.check_and_clear_error_flags()?.btf()
196 } {} 221 } {
222 check_timeout()?;
223 }
197 224
198 Ok(()) 225 Ok(())
199 } 226 }
200 227
201 unsafe fn recv_byte(&self) -> Result<u8, Error> { 228 unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
202 while { 229 while {
203 // Check for any potential error conditions. 230 // Check for any potential error conditions.
204 self.check_and_clear_error_flags()?; 231 self.check_and_clear_error_flags()?;
205 232
206 !T::regs().sr1().read().rxne() 233 !T::regs().sr1().read().rxne()
207 } {} 234 } {
235 check_timeout()?;
236 }
208 237
209 let value = T::regs().dr().read().dr(); 238 let value = T::regs().dr().read().dr();
210 Ok(value) 239 Ok(value)
211 } 240 }
212 241
213 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { 242 pub fn blocking_read_timeout(
243 &mut self,
244 addr: u8,
245 buffer: &mut [u8],
246 check_timeout: impl Fn() -> Result<(), Error>,
247 ) -> Result<(), Error> {
214 if let Some((last, buffer)) = buffer.split_last_mut() { 248 if let Some((last, buffer)) = buffer.split_last_mut() {
215 // Send a START condition and set ACK bit 249 // Send a START condition and set ACK bit
216 unsafe { 250 unsafe {
@@ -221,27 +255,33 @@ impl<'d, T: Instance> I2c<'d, T> {
221 } 255 }
222 256
223 // Wait until START condition was generated 257 // Wait until START condition was generated
224 while unsafe { !T::regs().sr1().read().start() } {} 258 while unsafe { !self.check_and_clear_error_flags()?.start() } {
259 check_timeout()?;
260 }
225 261
226 // Also wait until signalled we're master and everything is waiting for us 262 // Also wait until signalled we're master and everything is waiting for us
227 while { 263 while {
228 let sr2 = unsafe { T::regs().sr2().read() }; 264 let sr2 = unsafe { T::regs().sr2().read() };
229 !sr2.msl() && !sr2.busy() 265 !sr2.msl() && !sr2.busy()
230 } {} 266 } {
267 check_timeout()?;
268 }
231 269
232 // Set up current address, we're trying to talk to 270 // Set up current address, we're trying to talk to
233 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } 271 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) }
234 272
235 // Wait until address was sent 273 // Wait until address was sent
236 // Wait for the address to be acknowledged 274 // Wait for the address to be acknowledged
237 while unsafe { !self.check_and_clear_error_flags()?.addr() } {} 275 while unsafe { !self.check_and_clear_error_flags()?.addr() } {
276 check_timeout()?;
277 }
238 278
239 // Clear condition by reading SR2 279 // Clear condition by reading SR2
240 let _ = unsafe { T::regs().sr2().read() }; 280 let _ = unsafe { T::regs().sr2().read() };
241 281
242 // Receive bytes into buffer 282 // Receive bytes into buffer
243 for c in buffer { 283 for c in buffer {
244 *c = unsafe { self.recv_byte()? }; 284 *c = unsafe { self.recv_byte(&check_timeout)? };
245 } 285 }
246 286
247 // Prepare to send NACK then STOP after next byte 287 // Prepare to send NACK then STOP after next byte
@@ -253,10 +293,12 @@ impl<'d, T: Instance> I2c<'d, T> {
253 } 293 }
254 294
255 // Receive last byte 295 // Receive last byte
256 *last = unsafe { self.recv_byte()? }; 296 *last = unsafe { self.recv_byte(&check_timeout)? };
257 297
258 // Wait for the STOP to be sent. 298 // Wait for the STOP to be sent.
259 while unsafe { T::regs().cr1().read().stop() } {} 299 while unsafe { T::regs().cr1().read().stop() } {
300 check_timeout()?;
301 }
260 302
261 // Fallthrough is success 303 // Fallthrough is success
262 Ok(()) 304 Ok(())
@@ -265,25 +307,50 @@ impl<'d, T: Instance> I2c<'d, T> {
265 } 307 }
266 } 308 }
267 309
268 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 310 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
311 self.blocking_read_timeout(addr, buffer, || Ok(()))
312 }
313
314 pub fn blocking_write_timeout(
315 &mut self,
316 addr: u8,
317 bytes: &[u8],
318 check_timeout: impl Fn() -> Result<(), Error>,
319 ) -> Result<(), Error> {
269 unsafe { 320 unsafe {
270 self.write_bytes(addr, bytes)?; 321 self.write_bytes(addr, bytes, &check_timeout)?;
271 // Send a STOP condition 322 // Send a STOP condition
272 T::regs().cr1().modify(|reg| reg.set_stop(true)); 323 T::regs().cr1().modify(|reg| reg.set_stop(true));
273 // Wait for STOP condition to transmit. 324 // Wait for STOP condition to transmit.
274 while T::regs().cr1().read().stop() {} 325 while T::regs().cr1().read().stop() {
326 check_timeout()?;
327 }
275 }; 328 };
276 329
277 // Fallthrough is success 330 // Fallthrough is success
278 Ok(()) 331 Ok(())
279 } 332 }
280 333
281 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 334 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
282 unsafe { self.write_bytes(addr, bytes)? }; 335 self.blocking_write_timeout(addr, bytes, || Ok(()))
283 self.blocking_read(addr, buffer)?; 336 }
337
338 pub fn blocking_write_read_timeout(
339 &mut self,
340 addr: u8,
341 bytes: &[u8],
342 buffer: &mut [u8],
343 check_timeout: impl Fn() -> Result<(), Error>,
344 ) -> Result<(), Error> {
345 unsafe { self.write_bytes(addr, bytes, &check_timeout)? };
346 self.blocking_read_timeout(addr, buffer, &check_timeout)?;
284 347
285 Ok(()) 348 Ok(())
286 } 349 }
350
351 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
352 self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(()))
353 }
287} 354}
288 355
289impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 356impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 89b52da98..aa4e6bb08 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -147,14 +147,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
147 } 147 }
148 } 148 }
149 149
150 unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) { 150 unsafe fn master_read(
151 address: u8,
152 length: usize,
153 stop: Stop,
154 reload: bool,
155 restart: bool,
156 check_timeout: impl Fn() -> Result<(), Error>,
157 ) -> Result<(), Error> {
151 assert!(length < 256); 158 assert!(length < 256);
152 159
153 if !restart { 160 if !restart {
154 // Wait for any previous address sequence to end 161 // Wait for any previous address sequence to end
155 // automatically. This could be up to 50% of a bus 162 // automatically. This could be up to 50% of a bus
156 // cycle (ie. up to 0.5/freq) 163 // cycle (ie. up to 0.5/freq)
157 while T::regs().cr2().read().start() {} 164 while T::regs().cr2().read().start() {
165 check_timeout()?;
166 }
158 } 167 }
159 168
160 // Set START and prepare to receive bytes into 169 // Set START and prepare to receive bytes into
@@ -176,15 +185,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
176 w.set_autoend(stop.autoend()); 185 w.set_autoend(stop.autoend());
177 w.set_reload(reload); 186 w.set_reload(reload);
178 }); 187 });
188
189 Ok(())
179 } 190 }
180 191
181 unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) { 192 unsafe fn master_write(
193 address: u8,
194 length: usize,
195 stop: Stop,
196 reload: bool,
197 check_timeout: impl Fn() -> Result<(), Error>,
198 ) -> Result<(), Error> {
182 assert!(length < 256); 199 assert!(length < 256);
183 200
184 // Wait for any previous address sequence to end 201 // Wait for any previous address sequence to end
185 // automatically. This could be up to 50% of a bus 202 // automatically. This could be up to 50% of a bus
186 // cycle (ie. up to 0.5/freq) 203 // cycle (ie. up to 0.5/freq)
187 while T::regs().cr2().read().start() {} 204 while T::regs().cr2().read().start() {
205 check_timeout()?;
206 }
188 207
189 let reload = if reload { 208 let reload = if reload {
190 i2c::vals::Reload::NOTCOMPLETED 209 i2c::vals::Reload::NOTCOMPLETED
@@ -204,12 +223,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
204 w.set_autoend(stop.autoend()); 223 w.set_autoend(stop.autoend());
205 w.set_reload(reload); 224 w.set_reload(reload);
206 }); 225 });
226
227 Ok(())
207 } 228 }
208 229
209 unsafe fn master_continue(length: usize, reload: bool) { 230 unsafe fn master_continue(
231 length: usize,
232 reload: bool,
233 check_timeout: impl Fn() -> Result<(), Error>,
234 ) -> Result<(), Error> {
210 assert!(length < 256 && length > 0); 235 assert!(length < 256 && length > 0);
211 236
212 while !T::regs().isr().read().tcr() {} 237 while !T::regs().isr().read().tcr() {
238 check_timeout()?;
239 }
213 240
214 let reload = if reload { 241 let reload = if reload {
215 i2c::vals::Reload::NOTCOMPLETED 242 i2c::vals::Reload::NOTCOMPLETED
@@ -221,6 +248,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
221 w.set_nbytes(length as u8); 248 w.set_nbytes(length as u8);
222 w.set_reload(reload); 249 w.set_reload(reload);
223 }); 250 });
251
252 Ok(())
224 } 253 }
225 254
226 fn flush_txdr(&self) { 255 fn flush_txdr(&self) {
@@ -243,7 +272,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
243 //} 272 //}
244 } 273 }
245 274
246 fn wait_txe(&self) -> Result<(), Error> { 275 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
247 loop { 276 loop {
248 unsafe { 277 unsafe {
249 let isr = T::regs().isr().read(); 278 let isr = T::regs().isr().read();
@@ -261,10 +290,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
261 return Err(Error::Nack); 290 return Err(Error::Nack);
262 } 291 }
263 } 292 }
293
294 check_timeout()?;
264 } 295 }
265 } 296 }
266 297
267 fn wait_rxne(&self) -> Result<(), Error> { 298 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
268 loop { 299 loop {
269 unsafe { 300 unsafe {
270 let isr = T::regs().isr().read(); 301 let isr = T::regs().isr().read();
@@ -282,10 +313,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
282 return Err(Error::Nack); 313 return Err(Error::Nack);
283 } 314 }
284 } 315 }
316
317 check_timeout()?;
285 } 318 }
286 } 319 }
287 320
288 fn wait_tc(&self) -> Result<(), Error> { 321 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
289 loop { 322 loop {
290 unsafe { 323 unsafe {
291 let isr = T::regs().isr().read(); 324 let isr = T::regs().isr().read();
@@ -303,10 +336,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
303 return Err(Error::Nack); 336 return Err(Error::Nack);
304 } 337 }
305 } 338 }
339
340 check_timeout()?;
306 } 341 }
307 } 342 }
308 343
309 fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { 344 fn read_internal(
345 &mut self,
346 address: u8,
347 buffer: &mut [u8],
348 restart: bool,
349 check_timeout: impl Fn() -> Result<(), Error>,
350 ) -> Result<(), Error> {
310 let completed_chunks = buffer.len() / 255; 351 let completed_chunks = buffer.len() / 255;
311 let total_chunks = if completed_chunks * 255 == buffer.len() { 352 let total_chunks = if completed_chunks * 255 == buffer.len() {
312 completed_chunks 353 completed_chunks
@@ -322,20 +363,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
322 Stop::Automatic, 363 Stop::Automatic,
323 last_chunk_idx != 0, 364 last_chunk_idx != 0,
324 restart, 365 restart,
325 ); 366 &check_timeout,
367 )?;
326 } 368 }
327 369
328 for (number, chunk) in buffer.chunks_mut(255).enumerate() { 370 for (number, chunk) in buffer.chunks_mut(255).enumerate() {
329 if number != 0 { 371 if number != 0 {
330 // NOTE(unsafe) We have &mut self 372 // NOTE(unsafe) We have &mut self
331 unsafe { 373 unsafe {
332 Self::master_continue(chunk.len(), number != last_chunk_idx); 374 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
333 } 375 }
334 } 376 }
335 377
336 for byte in chunk { 378 for byte in chunk {
337 // Wait until we have received something 379 // Wait until we have received something
338 self.wait_rxne()?; 380 self.wait_rxne(&check_timeout)?;
339 381
340 unsafe { 382 unsafe {
341 *byte = T::regs().rxdr().read().rxdata(); 383 *byte = T::regs().rxdr().read().rxdata();
@@ -345,7 +387,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
345 Ok(()) 387 Ok(())
346 } 388 }
347 389
348 fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { 390 fn write_internal(
391 &mut self,
392 address: u8,
393 bytes: &[u8],
394 send_stop: bool,
395 check_timeout: impl Fn() -> Result<(), Error>,
396 ) -> Result<(), Error> {
349 let completed_chunks = bytes.len() / 255; 397 let completed_chunks = bytes.len() / 255;
350 let total_chunks = if completed_chunks * 255 == bytes.len() { 398 let total_chunks = if completed_chunks * 255 == bytes.len() {
351 completed_chunks 399 completed_chunks
@@ -359,14 +407,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
359 // ST SAD+W 407 // ST SAD+W
360 // NOTE(unsafe) We have &mut self 408 // NOTE(unsafe) We have &mut self
361 unsafe { 409 unsafe {
362 Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0); 410 Self::master_write(
411 address,
412 bytes.len().min(255),
413 Stop::Software,
414 last_chunk_idx != 0,
415 &check_timeout,
416 )?;
363 } 417 }
364 418
365 for (number, chunk) in bytes.chunks(255).enumerate() { 419 for (number, chunk) in bytes.chunks(255).enumerate() {
366 if number != 0 { 420 if number != 0 {
367 // NOTE(unsafe) We have &mut self 421 // NOTE(unsafe) We have &mut self
368 unsafe { 422 unsafe {
369 Self::master_continue(chunk.len(), number != last_chunk_idx); 423 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
370 } 424 }
371 } 425 }
372 426
@@ -374,7 +428,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
374 // Wait until we are allowed to send data 428 // Wait until we are allowed to send data
375 // (START has been ACKed or last byte when 429 // (START has been ACKed or last byte when
376 // through) 430 // through)
377 self.wait_txe()?; 431 self.wait_txe(&check_timeout)?;
378 432
379 unsafe { 433 unsafe {
380 T::regs().txdr().write(|w| w.set_txdata(*byte)); 434 T::regs().txdr().write(|w| w.set_txdata(*byte));
@@ -382,7 +436,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
382 } 436 }
383 } 437 }
384 // Wait until the write finishes 438 // Wait until the write finishes
385 self.wait_tc()?; 439 self.wait_tc(&check_timeout)?;
386 440
387 if send_stop { 441 if send_stop {
388 self.master_stop(); 442 self.master_stop();
@@ -396,6 +450,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
396 bytes: &[u8], 450 bytes: &[u8],
397 first_slice: bool, 451 first_slice: bool,
398 last_slice: bool, 452 last_slice: bool,
453 check_timeout: impl Fn() -> Result<(), Error>,
399 ) -> Result<(), Error> 454 ) -> Result<(), Error>
400 where 455 where
401 TXDMA: crate::i2c::TxDma<T>, 456 TXDMA: crate::i2c::TxDma<T>,
@@ -447,11 +502,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
447 total_len.min(255), 502 total_len.min(255),
448 Stop::Software, 503 Stop::Software,
449 (total_chunks != 1) || !last_slice, 504 (total_chunks != 1) || !last_slice,
450 ); 505 &check_timeout,
506 )?;
451 } 507 }
452 } else { 508 } else {
453 unsafe { 509 unsafe {
454 Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice); 510 Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?;
455 T::regs().cr1().modify(|w| w.set_tcie(true)); 511 T::regs().cr1().modify(|w| w.set_tcie(true));
456 } 512 }
457 } 513 }
@@ -461,32 +517,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
461 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); 517 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
462 518
463 if chunks_transferred == total_chunks { 519 if chunks_transferred == total_chunks {
464 return Poll::Ready(()); 520 return Poll::Ready(Ok(()));
465 } else if chunks_transferred != 0 { 521 } else if chunks_transferred != 0 {
466 remaining_len = remaining_len.saturating_sub(255); 522 remaining_len = remaining_len.saturating_sub(255);
467 let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; 523 let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice;
468 524
469 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers 525 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
470 unsafe { 526 unsafe {
471 Self::master_continue(remaining_len.min(255), !last_piece); 527 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
528 return Poll::Ready(Err(e));
529 }
472 T::regs().cr1().modify(|w| w.set_tcie(true)); 530 T::regs().cr1().modify(|w| w.set_tcie(true));
473 } 531 }
474 } 532 }
475 Poll::Pending 533 Poll::Pending
476 }) 534 })
477 .await; 535 .await?;
478 536
479 dma_transfer.await; 537 dma_transfer.await;
480 538
481 if last_slice { 539 if last_slice {
482 // This should be done already 540 // This should be done already
483 self.wait_tc()?; 541 self.wait_tc(&check_timeout)?;
484 self.master_stop(); 542 self.master_stop();
485 } 543 }
486 Ok(()) 544 Ok(())
487 } 545 }
488 546
489 async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> 547 async fn read_dma_internal(
548 &mut self,
549 address: u8,
550 buffer: &mut [u8],
551 restart: bool,
552 check_timeout: impl Fn() -> Result<(), Error>,
553 ) -> Result<(), Error>
490 where 554 where
491 RXDMA: crate::i2c::RxDma<T>, 555 RXDMA: crate::i2c::RxDma<T>,
492 { 556 {
@@ -527,7 +591,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
527 591
528 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 592 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
529 unsafe { 593 unsafe {
530 Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart); 594 Self::master_read(
595 address,
596 total_len.min(255),
597 Stop::Software,
598 total_chunks != 1,
599 restart,
600 &check_timeout,
601 )?;
531 } 602 }
532 603
533 poll_fn(|cx| { 604 poll_fn(|cx| {
@@ -535,25 +606,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
535 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); 606 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
536 607
537 if chunks_transferred == total_chunks { 608 if chunks_transferred == total_chunks {
538 return Poll::Ready(()); 609 return Poll::Ready(Ok(()));
539 } else if chunks_transferred != 0 { 610 } else if chunks_transferred != 0 {
540 remaining_len = remaining_len.saturating_sub(255); 611 remaining_len = remaining_len.saturating_sub(255);
541 let last_piece = chunks_transferred + 1 == total_chunks; 612 let last_piece = chunks_transferred + 1 == total_chunks;
542 613
543 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 614 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
544 unsafe { 615 unsafe {
545 Self::master_continue(remaining_len.min(255), !last_piece); 616 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
617 return Poll::Ready(Err(e));
618 }
546 T::regs().cr1().modify(|w| w.set_tcie(true)); 619 T::regs().cr1().modify(|w| w.set_tcie(true));
547 } 620 }
548 } 621 }
549 Poll::Pending 622 Poll::Pending
550 }) 623 })
551 .await; 624 .await?;
552 625
553 dma_transfer.await; 626 dma_transfer.await;
554 627
555 // This should be done already 628 // This should be done already
556 self.wait_tc()?; 629 self.wait_tc(&check_timeout)?;
557 self.master_stop(); 630 self.master_stop();
558 Ok(()) 631 Ok(())
559 } 632 }
@@ -566,9 +639,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
566 TXDMA: crate::i2c::TxDma<T>, 639 TXDMA: crate::i2c::TxDma<T>,
567 { 640 {
568 if bytes.is_empty() { 641 if bytes.is_empty() {
569 self.write_internal(address, bytes, true) 642 self.write_internal(address, bytes, true, || Ok(()))
570 } else { 643 } else {
571 self.write_dma_internal(address, bytes, true, true).await 644 self.write_dma_internal(address, bytes, true, true, || Ok(())).await
572 } 645 }
573 } 646 }
574 647
@@ -587,7 +660,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
587 let next = iter.next(); 660 let next = iter.next();
588 let is_last = next.is_none(); 661 let is_last = next.is_none();
589 662
590 self.write_dma_internal(address, c, first, is_last).await?; 663 self.write_dma_internal(address, c, first, is_last, || Ok(())).await?;
591 first = false; 664 first = false;
592 current = next; 665 current = next;
593 } 666 }
@@ -599,9 +672,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
599 RXDMA: crate::i2c::RxDma<T>, 672 RXDMA: crate::i2c::RxDma<T>,
600 { 673 {
601 if buffer.is_empty() { 674 if buffer.is_empty() {
602 self.read_internal(address, buffer, false) 675 self.read_internal(address, buffer, false, || Ok(()))
603 } else { 676 } else {
604 self.read_dma_internal(address, buffer, false).await 677 self.read_dma_internal(address, buffer, false, || Ok(())).await
605 } 678 }
606 } 679 }
607 680
@@ -611,15 +684,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
611 RXDMA: super::RxDma<T>, 684 RXDMA: super::RxDma<T>,
612 { 685 {
613 if bytes.is_empty() { 686 if bytes.is_empty() {
614 self.write_internal(address, bytes, false)?; 687 self.write_internal(address, bytes, false, || Ok(()))?;
615 } else { 688 } else {
616 self.write_dma_internal(address, bytes, true, true).await?; 689 self.write_dma_internal(address, bytes, true, true, || Ok(())).await?;
617 } 690 }
618 691
619 if buffer.is_empty() { 692 if buffer.is_empty() {
620 self.read_internal(address, buffer, true)?; 693 self.read_internal(address, buffer, true, || Ok(()))?;
621 } else { 694 } else {
622 self.read_dma_internal(address, buffer, true).await?; 695 self.read_dma_internal(address, buffer, true, || Ok(())).await?;
623 } 696 }
624 697
625 Ok(()) 698 Ok(())
@@ -628,22 +701,55 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
628 // ========================= 701 // =========================
629 // Blocking public API 702 // Blocking public API
630 703
631 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 704 pub fn blocking_read_timeout(
632 self.read_internal(address, buffer, false) 705 &mut self,
706 address: u8,
707 buffer: &mut [u8],
708 check_timeout: impl Fn() -> Result<(), Error>,
709 ) -> Result<(), Error> {
710 self.read_internal(address, buffer, false, &check_timeout)
633 // Automatic Stop 711 // Automatic Stop
634 } 712 }
635 713
714 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
715 self.blocking_read_timeout(address, buffer, || Ok(()))
716 }
717
718 pub fn blocking_write_timeout(
719 &mut self,
720 address: u8,
721 bytes: &[u8],
722 check_timeout: impl Fn() -> Result<(), Error>,
723 ) -> Result<(), Error> {
724 self.write_internal(address, bytes, true, &check_timeout)
725 }
726
636 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { 727 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
637 self.write_internal(address, bytes, true) 728 self.blocking_write_timeout(address, bytes, || Ok(()))
638 } 729 }
639 730
640 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 731 pub fn blocking_write_read_timeout(
641 self.write_internal(address, bytes, false)?; 732 &mut self,
642 self.read_internal(address, buffer, true) 733 address: u8,
734 bytes: &[u8],
735 buffer: &mut [u8],
736 check_timeout: impl Fn() -> Result<(), Error>,
737 ) -> Result<(), Error> {
738 self.write_internal(address, bytes, false, &check_timeout)?;
739 self.read_internal(address, buffer, true, &check_timeout)
643 // Automatic Stop 740 // Automatic Stop
644 } 741 }
645 742
646 pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { 743 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
744 self.blocking_write_read_timeout(address, bytes, buffer, || Ok(()))
745 }
746
747 pub fn blocking_write_vectored_timeout(
748 &mut self,
749 address: u8,
750 bytes: &[&[u8]],
751 check_timeout: impl Fn() -> Result<(), Error>,
752 ) -> Result<(), Error> {
647 if bytes.is_empty() { 753 if bytes.is_empty() {
648 return Err(Error::ZeroLengthTransfer); 754 return Err(Error::ZeroLengthTransfer);
649 } 755 }
@@ -657,7 +763,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
657 first_length.min(255), 763 first_length.min(255),
658 Stop::Software, 764 Stop::Software,
659 (first_length > 255) || (last_slice_index != 0), 765 (first_length > 255) || (last_slice_index != 0),
660 ); 766 &check_timeout,
767 )?;
661 } 768 }
662 769
663 for (idx, slice) in bytes.iter().enumerate() { 770 for (idx, slice) in bytes.iter().enumerate() {
@@ -673,7 +780,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
673 if idx != 0 { 780 if idx != 0 {
674 // NOTE(unsafe) We have &mut self 781 // NOTE(unsafe) We have &mut self
675 unsafe { 782 unsafe {
676 Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255)); 783 Self::master_continue(
784 slice_len.min(255),
785 (idx != last_slice_index) || (slice_len > 255),
786 &check_timeout,
787 )?;
677 } 788 }
678 } 789 }
679 790
@@ -681,7 +792,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
681 if number != 0 { 792 if number != 0 {
682 // NOTE(unsafe) We have &mut self 793 // NOTE(unsafe) We have &mut self
683 unsafe { 794 unsafe {
684 Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index)); 795 Self::master_continue(
796 chunk.len(),
797 (number != last_chunk_idx) || (idx != last_slice_index),
798 &check_timeout,
799 )?;
685 } 800 }
686 } 801 }
687 802
@@ -689,7 +804,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
689 // Wait until we are allowed to send data 804 // Wait until we are allowed to send data
690 // (START has been ACKed or last byte when 805 // (START has been ACKed or last byte when
691 // through) 806 // through)
692 self.wait_txe()?; 807 self.wait_txe(&check_timeout)?;
693 808
694 // Put byte on the wire 809 // Put byte on the wire
695 //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); 810 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
@@ -700,11 +815,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
700 } 815 }
701 } 816 }
702 // Wait until the write finishes 817 // Wait until the write finishes
703 self.wait_tc()?; 818 self.wait_tc(&check_timeout)?;
704 self.master_stop(); 819 self.master_stop();
705 820
706 Ok(()) 821 Ok(())
707 } 822 }
823
824 pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
825 self.blocking_write_vectored_timeout(address, bytes, || Ok(()))
826 }
708} 827}
709 828
710mod eh02 { 829mod eh02 {
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 0392e8086..bcf2feee8 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -52,7 +52,7 @@ pub mod sdmmc;
52pub mod spi; 52pub mod spi;
53#[cfg(usart)] 53#[cfg(usart)]
54pub mod usart; 54pub mod usart;
55#[cfg(usb)] 55#[cfg(all(usb, feature = "time"))]
56pub mod usb; 56pub mod usb;
57#[cfg(any(otgfs, otghs))] 57#[cfg(any(otgfs, otghs))]
58pub mod usb_otg; 58pub mod usb_otg;
diff --git a/embassy-stm32/src/subghz/timeout.rs b/embassy-stm32/src/subghz/timeout.rs
index 28b3b0c21..0ae49dd90 100644
--- a/embassy-stm32/src/subghz/timeout.rs
+++ b/embassy-stm32/src/subghz/timeout.rs
@@ -439,6 +439,7 @@ impl From<Timeout> for [u8; 3] {
439 } 439 }
440} 440}
441 441
442#[cfg(feature = "time")]
442impl From<Timeout> for embassy_time::Duration { 443impl From<Timeout> for embassy_time::Duration {
443 fn from(to: Timeout) -> Self { 444 fn from(to: Timeout) -> Self {
444 embassy_time::Duration::from_micros(to.as_micros().into()) 445 embassy_time::Duration::from_micros(to.as_micros().into())
diff --git a/embassy-stm32/src/subghz/tx_params.rs b/embassy-stm32/src/subghz/tx_params.rs
index cede6f2c1..03bdb1ea8 100644
--- a/embassy-stm32/src/subghz/tx_params.rs
+++ b/embassy-stm32/src/subghz/tx_params.rs
@@ -44,6 +44,7 @@ impl From<RampTime> for core::time::Duration {
44 } 44 }
45} 45}
46 46
47#[cfg(feature = "time")]
47impl From<RampTime> for embassy_time::Duration { 48impl From<RampTime> for embassy_time::Duration {
48 fn from(rt: RampTime) -> Self { 49 fn from(rt: RampTime) -> Self {
49 match rt { 50 match rt {
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
new file mode 100644
index 000000000..6e51c211d
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -0,0 +1,45 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
9use embassy_stm32::interrupt;
10use embassy_stm32::time::Hertz;
11use embassy_time::Duration;
12use {defmt_rtt as _, panic_probe as _};
13
14const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) -> ! {
19 info!("Hello world!");
20 let p = embassy_stm32::init(Default::default());
21
22 let irq = interrupt::take!(I2C2_EV);
23 let mut i2c = I2c::new(
24 p.I2C2,
25 p.PB10,
26 p.PB11,
27 irq,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33
34 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
35 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
36 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
37
38 let mut data = [0u8; 1];
39
40 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
41 Ok(()) => info!("Whoami: {}", data[0]),
42 Err(Error::Timeout) => error!("Operation timed out"),
43 Err(e) => error!("I2c Error: {:?}", e),
44 }
45}
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs
new file mode 100644
index 000000000..d44319ae6
--- /dev/null
+++ b/examples/stm32h7/src/bin/i2c.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
8use embassy_stm32::interrupt;
9use embassy_stm32::time::Hertz;
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) -> ! {
18 info!("Hello world!");
19 let p = embassy_stm32::init(Default::default());
20
21 let irq = interrupt::take!(I2C2_EV);
22 let mut i2c = I2c::new(
23 p.I2C2,
24 p.PB10,
25 p.PB11,
26 irq,
27 p.DMA1_CH4,
28 p.DMA1_CH5,
29 Hertz(100_000),
30 Default::default(),
31 );
32
33 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
34 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
35 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
36
37 let mut data = [0u8; 1];
38
39 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
40 Ok(()) => info!("Whoami: {}", data[0]),
41 Err(Error::Timeout) => error!("Operation timed out"),
42 Err(e) => error!("I2c Error: {:?}", e),
43 }
44}