diff options
| author | chemicstry <[email protected]> | 2022-10-24 12:33:17 +0300 |
|---|---|---|
| committer | chemicstry <[email protected]> | 2022-10-24 12:33:17 +0300 |
| commit | 1bed02296cf15013e0149b36c3ddedb3278e9b88 (patch) | |
| tree | d2cbc692ea1aab186f8994c24aab97fb4c877faf | |
| parent | d99841fea90caccfd95c2dad8f233ab3198f7371 (diff) | |
i2cv2 timeouts
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 188 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/i2c.rs | 41 |
2 files changed, 174 insertions, 55 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 89b52da98..40413b696 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,19 @@ 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(address: u8, length: usize, stop: Stop, reload: bool, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 182 | assert!(length < 256); | 193 | assert!(length < 256); |
| 183 | 194 | ||
| 184 | // Wait for any previous address sequence to end | 195 | // Wait for any previous address sequence to end |
| 185 | // automatically. This could be up to 50% of a bus | 196 | // automatically. This could be up to 50% of a bus |
| 186 | // cycle (ie. up to 0.5/freq) | 197 | // cycle (ie. up to 0.5/freq) |
| 187 | while T::regs().cr2().read().start() {} | 198 | while T::regs().cr2().read().start() { |
| 199 | check_timeout()?; | ||
| 200 | } | ||
| 188 | 201 | ||
| 189 | let reload = if reload { | 202 | let reload = if reload { |
| 190 | i2c::vals::Reload::NOTCOMPLETED | 203 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -204,12 +217,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 204 | w.set_autoend(stop.autoend()); | 217 | w.set_autoend(stop.autoend()); |
| 205 | w.set_reload(reload); | 218 | w.set_reload(reload); |
| 206 | }); | 219 | }); |
| 220 | |||
| 221 | Ok(()) | ||
| 207 | } | 222 | } |
| 208 | 223 | ||
| 209 | unsafe fn master_continue(length: usize, reload: bool) { | 224 | unsafe fn master_continue(length: usize, reload: bool, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 210 | assert!(length < 256 && length > 0); | 225 | assert!(length < 256 && length > 0); |
| 211 | 226 | ||
| 212 | while !T::regs().isr().read().tcr() {} | 227 | while !T::regs().isr().read().tcr() { |
| 228 | check_timeout()?; | ||
| 229 | } | ||
| 213 | 230 | ||
| 214 | let reload = if reload { | 231 | let reload = if reload { |
| 215 | i2c::vals::Reload::NOTCOMPLETED | 232 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -221,6 +238,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 221 | w.set_nbytes(length as u8); | 238 | w.set_nbytes(length as u8); |
| 222 | w.set_reload(reload); | 239 | w.set_reload(reload); |
| 223 | }); | 240 | }); |
| 241 | |||
| 242 | Ok(()) | ||
| 224 | } | 243 | } |
| 225 | 244 | ||
| 226 | fn flush_txdr(&self) { | 245 | fn flush_txdr(&self) { |
| @@ -243,7 +262,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 243 | //} | 262 | //} |
| 244 | } | 263 | } |
| 245 | 264 | ||
| 246 | fn wait_txe(&self) -> Result<(), Error> { | 265 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 247 | loop { | 266 | loop { |
| 248 | unsafe { | 267 | unsafe { |
| 249 | let isr = T::regs().isr().read(); | 268 | let isr = T::regs().isr().read(); |
| @@ -261,10 +280,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 261 | return Err(Error::Nack); | 280 | return Err(Error::Nack); |
| 262 | } | 281 | } |
| 263 | } | 282 | } |
| 283 | |||
| 284 | check_timeout()?; | ||
| 264 | } | 285 | } |
| 265 | } | 286 | } |
| 266 | 287 | ||
| 267 | fn wait_rxne(&self) -> Result<(), Error> { | 288 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 268 | loop { | 289 | loop { |
| 269 | unsafe { | 290 | unsafe { |
| 270 | let isr = T::regs().isr().read(); | 291 | let isr = T::regs().isr().read(); |
| @@ -282,10 +303,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 282 | return Err(Error::Nack); | 303 | return Err(Error::Nack); |
| 283 | } | 304 | } |
| 284 | } | 305 | } |
| 306 | |||
| 307 | check_timeout()?; | ||
| 285 | } | 308 | } |
| 286 | } | 309 | } |
| 287 | 310 | ||
| 288 | fn wait_tc(&self) -> Result<(), Error> { | 311 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 289 | loop { | 312 | loop { |
| 290 | unsafe { | 313 | unsafe { |
| 291 | let isr = T::regs().isr().read(); | 314 | let isr = T::regs().isr().read(); |
| @@ -303,10 +326,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 303 | return Err(Error::Nack); | 326 | return Err(Error::Nack); |
| 304 | } | 327 | } |
| 305 | } | 328 | } |
| 329 | |||
| 330 | check_timeout()?; | ||
| 306 | } | 331 | } |
| 307 | } | 332 | } |
| 308 | 333 | ||
| 309 | fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { | 334 | fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 310 | let completed_chunks = buffer.len() / 255; | 335 | let completed_chunks = buffer.len() / 255; |
| 311 | let total_chunks = if completed_chunks * 255 == buffer.len() { | 336 | let total_chunks = if completed_chunks * 255 == buffer.len() { |
| 312 | completed_chunks | 337 | completed_chunks |
| @@ -322,20 +347,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 322 | Stop::Automatic, | 347 | Stop::Automatic, |
| 323 | last_chunk_idx != 0, | 348 | last_chunk_idx != 0, |
| 324 | restart, | 349 | restart, |
| 325 | ); | 350 | &check_timeout |
| 351 | )?; | ||
| 326 | } | 352 | } |
| 327 | 353 | ||
| 328 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { | 354 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { |
| 329 | if number != 0 { | 355 | if number != 0 { |
| 330 | // NOTE(unsafe) We have &mut self | 356 | // NOTE(unsafe) We have &mut self |
| 331 | unsafe { | 357 | unsafe { |
| 332 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 358 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 333 | } | 359 | } |
| 334 | } | 360 | } |
| 335 | 361 | ||
| 336 | for byte in chunk { | 362 | for byte in chunk { |
| 337 | // Wait until we have received something | 363 | // Wait until we have received something |
| 338 | self.wait_rxne()?; | 364 | self.wait_rxne(&check_timeout)?; |
| 339 | 365 | ||
| 340 | unsafe { | 366 | unsafe { |
| 341 | *byte = T::regs().rxdr().read().rxdata(); | 367 | *byte = T::regs().rxdr().read().rxdata(); |
| @@ -345,7 +371,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 345 | Ok(()) | 371 | Ok(()) |
| 346 | } | 372 | } |
| 347 | 373 | ||
| 348 | fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | 374 | fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 349 | let completed_chunks = bytes.len() / 255; | 375 | let completed_chunks = bytes.len() / 255; |
| 350 | let total_chunks = if completed_chunks * 255 == bytes.len() { | 376 | let total_chunks = if completed_chunks * 255 == bytes.len() { |
| 351 | completed_chunks | 377 | completed_chunks |
| @@ -359,14 +385,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 359 | // ST SAD+W | 385 | // ST SAD+W |
| 360 | // NOTE(unsafe) We have &mut self | 386 | // NOTE(unsafe) We have &mut self |
| 361 | unsafe { | 387 | unsafe { |
| 362 | Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0); | 388 | Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0, &check_timeout)?; |
| 363 | } | 389 | } |
| 364 | 390 | ||
| 365 | for (number, chunk) in bytes.chunks(255).enumerate() { | 391 | for (number, chunk) in bytes.chunks(255).enumerate() { |
| 366 | if number != 0 { | 392 | if number != 0 { |
| 367 | // NOTE(unsafe) We have &mut self | 393 | // NOTE(unsafe) We have &mut self |
| 368 | unsafe { | 394 | unsafe { |
| 369 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 395 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 370 | } | 396 | } |
| 371 | } | 397 | } |
| 372 | 398 | ||
| @@ -374,7 +400,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 374 | // Wait until we are allowed to send data | 400 | // Wait until we are allowed to send data |
| 375 | // (START has been ACKed or last byte when | 401 | // (START has been ACKed or last byte when |
| 376 | // through) | 402 | // through) |
| 377 | self.wait_txe()?; | 403 | self.wait_txe(&check_timeout)?; |
| 378 | 404 | ||
| 379 | unsafe { | 405 | unsafe { |
| 380 | T::regs().txdr().write(|w| w.set_txdata(*byte)); | 406 | T::regs().txdr().write(|w| w.set_txdata(*byte)); |
| @@ -382,7 +408,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 382 | } | 408 | } |
| 383 | } | 409 | } |
| 384 | // Wait until the write finishes | 410 | // Wait until the write finishes |
| 385 | self.wait_tc()?; | 411 | self.wait_tc(&check_timeout)?; |
| 386 | 412 | ||
| 387 | if send_stop { | 413 | if send_stop { |
| 388 | self.master_stop(); | 414 | self.master_stop(); |
| @@ -396,6 +422,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 396 | bytes: &[u8], | 422 | bytes: &[u8], |
| 397 | first_slice: bool, | 423 | first_slice: bool, |
| 398 | last_slice: bool, | 424 | last_slice: bool, |
| 425 | check_timeout: impl Fn() -> Result<(), Error> | ||
| 399 | ) -> Result<(), Error> | 426 | ) -> Result<(), Error> |
| 400 | where | 427 | where |
| 401 | TXDMA: crate::i2c::TxDma<T>, | 428 | TXDMA: crate::i2c::TxDma<T>, |
| @@ -447,11 +474,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 447 | total_len.min(255), | 474 | total_len.min(255), |
| 448 | Stop::Software, | 475 | Stop::Software, |
| 449 | (total_chunks != 1) || !last_slice, | 476 | (total_chunks != 1) || !last_slice, |
| 450 | ); | 477 | &check_timeout |
| 478 | )?; | ||
| 451 | } | 479 | } |
| 452 | } else { | 480 | } else { |
| 453 | unsafe { | 481 | unsafe { |
| 454 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice); | 482 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?; |
| 455 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 483 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 456 | } | 484 | } |
| 457 | } | 485 | } |
| @@ -461,32 +489,34 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 461 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 489 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 462 | 490 | ||
| 463 | if chunks_transferred == total_chunks { | 491 | if chunks_transferred == total_chunks { |
| 464 | return Poll::Ready(()); | 492 | return Poll::Ready(Ok(())); |
| 465 | } else if chunks_transferred != 0 { | 493 | } else if chunks_transferred != 0 { |
| 466 | remaining_len = remaining_len.saturating_sub(255); | 494 | remaining_len = remaining_len.saturating_sub(255); |
| 467 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; | 495 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; |
| 468 | 496 | ||
| 469 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | 497 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers |
| 470 | unsafe { | 498 | unsafe { |
| 471 | Self::master_continue(remaining_len.min(255), !last_piece); | 499 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 500 | return Poll::Ready(Err(e)); | ||
| 501 | } | ||
| 472 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 502 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 473 | } | 503 | } |
| 474 | } | 504 | } |
| 475 | Poll::Pending | 505 | Poll::Pending |
| 476 | }) | 506 | }) |
| 477 | .await; | 507 | .await?; |
| 478 | 508 | ||
| 479 | dma_transfer.await; | 509 | dma_transfer.await; |
| 480 | 510 | ||
| 481 | if last_slice { | 511 | if last_slice { |
| 482 | // This should be done already | 512 | // This should be done already |
| 483 | self.wait_tc()?; | 513 | self.wait_tc(&check_timeout)?; |
| 484 | self.master_stop(); | 514 | self.master_stop(); |
| 485 | } | 515 | } |
| 486 | Ok(()) | 516 | Ok(()) |
| 487 | } | 517 | } |
| 488 | 518 | ||
| 489 | async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> | 519 | async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> |
| 490 | where | 520 | where |
| 491 | RXDMA: crate::i2c::RxDma<T>, | 521 | RXDMA: crate::i2c::RxDma<T>, |
| 492 | { | 522 | { |
| @@ -527,7 +557,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 527 | 557 | ||
| 528 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 558 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 529 | unsafe { | 559 | unsafe { |
| 530 | Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart); | 560 | Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart, &check_timeout)?; |
| 531 | } | 561 | } |
| 532 | 562 | ||
| 533 | poll_fn(|cx| { | 563 | poll_fn(|cx| { |
| @@ -535,25 +565,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 535 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 565 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 536 | 566 | ||
| 537 | if chunks_transferred == total_chunks { | 567 | if chunks_transferred == total_chunks { |
| 538 | return Poll::Ready(()); | 568 | return Poll::Ready(Ok(())); |
| 539 | } else if chunks_transferred != 0 { | 569 | } else if chunks_transferred != 0 { |
| 540 | remaining_len = remaining_len.saturating_sub(255); | 570 | remaining_len = remaining_len.saturating_sub(255); |
| 541 | let last_piece = chunks_transferred + 1 == total_chunks; | 571 | let last_piece = chunks_transferred + 1 == total_chunks; |
| 542 | 572 | ||
| 543 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 573 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 544 | unsafe { | 574 | unsafe { |
| 545 | Self::master_continue(remaining_len.min(255), !last_piece); | 575 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 576 | return Poll::Ready(Err(e)) | ||
| 577 | } | ||
| 546 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 578 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 547 | } | 579 | } |
| 548 | } | 580 | } |
| 549 | Poll::Pending | 581 | Poll::Pending |
| 550 | }) | 582 | }) |
| 551 | .await; | 583 | .await?; |
| 552 | 584 | ||
| 553 | dma_transfer.await; | 585 | dma_transfer.await; |
| 554 | 586 | ||
| 555 | // This should be done already | 587 | // This should be done already |
| 556 | self.wait_tc()?; | 588 | self.wait_tc(&check_timeout)?; |
| 557 | self.master_stop(); | 589 | self.master_stop(); |
| 558 | Ok(()) | 590 | Ok(()) |
| 559 | } | 591 | } |
| @@ -561,18 +593,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 561 | // ========================= | 593 | // ========================= |
| 562 | // Async public API | 594 | // Async public API |
| 563 | 595 | ||
| 564 | pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> | 596 | pub async fn write_timeout(&mut self, address: u8, bytes: &[u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> |
| 565 | where | 597 | where |
| 566 | TXDMA: crate::i2c::TxDma<T>, | 598 | TXDMA: crate::i2c::TxDma<T>, |
| 567 | { | 599 | { |
| 568 | if bytes.is_empty() { | 600 | if bytes.is_empty() { |
| 569 | self.write_internal(address, bytes, true) | 601 | self.write_internal(address, bytes, true, &check_timeout) |
| 570 | } else { | 602 | } else { |
| 571 | self.write_dma_internal(address, bytes, true, true).await | 603 | self.write_dma_internal(address, bytes, true, true, &check_timeout).await |
| 572 | } | 604 | } |
| 573 | } | 605 | } |
| 574 | 606 | ||
| 575 | pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> | 607 | pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> |
| 608 | where | ||
| 609 | TXDMA: crate::i2c::TxDma<T>, | ||
| 610 | { | ||
| 611 | self.write_timeout(address, bytes, || Ok(())).await | ||
| 612 | } | ||
| 613 | |||
| 614 | pub async fn write_vectored_timeout(&mut self, address: u8, bytes: &[&[u8]], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> | ||
| 576 | where | 615 | where |
| 577 | TXDMA: crate::i2c::TxDma<T>, | 616 | TXDMA: crate::i2c::TxDma<T>, |
| 578 | { | 617 | { |
| @@ -587,63 +626,97 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 587 | let next = iter.next(); | 626 | let next = iter.next(); |
| 588 | let is_last = next.is_none(); | 627 | let is_last = next.is_none(); |
| 589 | 628 | ||
| 590 | self.write_dma_internal(address, c, first, is_last).await?; | 629 | self.write_dma_internal(address, c, first, is_last, &check_timeout).await?; |
| 591 | first = false; | 630 | first = false; |
| 592 | current = next; | 631 | current = next; |
| 593 | } | 632 | } |
| 594 | Ok(()) | 633 | Ok(()) |
| 595 | } | 634 | } |
| 596 | 635 | ||
| 597 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | 636 | pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> |
| 637 | where | ||
| 638 | TXDMA: crate::i2c::TxDma<T>, | ||
| 639 | { | ||
| 640 | self.write_vectored_timeout(address, bytes, || Ok(())).await | ||
| 641 | } | ||
| 642 | |||
| 643 | pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> | ||
| 598 | where | 644 | where |
| 599 | RXDMA: crate::i2c::RxDma<T>, | 645 | RXDMA: crate::i2c::RxDma<T>, |
| 600 | { | 646 | { |
| 601 | if buffer.is_empty() { | 647 | if buffer.is_empty() { |
| 602 | self.read_internal(address, buffer, false) | 648 | self.read_internal(address, buffer, false, &check_timeout) |
| 603 | } else { | 649 | } else { |
| 604 | self.read_dma_internal(address, buffer, false).await | 650 | self.read_dma_internal(address, buffer, false, &check_timeout).await |
| 605 | } | 651 | } |
| 606 | } | 652 | } |
| 607 | 653 | ||
| 608 | pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> | 654 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> |
| 655 | where | ||
| 656 | RXDMA: crate::i2c::RxDma<T>, | ||
| 657 | { | ||
| 658 | self.read_timeout(address, buffer, || Ok(())).await | ||
| 659 | } | ||
| 660 | |||
| 661 | pub async fn write_read_timeout(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> | ||
| 609 | where | 662 | where |
| 610 | TXDMA: super::TxDma<T>, | 663 | TXDMA: super::TxDma<T>, |
| 611 | RXDMA: super::RxDma<T>, | 664 | RXDMA: super::RxDma<T>, |
| 612 | { | 665 | { |
| 613 | if bytes.is_empty() { | 666 | if bytes.is_empty() { |
| 614 | self.write_internal(address, bytes, false)?; | 667 | self.write_internal(address, bytes, false, &check_timeout)?; |
| 615 | } else { | 668 | } else { |
| 616 | self.write_dma_internal(address, bytes, true, true).await?; | 669 | self.write_dma_internal(address, bytes, true, true, &check_timeout).await?; |
| 617 | } | 670 | } |
| 618 | 671 | ||
| 619 | if buffer.is_empty() { | 672 | if buffer.is_empty() { |
| 620 | self.read_internal(address, buffer, true)?; | 673 | self.read_internal(address, buffer, true, &check_timeout)?; |
| 621 | } else { | 674 | } else { |
| 622 | self.read_dma_internal(address, buffer, true).await?; | 675 | self.read_dma_internal(address, buffer, true, &check_timeout).await?; |
| 623 | } | 676 | } |
| 624 | 677 | ||
| 625 | Ok(()) | 678 | Ok(()) |
| 626 | } | 679 | } |
| 627 | 680 | ||
| 681 | pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> | ||
| 682 | where | ||
| 683 | TXDMA: super::TxDma<T>, | ||
| 684 | RXDMA: super::RxDma<T>, | ||
| 685 | { | ||
| 686 | self.write_read_timeout(address, bytes, buffer, || Ok(())).await | ||
| 687 | } | ||
| 688 | |||
| 628 | // ========================= | 689 | // ========================= |
| 629 | // Blocking public API | 690 | // Blocking public API |
| 630 | 691 | ||
| 631 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 692 | pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 632 | self.read_internal(address, buffer, false) | 693 | self.read_internal(address, buffer, false, &check_timeout) |
| 633 | // Automatic Stop | 694 | // Automatic Stop |
| 634 | } | 695 | } |
| 635 | 696 | ||
| 697 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 698 | self.blocking_read_timeout(address, buffer, || Ok(())) | ||
| 699 | } | ||
| 700 | |||
| 701 | pub fn blocking_write_timeout(&mut self, address: u8, bytes: &[u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||
| 702 | self.write_internal(address, bytes, true, &check_timeout) | ||
| 703 | } | ||
| 704 | |||
| 636 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | 705 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { |
| 637 | self.write_internal(address, bytes, true) | 706 | self.blocking_write_timeout(address, bytes, || Ok(())) |
| 638 | } | 707 | } |
| 639 | 708 | ||
| 640 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | 709 | pub fn blocking_write_read_timeout(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 641 | self.write_internal(address, bytes, false)?; | 710 | self.write_internal(address, bytes, false, &check_timeout)?; |
| 642 | self.read_internal(address, buffer, true) | 711 | self.read_internal(address, buffer, true, &check_timeout) |
| 643 | // Automatic Stop | 712 | // Automatic Stop |
| 644 | } | 713 | } |
| 645 | 714 | ||
| 646 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | 715 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { |
| 716 | self.blocking_write_read_timeout(address, bytes, buffer, || Ok(())) | ||
| 717 | } | ||
| 718 | |||
| 719 | pub fn blocking_write_vectored_timeout(&mut self, address: u8, bytes: &[&[u8]], check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | ||
| 647 | if bytes.is_empty() { | 720 | if bytes.is_empty() { |
| 648 | return Err(Error::ZeroLengthTransfer); | 721 | return Err(Error::ZeroLengthTransfer); |
| 649 | } | 722 | } |
| @@ -657,7 +730,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 657 | first_length.min(255), | 730 | first_length.min(255), |
| 658 | Stop::Software, | 731 | Stop::Software, |
| 659 | (first_length > 255) || (last_slice_index != 0), | 732 | (first_length > 255) || (last_slice_index != 0), |
| 660 | ); | 733 | &check_timeout |
| 734 | )?; | ||
| 661 | } | 735 | } |
| 662 | 736 | ||
| 663 | for (idx, slice) in bytes.iter().enumerate() { | 737 | for (idx, slice) in bytes.iter().enumerate() { |
| @@ -673,7 +747,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 673 | if idx != 0 { | 747 | if idx != 0 { |
| 674 | // NOTE(unsafe) We have &mut self | 748 | // NOTE(unsafe) We have &mut self |
| 675 | unsafe { | 749 | unsafe { |
| 676 | Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255)); | 750 | Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255), &check_timeout)?; |
| 677 | } | 751 | } |
| 678 | } | 752 | } |
| 679 | 753 | ||
| @@ -681,7 +755,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 681 | if number != 0 { | 755 | if number != 0 { |
| 682 | // NOTE(unsafe) We have &mut self | 756 | // NOTE(unsafe) We have &mut self |
| 683 | unsafe { | 757 | unsafe { |
| 684 | Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index)); | 758 | Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index), &check_timeout)?; |
| 685 | } | 759 | } |
| 686 | } | 760 | } |
| 687 | 761 | ||
| @@ -689,7 +763,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 689 | // Wait until we are allowed to send data | 763 | // Wait until we are allowed to send data |
| 690 | // (START has been ACKed or last byte when | 764 | // (START has been ACKed or last byte when |
| 691 | // through) | 765 | // through) |
| 692 | self.wait_txe()?; | 766 | self.wait_txe(&check_timeout)?; |
| 693 | 767 | ||
| 694 | // Put byte on the wire | 768 | // Put byte on the wire |
| 695 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); | 769 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); |
| @@ -700,11 +774,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 700 | } | 774 | } |
| 701 | } | 775 | } |
| 702 | // Wait until the write finishes | 776 | // Wait until the write finishes |
| 703 | self.wait_tc()?; | 777 | self.wait_tc(&check_timeout)?; |
| 704 | self.master_stop(); | 778 | self.master_stop(); |
| 705 | 779 | ||
| 706 | Ok(()) | 780 | Ok(()) |
| 707 | } | 781 | } |
| 782 | |||
| 783 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | ||
| 784 | self.blocking_write_vectored_timeout(address, bytes, || Ok(())) | ||
| 785 | } | ||
| 708 | } | 786 | } |
| 709 | 787 | ||
| 710 | mod eh02 { | 788 | mod eh02 { |
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs new file mode 100644 index 000000000..7a314b996 --- /dev/null +++ b/examples/stm32h7/src/bin/i2c.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_time::Duration; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | const ADDRESS: u8 = 0x5F; | ||
| 14 | const WHOAMI: u8 = 0x0F; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); | ||
| 33 | |||
| 34 | let mut data = [0u8; 1]; | ||
| 35 | |||
| 36 | match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 37 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 38 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 39 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 40 | } | ||
| 41 | } | ||
