aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/i2c/v2.rs110
1 files changed, 49 insertions, 61 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 39e6702e5..853bc128f 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1,6 +1,5 @@
1use core::cmp; 1use core::cmp;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::sync::atomic::{AtomicUsize, Ordering};
4use core::task::Poll; 3use core::task::Poll;
5 4
6use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
@@ -35,14 +34,12 @@ impl Default for Config {
35 34
36pub struct State { 35pub struct State {
37 waker: AtomicWaker, 36 waker: AtomicWaker,
38 chunks_transferred: AtomicUsize,
39} 37}
40 38
41impl State { 39impl State {
42 pub(crate) const fn new() -> Self { 40 pub(crate) const fn new() -> Self {
43 Self { 41 Self {
44 waker: AtomicWaker::new(), 42 waker: AtomicWaker::new(),
45 chunks_transferred: AtomicUsize::new(0),
46 } 43 }
47 } 44 }
48} 45}
@@ -130,10 +127,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
130 let isr = regs.isr().read(); 127 let isr = regs.isr().read();
131 128
132 if isr.tcr() || isr.tc() { 129 if isr.tcr() || isr.tc() {
133 let state = T::state(); 130 T::state().waker.wake();
134 let transferred = state.chunks_transferred.load(Ordering::Relaxed);
135 state.chunks_transferred.store(transferred + 1, Ordering::Relaxed);
136 state.waker.wake();
137 } 131 }
138 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable 132 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
139 // the interrupt 133 // the interrupt
@@ -457,12 +451,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
457 TXDMA: crate::i2c::TxDma<T>, 451 TXDMA: crate::i2c::TxDma<T>,
458 { 452 {
459 let total_len = write.len(); 453 let total_len = write.len();
460 let completed_chunks = total_len / 255;
461 let total_chunks = if completed_chunks * 255 == total_len {
462 completed_chunks
463 } else {
464 completed_chunks + 1
465 };
466 454
467 let dma_transfer = unsafe { 455 let dma_transfer = unsafe {
468 let regs = T::regs(); 456 let regs = T::regs();
@@ -480,7 +468,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
480 }; 468 };
481 469
482 let state = T::state(); 470 let state = T::state();
483 state.chunks_transferred.store(0, Ordering::Relaxed);
484 let mut remaining_len = total_len; 471 let mut remaining_len = total_len;
485 472
486 let on_drop = OnDrop::new(|| { 473 let on_drop = OnDrop::new(|| {
@@ -495,33 +482,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
495 } 482 }
496 }); 483 });
497 484
498 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
499 if first_slice {
500 unsafe {
501 Self::master_write(
502 address,
503 total_len.min(255),
504 Stop::Software,
505 (total_chunks != 1) || !last_slice,
506 &check_timeout,
507 )?;
508 }
509 } else {
510 unsafe {
511 Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?;
512 T::regs().cr1().modify(|w| w.set_tcie(true));
513 }
514 }
515
516 poll_fn(|cx| { 485 poll_fn(|cx| {
517 state.waker.register(cx.waker()); 486 state.waker.register(cx.waker());
518 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
519 487
520 if chunks_transferred == total_chunks { 488 let isr = unsafe { T::regs().isr().read() };
489 if remaining_len == total_len {
490 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
491 if first_slice {
492 unsafe {
493 Self::master_write(
494 address,
495 total_len.min(255),
496 Stop::Software,
497 (total_len > 255) || !last_slice,
498 &check_timeout,
499 )?;
500 }
501 } else {
502 unsafe {
503 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
504 T::regs().cr1().modify(|w| w.set_tcie(true));
505 }
506 }
507 } else if !(isr.tcr() || isr.tc()) {
508 // poll_fn was woken without an interrupt present
509 return Poll::Pending;
510 } else if remaining_len == 0 {
521 return Poll::Ready(Ok(())); 511 return Poll::Ready(Ok(()));
522 } else if chunks_transferred != 0 { 512 } else {
523 remaining_len = remaining_len.saturating_sub(255); 513 let last_piece = (remaining_len <= 255) && last_slice;
524 let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice;
525 514
526 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers 515 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
527 unsafe { 516 unsafe {
@@ -531,6 +520,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
531 T::regs().cr1().modify(|w| w.set_tcie(true)); 520 T::regs().cr1().modify(|w| w.set_tcie(true));
532 } 521 }
533 } 522 }
523
524 remaining_len = remaining_len.saturating_sub(255);
534 Poll::Pending 525 Poll::Pending
535 }) 526 })
536 .await?; 527 .await?;
@@ -559,12 +550,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
559 RXDMA: crate::i2c::RxDma<T>, 550 RXDMA: crate::i2c::RxDma<T>,
560 { 551 {
561 let total_len = buffer.len(); 552 let total_len = buffer.len();
562 let completed_chunks = total_len / 255;
563 let total_chunks = if completed_chunks * 255 == total_len {
564 completed_chunks
565 } else {
566 completed_chunks + 1
567 };
568 553
569 let dma_transfer = unsafe { 554 let dma_transfer = unsafe {
570 let regs = T::regs(); 555 let regs = T::regs();
@@ -580,7 +565,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
580 }; 565 };
581 566
582 let state = T::state(); 567 let state = T::state();
583 state.chunks_transferred.store(0, Ordering::Relaxed);
584 let mut remaining_len = total_len; 568 let mut remaining_len = total_len;
585 569
586 let on_drop = OnDrop::new(|| { 570 let on_drop = OnDrop::new(|| {
@@ -593,27 +577,29 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
593 } 577 }
594 }); 578 });
595 579
596 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
597 unsafe {
598 Self::master_read(
599 address,
600 total_len.min(255),
601 Stop::Software,
602 total_chunks != 1,
603 restart,
604 &check_timeout,
605 )?;
606 }
607
608 poll_fn(|cx| { 580 poll_fn(|cx| {
609 state.waker.register(cx.waker()); 581 state.waker.register(cx.waker());
610 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
611 582
612 if chunks_transferred == total_chunks { 583 let isr = unsafe { T::regs().isr().read() };
584 if remaining_len == total_len {
585 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
586 unsafe {
587 Self::master_read(
588 address,
589 total_len.min(255),
590 Stop::Software,
591 total_len > 255,
592 restart,
593 &check_timeout,
594 )?;
595 }
596 } else if !(isr.tcr() || isr.tc()) {
597 // poll_fn was woken without an interrupt present
598 return Poll::Pending;
599 } else if remaining_len == 0 {
613 return Poll::Ready(Ok(())); 600 return Poll::Ready(Ok(()));
614 } else if chunks_transferred != 0 { 601 } else {
615 remaining_len = remaining_len.saturating_sub(255); 602 let last_piece = remaining_len <= 255;
616 let last_piece = chunks_transferred + 1 == total_chunks;
617 603
618 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 604 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
619 unsafe { 605 unsafe {
@@ -623,6 +609,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
623 T::regs().cr1().modify(|w| w.set_tcie(true)); 609 T::regs().cr1().modify(|w| w.set_tcie(true));
624 } 610 }
625 } 611 }
612
613 remaining_len = remaining_len.saturating_sub(255);
626 Poll::Pending 614 Poll::Pending
627 }) 615 })
628 .await?; 616 .await?;