diff options
| author | Shaw Drastin <[email protected]> | 2025-02-12 20:54:07 +0800 |
|---|---|---|
| committer | Shaw Drastin <[email protected]> | 2025-02-12 21:16:18 +0800 |
| commit | 1c1aea62d00fcf920c8c756eb9a8518c1d9338cd (patch) | |
| tree | d909726160c1a333ce4ad999bac4aea39e30c870 | |
| parent | 712143b81fd02cca2621f021438fdfd042563651 (diff) | |
stm32: i2c-v2: Add error handling
Currently when error occurres, we have to wait for timeout, which is
less than ideal. Enable related interrupts, and return Err when error
occurres.
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 05ac9afcc..e2eb6f367 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -13,13 +13,17 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 13 | let regs = T::info().regs; | 13 | let regs = T::info().regs; |
| 14 | let isr = regs.isr().read(); | 14 | let isr = regs.isr().read(); |
| 15 | 15 | ||
| 16 | if isr.tcr() || isr.tc() { | 16 | if isr.tcr() || isr.tc() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { |
| 17 | T::state().waker.wake(); | 17 | T::state().waker.wake(); |
| 18 | } | 18 | } |
| 19 | // The flag can only be cleared by writting to nbytes, we won't do that here, so disable | ||
| 20 | // the interrupt | ||
| 21 | critical_section::with(|_| { | 19 | critical_section::with(|_| { |
| 22 | regs.cr1().modify(|w| w.set_tcie(false)); | 20 | regs.cr1().modify(|w| { |
| 21 | // The flag can only be cleared by writting to nbytes, we won't do that here | ||
| 22 | w.set_tcie(false); | ||
| 23 | // Error flags are to be read in the routines, so we also don't clear them here | ||
| 24 | w.set_nackie(false); | ||
| 25 | w.set_errie(false); | ||
| 26 | }); | ||
| 23 | }); | 27 | }); |
| 24 | } | 28 | } |
| 25 | 29 | ||
| @@ -449,6 +453,8 @@ impl<'d> I2c<'d, Async> { | |||
| 449 | if first_slice { | 453 | if first_slice { |
| 450 | w.set_tcie(true); | 454 | w.set_tcie(true); |
| 451 | } | 455 | } |
| 456 | w.set_nackie(true); | ||
| 457 | w.set_errie(true); | ||
| 452 | }); | 458 | }); |
| 453 | let dst = regs.txdr().as_ptr() as *mut u8; | 459 | let dst = regs.txdr().as_ptr() as *mut u8; |
| 454 | 460 | ||
| @@ -459,18 +465,41 @@ impl<'d> I2c<'d, Async> { | |||
| 459 | 465 | ||
| 460 | let on_drop = OnDrop::new(|| { | 466 | let on_drop = OnDrop::new(|| { |
| 461 | let regs = self.info.regs; | 467 | let regs = self.info.regs; |
| 468 | let isr = regs.isr().read(); | ||
| 462 | regs.cr1().modify(|w| { | 469 | regs.cr1().modify(|w| { |
| 463 | if last_slice { | 470 | if last_slice || isr.nackf() || isr.arlo() || isr.berr() || isr.ovr() { |
| 464 | w.set_txdmaen(false); | 471 | w.set_txdmaen(false); |
| 465 | } | 472 | } |
| 466 | w.set_tcie(false); | 473 | w.set_tcie(false); |
| 467 | }) | 474 | w.set_nackie(false); |
| 475 | w.set_errie(false); | ||
| 476 | }); | ||
| 477 | regs.icr().write(|w| { | ||
| 478 | w.set_nackcf(true); | ||
| 479 | w.set_berrcf(true); | ||
| 480 | w.set_arlocf(true); | ||
| 481 | w.set_ovrcf(true); | ||
| 482 | }); | ||
| 468 | }); | 483 | }); |
| 469 | 484 | ||
| 470 | poll_fn(|cx| { | 485 | poll_fn(|cx| { |
| 471 | self.state.waker.register(cx.waker()); | 486 | self.state.waker.register(cx.waker()); |
| 472 | 487 | ||
| 473 | let isr = self.info.regs.isr().read(); | 488 | let isr = self.info.regs.isr().read(); |
| 489 | |||
| 490 | if isr.nackf() { | ||
| 491 | return Poll::Ready(Err(Error::Nack)); | ||
| 492 | } | ||
| 493 | if isr.arlo() { | ||
| 494 | return Poll::Ready(Err(Error::Arbitration)); | ||
| 495 | } | ||
| 496 | if isr.berr() { | ||
| 497 | return Poll::Ready(Err(Error::Bus)); | ||
| 498 | } | ||
| 499 | if isr.ovr() { | ||
| 500 | return Poll::Ready(Err(Error::Overrun)); | ||
| 501 | } | ||
| 502 | |||
| 474 | if remaining_len == total_len { | 503 | if remaining_len == total_len { |
| 475 | if first_slice { | 504 | if first_slice { |
| 476 | Self::master_write( | 505 | Self::master_write( |
| @@ -531,6 +560,8 @@ impl<'d> I2c<'d, Async> { | |||
| 531 | regs.cr1().modify(|w| { | 560 | regs.cr1().modify(|w| { |
| 532 | w.set_rxdmaen(true); | 561 | w.set_rxdmaen(true); |
| 533 | w.set_tcie(true); | 562 | w.set_tcie(true); |
| 563 | w.set_nackie(true); | ||
| 564 | w.set_errie(true); | ||
| 534 | }); | 565 | }); |
| 535 | let src = regs.rxdr().as_ptr() as *mut u8; | 566 | let src = regs.rxdr().as_ptr() as *mut u8; |
| 536 | 567 | ||
| @@ -544,13 +575,35 @@ impl<'d> I2c<'d, Async> { | |||
| 544 | regs.cr1().modify(|w| { | 575 | regs.cr1().modify(|w| { |
| 545 | w.set_rxdmaen(false); | 576 | w.set_rxdmaen(false); |
| 546 | w.set_tcie(false); | 577 | w.set_tcie(false); |
| 547 | }) | 578 | w.set_nackie(false); |
| 579 | w.set_errie(false); | ||
| 580 | }); | ||
| 581 | regs.icr().write(|w| { | ||
| 582 | w.set_nackcf(true); | ||
| 583 | w.set_berrcf(true); | ||
| 584 | w.set_arlocf(true); | ||
| 585 | w.set_ovrcf(true); | ||
| 586 | }); | ||
| 548 | }); | 587 | }); |
| 549 | 588 | ||
| 550 | poll_fn(|cx| { | 589 | poll_fn(|cx| { |
| 551 | self.state.waker.register(cx.waker()); | 590 | self.state.waker.register(cx.waker()); |
| 552 | 591 | ||
| 553 | let isr = self.info.regs.isr().read(); | 592 | let isr = self.info.regs.isr().read(); |
| 593 | |||
| 594 | if isr.nackf() { | ||
| 595 | return Poll::Ready(Err(Error::Nack)); | ||
| 596 | } | ||
| 597 | if isr.arlo() { | ||
| 598 | return Poll::Ready(Err(Error::Arbitration)); | ||
| 599 | } | ||
| 600 | if isr.berr() { | ||
| 601 | return Poll::Ready(Err(Error::Bus)); | ||
| 602 | } | ||
| 603 | if isr.ovr() { | ||
| 604 | return Poll::Ready(Err(Error::Overrun)); | ||
| 605 | } | ||
| 606 | |||
| 554 | if remaining_len == total_len { | 607 | if remaining_len == total_len { |
| 555 | Self::master_read( | 608 | Self::master_read( |
| 556 | self.info, | 609 | self.info, |
