From aa5c0c02425104fceea9e5dc773e3f5c346e9656 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 09:49:25 +0100 Subject: stm32/i2c_v2: Add transaction test --- examples/stm32f0/Cargo.toml | 1 + examples/stm32f0/src/bin/i2c_transaction_test.rs | 219 +++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 examples/stm32f0/src/bin/i2c_transaction_test.rs (limited to 'examples') 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"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f0/src/bin/i2c_transaction_test.rs b/examples/stm32f0/src/bin/i2c_transaction_test.rs new file mode 100644 index 000000000..0ecc3e8b1 --- /dev/null +++ b/examples/stm32f0/src/bin/i2c_transaction_test.rs @@ -0,0 +1,219 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // For STM32F072RB on NUCLEO board + let p = embassy_stm32::init(Default::default()); + + info!("I2C Transaction Test Starting..."); + + // Initialize I2C1: PB6=SCL, PB7=SDA + let mut config = Config::default(); + config.frequency = Hertz(100_000); + let mut i2c = I2c::new_blocking( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + config, + ); + + let slave_addr = 0x50u8; + + // Wait for devices to initialize + Timer::after_millis(100).await; + + info!("=== Test 1: Consecutive Writes (Should Merge) ==="); + test_consecutive_writes(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 2: Consecutive Reads (Should Merge) ==="); + test_consecutive_reads(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 3: Write then Read (RESTART) ==="); + test_write_then_read(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 4: Read then Write (RESTART) ==="); + test_read_then_write(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 5: Complex Mixed Sequence ==="); + test_mixed_sequence(&mut i2c, slave_addr); + Timer::after_millis(500).await; + + info!("=== Test 6: Single Operations ==="); + test_single_operations(&mut i2c, slave_addr); + + info!("All tests complete!"); + + loop { + Timer::after_secs(1).await; + } +} + +fn test_consecutive_writes(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+W, data1, data2, data3, STOP + // NO intermediate RESTART/STOP between writes + 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"), + Err(e) => warn!("✗ Consecutive writes failed: {:?}", e), + } + + info!("Expected: START, ADDR+W, [9 bytes], STOP"); + info!("Check Analog Discovery: No RESTART between writes"); +} + +fn test_consecutive_reads(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { + // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP + // NO intermediate RESTART/STOP between reads + 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"); + info!(" buf1: {:02x}", buf1); + info!(" buf2: {:02x}", buf2); + info!(" buf3: {:02x}", buf3); + } + Err(e) => warn!("✗ Consecutive reads failed: {:?}", e), + } + + info!("Expected: START, ADDR+R, [9 bytes], NACK on last, STOP"); + info!("Check Analog Discovery: No RESTART between reads"); +} + +fn test_write_then_read(i2c: &mut I2c<'static, 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"); + info!(" Written: {:02x}", write_data); + info!(" Read: {:02x}", read_buf); + } + Err(e) => warn!("✗ Write-then-read failed: {:?}", e), + } + + info!("Expected: START, ADDR+W, [2 bytes], RESTART, ADDR+R, [4 bytes], NACK, STOP"); + info!("Check Analog Discovery: RESTART between write and read"); +} + +fn test_read_then_write(i2c: &mut I2c<'static, 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"); + info!(" Read: {:02x}", read_buf); + info!(" Written: {:02x}", write_data); + } + Err(e) => warn!("✗ Read-then-write failed: {:?}", e), + } + + info!("Expected: START, ADDR+R, [3 bytes], NACK, RESTART, ADDR+W, [3 bytes], STOP"); + info!("Check Analog Discovery: RESTART between read and write"); +} + +fn test_mixed_sequence(i2c: &mut I2c<'static, 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!(" r1: {:02x}", r1); + info!(" r2: {:02x}", r2); + info!(" r3: {:02x}", r3); + } + Err(e) => warn!("✗ Mixed sequence failed: {:?}", e), + } + + info!("Expected sequence:"); + info!(" START, ADDR+W, [4 bytes merged], RESTART,"); + info!(" ADDR+R, [4 bytes merged], NACK, RESTART,"); + info!(" ADDR+W, [1 byte], RESTART,"); + info!(" ADDR+R, [1 byte], NACK, STOP"); +} + +fn test_single_operations(i2c: &mut I2c<'static, 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) => warn!("✗ Single write failed: {:?}", e), + } + + // 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) => warn!("✗ Single read failed: {:?}", e), + } +} -- cgit From 973fdb6b222a24e881c722b33767aab76ab92896 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 12 Nov 2025 21:02:10 +0100 Subject: stm32: Add i2c v2 transaction test --- examples/stm32f0/Cargo.toml | 1 - examples/stm32f0/src/bin/i2c_transaction_test.rs | 219 ----------------------- 2 files changed, 220 deletions(-) delete mode 100644 examples/stm32f0/src/bin/i2c_transaction_test.rs (limited to 'examples') diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 177dd0ac2..a78873d21 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,7 +16,6 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f0/src/bin/i2c_transaction_test.rs b/examples/stm32f0/src/bin/i2c_transaction_test.rs deleted file mode 100644 index 0ecc3e8b1..000000000 --- a/examples/stm32f0/src/bin/i2c_transaction_test.rs +++ /dev/null @@ -1,219 +0,0 @@ -#![no_std] -#![no_main] - -use defmt::*; -use embassy_executor::Spawner; -use embassy_stm32::i2c::{Config, I2c, Master}; -use embassy_stm32::mode::Blocking; -use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; -use embassy_time::Timer; -use embedded_hal_1::i2c::Operation; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - // For STM32F072RB on NUCLEO board - let p = embassy_stm32::init(Default::default()); - - info!("I2C Transaction Test Starting..."); - - // Initialize I2C1: PB6=SCL, PB7=SDA - let mut config = Config::default(); - config.frequency = Hertz(100_000); - let mut i2c = I2c::new_blocking( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA - config, - ); - - let slave_addr = 0x50u8; - - // Wait for devices to initialize - Timer::after_millis(100).await; - - info!("=== Test 1: Consecutive Writes (Should Merge) ==="); - test_consecutive_writes(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 2: Consecutive Reads (Should Merge) ==="); - test_consecutive_reads(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 3: Write then Read (RESTART) ==="); - test_write_then_read(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 4: Read then Write (RESTART) ==="); - test_read_then_write(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 5: Complex Mixed Sequence ==="); - test_mixed_sequence(&mut i2c, slave_addr); - Timer::after_millis(500).await; - - info!("=== Test 6: Single Operations ==="); - test_single_operations(&mut i2c, slave_addr); - - info!("All tests complete!"); - - loop { - Timer::after_secs(1).await; - } -} - -fn test_consecutive_writes(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+W, data1, data2, data3, STOP - // NO intermediate RESTART/STOP between writes - 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"), - Err(e) => warn!("✗ Consecutive writes failed: {:?}", e), - } - - info!("Expected: START, ADDR+W, [9 bytes], STOP"); - info!("Check Analog Discovery: No RESTART between writes"); -} - -fn test_consecutive_reads(i2c: &mut I2c<'static, Blocking, Master>, addr: u8) { - // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP - // NO intermediate RESTART/STOP between reads - 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"); - info!(" buf1: {:02x}", buf1); - info!(" buf2: {:02x}", buf2); - info!(" buf3: {:02x}", buf3); - } - Err(e) => warn!("✗ Consecutive reads failed: {:?}", e), - } - - info!("Expected: START, ADDR+R, [9 bytes], NACK on last, STOP"); - info!("Check Analog Discovery: No RESTART between reads"); -} - -fn test_write_then_read(i2c: &mut I2c<'static, 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"); - info!(" Written: {:02x}", write_data); - info!(" Read: {:02x}", read_buf); - } - Err(e) => warn!("✗ Write-then-read failed: {:?}", e), - } - - info!("Expected: START, ADDR+W, [2 bytes], RESTART, ADDR+R, [4 bytes], NACK, STOP"); - info!("Check Analog Discovery: RESTART between write and read"); -} - -fn test_read_then_write(i2c: &mut I2c<'static, 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"); - info!(" Read: {:02x}", read_buf); - info!(" Written: {:02x}", write_data); - } - Err(e) => warn!("✗ Read-then-write failed: {:?}", e), - } - - info!("Expected: START, ADDR+R, [3 bytes], NACK, RESTART, ADDR+W, [3 bytes], STOP"); - info!("Check Analog Discovery: RESTART between read and write"); -} - -fn test_mixed_sequence(i2c: &mut I2c<'static, 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!(" r1: {:02x}", r1); - info!(" r2: {:02x}", r2); - info!(" r3: {:02x}", r3); - } - Err(e) => warn!("✗ Mixed sequence failed: {:?}", e), - } - - info!("Expected sequence:"); - info!(" START, ADDR+W, [4 bytes merged], RESTART,"); - info!(" ADDR+R, [4 bytes merged], NACK, RESTART,"); - info!(" ADDR+W, [1 byte], RESTART,"); - info!(" ADDR+R, [1 byte], NACK, STOP"); -} - -fn test_single_operations(i2c: &mut I2c<'static, 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) => warn!("✗ Single write failed: {:?}", e), - } - - // 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) => warn!("✗ Single read failed: {:?}", e), - } -} -- cgit From 2553ced205d49d2890e000069f5a170b75d267a9 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 13 Nov 2025 14:36:31 +0100 Subject: stm32: Move i2c_master test to examples --- examples/stm32f0/Cargo.toml | 1 + examples/stm32f0/src/bin/i2c_master.rs | 609 +++++++++++++++++++++++++++++++++ 2 files changed, 610 insertions(+) create mode 100644 examples/stm32f0/src/bin/i2c_master.rs (limited to 'examples') 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"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 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 @@ +#![no_std] +#![no_main] + +// 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 + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Config, I2c, Master}; +use embassy_stm32::mode::{Async, Blocking}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use embassy_time::Timer; +use embedded_hal_1::i2c::Operation; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Run stm32 I2C v2 Master Tests..."); + + let mut i2c_peri = p.I2C1; + let mut scl = p.PB8; + let mut sda = p.PB9; + + 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 = p.DMA1_CH2; + let rx_dma = p.DMA1_CH3; + + let mut i2c = I2c::new(i2c_peri, scl, sda, Irqs, 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