diff options
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 265 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 12 |
3 files changed, 225 insertions, 58 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 2416005b5..2c606c3c9 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -311,10 +311,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { | |||
| 311 | 311 | ||
| 312 | fn transaction( | 312 | fn transaction( |
| 313 | &mut self, | 313 | &mut self, |
| 314 | _address: u8, | 314 | address: u8, |
| 315 | _operations: &mut [embedded_hal_1::i2c::Operation<'_>], | 315 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], |
| 316 | ) -> Result<(), Self::Error> { | 316 | ) -> Result<(), Self::Error> { |
| 317 | todo!(); | 317 | self.blocking_transaction(address, operations) |
| 318 | } | 318 | } |
| 319 | } | 319 | } |
| 320 | 320 | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index cbbc201de..f1ed7ca40 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -10,6 +10,7 @@ use core::task::Poll; | |||
| 10 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 13 | use embedded_hal_1::i2c::Operation; | ||
| 13 | 14 | ||
| 14 | use super::*; | 15 | use super::*; |
| 15 | use crate::dma::Transfer; | 16 | use crate::dma::Transfer; |
| @@ -41,6 +42,68 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 41 | }); | 42 | }); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 45 | /// Frame type in I2C transaction. | ||
| 46 | /// | ||
| 47 | /// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST | ||
| 48 | /// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an | ||
| 49 | /// ACK or NACK after the last byte received. | ||
| 50 | /// | ||
| 51 | /// For write operations, the following options are identical because they differ only in the (N)ACK | ||
| 52 | /// treatment relevant for read operations: | ||
| 53 | /// | ||
| 54 | /// - `FirstFrame` and `FirstAndNextFrame` | ||
| 55 | /// - `NextFrame` and `LastFrameNoStop` | ||
| 56 | /// | ||
| 57 | /// Abbreviations used below: | ||
| 58 | /// | ||
| 59 | /// - `ST` = start condition | ||
| 60 | /// - `SR` = repeated start condition | ||
| 61 | /// - `SP` = stop condition | ||
| 62 | #[derive(Copy, Clone)] | ||
| 63 | enum FrameOptions { | ||
| 64 | /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this | ||
| 65 | /// transaction. | ||
| 66 | FirstAndLastFrame, | ||
| 67 | /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but | ||
| 68 | /// not the last frame overall. | ||
| 69 | FirstFrame, | ||
| 70 | /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last | ||
| 71 | /// frame in a read operation. | ||
| 72 | FirstAndNextFrame, | ||
| 73 | /// `[ACK]` Middle frame in a read operation (neither first nor last). | ||
| 74 | NextFrame, | ||
| 75 | /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. | ||
| 76 | LastFrame, | ||
| 77 | /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. | ||
| 78 | LastFrameNoStop, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl FrameOptions { | ||
| 82 | /// Sends start or repeated start condition before transfer. | ||
| 83 | fn send_start(self) -> bool { | ||
| 84 | match self { | ||
| 85 | Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, | ||
| 86 | Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Sends stop condition after transfer. | ||
| 91 | fn send_stop(self) -> bool { | ||
| 92 | match self { | ||
| 93 | Self::FirstAndLastFrame | Self::LastFrame => true, | ||
| 94 | Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /// Sends NACK after last byte received, indicating end of read operation. | ||
| 99 | fn send_nack(self) -> bool { | ||
| 100 | match self { | ||
| 101 | Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, | ||
| 102 | Self::FirstAndNextFrame | Self::NextFrame => false, | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 44 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 107 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 108 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 46 | T::regs().cr1().modify(|reg| { | 109 | T::regs().cr1().modify(|reg| { |
| @@ -124,46 +187,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 124 | Ok(sr1) | 187 | Ok(sr1) |
| 125 | } | 188 | } |
| 126 | 189 | ||
| 127 | fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { | 190 | fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { |
| 128 | // Send a START condition | 191 | if frame.send_start() { |
| 192 | // Send a START condition | ||
| 129 | 193 | ||
| 130 | T::regs().cr1().modify(|reg| { | 194 | T::regs().cr1().modify(|reg| { |
| 131 | reg.set_start(true); | 195 | reg.set_start(true); |
| 132 | }); | 196 | }); |
| 133 | 197 | ||
| 134 | // Wait until START condition was generated | 198 | // Wait until START condition was generated |
| 135 | while !Self::check_and_clear_error_flags()?.start() { | 199 | while !Self::check_and_clear_error_flags()?.start() { |
| 136 | timeout.check()?; | 200 | timeout.check()?; |
| 137 | } | 201 | } |
| 138 | 202 | ||
| 139 | // Also wait until signalled we're master and everything is waiting for us | 203 | // Also wait until signalled we're master and everything is waiting for us |
| 140 | while { | 204 | while { |
| 141 | Self::check_and_clear_error_flags()?; | 205 | Self::check_and_clear_error_flags()?; |
| 142 | 206 | ||
| 143 | let sr2 = T::regs().sr2().read(); | 207 | let sr2 = T::regs().sr2().read(); |
| 144 | !sr2.msl() && !sr2.busy() | 208 | !sr2.msl() && !sr2.busy() |
| 145 | } { | 209 | } { |
| 146 | timeout.check()?; | 210 | timeout.check()?; |
| 147 | } | 211 | } |
| 148 | 212 | ||
| 149 | // Set up current address, we're trying to talk to | 213 | // Set up current address, we're trying to talk to |
| 150 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); | 214 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); |
| 151 | 215 | ||
| 152 | // Wait until address was sent | 216 | // Wait until address was sent |
| 153 | // Wait for the address to be acknowledged | 217 | // Wait for the address to be acknowledged |
| 154 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 218 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 155 | while !Self::check_and_clear_error_flags()?.addr() { | 219 | while !Self::check_and_clear_error_flags()?.addr() { |
| 156 | timeout.check()?; | 220 | timeout.check()?; |
| 157 | } | 221 | } |
| 158 | 222 | ||
| 159 | // Clear condition by reading SR2 | 223 | // Clear condition by reading SR2 |
| 160 | let _ = T::regs().sr2().read(); | 224 | let _ = T::regs().sr2().read(); |
| 225 | } | ||
| 161 | 226 | ||
| 162 | // Send bytes | 227 | // Send bytes |
| 163 | for c in bytes { | 228 | for c in bytes { |
| 164 | self.send_byte(*c, timeout)?; | 229 | self.send_byte(*c, timeout)?; |
| 165 | } | 230 | } |
| 166 | 231 | ||
| 232 | if frame.send_stop() { | ||
| 233 | // Send a STOP condition | ||
| 234 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||
| 235 | // Wait for STOP condition to transmit. | ||
| 236 | while T::regs().cr1().read().stop() { | ||
| 237 | timeout.check()?; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 167 | // Fallthrough is success | 241 | // Fallthrough is success |
| 168 | Ok(()) | 242 | Ok(()) |
| 169 | } | 243 | } |
| @@ -205,8 +279,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 205 | Ok(value) | 279 | Ok(value) |
| 206 | } | 280 | } |
| 207 | 281 | ||
| 208 | fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { | 282 | fn blocking_read_timeout( |
| 209 | if let Some((last, buffer)) = buffer.split_last_mut() { | 283 | &mut self, |
| 284 | addr: u8, | ||
| 285 | buffer: &mut [u8], | ||
| 286 | timeout: Timeout, | ||
| 287 | frame: FrameOptions, | ||
| 288 | ) -> Result<(), Error> { | ||
| 289 | let Some((last, buffer)) = buffer.split_last_mut() else { | ||
| 290 | return Err(Error::Overrun); | ||
| 291 | }; | ||
| 292 | |||
| 293 | if frame.send_start() { | ||
| 210 | // Send a START condition and set ACK bit | 294 | // Send a START condition and set ACK bit |
| 211 | T::regs().cr1().modify(|reg| { | 295 | T::regs().cr1().modify(|reg| { |
| 212 | reg.set_start(true); | 296 | reg.set_start(true); |
| @@ -237,49 +321,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 237 | 321 | ||
| 238 | // Clear condition by reading SR2 | 322 | // Clear condition by reading SR2 |
| 239 | let _ = T::regs().sr2().read(); | 323 | let _ = T::regs().sr2().read(); |
| 324 | } | ||
| 240 | 325 | ||
| 241 | // Receive bytes into buffer | 326 | // Receive bytes into buffer |
| 242 | for c in buffer { | 327 | for c in buffer { |
| 243 | *c = self.recv_byte(timeout)?; | 328 | *c = self.recv_byte(timeout)?; |
| 244 | } | 329 | } |
| 245 | 330 | ||
| 246 | // Prepare to send NACK then STOP after next byte | 331 | // Prepare to send NACK then STOP after next byte |
| 247 | T::regs().cr1().modify(|reg| { | 332 | T::regs().cr1().modify(|reg| { |
| 333 | if frame.send_nack() { | ||
| 248 | reg.set_ack(false); | 334 | reg.set_ack(false); |
| 335 | } | ||
| 336 | if frame.send_stop() { | ||
| 249 | reg.set_stop(true); | 337 | reg.set_stop(true); |
| 250 | }); | 338 | } |
| 339 | }); | ||
| 251 | 340 | ||
| 252 | // Receive last byte | 341 | // Receive last byte |
| 253 | *last = self.recv_byte(timeout)?; | 342 | *last = self.recv_byte(timeout)?; |
| 254 | 343 | ||
| 344 | if frame.send_stop() { | ||
| 255 | // Wait for the STOP to be sent. | 345 | // Wait for the STOP to be sent. |
| 256 | while T::regs().cr1().read().stop() { | 346 | while T::regs().cr1().read().stop() { |
| 257 | timeout.check()?; | 347 | timeout.check()?; |
| 258 | } | 348 | } |
| 259 | |||
| 260 | // Fallthrough is success | ||
| 261 | Ok(()) | ||
| 262 | } else { | ||
| 263 | Err(Error::Overrun) | ||
| 264 | } | 349 | } |
| 350 | |||
| 351 | // Fallthrough is success | ||
| 352 | Ok(()) | ||
| 265 | } | 353 | } |
| 266 | 354 | ||
| 267 | /// Blocking read. | 355 | /// Blocking read. |
| 268 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { | 356 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { |
| 269 | self.blocking_read_timeout(addr, read, self.timeout()) | 357 | self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) |
| 270 | } | 358 | } |
| 271 | 359 | ||
| 272 | /// Blocking write. | 360 | /// Blocking write. |
| 273 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { | 361 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { |
| 274 | let timeout = self.timeout(); | 362 | self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; |
| 275 | |||
| 276 | self.write_bytes(addr, write, timeout)?; | ||
| 277 | // Send a STOP condition | ||
| 278 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | ||
| 279 | // Wait for STOP condition to transmit. | ||
| 280 | while T::regs().cr1().read().stop() { | ||
| 281 | timeout.check()?; | ||
| 282 | } | ||
| 283 | 363 | ||
| 284 | // Fallthrough is success | 364 | // Fallthrough is success |
| 285 | Ok(()) | 365 | Ok(()) |
| @@ -287,10 +367,85 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 287 | 367 | ||
| 288 | /// Blocking write, restart, read. | 368 | /// Blocking write, restart, read. |
| 289 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 369 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 370 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 371 | // stop condition below. | ||
| 372 | if read.is_empty() { | ||
| 373 | return Err(Error::Overrun); | ||
| 374 | } | ||
| 375 | |||
| 290 | let timeout = self.timeout(); | 376 | let timeout = self.timeout(); |
| 291 | 377 | ||
| 292 | self.write_bytes(addr, write, timeout)?; | 378 | self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; |
| 293 | self.blocking_read_timeout(addr, read, timeout)?; | 379 | self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; |
| 380 | |||
| 381 | Ok(()) | ||
| 382 | } | ||
| 383 | |||
| 384 | /// Blocking transaction with operations. | ||
| 385 | /// | ||
| 386 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 387 | /// | ||
| 388 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 389 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 390 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 391 | // stop condition below. | ||
| 392 | if operations.iter().any(|op| match op { | ||
| 393 | Operation::Read(read) => read.is_empty(), | ||
| 394 | Operation::Write(_) => false, | ||
| 395 | }) { | ||
| 396 | return Err(Error::Overrun); | ||
| 397 | } | ||
| 398 | |||
| 399 | let timeout = self.timeout(); | ||
| 400 | |||
| 401 | let mut operations = operations.iter_mut(); | ||
| 402 | |||
| 403 | let mut prev_op: Option<&mut Operation<'_>> = None; | ||
| 404 | let mut next_op = operations.next(); | ||
| 405 | |||
| 406 | while let Some(op) = next_op { | ||
| 407 | next_op = operations.next(); | ||
| 408 | |||
| 409 | // Check if this is the first frame of this type. This is the case for the first overall | ||
| 410 | // frame in the transaction and whenever the type of operation changes. | ||
| 411 | let first_frame = | ||
| 412 | match (prev_op.as_ref(), &op) { | ||
| 413 | (None, _) => true, | ||
| 414 | (Some(Operation::Read(_)), Operation::Write(_)) | ||
| 415 | | (Some(Operation::Write(_)), Operation::Read(_)) => true, | ||
| 416 | (Some(Operation::Read(_)), Operation::Read(_)) | ||
| 417 | | (Some(Operation::Write(_)), Operation::Write(_)) => false, | ||
| 418 | }; | ||
| 419 | |||
| 420 | let frame = match (first_frame, next_op.as_ref()) { | ||
| 421 | // If this is the first frame of this type, we generate a (repeated) start condition | ||
| 422 | // but have to consider the next operation: if it is the last, we generate the final | ||
| 423 | // stop condition. Otherwise, we branch on the operation: with read operations, only | ||
| 424 | // the last byte overall (before a write operation or the end of the transaction) is | ||
| 425 | // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte. | ||
| 426 | (true, None) => FrameOptions::FirstAndLastFrame, | ||
| 427 | // Make sure to keep sending ACK for last byte in read operation when it is followed | ||
| 428 | // by another consecutive read operation. If the current operation is write, this is | ||
| 429 | // identical to `FirstFrame`. | ||
| 430 | (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame, | ||
| 431 | // Otherwise, send NACK for last byte (in read operation). (For write, this does not | ||
| 432 | // matter and could also be `FirstAndNextFrame`.) | ||
| 433 | (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame, | ||
| 434 | |||
| 435 | // If this is not the first frame of its type, we do not generate a (repeated) start | ||
| 436 | // condition. Otherwise, we branch the same way as above. | ||
| 437 | (false, None) => FrameOptions::LastFrame, | ||
| 438 | (false, Some(Operation::Read(_))) => FrameOptions::NextFrame, | ||
| 439 | (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop, | ||
| 440 | }; | ||
| 441 | |||
| 442 | match op { | ||
| 443 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, | ||
| 444 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, | ||
| 445 | } | ||
| 446 | |||
| 447 | prev_op = Some(op); | ||
| 448 | } | ||
| 294 | 449 | ||
| 295 | Ok(()) | 450 | Ok(()) |
| 296 | } | 451 | } |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index bd3abaac1..1ac2740df 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -4,6 +4,7 @@ use core::task::Poll; | |||
| 4 | 4 | ||
| 5 | use embassy_embedded_hal::SetConfig; | 5 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embedded_hal_1::i2c::Operation; | ||
| 7 | 8 | ||
| 8 | use super::*; | 9 | use super::*; |
| 9 | use crate::dma::Transfer; | 10 | use crate::dma::Transfer; |
| @@ -579,6 +580,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 579 | // Automatic Stop | 580 | // Automatic Stop |
| 580 | } | 581 | } |
| 581 | 582 | ||
| 583 | /// Blocking transaction with operations. | ||
| 584 | /// | ||
| 585 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 586 | /// | ||
| 587 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 588 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 589 | let _ = addr; | ||
| 590 | let _ = operations; | ||
| 591 | todo!() | ||
| 592 | } | ||
| 593 | |||
| 582 | /// Blocking write multiple buffers. | 594 | /// Blocking write multiple buffers. |
| 583 | /// | 595 | /// |
| 584 | /// The buffers are concatenated in a single write transaction. | 596 | /// The buffers are concatenated in a single write transaction. |
