#![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"); } } }