aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2022-10-24 11:30:04 +0300
committerchemicstry <[email protected]>2022-10-24 11:30:04 +0300
commit4ce4131f8bad84ab38f595ac02dc5292611aaac0 (patch)
treec497f19026de4217443dedd8c82ab3c99e44a690
parentce1cba761c2942b7faa27f4098487c6468784729 (diff)
Implement i2cv1 timeout
-rw-r--r--embassy-stm32/src/i2c/mod.rs3
-rw-r--r--embassy-stm32/src/i2c/timeout.rs132
-rw-r--r--embassy-stm32/src/i2c/v1.rs101
-rw-r--r--examples/stm32f4/src/bin/i2c.rs30
4 files changed, 243 insertions, 23 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 9d314f411..f4f64992c 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -7,6 +7,9 @@ use crate::interrupt::Interrupt;
7mod _version; 7mod _version;
8pub use _version::*; 8pub use _version::*;
9 9
10mod timeout;
11pub use timeout::*;
12
10use crate::peripherals; 13use crate::peripherals;
11 14
12#[derive(Debug)] 15#[derive(Debug)]
diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs
new file mode 100644
index 000000000..12319af8a
--- /dev/null
+++ b/embassy-stm32/src/i2c/timeout.rs
@@ -0,0 +1,132 @@
1use embassy_time::{Duration, Instant};
2
3use super::{Error, I2c, Instance};
4
5pub struct TimeoutI2c<'d, T: Instance> {
6 i2c: &'d mut I2c<'d, T>,
7 timeout: Duration,
8}
9
10fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
11 let deadline = Instant::now() + timeout;
12 move || {
13 if Instant::now() > deadline {
14 Err(Error::Timeout)
15 } else {
16 Ok(())
17 }
18 }
19}
20
21impl<'d, T: Instance> TimeoutI2c<'d, T> {
22 pub fn new(i2c: &'d mut I2c<'d, T>, timeout: Duration) -> Self {
23 Self { i2c, timeout }
24 }
25
26 pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> {
27 self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout))
28 }
29
30 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
31 self.blocking_read_timeout(addr, buffer, self.timeout)
32 }
33
34 pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> {
35 self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout))
36 }
37
38 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
39 self.blocking_write_timeout(addr, bytes, self.timeout)
40 }
41
42 pub fn blocking_write_read_timeout(
43 &mut self,
44 addr: u8,
45 bytes: &[u8],
46 buffer: &mut [u8],
47 timeout: Duration,
48 ) -> Result<(), Error> {
49 self.i2c
50 .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout))
51 }
52
53 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
54 self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout)
55 }
56}
57
58impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T> {
59 type Error = Error;
60
61 fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
62 self.blocking_read(addr, buffer)
63 }
64}
65
66impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T> {
67 type Error = Error;
68
69 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
70 self.blocking_write(addr, bytes)
71 }
72}
73
74impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T> {
75 type Error = Error;
76
77 fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
78 self.blocking_write_read(addr, bytes, buffer)
79 }
80}
81
82#[cfg(feature = "unstable-traits")]
83mod eh1 {
84 use super::*;
85
86 impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T> {
87 type Error = Error;
88 }
89
90 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T> {
91 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
92 self.blocking_read(address, buffer)
93 }
94
95 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
96 self.blocking_write(address, buffer)
97 }
98
99 fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
100 where
101 B: IntoIterator<Item = u8>,
102 {
103 todo!();
104 }
105
106 fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error>
107 where
108 B: IntoIterator<Item = u8>,
109 {
110 todo!();
111 }
112
113 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
114 self.blocking_write_read(address, wr_buffer, rd_buffer)
115 }
116
117 fn transaction<'a>(
118 &mut self,
119 _address: u8,
120 _operations: &mut [embedded_hal_1::i2c::Operation<'a>],
121 ) -> Result<(), Self::Error> {
122 todo!();
123 }
124
125 fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
126 where
127 O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
128 {
129 todo!();
130 }
131 }
132}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index f39a37df6..92a898824 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -141,7 +141,12 @@ impl<'d, T: Instance> I2c<'d, T> {
141 Ok(sr1) 141 Ok(sr1)
142 } 142 }
143 143
144 unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 144 unsafe fn write_bytes(
145 &mut self,
146 addr: u8,
147 bytes: &[u8],
148 check_timeout: impl Fn() -> Result<(), Error>,
149 ) -> Result<(), Error> {
145 // Send a START condition 150 // Send a START condition
146 151
147 T::regs().cr1().modify(|reg| { 152 T::regs().cr1().modify(|reg| {
@@ -149,7 +154,9 @@ impl<'d, T: Instance> I2c<'d, T> {
149 }); 154 });
150 155
151 // Wait until START condition was generated 156 // Wait until START condition was generated
152 while !self.check_and_clear_error_flags()?.start() {} 157 while !self.check_and_clear_error_flags()?.start() {
158 check_timeout()?;
159 }
153 160
154 // Also wait until signalled we're master and everything is waiting for us 161 // Also wait until signalled we're master and everything is waiting for us
155 while { 162 while {
@@ -157,7 +164,9 @@ impl<'d, T: Instance> I2c<'d, T> {
157 164
158 let sr2 = T::regs().sr2().read(); 165 let sr2 = T::regs().sr2().read();
159 !sr2.msl() && !sr2.busy() 166 !sr2.msl() && !sr2.busy()
160 } {} 167 } {
168 check_timeout()?;
169 }
161 170
162 // Set up current address, we're trying to talk to 171 // Set up current address, we're trying to talk to
163 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 172 T::regs().dr().write(|reg| reg.set_dr(addr << 1));
@@ -165,26 +174,30 @@ impl<'d, T: Instance> I2c<'d, T> {
165 // Wait until address was sent 174 // Wait until address was sent
166 // Wait for the address to be acknowledged 175 // Wait for the address to be acknowledged
167 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 176 // 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() {} 177 while !self.check_and_clear_error_flags()?.addr() {
178 check_timeout()?;
179 }
169 180
170 // Clear condition by reading SR2 181 // Clear condition by reading SR2
171 let _ = T::regs().sr2().read(); 182 let _ = T::regs().sr2().read();
172 183
173 // Send bytes 184 // Send bytes
174 for c in bytes { 185 for c in bytes {
175 self.send_byte(*c)?; 186 self.send_byte(*c, &check_timeout)?;
176 } 187 }
177 188
178 // Fallthrough is success 189 // Fallthrough is success
179 Ok(()) 190 Ok(())
180 } 191 }
181 192
182 unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> { 193 unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
183 // Wait until we're ready for sending 194 // Wait until we're ready for sending
184 while { 195 while {
185 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 196 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
186 !self.check_and_clear_error_flags()?.txe() 197 !self.check_and_clear_error_flags()?.txe()
187 } {} 198 } {
199 check_timeout()?;
200 }
188 201
189 // Push out a byte of data 202 // Push out a byte of data
190 T::regs().dr().write(|reg| reg.set_dr(byte)); 203 T::regs().dr().write(|reg| reg.set_dr(byte));
@@ -193,24 +206,33 @@ impl<'d, T: Instance> I2c<'d, T> {
193 while { 206 while {
194 // Check for any potential error conditions. 207 // Check for any potential error conditions.
195 !self.check_and_clear_error_flags()?.btf() 208 !self.check_and_clear_error_flags()?.btf()
196 } {} 209 } {
210 check_timeout()?;
211 }
197 212
198 Ok(()) 213 Ok(())
199 } 214 }
200 215
201 unsafe fn recv_byte(&self) -> Result<u8, Error> { 216 unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
202 while { 217 while {
203 // Check for any potential error conditions. 218 // Check for any potential error conditions.
204 self.check_and_clear_error_flags()?; 219 self.check_and_clear_error_flags()?;
205 220
206 !T::regs().sr1().read().rxne() 221 !T::regs().sr1().read().rxne()
207 } {} 222 } {
223 check_timeout()?;
224 }
208 225
209 let value = T::regs().dr().read().dr(); 226 let value = T::regs().dr().read().dr();
210 Ok(value) 227 Ok(value)
211 } 228 }
212 229
213 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { 230 pub fn blocking_read_timeout(
231 &mut self,
232 addr: u8,
233 buffer: &mut [u8],
234 check_timeout: impl Fn() -> Result<(), Error>,
235 ) -> Result<(), Error> {
214 if let Some((last, buffer)) = buffer.split_last_mut() { 236 if let Some((last, buffer)) = buffer.split_last_mut() {
215 // Send a START condition and set ACK bit 237 // Send a START condition and set ACK bit
216 unsafe { 238 unsafe {
@@ -221,27 +243,33 @@ impl<'d, T: Instance> I2c<'d, T> {
221 } 243 }
222 244
223 // Wait until START condition was generated 245 // Wait until START condition was generated
224 while unsafe { !T::regs().sr1().read().start() } {} 246 while unsafe { !self.check_and_clear_error_flags()?.start() } {
247 check_timeout()?;
248 }
225 249
226 // Also wait until signalled we're master and everything is waiting for us 250 // Also wait until signalled we're master and everything is waiting for us
227 while { 251 while {
228 let sr2 = unsafe { T::regs().sr2().read() }; 252 let sr2 = unsafe { T::regs().sr2().read() };
229 !sr2.msl() && !sr2.busy() 253 !sr2.msl() && !sr2.busy()
230 } {} 254 } {
255 check_timeout()?;
256 }
231 257
232 // Set up current address, we're trying to talk to 258 // Set up current address, we're trying to talk to
233 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } 259 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) }
234 260
235 // Wait until address was sent 261 // Wait until address was sent
236 // Wait for the address to be acknowledged 262 // Wait for the address to be acknowledged
237 while unsafe { !self.check_and_clear_error_flags()?.addr() } {} 263 while unsafe { !self.check_and_clear_error_flags()?.addr() } {
264 check_timeout()?;
265 }
238 266
239 // Clear condition by reading SR2 267 // Clear condition by reading SR2
240 let _ = unsafe { T::regs().sr2().read() }; 268 let _ = unsafe { T::regs().sr2().read() };
241 269
242 // Receive bytes into buffer 270 // Receive bytes into buffer
243 for c in buffer { 271 for c in buffer {
244 *c = unsafe { self.recv_byte()? }; 272 *c = unsafe { self.recv_byte(&check_timeout)? };
245 } 273 }
246 274
247 // Prepare to send NACK then STOP after next byte 275 // Prepare to send NACK then STOP after next byte
@@ -253,10 +281,12 @@ impl<'d, T: Instance> I2c<'d, T> {
253 } 281 }
254 282
255 // Receive last byte 283 // Receive last byte
256 *last = unsafe { self.recv_byte()? }; 284 *last = unsafe { self.recv_byte(&check_timeout)? };
257 285
258 // Wait for the STOP to be sent. 286 // Wait for the STOP to be sent.
259 while unsafe { T::regs().cr1().read().stop() } {} 287 while unsafe { T::regs().cr1().read().stop() } {
288 check_timeout()?;
289 }
260 290
261 // Fallthrough is success 291 // Fallthrough is success
262 Ok(()) 292 Ok(())
@@ -265,25 +295,50 @@ impl<'d, T: Instance> I2c<'d, T> {
265 } 295 }
266 } 296 }
267 297
268 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 298 pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
299 self.blocking_read_timeout(addr, buffer, || Ok(()))
300 }
301
302 pub fn blocking_write_timeout(
303 &mut self,
304 addr: u8,
305 bytes: &[u8],
306 check_timeout: impl Fn() -> Result<(), Error>,
307 ) -> Result<(), Error> {
269 unsafe { 308 unsafe {
270 self.write_bytes(addr, bytes)?; 309 self.write_bytes(addr, bytes, &check_timeout)?;
271 // Send a STOP condition 310 // Send a STOP condition
272 T::regs().cr1().modify(|reg| reg.set_stop(true)); 311 T::regs().cr1().modify(|reg| reg.set_stop(true));
273 // Wait for STOP condition to transmit. 312 // Wait for STOP condition to transmit.
274 while T::regs().cr1().read().stop() {} 313 while T::regs().cr1().read().stop() {
314 check_timeout()?;
315 }
275 }; 316 };
276 317
277 // Fallthrough is success 318 // Fallthrough is success
278 Ok(()) 319 Ok(())
279 } 320 }
280 321
281 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
282 unsafe { self.write_bytes(addr, bytes)? }; 323 self.blocking_write_timeout(addr, bytes, || Ok(()))
283 self.blocking_read(addr, buffer)?; 324 }
325
326 pub fn blocking_write_read_timeout(
327 &mut self,
328 addr: u8,
329 bytes: &[u8],
330 buffer: &mut [u8],
331 check_timeout: impl Fn() -> Result<(), Error>,
332 ) -> Result<(), Error> {
333 unsafe { self.write_bytes(addr, bytes, &check_timeout)? };
334 self.blocking_read_timeout(addr, buffer, &check_timeout)?;
284 335
285 Ok(()) 336 Ok(())
286 } 337 }
338
339 pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
340 self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(()))
341 }
287} 342}
288 343
289impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 344impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
new file mode 100644
index 000000000..99e3cecfc
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -0,0 +1,30 @@
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::time::Hertz;
9use embassy_time::Duration;
10use {defmt_rtt as _, panic_probe as _};
11
12const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F;
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) -> ! {
17 info!("Hello world!");
18 let p = embassy_stm32::init(Default::default());
19
20 let mut i2c = I2c::new(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
21 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
22
23 let mut data = [0u8; 1];
24
25 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
26 Ok(()) => info!("Whoami: {}", data[0]),
27 Err(Error::Timeout) => error!("Operation timed out"),
28 Err(e) => error!("I2c Error: {:?}", e),
29 }
30}