From 03050a369befb7aeed88079626de21b4055ebccb Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 09:14:03 +0100 Subject: stm32/i2c: Add comprehensive v2 Master API tests and fix async issues --- embassy-stm32/src/i2c/v2.rs | 28 +- tests/stm32/Cargo.toml | 4 +- tests/stm32/src/bin/i2c_v2.rs | 398 ---------------------- tests/stm32/src/bin/i2c_v2_master.rs | 618 +++++++++++++++++++++++++++++++++++ 4 files changed, 627 insertions(+), 421 deletions(-) delete mode 100644 tests/stm32/src/bin/i2c_v2.rs create mode 100644 tests/stm32/src/bin/i2c_v2_master.rs diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index c9656d2c2..9771d7c98 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1003,9 +1003,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Poll::Ready(Ok(())); } } else if isr.tcr() { - // poll_fn was woken without an interrupt present - return Poll::Pending; - } else { + // Transfer Complete Reload - need to set up next chunk let last_piece = remaining_len <= 255; if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) { @@ -1017,6 +1015,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Poll::Ready(Ok(())); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); + } else { + // poll_fn was woken without TCR interrupt + return Poll::Pending; } remaining_len = remaining_len.saturating_sub(255); @@ -1052,25 +1053,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { #[cfg(all(feature = "low-power", stm32wlex))] let _device_busy = crate::low_power::DeviceBusy::new_stop1(); - let timeout = self.timeout(); - if write.is_empty() { - return Err(Error::ZeroLengthTransfer); - } - let mut iter = write.iter(); - - let mut first = true; - let mut current = iter.next(); - while let Some(c) = current { - let next = iter.next(); - let is_last = next.is_none(); - - let fut = self.write_dma_internal(address, c, first, is_last, is_last, false, timeout); - timeout.with(fut).await?; - first = false; - current = next; - } - Ok(()) + // For now, use blocking implementation for write_vectored + // This avoids complexity of handling multiple non-contiguous buffers with DMA + self.blocking_write_vectored((address.addr() & 0xFF) as u8, write) } /// Read. diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index fa757e276..1912a772c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -161,8 +161,8 @@ path = "src/bin/hash.rs" required-features = [ "hash",] [[bin]] -name = "i2c_v2" -path = "src/bin/i2c_v2.rs" +name = "i2c_v2_master" +path = "src/bin/i2c_v2_master.rs" required-features = [ "stm32f072rb",] [[bin]] diff --git a/tests/stm32/src/bin/i2c_v2.rs b/tests/stm32/src/bin/i2c_v2.rs deleted file mode 100644 index 087b8bbd9..000000000 --- a/tests/stm32/src/bin/i2c_v2.rs +++ /dev/null @@ -1,398 +0,0 @@ -#![no_std] -#![no_main] -// required-features: stm32f072rb -// -// Hardware Setup for NUCLEO-F072RB: -// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector -// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) -// - Default slave address: 0x50 -// - Pull-up resistors: 4.7kΩ on both SCL and SDA -// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) -// -// Analog Discovery Setup: -// - Configure as I2C Slave at address 0x50 -// - DIO 0: SCL -// - DIO 1: SDA -// - Enable pull-ups or use external 4.7kΩ pull-up resistors - -#[path = "../common.rs"] -mod common; - -use common::*; -use embassy_executor::Spawner; -use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::{Async, Blocking}; -use embassy_stm32::time::Hertz; -use embassy_time::Timer; -use embedded_hal_1::i2c::Operation; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = init(); - info!("I2C v2 Transaction Test Starting..."); - - let mut i2c_peri = peri!(p, I2C); - let mut scl = peri!(p, I2C_SCL); - let mut sda = peri!(p, I2C_SDA); - - let mut config = Config::default(); - config.frequency = Hertz(100_000); - - // I2C slave address for Analog Discovery or test EEPROM - let slave_addr = 0x50u8; - - // Wait for slave device to be ready - Timer::after_millis(100).await; - - // ========== BLOCKING TESTS ========== - info!("========== BLOCKING TRANSACTION TESTS =========="); - { - let mut i2c = I2c::new_blocking( - i2c_peri.reborrow(), - scl.reborrow(), - sda.reborrow(), - config, - ); - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_blocking(&mut i2c, slave_addr); - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_blocking(&mut i2c, slave_addr); - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read_blocking(&mut i2c, slave_addr); - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write_blocking(&mut i2c, slave_addr); - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence_blocking(&mut i2c, slave_addr); - - info!("=== Test 6: Single Operations ==="); - test_single_operations_blocking(&mut i2c, slave_addr); - - info!("Blocking tests OK"); - } - - Timer::after_millis(100).await; - - // ========== ASYNC TESTS ========== - info!("========== ASYNC TRANSACTION TESTS (DMA) =========="); - { - let tx_dma = peri!(p, I2C_TX_DMA); - let rx_dma = peri!(p, I2C_RX_DMA); - let irq = irqs!(I2C); - - let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes_async(&mut i2c, slave_addr).await; - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads_async(&mut i2c, slave_addr).await; - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read_async(&mut i2c, slave_addr).await; - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write_async(&mut i2c, slave_addr).await; - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence_async(&mut i2c, slave_addr).await; - - info!("=== Test 6: Single Operations ==="); - test_single_operations_async(&mut i2c, slave_addr).await; - - info!("Async tests OK"); - } - - info!("All tests OK"); - cortex_m::asm::bkpt(); -} - -fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+W, data1, data2, data3, STOP - // NO intermediate RESTART/STOP between writes - they should be merged - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP - // NO intermediate RESTART/STOP between reads - they should be merged - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Complex: W, W, R, R, W, R - // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.blocking_transaction(addr, &mut ops) { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} - -// ==================== ASYNC TEST FUNCTIONS ==================== - -async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let data1 = [0x10, 0x11, 0x12]; - let data2 = [0x20, 0x21]; - let data3 = [0x30, 0x31, 0x32, 0x33]; - - let mut ops = [ - Operation::Write(&data1), - Operation::Write(&data2), - Operation::Write(&data3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), - Err(e) => { - error!("✗ Consecutive writes failed: {:?}", e); - defmt::panic!("Test failed: consecutive writes"); - } - } -} - -async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut buf1 = [0u8; 4]; - let mut buf2 = [0u8; 3]; - let mut buf3 = [0u8; 2]; - - let mut ops = [ - Operation::Read(&mut buf1), - Operation::Read(&mut buf2), - Operation::Read(&mut buf3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Consecutive reads succeeded (merged 9 bytes)"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => { - error!("✗ Consecutive reads failed: {:?}", e); - defmt::panic!("Test failed: consecutive reads"); - } - } -} - -async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let write_data = [0xAA, 0xBB]; - let mut read_buf = [0u8; 4]; - - let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Write-then-read succeeded with RESTART"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => { - error!("✗ Write-then-read failed: {:?}", e); - defmt::panic!("Test failed: write-then-read"); - } - } -} - -async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let mut read_buf = [0u8; 3]; - let write_data = [0xCC, 0xDD, 0xEE]; - - let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Read-then-write succeeded with RESTART"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => { - error!("✗ Read-then-write failed: {:?}", e); - defmt::panic!("Test failed: read-then-write"); - } - } -} - -async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - let w1 = [0x01, 0x02]; - let w2 = [0x03, 0x04]; - let mut r1 = [0u8; 2]; - let mut r2 = [0u8; 2]; - let w3 = [0x05]; - let mut r3 = [0u8; 1]; - - let mut ops = [ - Operation::Write(&w1), - Operation::Write(&w2), - Operation::Read(&mut r1), - Operation::Read(&mut r2), - Operation::Write(&w3), - Operation::Read(&mut r3), - ]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => { - info!("✓ Mixed sequence succeeded"); - info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); - } - Err(e) => { - error!("✗ Mixed sequence failed: {:?}", e); - defmt::panic!("Test failed: mixed sequence"); - } - } -} - -async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { - // Test single write - let write_data = [0xFF]; - let mut ops = [Operation::Write(&write_data)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single write succeeded"), - Err(e) => { - error!("✗ Single write failed: {:?}", e); - defmt::panic!("Test failed: single write"); - } - } - - // Test single read - let mut read_buf = [0u8; 1]; - let mut ops = [Operation::Read(&mut read_buf)]; - - match i2c.transaction(addr, &mut ops).await { - Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), - Err(e) => { - error!("✗ Single read failed: {:?}", e); - defmt::panic!("Test failed: single read"); - } - } -} diff --git a/tests/stm32/src/bin/i2c_v2_master.rs b/tests/stm32/src/bin/i2c_v2_master.rs new file mode 100644 index 000000000..b841d556a --- /dev/null +++ b/tests/stm32/src/bin/i2c_v2_master.rs @@ -0,0 +1,618 @@ +#![no_std] +#![no_main] +// required-features: stm32f072rb +// +// Hardware Setup for NUCLEO-F072RB: +// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector +// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) +// - Default slave address: 0x50 +// - Pull-up resistors: 4.7kΩ on both SCL and SDA +// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) +// +// Analog Discovery - Waveforms Setup: +// - Increase buffer size: Settings -> Device Manager -> Option 4 +// - Run Protocol Analyzer +// - Configure as I2C Slave at address 0x50 +// - Connect and configure DIO pins for SCL and SDA +// - Frequency: 100kHz - [✓] Clock Stretching + +#[path = "../common.rs"] +mod common; + +use common::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::{Async, Blocking}; +use embassy_stm32::time::Hertz; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = init(); + info!("Run stm32 I2C v2 Master Tests..."); + + let mut i2c_peri = peri!(p, I2C); + let mut scl = peri!(p, I2C_SCL); + let mut sda = peri!(p, I2C_SDA); + + let mut config = Config::default(); + config.frequency = Hertz(100_000); + + // I2C slave address for Analog Discovery or test EEPROM + let slave_addr = 0x50u8; + + // Wait for slave device to be ready + Timer::after_millis(100).await; + + // ========== BLOCKING DIRECT API TESTS ========== + info!("========== BLOCKING DIRECT API TESTS =========="); + { + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + info!("=== Test 1: Direct blocking_write ==="); + test_blocking_write(&mut i2c, slave_addr); + + info!("=== Test 2: Direct blocking_read ==="); + test_blocking_read(&mut i2c, slave_addr); + + info!("=== Test 3: Direct blocking_write_read ==="); + test_blocking_write_read(&mut i2c, slave_addr); + + info!("=== Test 4: Direct blocking_write_vectored ==="); + test_blocking_write_vectored(&mut i2c, slave_addr); + + info!("=== Test 5: Large buffer (>255 bytes) ==="); + test_blocking_large_buffer(&mut i2c, slave_addr); + + info!("Blocking direct API tests OK"); + } + + Timer::after_millis(100).await; + + // ========== BLOCKING TRANSACTION TESTS ========== + info!("========== BLOCKING TRANSACTION TESTS =========="); + { + let mut i2c = I2c::new_blocking( + i2c_peri.reborrow(), + scl.reborrow(), + sda.reborrow(), + config, + ); + + info!("=== Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_blocking(&mut i2c, slave_addr); + + info!("=== Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_blocking(&mut i2c, slave_addr); + + info!("=== Test 8: Write then Read (RESTART) ==="); + test_write_then_read_blocking(&mut i2c, slave_addr); + + info!("=== Test 9: Read then Write (RESTART) ==="); + test_read_then_write_blocking(&mut i2c, slave_addr); + + info!("=== Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_blocking(&mut i2c, slave_addr); + + info!("=== Test 11: Single Operations ==="); + test_single_operations_blocking(&mut i2c, slave_addr); + + info!("Blocking transaction tests OK"); + } + + Timer::after_millis(100).await; + + // ========== ASYNC TESTS (DMA) ========== + info!("========== ASYNC TESTS (DMA) =========="); + { + let tx_dma = peri!(p, I2C_TX_DMA); + let rx_dma = peri!(p, I2C_RX_DMA); + let irq = irqs!(I2C); + + let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config); + + // Direct API tests (reusing same I2C instance) + info!("=== Direct API Test 1: write() ==="); + test_async_write(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 2: read() ==="); + test_async_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 3: write_read() ==="); + test_async_write_read(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 4: write_vectored() ==="); + test_async_write_vectored(&mut i2c, slave_addr).await; + + info!("=== Direct API Test 5: Large buffer (>255 bytes) ==="); + test_async_large_buffer(&mut i2c, slave_addr).await; + + info!("Async Direct API tests OK"); + + // Transaction tests + info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 8: Write then Read (RESTART) ==="); + test_write_then_read_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 9: Read then Write (RESTART) ==="); + test_read_then_write_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 10: Complex Mixed Sequence ==="); + test_mixed_sequence_async(&mut i2c, slave_addr).await; + + info!("=== Transaction Test 11: Single Operations ==="); + test_single_operations_async(&mut i2c, slave_addr).await; + + info!("Async transaction tests OK"); + } + + info!("All tests OK"); + cortex_m::asm::bkpt(); +} + +// ==================== BLOCKING DIRECT API TEST FUNCTIONS ==================== + +fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.blocking_write(addr, &write_data) { + Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ blocking_write failed: {:?}", e); + defmt::panic!("Test failed: blocking_write"); + } + } +} + +fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ blocking_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_read"); + } + } +} + +fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.blocking_write_read(addr, &write_data, &mut read_buf) { + Ok(_) => { + info!("✓ blocking_write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ blocking_write_read failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_read"); + } + } +} + +fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.blocking_write_vectored(addr, &bufs) { + Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ blocking_write_vectored failed: {:?}", e); + defmt::panic!("Test failed: blocking_write_vectored"); + } + } +} + +fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.blocking_write(addr, &write_buf) { + Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer write failed: {:?}", e); + defmt::panic!("Test failed: large buffer write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.blocking_read(addr, &mut read_buf) { + Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"), + Err(e) => { + error!("✗ Large buffer read failed: {:?}", e); + defmt::panic!("Test failed: large buffer read"); + } + } +} + +// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ==================== + +fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes - they should be merged + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads - they should be merged + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Complex: W, W, R, R, W, R + // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.blocking_transaction(addr, &mut ops) { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} + +// ==================== ASYNC DIRECT API TEST FUNCTIONS ==================== + +async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x42, 0x43, 0x44, 0x45]; + + match i2c.write(addr, &write_data).await { + Ok(_) => info!("✓ async write succeeded: {:02x}", write_data), + Err(e) => { + error!("✗ async write failed: {:?}", e); + defmt::panic!("Test failed: async write"); + } + } +} + +async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 8]; + + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf), + Err(e) => { + error!("✗ async read failed: {:?}", e); + defmt::panic!("Test failed: async read"); + } + } +} + +async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0x50, 0x51]; + let mut read_buf = [0u8; 6]; + + match i2c.write_read(addr, &write_data, &mut read_buf).await { + Ok(_) => { + info!("✓ async write_read succeeded"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ async write_read failed: {:?}", e); + defmt::panic!("Test failed: async write_read"); + } + } +} + +async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let buf1 = [0x60, 0x61, 0x62]; + let buf2 = [0x70, 0x71]; + let buf3 = [0x80, 0x81, 0x82, 0x83]; + let bufs = [&buf1[..], &buf2[..], &buf3[..]]; + + match i2c.write_vectored(addr.into(), &bufs).await { + Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"), + Err(e) => { + error!("✗ async write_vectored failed: {:?}", e); + defmt::panic!("Test failed: async write_vectored"); + } + } +} + +async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes) + let mut write_buf = [0u8; 300]; + for (i, byte) in write_buf.iter_mut().enumerate() { + *byte = (i & 0xFF) as u8; + } + + match i2c.write(addr, &write_buf).await { + Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async write failed: {:?}", e); + defmt::panic!("Test failed: large buffer async write"); + } + } + + // Test large read + let mut read_buf = [0u8; 300]; + match i2c.read(addr, &mut read_buf).await { + Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"), + Err(e) => { + error!("✗ Large buffer async read failed: {:?}", e); + defmt::panic!("Test failed: large buffer async read"); + } + } +} + +// ==================== ASYNC TRANSACTION TEST FUNCTIONS ==================== + +async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let data1 = [0x10, 0x11, 0x12]; + let data2 = [0x20, 0x21]; + let data3 = [0x30, 0x31, 0x32, 0x33]; + + let mut ops = [ + Operation::Write(&data1), + Operation::Write(&data2), + Operation::Write(&data3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"), + Err(e) => { + error!("✗ Consecutive writes failed: {:?}", e); + defmt::panic!("Test failed: consecutive writes"); + } + } +} + +async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut buf1 = [0u8; 4]; + let mut buf2 = [0u8; 3]; + let mut buf3 = [0u8; 2]; + + let mut ops = [ + Operation::Read(&mut buf1), + Operation::Read(&mut buf2), + Operation::Read(&mut buf3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Consecutive reads succeeded (merged 9 bytes)"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => { + error!("✗ Consecutive reads failed: {:?}", e); + defmt::panic!("Test failed: consecutive reads"); + } + } +} + +async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let write_data = [0xAA, 0xBB]; + let mut read_buf = [0u8; 4]; + + let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Write-then-read succeeded with RESTART"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => { + error!("✗ Write-then-read failed: {:?}", e); + defmt::panic!("Test failed: write-then-read"); + } + } +} + +async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let mut read_buf = [0u8; 3]; + let write_data = [0xCC, 0xDD, 0xEE]; + + let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Read-then-write succeeded with RESTART"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => { + error!("✗ Read-then-write failed: {:?}", e); + defmt::panic!("Test failed: read-then-write"); + } + } +} + +async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + let w1 = [0x01, 0x02]; + let w2 = [0x03, 0x04]; + let mut r1 = [0u8; 2]; + let mut r2 = [0u8; 2]; + let w3 = [0x05]; + let mut r3 = [0u8; 1]; + + let mut ops = [ + Operation::Write(&w1), + Operation::Write(&w2), + Operation::Read(&mut r1), + Operation::Read(&mut r2), + Operation::Write(&w3), + Operation::Read(&mut r3), + ]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => { + info!("✓ Mixed sequence succeeded"); + info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]"); + } + Err(e) => { + error!("✗ Mixed sequence failed: {:?}", e); + defmt::panic!("Test failed: mixed sequence"); + } + } +} + +async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) { + // Test single write + let write_data = [0xFF]; + let mut ops = [Operation::Write(&write_data)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single write succeeded"), + Err(e) => { + error!("✗ Single write failed: {:?}", e); + defmt::panic!("Test failed: single write"); + } + } + + // Test single read + let mut read_buf = [0u8; 1]; + let mut ops = [Operation::Read(&mut read_buf)]; + + match i2c.transaction(addr, &mut ops).await { + Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]), + Err(e) => { + error!("✗ Single read failed: {:?}", e); + defmt::panic!("Test failed: single read"); + } + } +} -- cgit