aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-13 20:40:48 +0000
committerGitHub <[email protected]>2025-11-13 20:40:48 +0000
commite18ae87c3ad7ca08d1ee613b5748e51d72fe0681 (patch)
tree29c9672d3eef0c7aacab9caa22c0ae4d1c39abcd
parent86fbcbdd7b9a5d37f6a7b1553e1ad0b5e5c8aa96 (diff)
parent4219415e66f20b72d7d09d17195bd1c414bfa8cd (diff)
Merge pull request #4875 from HybridChild/stm32_i2c_v2_transaction
stm32/i2c: Implement v2 transaction API and fix async DMA issues
-rw-r--r--embassy-stm32/CHANGELOG.md3
-rw-r--r--embassy-stm32/src/i2c/v2.rs704
-rw-r--r--examples/stm32f0/Cargo.toml1
-rw-r--r--examples/stm32f0/src/bin/i2c_master.rs609
4 files changed, 1253 insertions, 64 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 7d1c9c2a9..8bd930e79 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -44,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
44- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) 44- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723)
45- fix: usart: fix race condition in ringbuffered usart 45- fix: usart: fix race condition in ringbuffered usart
46- feat: Add backup_sram::init() for H5 devices to access BKPSRAM 46- feat: Add backup_sram::init() for H5 devices to access BKPSRAM
47- feat: Add I2C MultiMaster (Slave) support for I2C v1 47- feat: stm32/i2c v1: Add I2C MultiMaster (Slave) support
48- feat: stm32/i2c v2: Add transaction() and blocking_transaction() methods with contract-compliant operation merging
48- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) 49- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821))
49- low-power: update rtc api to allow reconfig 50- low-power: update rtc api to allow reconfig
50- adc: consolidate ringbuffer 51- adc: consolidate ringbuffer
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 4527e55b9..61e550ad4 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -98,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
98} 98}
99 99
100impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 100impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
101 #[inline]
102 fn to_reload(reload: bool) -> i2c::vals::Reload {
103 if reload {
104 i2c::vals::Reload::NOT_COMPLETED
105 } else {
106 i2c::vals::Reload::COMPLETED
107 }
108 }
109
110 /// Calculate total bytes in a group of operations
111 #[inline]
112 fn total_operation_bytes(operations: &[Operation<'_>]) -> usize {
113 operations
114 .iter()
115 .map(|op| match op {
116 Operation::Write(buf) => buf.len(),
117 Operation::Read(buf) => buf.len(),
118 })
119 .sum()
120 }
121
101 pub(crate) fn init(&mut self, config: Config) { 122 pub(crate) fn init(&mut self, config: Config) {
102 self.info.regs.cr1().modify(|reg| { 123 self.info.regs.cr1().modify(|reg| {
103 reg.set_pe(false); 124 reg.set_pe(false);
@@ -147,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
147 // `buffer`. The START bit can be set even if the bus 168 // `buffer`. The START bit can be set even if the bus
148 // is BUSY or I2C is in slave mode. 169 // is BUSY or I2C is in slave mode.
149 170
150 let reload = if reload {
151 i2c::vals::Reload::NOT_COMPLETED
152 } else {
153 i2c::vals::Reload::COMPLETED
154 };
155
156 info.regs.cr2().modify(|w| { 171 info.regs.cr2().modify(|w| {
157 w.set_sadd(address.addr() << 1); 172 w.set_sadd(address.addr() << 1);
158 w.set_add10(address.add_mode()); 173 w.set_add10(address.add_mode());
@@ -160,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
160 w.set_nbytes(length as u8); 175 w.set_nbytes(length as u8);
161 w.set_start(true); 176 w.set_start(true);
162 w.set_autoend(stop.autoend()); 177 w.set_autoend(stop.autoend());
163 w.set_reload(reload); 178 w.set_reload(Self::to_reload(reload));
164 }); 179 });
165 180
166 Ok(()) 181 Ok(())
@@ -172,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
172 length: usize, 187 length: usize,
173 stop: Stop, 188 stop: Stop,
174 reload: bool, 189 reload: bool,
190 restart: bool,
175 timeout: Timeout, 191 timeout: Timeout,
176 ) -> Result<(), Error> { 192 ) -> Result<(), Error> {
177 assert!(length < 256); 193 assert!(length < 256);
178 194
179 // Wait for any previous address sequence to end 195 if !restart {
180 // automatically. This could be up to 50% of a bus 196 // Wait for any previous address sequence to end
181 // cycle (ie. up to 0.5/freq) 197 // automatically. This could be up to 50% of a bus
182 while info.regs.cr2().read().start() { 198 // cycle (ie. up to 0.5/freq)
183 timeout.check()?; 199 while info.regs.cr2().read().start() {
184 } 200 timeout.check()?;
201 }
185 202
186 // Wait for the bus to be free 203 // Wait for the bus to be free
187 while info.regs.isr().read().busy() { 204 while info.regs.isr().read().busy() {
188 timeout.check()?; 205 timeout.check()?;
206 }
189 } 207 }
190 208
191 let reload = if reload {
192 i2c::vals::Reload::NOT_COMPLETED
193 } else {
194 i2c::vals::Reload::COMPLETED
195 };
196
197 // Set START and prepare to send `bytes`. The 209 // Set START and prepare to send `bytes`. The
198 // START bit can be set even if the bus is BUSY or 210 // START bit can be set even if the bus is BUSY or
199 // I2C is in slave mode. 211 // I2C is in slave mode.
@@ -204,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
204 w.set_nbytes(length as u8); 216 w.set_nbytes(length as u8);
205 w.set_start(true); 217 w.set_start(true);
206 w.set_autoend(stop.autoend()); 218 w.set_autoend(stop.autoend());
207 w.set_reload(reload); 219 w.set_reload(Self::to_reload(reload));
208 }); 220 });
209 221
210 Ok(()) 222 Ok(())
211 } 223 }
212 224
213 fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { 225 fn reload(
226 info: &'static Info,
227 length: usize,
228 will_reload: bool,
229 stop: Stop,
230 timeout: Timeout,
231 ) -> Result<(), Error> {
214 assert!(length < 256 && length > 0); 232 assert!(length < 256 && length > 0);
215 233
216 while !info.regs.isr().read().tcr() { 234 // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete)
235 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
236 // Both indicate the peripheral is ready for the next transfer
237 loop {
238 let isr = info.regs.isr().read();
239 if isr.tcr() || isr.tc() {
240 break;
241 }
217 timeout.check()?; 242 timeout.check()?;
218 } 243 }
219 244
220 let will_reload = if will_reload {
221 i2c::vals::Reload::NOT_COMPLETED
222 } else {
223 i2c::vals::Reload::COMPLETED
224 };
225
226 info.regs.cr2().modify(|w| { 245 info.regs.cr2().modify(|w| {
227 w.set_nbytes(length as u8); 246 w.set_nbytes(length as u8);
228 w.set_reload(will_reload); 247 w.set_reload(Self::to_reload(will_reload));
248 w.set_autoend(stop.autoend());
229 }); 249 });
230 250
231 Ok(()) 251 Ok(())
@@ -369,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
369 loop { 389 loop {
370 let isr = self.info.regs.isr().read(); 390 let isr = self.info.regs.isr().read();
371 self.error_occurred(&isr, timeout)?; 391 self.error_occurred(&isr, timeout)?;
372 if isr.tc() { 392 // Wait for either TC or TCR - both indicate transfer completion
393 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
394 if isr.tc() || isr.tcr() {
373 return Ok(()); 395 return Ok(());
374 } 396 }
375 timeout.check()?; 397 timeout.check()?;
@@ -396,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
396 address, 418 address,
397 read.len().min(255), 419 read.len().min(255),
398 Stop::Automatic, 420 Stop::Automatic,
399 last_chunk_idx != 0, 421 last_chunk_idx != 0, // reload
400 restart, 422 restart,
401 timeout, 423 timeout,
402 )?; 424 )?;
403 425
404 for (number, chunk) in read.chunks_mut(255).enumerate() { 426 for (number, chunk) in read.chunks_mut(255).enumerate() {
405 if number != 0 { 427 if number != 0 {
406 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 428 Self::reload(
429 self.info,
430 chunk.len(),
431 number != last_chunk_idx,
432 Stop::Automatic,
433 timeout,
434 )?;
407 } 435 }
408 436
409 for byte in chunk { 437 for byte in chunk {
@@ -441,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
441 write.len().min(255), 469 write.len().min(255),
442 Stop::Software, 470 Stop::Software,
443 last_chunk_idx != 0, 471 last_chunk_idx != 0,
472 false, // restart
444 timeout, 473 timeout,
445 ) { 474 ) {
446 if send_stop { 475 if send_stop {
@@ -451,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
451 480
452 for (number, chunk) in write.chunks(255).enumerate() { 481 for (number, chunk) in write.chunks(255).enumerate() {
453 if number != 0 { 482 if number != 0 {
454 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 483 Self::reload(
484 self.info,
485 chunk.len(),
486 number != last_chunk_idx,
487 Stop::Software,
488 timeout,
489 )?;
455 } 490 }
456 491
457 for byte in chunk { 492 for byte in chunk {
@@ -507,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
507 /// 542 ///
508 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 543 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
509 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 544 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
510 let _ = addr; 545 if operations.is_empty() {
511 let _ = operations; 546 return Err(Error::ZeroLengthTransfer);
512 todo!() 547 }
548
549 let address = addr.into();
550 let timeout = self.timeout();
551
552 // Group consecutive operations of the same type
553 let mut op_idx = 0;
554 let mut is_first_group = true;
555
556 while op_idx < operations.len() {
557 // Determine the type of current group and find all consecutive operations of same type
558 let is_read = matches!(operations[op_idx], Operation::Read(_));
559 let group_start = op_idx;
560
561 // Find end of this group (consecutive operations of same type)
562 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
563 op_idx += 1;
564 }
565 let group_end = op_idx;
566 let is_last_group = op_idx >= operations.len();
567
568 // Execute this group of operations
569 if is_read {
570 self.execute_read_group(
571 address,
572 &mut operations[group_start..group_end],
573 is_first_group,
574 is_last_group,
575 timeout,
576 )?;
577 } else {
578 self.execute_write_group(
579 address,
580 &operations[group_start..group_end],
581 is_first_group,
582 is_last_group,
583 timeout,
584 )?;
585 }
586
587 is_first_group = false;
588 }
589
590 Ok(())
591 }
592
593 fn execute_write_group(
594 &mut self,
595 address: Address,
596 operations: &[Operation<'_>],
597 is_first_group: bool,
598 is_last_group: bool,
599 timeout: Timeout,
600 ) -> Result<(), Error> {
601 // Calculate total bytes across all operations in this group
602 let total_bytes = Self::total_operation_bytes(operations);
603
604 if total_bytes == 0 {
605 // Handle empty write group - just send address
606 if is_first_group {
607 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
608 }
609 if is_last_group {
610 self.master_stop();
611 }
612 return Ok(());
613 }
614
615 let mut total_remaining = total_bytes;
616 let mut first_chunk = true;
617
618 for operation in operations {
619 if let Operation::Write(buffer) = operation {
620 for chunk in buffer.chunks(255) {
621 let chunk_len = chunk.len();
622 total_remaining -= chunk_len;
623 let is_last_chunk = total_remaining == 0;
624 let will_reload = !is_last_chunk;
625
626 if first_chunk {
627 // First chunk: initiate transfer
628 // If not first group, use RESTART instead of START
629 Self::master_write(
630 self.info,
631 address,
632 chunk_len,
633 Stop::Software,
634 will_reload,
635 !is_first_group,
636 timeout,
637 )?;
638 first_chunk = false;
639 } else {
640 // Subsequent chunks: use reload
641 // Always use Software stop for writes
642 Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?;
643 }
644
645 // Send data bytes
646 for byte in chunk {
647 self.wait_txis(timeout)?;
648 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
649 }
650 }
651 }
652 }
653
654 // Wait for transfer to complete
655 if is_last_group {
656 self.wait_tc(timeout)?;
657 self.master_stop();
658 self.wait_stop(timeout)?;
659 } else {
660 // Wait for TC before next group (enables RESTART)
661 self.wait_tc(timeout)?;
662 }
663
664 Ok(())
665 }
666
667 fn execute_read_group(
668 &mut self,
669 address: Address,
670 operations: &mut [Operation<'_>],
671 is_first_group: bool,
672 is_last_group: bool,
673 timeout: Timeout,
674 ) -> Result<(), Error> {
675 // Calculate total bytes across all operations in this group
676 let total_bytes = Self::total_operation_bytes(operations);
677
678 if total_bytes == 0 {
679 // Handle empty read group
680 if is_first_group {
681 Self::master_read(
682 self.info,
683 address,
684 0,
685 if is_last_group { Stop::Automatic } else { Stop::Software },
686 false, // reload
687 !is_first_group,
688 timeout,
689 )?;
690 }
691 if is_last_group {
692 self.wait_stop(timeout)?;
693 }
694 return Ok(());
695 }
696
697 let mut total_remaining = total_bytes;
698 let mut first_chunk = true;
699
700 for operation in operations {
701 if let Operation::Read(buffer) = operation {
702 for chunk in buffer.chunks_mut(255) {
703 let chunk_len = chunk.len();
704 total_remaining -= chunk_len;
705 let is_last_chunk = total_remaining == 0;
706 let will_reload = !is_last_chunk;
707
708 if first_chunk {
709 // First chunk: initiate transfer
710 let stop = if is_last_group && is_last_chunk {
711 Stop::Automatic
712 } else {
713 Stop::Software
714 };
715
716 Self::master_read(
717 self.info,
718 address,
719 chunk_len,
720 stop,
721 will_reload,
722 !is_first_group, // restart if not first group
723 timeout,
724 )?;
725 first_chunk = false;
726 } else {
727 // Subsequent chunks: use reload
728 let stop = if is_last_group && is_last_chunk {
729 Stop::Automatic
730 } else {
731 Stop::Software
732 };
733 Self::reload(self.info, chunk_len, will_reload, stop, timeout)?;
734 }
735
736 // Receive data bytes
737 for byte in chunk {
738 self.wait_rxne(timeout)?;
739 *byte = self.info.regs.rxdr().read().rxdata();
740 }
741 }
742 }
743 }
744
745 // Wait for transfer to complete
746 if is_last_group {
747 self.wait_stop(timeout)?;
748 }
749 // For non-last read groups, don't wait for TC - the peripheral may hold SCL low
750 // in Software AUTOEND mode until the next START is issued. Just proceed directly
751 // to the next group which will issue RESTART and release the clock.
752
753 Ok(())
513 } 754 }
514 755
515 /// Blocking write multiple buffers. 756 /// Blocking write multiple buffers.
@@ -531,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
531 first_length.min(255), 772 first_length.min(255),
532 Stop::Software, 773 Stop::Software,
533 (first_length > 255) || (last_slice_index != 0), 774 (first_length > 255) || (last_slice_index != 0),
775 false, // restart
534 timeout, 776 timeout,
535 ) { 777 ) {
536 self.master_stop(); 778 self.master_stop();
@@ -552,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
552 self.info, 794 self.info,
553 slice_len.min(255), 795 slice_len.min(255),
554 (idx != last_slice_index) || (slice_len > 255), 796 (idx != last_slice_index) || (slice_len > 255),
797 Stop::Software,
555 timeout, 798 timeout,
556 ) { 799 ) {
557 if err != Error::Nack { 800 if err != Error::Nack {
@@ -567,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
567 self.info, 810 self.info,
568 chunk.len(), 811 chunk.len(),
569 (number != last_chunk_idx) || (idx != last_slice_index), 812 (number != last_chunk_idx) || (idx != last_slice_index),
813 Stop::Software,
570 timeout, 814 timeout,
571 ) { 815 ) {
572 if err != Error::Nack { 816 if err != Error::Nack {
@@ -610,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
610 first_slice: bool, 854 first_slice: bool,
611 last_slice: bool, 855 last_slice: bool,
612 send_stop: bool, 856 send_stop: bool,
857 restart: bool,
613 timeout: Timeout, 858 timeout: Timeout,
614 ) -> Result<(), Error> { 859 ) -> Result<(), Error> {
615 let total_len = write.len(); 860 let total_len = write.len();
@@ -676,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
676 total_len.min(255), 921 total_len.min(255),
677 Stop::Software, 922 Stop::Software,
678 (total_len > 255) || !last_slice, 923 (total_len > 255) || !last_slice,
924 restart,
679 timeout, 925 timeout,
680 )?; 926 )?;
681 } else { 927 } else {
682 Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; 928 Self::reload(
929 self.info,
930 total_len.min(255),
931 (total_len > 255) || !last_slice,
932 Stop::Software,
933 timeout,
934 )?;
683 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 935 self.info.regs.cr1().modify(|w| w.set_tcie(true));
684 } 936 }
685 } else if !(isr.tcr() || isr.tc()) { 937 } else if !(isr.tcr() || isr.tc()) {
@@ -688,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
688 } else if remaining_len == 0 { 940 } else if remaining_len == 0 {
689 return Poll::Ready(Ok(())); 941 return Poll::Ready(Ok(()));
690 } else { 942 } else {
691 let last_piece = (remaining_len <= 255) && last_slice; 943 if let Err(e) = Self::reload(
692 944 self.info,
693 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 945 remaining_len.min(255),
946 (remaining_len > 255) || !last_slice,
947 Stop::Software,
948 timeout,
949 ) {
694 return Poll::Ready(Err(e)); 950 return Poll::Ready(Err(e));
695 } 951 }
696 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 952 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -702,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
702 .await?; 958 .await?;
703 959
704 dma_transfer.await; 960 dma_transfer.await;
705 if last_slice { 961
706 // This should be done already 962 // Always wait for TC after DMA completes - needed for consecutive buffers
707 self.wait_tc(timeout)?; 963 self.wait_tc(timeout)?;
708 }
709 964
710 if last_slice & send_stop { 965 if last_slice & send_stop {
711 self.master_stop(); 966 self.master_stop();
@@ -780,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
780 address, 1035 address,
781 total_len.min(255), 1036 total_len.min(255),
782 Stop::Automatic, 1037 Stop::Automatic,
783 total_len > 255, 1038 total_len > 255, // reload
784 restart, 1039 restart,
785 timeout, 1040 timeout,
786 )?; 1041 )?;
@@ -788,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
788 return Poll::Ready(Ok(())); 1043 return Poll::Ready(Ok(()));
789 } 1044 }
790 } else if isr.tcr() { 1045 } else if isr.tcr() {
791 // poll_fn was woken without an interrupt present 1046 // Transfer Complete Reload - need to set up next chunk
792 return Poll::Pending;
793 } else {
794 let last_piece = remaining_len <= 255; 1047 let last_piece = remaining_len <= 255;
795 1048
796 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 1049 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) {
797 return Poll::Ready(Err(e)); 1050 return Poll::Ready(Err(e));
798 } 1051 }
799 // Return here if we are on last chunk, 1052 // Return here if we are on last chunk,
@@ -802,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
802 return Poll::Ready(Ok(())); 1055 return Poll::Ready(Ok(()));
803 } 1056 }
804 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1057 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1058 } else {
1059 // poll_fn was woken without TCR interrupt
1060 return Poll::Pending;
805 } 1061 }
806 1062
807 remaining_len = remaining_len.saturating_sub(255); 1063 remaining_len = remaining_len.saturating_sub(255);
@@ -826,7 +1082,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
826 self.write_internal(address.into(), write, true, timeout) 1082 self.write_internal(address.into(), write, true, timeout)
827 } else { 1083 } else {
828 timeout 1084 timeout
829 .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) 1085 .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout))
830 .await 1086 .await
831 } 1087 }
832 } 1088 }
@@ -842,16 +1098,24 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
842 if write.is_empty() { 1098 if write.is_empty() {
843 return Err(Error::ZeroLengthTransfer); 1099 return Err(Error::ZeroLengthTransfer);
844 } 1100 }
845 let mut iter = write.iter();
846 1101
1102 let mut iter = write.iter();
847 let mut first = true; 1103 let mut first = true;
848 let mut current = iter.next(); 1104 let mut current = iter.next();
1105
849 while let Some(c) = current { 1106 while let Some(c) = current {
850 let next = iter.next(); 1107 let next = iter.next();
851 let is_last = next.is_none(); 1108 let is_last = next.is_none();
852 1109
853 let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); 1110 let fut = self.write_dma_internal(
1111 address, c, first, // first_slice
1112 is_last, // last_slice
1113 is_last, // send_stop (only on last buffer)
1114 false, // restart (false for all - they're one continuous write)
1115 timeout,
1116 );
854 timeout.with(fut).await?; 1117 timeout.with(fut).await?;
1118
855 first = false; 1119 first = false;
856 current = next; 1120 current = next;
857 } 1121 }
@@ -881,7 +1145,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
881 if write.is_empty() { 1145 if write.is_empty() {
882 self.write_internal(address.into(), write, false, timeout)?; 1146 self.write_internal(address.into(), write, false, timeout)?;
883 } else { 1147 } else {
884 let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); 1148 let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout);
885 timeout.with(fut).await?; 1149 timeout.with(fut).await?;
886 } 1150 }
887 1151
@@ -903,9 +1167,299 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 1167 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))] 1168 #[cfg(all(feature = "low-power", stm32wlex))]
905 let _device_busy = crate::low_power::DeviceBusy::new_stop1(); 1169 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
906 let _ = addr; 1170
907 let _ = operations; 1171 if operations.is_empty() {
908 todo!() 1172 return Err(Error::ZeroLengthTransfer);
1173 }
1174
1175 let address = addr.into();
1176 let timeout = self.timeout();
1177
1178 // Group consecutive operations of the same type
1179 let mut op_idx = 0;
1180 let mut is_first_group = true;
1181
1182 while op_idx < operations.len() {
1183 // Determine the type of current group and find all consecutive operations of same type
1184 let is_read = matches!(operations[op_idx], Operation::Read(_));
1185 let group_start = op_idx;
1186
1187 // Find end of this group (consecutive operations of same type)
1188 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
1189 op_idx += 1;
1190 }
1191 let group_end = op_idx;
1192 let is_last_group = op_idx >= operations.len();
1193
1194 // Execute this group of operations
1195 if is_read {
1196 self.execute_read_group_async(
1197 address,
1198 &mut operations[group_start..group_end],
1199 is_first_group,
1200 is_last_group,
1201 timeout,
1202 )
1203 .await?;
1204 } else {
1205 self.execute_write_group_async(
1206 address,
1207 &operations[group_start..group_end],
1208 is_first_group,
1209 is_last_group,
1210 timeout,
1211 )
1212 .await?;
1213 }
1214
1215 is_first_group = false;
1216 }
1217
1218 Ok(())
1219 }
1220
1221 async fn execute_write_group_async(
1222 &mut self,
1223 address: Address,
1224 operations: &[Operation<'_>],
1225 is_first_group: bool,
1226 is_last_group: bool,
1227 timeout: Timeout,
1228 ) -> Result<(), Error> {
1229 // Calculate total bytes across all operations in this group
1230 let total_bytes = Self::total_operation_bytes(operations);
1231
1232 if total_bytes == 0 {
1233 // Handle empty write group using blocking call
1234 if is_first_group {
1235 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
1236 }
1237 if is_last_group {
1238 self.master_stop();
1239 }
1240 return Ok(());
1241 }
1242
1243 // Collect all write buffers
1244 let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new();
1245 for operation in operations {
1246 if let Operation::Write(buffer) = operation {
1247 if !buffer.is_empty() {
1248 let _ = write_buffers.push(buffer);
1249 }
1250 }
1251 }
1252
1253 if write_buffers.is_empty() {
1254 return Ok(());
1255 }
1256
1257 // Send each buffer using DMA
1258 let num_buffers = write_buffers.len();
1259 for (idx, buffer) in write_buffers.iter().enumerate() {
1260 let is_first_buffer = idx == 0;
1261 let is_last_buffer = idx == num_buffers - 1;
1262
1263 let fut = self.write_dma_internal(
1264 address,
1265 buffer,
1266 is_first_buffer, // first_slice
1267 is_last_buffer, // last_slice
1268 is_last_buffer && is_last_group, // send_stop
1269 is_first_buffer && !is_first_group, // restart (only for first buffer if not first group)
1270 timeout,
1271 );
1272 timeout.with(fut).await?;
1273 }
1274
1275 Ok(())
1276 }
1277
1278 async fn execute_read_group_async(
1279 &mut self,
1280 address: Address,
1281 operations: &mut [Operation<'_>],
1282 is_first_group: bool,
1283 is_last_group: bool,
1284 timeout: Timeout,
1285 ) -> Result<(), Error> {
1286 // Calculate total bytes across all operations in this group
1287 let total_bytes = Self::total_operation_bytes(operations);
1288
1289 if total_bytes == 0 {
1290 // Handle empty read group using blocking call
1291 if is_first_group {
1292 Self::master_read(
1293 self.info,
1294 address,
1295 0,
1296 if is_last_group { Stop::Automatic } else { Stop::Software },
1297 false, // reload
1298 !is_first_group,
1299 timeout,
1300 )?;
1301 }
1302 if is_last_group {
1303 self.wait_stop(timeout)?;
1304 }
1305 return Ok(());
1306 }
1307
1308 // Use DMA for read operations - need to handle multiple buffers
1309 let restart = !is_first_group;
1310 let mut total_remaining = total_bytes;
1311 let mut is_first_in_group = true;
1312
1313 for operation in operations {
1314 if let Operation::Read(buffer) = operation {
1315 if buffer.is_empty() {
1316 // Skip empty buffers
1317 continue;
1318 }
1319
1320 let buf_len = buffer.len();
1321 total_remaining -= buf_len;
1322 let is_last_in_group = total_remaining == 0;
1323
1324 // Perform DMA read
1325 if is_first_in_group {
1326 // First buffer: use read_dma_internal which handles restart properly
1327 // Only use Automatic stop if this is the last buffer in the last group
1328 let stop_mode = if is_last_group && is_last_in_group {
1329 Stop::Automatic
1330 } else {
1331 Stop::Software
1332 };
1333
1334 // We need a custom DMA read that respects our stop mode
1335 self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout)
1336 .await?;
1337 is_first_in_group = false;
1338 } else {
1339 // Subsequent buffers: need to reload and continue
1340 let stop_mode = if is_last_group && is_last_in_group {
1341 Stop::Automatic
1342 } else {
1343 Stop::Software
1344 };
1345
1346 self.read_dma_group_internal(
1347 address, buffer, false, // no restart for subsequent buffers in same group
1348 stop_mode, timeout,
1349 )
1350 .await?;
1351 }
1352 }
1353 }
1354
1355 // Wait for transfer to complete
1356 if is_last_group {
1357 self.wait_stop(timeout)?;
1358 }
1359
1360 Ok(())
1361 }
1362
1363 /// Internal DMA read helper for transaction groups
1364 async fn read_dma_group_internal(
1365 &mut self,
1366 address: Address,
1367 buffer: &mut [u8],
1368 restart: bool,
1369 stop_mode: Stop,
1370 timeout: Timeout,
1371 ) -> Result<(), Error> {
1372 let total_len = buffer.len();
1373
1374 let dma_transfer = unsafe {
1375 let regs = self.info.regs;
1376 regs.cr1().modify(|w| {
1377 w.set_rxdmaen(true);
1378 w.set_tcie(true);
1379 w.set_nackie(true);
1380 w.set_errie(true);
1381 });
1382 let src = regs.rxdr().as_ptr() as *mut u8;
1383
1384 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1385 };
1386
1387 let mut remaining_len = total_len;
1388
1389 let on_drop = OnDrop::new(|| {
1390 let regs = self.info.regs;
1391 regs.cr1().modify(|w| {
1392 w.set_rxdmaen(false);
1393 w.set_tcie(false);
1394 w.set_nackie(false);
1395 w.set_errie(false);
1396 });
1397 regs.icr().write(|w| {
1398 w.set_nackcf(true);
1399 w.set_berrcf(true);
1400 w.set_arlocf(true);
1401 w.set_ovrcf(true);
1402 });
1403 });
1404
1405 poll_fn(|cx| {
1406 self.state.waker.register(cx.waker());
1407
1408 let isr = self.info.regs.isr().read();
1409
1410 if isr.nackf() {
1411 return Poll::Ready(Err(Error::Nack));
1412 }
1413 if isr.arlo() {
1414 return Poll::Ready(Err(Error::Arbitration));
1415 }
1416 if isr.berr() {
1417 return Poll::Ready(Err(Error::Bus));
1418 }
1419 if isr.ovr() {
1420 return Poll::Ready(Err(Error::Overrun));
1421 }
1422
1423 if remaining_len == total_len {
1424 Self::master_read(
1425 self.info,
1426 address,
1427 total_len.min(255),
1428 stop_mode,
1429 total_len > 255, // reload
1430 restart,
1431 timeout,
1432 )?;
1433 if total_len <= 255 {
1434 return Poll::Ready(Ok(()));
1435 }
1436 } else if isr.tcr() {
1437 // Transfer Complete Reload - need to set up next chunk
1438 let last_piece = remaining_len <= 255;
1439
1440 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) {
1441 return Poll::Ready(Err(e));
1442 }
1443 // Return here if we are on last chunk,
1444 // end of transfer will be awaited with the DMA below
1445 if last_piece {
1446 return Poll::Ready(Ok(()));
1447 }
1448 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1449 } else {
1450 // poll_fn was woken without TCR interrupt
1451 return Poll::Pending;
1452 }
1453
1454 remaining_len = remaining_len.saturating_sub(255);
1455 Poll::Pending
1456 })
1457 .await?;
1458
1459 dma_transfer.await;
1460 drop(on_drop);
1461
1462 Ok(())
909 } 1463 }
910} 1464}
911 1465
@@ -1043,7 +1597,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1043 if number == 0 { 1597 if number == 0 {
1044 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1598 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1045 } else { 1599 } else {
1046 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1600 Self::reload(
1601 self.info,
1602 chunk.len(),
1603 number != last_chunk_idx,
1604 Stop::Software,
1605 timeout,
1606 )?;
1047 } 1607 }
1048 1608
1049 let mut index = 0; 1609 let mut index = 0;
@@ -1092,7 +1652,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1092 if number == 0 { 1652 if number == 0 {
1093 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1653 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1094 } else { 1654 } else {
1095 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1655 Self::reload(
1656 self.info,
1657 chunk.len(),
1658 number != last_chunk_idx,
1659 Stop::Software,
1660 timeout,
1661 )?;
1096 } 1662 }
1097 1663
1098 let mut index = 0; 1664 let mut index = 0;
@@ -1228,7 +1794,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1228 Poll::Pending 1794 Poll::Pending
1229 } else if isr.tcr() { 1795 } else if isr.tcr() {
1230 let is_last_slice = remaining_len <= 255; 1796 let is_last_slice = remaining_len <= 255;
1231 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1797 if let Err(e) = Self::reload(
1798 self.info,
1799 remaining_len.min(255),
1800 !is_last_slice,
1801 Stop::Software,
1802 timeout,
1803 ) {
1232 return Poll::Ready(Err(e)); 1804 return Poll::Ready(Err(e));
1233 } 1805 }
1234 remaining_len = remaining_len.saturating_sub(255); 1806 remaining_len = remaining_len.saturating_sub(255);
@@ -1292,7 +1864,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1292 Poll::Pending 1864 Poll::Pending
1293 } else if isr.tcr() { 1865 } else if isr.tcr() {
1294 let is_last_slice = remaining_len <= 255; 1866 let is_last_slice = remaining_len <= 255;
1295 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1867 if let Err(e) = Self::reload(
1868 self.info,
1869 remaining_len.min(255),
1870 !is_last_slice,
1871 Stop::Software,
1872 timeout,
1873 ) {
1296 return Poll::Ready(Err(e)); 1874 return Poll::Ready(Err(e));
1297 } 1875 }
1298 remaining_len = remaining_len.saturating_sub(255); 1876 remaining_len = remaining_len.saturating_sub(255);
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index a78873d21..177dd0ac2 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -16,6 +16,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] }
16embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 16embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
17embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 17embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
18embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 18embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
19embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19static_cell = "2" 20static_cell = "2"
20portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 21portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
21 22
diff --git a/examples/stm32f0/src/bin/i2c_master.rs b/examples/stm32f0/src/bin/i2c_master.rs
new file mode 100644
index 000000000..2e61ecdf7
--- /dev/null
+++ b/examples/stm32f0/src/bin/i2c_master.rs
@@ -0,0 +1,609 @@
1#![no_std]
2#![no_main]
3
4// Hardware Setup for NUCLEO-F072RB:
5// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector
6// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM)
7// - Default slave address: 0x50
8// - Pull-up resistors: 4.7kΩ on both SCL and SDA
9// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA)
10//
11// Analog Discovery - Waveforms Setup:
12// - Increase buffer size: Settings -> Device Manager -> Option 4
13// - Run Protocol Analyzer
14// - Configure as I2C Slave at address 0x50
15// - Connect and configure DIO pins for SCL and SDA
16// - Frequency: 100kHz - [✓] Clock Stretching
17
18use defmt::*;
19use embassy_executor::Spawner;
20use embassy_stm32::i2c::{Config, I2c, Master};
21use embassy_stm32::mode::{Async, Blocking};
22use embassy_stm32::time::Hertz;
23use embassy_stm32::{bind_interrupts, i2c, peripherals};
24use embassy_time::Timer;
25use embedded_hal_1::i2c::Operation;
26use {defmt_rtt as _, panic_probe as _};
27
28bind_interrupts!(struct Irqs {
29 I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
30});
31
32#[embassy_executor::main]
33async fn main(_spawner: Spawner) {
34 let p = embassy_stm32::init(Default::default());
35 info!("Run stm32 I2C v2 Master Tests...");
36
37 let mut i2c_peri = p.I2C1;
38 let mut scl = p.PB8;
39 let mut sda = p.PB9;
40
41 let mut config = Config::default();
42 config.frequency = Hertz(100_000);
43
44 // I2C slave address for Analog Discovery or test EEPROM
45 let slave_addr = 0x50u8;
46
47 // Wait for slave device to be ready
48 Timer::after_millis(100).await;
49
50 // ========== BLOCKING DIRECT API TESTS ==========
51 info!("========== BLOCKING DIRECT API TESTS ==========");
52 {
53 let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config);
54
55 info!("=== Test 1: Direct blocking_write ===");
56 test_blocking_write(&mut i2c, slave_addr);
57
58 info!("=== Test 2: Direct blocking_read ===");
59 test_blocking_read(&mut i2c, slave_addr);
60
61 info!("=== Test 3: Direct blocking_write_read ===");
62 test_blocking_write_read(&mut i2c, slave_addr);
63
64 info!("=== Test 4: Direct blocking_write_vectored ===");
65 test_blocking_write_vectored(&mut i2c, slave_addr);
66
67 info!("=== Test 5: Large buffer (>255 bytes) ===");
68 test_blocking_large_buffer(&mut i2c, slave_addr);
69
70 info!("Blocking direct API tests OK");
71 }
72
73 Timer::after_millis(100).await;
74
75 // ========== BLOCKING TRANSACTION TESTS ==========
76 info!("========== BLOCKING TRANSACTION TESTS ==========");
77 {
78 let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config);
79
80 info!("=== Test 6: Consecutive Writes (Should Merge) ===");
81 test_consecutive_writes_blocking(&mut i2c, slave_addr);
82
83 info!("=== Test 7: Consecutive Reads (Should Merge) ===");
84 test_consecutive_reads_blocking(&mut i2c, slave_addr);
85
86 info!("=== Test 8: Write then Read (RESTART) ===");
87 test_write_then_read_blocking(&mut i2c, slave_addr);
88
89 info!("=== Test 9: Read then Write (RESTART) ===");
90 test_read_then_write_blocking(&mut i2c, slave_addr);
91
92 info!("=== Test 10: Complex Mixed Sequence ===");
93 test_mixed_sequence_blocking(&mut i2c, slave_addr);
94
95 info!("=== Test 11: Single Operations ===");
96 test_single_operations_blocking(&mut i2c, slave_addr);
97
98 info!("Blocking transaction tests OK");
99 }
100
101 Timer::after_millis(100).await;
102
103 // ========== ASYNC TESTS (DMA) ==========
104 info!("========== ASYNC TESTS (DMA) ==========");
105 {
106 let tx_dma = p.DMA1_CH2;
107 let rx_dma = p.DMA1_CH3;
108
109 let mut i2c = I2c::new(i2c_peri, scl, sda, Irqs, tx_dma, rx_dma, config);
110
111 // Direct API tests (reusing same I2C instance)
112 info!("=== Direct API Test 1: write() ===");
113 test_async_write(&mut i2c, slave_addr).await;
114
115 info!("=== Direct API Test 2: read() ===");
116 test_async_read(&mut i2c, slave_addr).await;
117
118 info!("=== Direct API Test 3: write_read() ===");
119 test_async_write_read(&mut i2c, slave_addr).await;
120
121 info!("=== Direct API Test 4: write_vectored() ===");
122 test_async_write_vectored(&mut i2c, slave_addr).await;
123
124 info!("=== Direct API Test 5: Large buffer (>255 bytes) ===");
125 test_async_large_buffer(&mut i2c, slave_addr).await;
126
127 info!("Async Direct API tests OK");
128
129 // Transaction tests
130 info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ===");
131 test_consecutive_writes_async(&mut i2c, slave_addr).await;
132
133 info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ===");
134 test_consecutive_reads_async(&mut i2c, slave_addr).await;
135
136 info!("=== Transaction Test 8: Write then Read (RESTART) ===");
137 test_write_then_read_async(&mut i2c, slave_addr).await;
138
139 info!("=== Transaction Test 9: Read then Write (RESTART) ===");
140 test_read_then_write_async(&mut i2c, slave_addr).await;
141
142 info!("=== Transaction Test 10: Complex Mixed Sequence ===");
143 test_mixed_sequence_async(&mut i2c, slave_addr).await;
144
145 info!("=== Transaction Test 11: Single Operations ===");
146 test_single_operations_async(&mut i2c, slave_addr).await;
147
148 info!("Async transaction tests OK");
149 }
150
151 info!("All tests OK");
152 cortex_m::asm::bkpt();
153}
154
155// ==================== BLOCKING DIRECT API TEST FUNCTIONS ====================
156
157fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
158 let write_data = [0x42, 0x43, 0x44, 0x45];
159
160 match i2c.blocking_write(addr, &write_data) {
161 Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data),
162 Err(e) => {
163 error!("✗ blocking_write failed: {:?}", e);
164 defmt::panic!("Test failed: blocking_write");
165 }
166 }
167}
168
169fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
170 let mut read_buf = [0u8; 8];
171
172 match i2c.blocking_read(addr, &mut read_buf) {
173 Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf),
174 Err(e) => {
175 error!("✗ blocking_read failed: {:?}", e);
176 defmt::panic!("Test failed: blocking_read");
177 }
178 }
179}
180
181fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
182 let write_data = [0x50, 0x51];
183 let mut read_buf = [0u8; 6];
184
185 match i2c.blocking_write_read(addr, &write_data, &mut read_buf) {
186 Ok(_) => {
187 info!("✓ blocking_write_read succeeded");
188 info!(" Written: {:02x}", write_data);
189 info!(" Read: {:02x}", read_buf);
190 }
191 Err(e) => {
192 error!("✗ blocking_write_read failed: {:?}", e);
193 defmt::panic!("Test failed: blocking_write_read");
194 }
195 }
196}
197
198fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
199 let buf1 = [0x60, 0x61, 0x62];
200 let buf2 = [0x70, 0x71];
201 let buf3 = [0x80, 0x81, 0x82, 0x83];
202 let bufs = [&buf1[..], &buf2[..], &buf3[..]];
203
204 match i2c.blocking_write_vectored(addr, &bufs) {
205 Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"),
206 Err(e) => {
207 error!("✗ blocking_write_vectored failed: {:?}", e);
208 defmt::panic!("Test failed: blocking_write_vectored");
209 }
210 }
211}
212
213fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
214 // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes)
215 let mut write_buf = [0u8; 300];
216 for (i, byte) in write_buf.iter_mut().enumerate() {
217 *byte = (i & 0xFF) as u8;
218 }
219
220 match i2c.blocking_write(addr, &write_buf) {
221 Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"),
222 Err(e) => {
223 error!("✗ Large buffer write failed: {:?}", e);
224 defmt::panic!("Test failed: large buffer write");
225 }
226 }
227
228 // Test large read
229 let mut read_buf = [0u8; 300];
230 match i2c.blocking_read(addr, &mut read_buf) {
231 Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"),
232 Err(e) => {
233 error!("✗ Large buffer read failed: {:?}", e);
234 defmt::panic!("Test failed: large buffer read");
235 }
236 }
237}
238
239// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ====================
240
241fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
242 // Expected on bus: START, ADDR+W, data1, data2, data3, STOP
243 // NO intermediate RESTART/STOP between writes - they should be merged
244 let data1 = [0x10, 0x11, 0x12];
245 let data2 = [0x20, 0x21];
246 let data3 = [0x30, 0x31, 0x32, 0x33];
247
248 let mut ops = [
249 Operation::Write(&data1),
250 Operation::Write(&data2),
251 Operation::Write(&data3),
252 ];
253
254 match i2c.blocking_transaction(addr, &mut ops) {
255 Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"),
256 Err(e) => {
257 error!("✗ Consecutive writes failed: {:?}", e);
258 defmt::panic!("Test failed: consecutive writes");
259 }
260 }
261}
262
263fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
264 // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP
265 // NO intermediate RESTART/STOP between reads - they should be merged
266 let mut buf1 = [0u8; 4];
267 let mut buf2 = [0u8; 3];
268 let mut buf3 = [0u8; 2];
269
270 let mut ops = [
271 Operation::Read(&mut buf1),
272 Operation::Read(&mut buf2),
273 Operation::Read(&mut buf3),
274 ];
275
276 match i2c.blocking_transaction(addr, &mut ops) {
277 Ok(_) => {
278 info!("✓ Consecutive reads succeeded (merged 9 bytes)");
279 info!(" buf1: {:02x}", buf1);
280 info!(" buf2: {:02x}", buf2);
281 info!(" buf3: {:02x}", buf3);
282 }
283 Err(e) => {
284 error!("✗ Consecutive reads failed: {:?}", e);
285 defmt::panic!("Test failed: consecutive reads");
286 }
287 }
288}
289
290fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
291 // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP
292 let write_data = [0xAA, 0xBB];
293 let mut read_buf = [0u8; 4];
294
295 let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)];
296
297 match i2c.blocking_transaction(addr, &mut ops) {
298 Ok(_) => {
299 info!("✓ Write-then-read succeeded with RESTART");
300 info!(" Written: {:02x}", write_data);
301 info!(" Read: {:02x}", read_buf);
302 }
303 Err(e) => {
304 error!("✗ Write-then-read failed: {:?}", e);
305 defmt::panic!("Test failed: write-then-read");
306 }
307 }
308}
309
310fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
311 // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP
312 let mut read_buf = [0u8; 3];
313 let write_data = [0xCC, 0xDD, 0xEE];
314
315 let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)];
316
317 match i2c.blocking_transaction(addr, &mut ops) {
318 Ok(_) => {
319 info!("✓ Read-then-write succeeded with RESTART");
320 info!(" Read: {:02x}", read_buf);
321 info!(" Written: {:02x}", write_data);
322 }
323 Err(e) => {
324 error!("✗ Read-then-write failed: {:?}", e);
325 defmt::panic!("Test failed: read-then-write");
326 }
327 }
328}
329
330fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
331 // Complex: W, W, R, R, W, R
332 // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R]
333 let w1 = [0x01, 0x02];
334 let w2 = [0x03, 0x04];
335 let mut r1 = [0u8; 2];
336 let mut r2 = [0u8; 2];
337 let w3 = [0x05];
338 let mut r3 = [0u8; 1];
339
340 let mut ops = [
341 Operation::Write(&w1),
342 Operation::Write(&w2),
343 Operation::Read(&mut r1),
344 Operation::Read(&mut r2),
345 Operation::Write(&w3),
346 Operation::Read(&mut r3),
347 ];
348
349 match i2c.blocking_transaction(addr, &mut ops) {
350 Ok(_) => {
351 info!("✓ Mixed sequence succeeded");
352 info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]");
353 }
354 Err(e) => {
355 error!("✗ Mixed sequence failed: {:?}", e);
356 defmt::panic!("Test failed: mixed sequence");
357 }
358 }
359}
360
361fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
362 // Test single write
363 let write_data = [0xFF];
364 let mut ops = [Operation::Write(&write_data)];
365
366 match i2c.blocking_transaction(addr, &mut ops) {
367 Ok(_) => info!("✓ Single write succeeded"),
368 Err(e) => {
369 error!("✗ Single write failed: {:?}", e);
370 defmt::panic!("Test failed: single write");
371 }
372 }
373
374 // Test single read
375 let mut read_buf = [0u8; 1];
376 let mut ops = [Operation::Read(&mut read_buf)];
377
378 match i2c.blocking_transaction(addr, &mut ops) {
379 Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]),
380 Err(e) => {
381 error!("✗ Single read failed: {:?}", e);
382 defmt::panic!("Test failed: single read");
383 }
384 }
385}
386
387// ==================== ASYNC DIRECT API TEST FUNCTIONS ====================
388
389async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
390 let write_data = [0x42, 0x43, 0x44, 0x45];
391
392 match i2c.write(addr, &write_data).await {
393 Ok(_) => info!("✓ async write succeeded: {:02x}", write_data),
394 Err(e) => {
395 error!("✗ async write failed: {:?}", e);
396 defmt::panic!("Test failed: async write");
397 }
398 }
399}
400
401async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
402 let mut read_buf = [0u8; 8];
403
404 match i2c.read(addr, &mut read_buf).await {
405 Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf),
406 Err(e) => {
407 error!("✗ async read failed: {:?}", e);
408 defmt::panic!("Test failed: async read");
409 }
410 }
411}
412
413async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
414 let write_data = [0x50, 0x51];
415 let mut read_buf = [0u8; 6];
416
417 match i2c.write_read(addr, &write_data, &mut read_buf).await {
418 Ok(_) => {
419 info!("✓ async write_read succeeded");
420 info!(" Written: {:02x}", write_data);
421 info!(" Read: {:02x}", read_buf);
422 }
423 Err(e) => {
424 error!("✗ async write_read failed: {:?}", e);
425 defmt::panic!("Test failed: async write_read");
426 }
427 }
428}
429
430async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
431 let buf1 = [0x60, 0x61, 0x62];
432 let buf2 = [0x70, 0x71];
433 let buf3 = [0x80, 0x81, 0x82, 0x83];
434 let bufs = [&buf1[..], &buf2[..], &buf3[..]];
435
436 match i2c.write_vectored(addr.into(), &bufs).await {
437 Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"),
438 Err(e) => {
439 error!("✗ async write_vectored failed: {:?}", e);
440 defmt::panic!("Test failed: async write_vectored");
441 }
442 }
443}
444
445async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
446 // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes)
447 let mut write_buf = [0u8; 300];
448 for (i, byte) in write_buf.iter_mut().enumerate() {
449 *byte = (i & 0xFF) as u8;
450 }
451
452 match i2c.write(addr, &write_buf).await {
453 Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"),
454 Err(e) => {
455 error!("✗ Large buffer async write failed: {:?}", e);
456 defmt::panic!("Test failed: large buffer async write");
457 }
458 }
459
460 // Test large read
461 let mut read_buf = [0u8; 300];
462 match i2c.read(addr, &mut read_buf).await {
463 Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"),
464 Err(e) => {
465 error!("✗ Large buffer async read failed: {:?}", e);
466 defmt::panic!("Test failed: large buffer async read");
467 }
468 }
469}
470
471// ==================== ASYNC TRANSACTION TEST FUNCTIONS ====================
472
473async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
474 let data1 = [0x10, 0x11, 0x12];
475 let data2 = [0x20, 0x21];
476 let data3 = [0x30, 0x31, 0x32, 0x33];
477
478 let mut ops = [
479 Operation::Write(&data1),
480 Operation::Write(&data2),
481 Operation::Write(&data3),
482 ];
483
484 match i2c.transaction(addr, &mut ops).await {
485 Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"),
486 Err(e) => {
487 error!("✗ Consecutive writes failed: {:?}", e);
488 defmt::panic!("Test failed: consecutive writes");
489 }
490 }
491}
492
493async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
494 let mut buf1 = [0u8; 4];
495 let mut buf2 = [0u8; 3];
496 let mut buf3 = [0u8; 2];
497
498 let mut ops = [
499 Operation::Read(&mut buf1),
500 Operation::Read(&mut buf2),
501 Operation::Read(&mut buf3),
502 ];
503
504 match i2c.transaction(addr, &mut ops).await {
505 Ok(_) => {
506 info!("✓ Consecutive reads succeeded (merged 9 bytes)");
507 info!(" buf1: {:02x}", buf1);
508 info!(" buf2: {:02x}", buf2);
509 info!(" buf3: {:02x}", buf3);
510 }
511 Err(e) => {
512 error!("✗ Consecutive reads failed: {:?}", e);
513 defmt::panic!("Test failed: consecutive reads");
514 }
515 }
516}
517
518async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
519 let write_data = [0xAA, 0xBB];
520 let mut read_buf = [0u8; 4];
521
522 let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)];
523
524 match i2c.transaction(addr, &mut ops).await {
525 Ok(_) => {
526 info!("✓ Write-then-read succeeded with RESTART");
527 info!(" Written: {:02x}", write_data);
528 info!(" Read: {:02x}", read_buf);
529 }
530 Err(e) => {
531 error!("✗ Write-then-read failed: {:?}", e);
532 defmt::panic!("Test failed: write-then-read");
533 }
534 }
535}
536
537async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
538 let mut read_buf = [0u8; 3];
539 let write_data = [0xCC, 0xDD, 0xEE];
540
541 let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)];
542
543 match i2c.transaction(addr, &mut ops).await {
544 Ok(_) => {
545 info!("✓ Read-then-write succeeded with RESTART");
546 info!(" Read: {:02x}", read_buf);
547 info!(" Written: {:02x}", write_data);
548 }
549 Err(e) => {
550 error!("✗ Read-then-write failed: {:?}", e);
551 defmt::panic!("Test failed: read-then-write");
552 }
553 }
554}
555
556async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
557 let w1 = [0x01, 0x02];
558 let w2 = [0x03, 0x04];
559 let mut r1 = [0u8; 2];
560 let mut r2 = [0u8; 2];
561 let w3 = [0x05];
562 let mut r3 = [0u8; 1];
563
564 let mut ops = [
565 Operation::Write(&w1),
566 Operation::Write(&w2),
567 Operation::Read(&mut r1),
568 Operation::Read(&mut r2),
569 Operation::Write(&w3),
570 Operation::Read(&mut r3),
571 ];
572
573 match i2c.transaction(addr, &mut ops).await {
574 Ok(_) => {
575 info!("✓ Mixed sequence succeeded");
576 info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]");
577 }
578 Err(e) => {
579 error!("✗ Mixed sequence failed: {:?}", e);
580 defmt::panic!("Test failed: mixed sequence");
581 }
582 }
583}
584
585async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
586 // Test single write
587 let write_data = [0xFF];
588 let mut ops = [Operation::Write(&write_data)];
589
590 match i2c.transaction(addr, &mut ops).await {
591 Ok(_) => info!("✓ Single write succeeded"),
592 Err(e) => {
593 error!("✗ Single write failed: {:?}", e);
594 defmt::panic!("Test failed: single write");
595 }
596 }
597
598 // Test single read
599 let mut read_buf = [0u8; 1];
600 let mut ops = [Operation::Read(&mut read_buf)];
601
602 match i2c.transaction(addr, &mut ops).await {
603 Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]),
604 Err(e) => {
605 error!("✗ Single read failed: {:?}", e);
606 defmt::panic!("Test failed: single read");
607 }
608 }
609}