From 86a4cfb6bf9cbf4c75184a0eb278bcc46d7ddc47 Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Mon, 6 Apr 2026 15:24:55 -0700 Subject: [PATCH 1/4] Add slave event for rx and tx received at the same time. Update i2c master test. --- Cargo.toml | 1 + src/i2c_core/slave.rs | 15 +- src/main.rs | 31 ++-- src/tests/functional/i2c_master_slave_test.rs | 155 +++++++++++++++--- src/tests/functional/i2c_test.rs | 2 +- 5 files changed, 170 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56591bd..7e69586 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ edition = "2021" default = [] std = [] isr-handlers = [] # Export ISR handlers with #[no_mangle] - disable for kernel integration +i2c_master = [] i2c_target = [] i3c_master = [] i3c_target = [] diff --git a/src/i2c_core/slave.rs b/src/i2c_core/slave.rs index 63ab7c6..f85e9b1 100644 --- a/src/i2c_core/slave.rs +++ b/src/i2c_core/slave.rs @@ -52,6 +52,8 @@ pub enum SlaveEvent { DataReceived { len: usize }, /// Data sent to master DataSent { len: usize }, + /// Data received from master and send data to master (combined event) + DataReceivedAndSent { rx_len: usize, tx_len: usize }, /// Stop condition received Stop, } @@ -385,8 +387,17 @@ impl Ast1060I2c<'_> { | constants::AST_I2CS_WAIT_TX_DMA { // S: rx_done | wait_tx - return Some(SlaveEvent::DataSent { - len: usize::from(self.regs().i2cc0c().read().tx_data_byte_count().bits() + 1), + return Some(SlaveEvent::DataReceivedAndSent { + rx_len: usize::from( + self.regs() + .i2cc0c() + .read() + .actual_rxd_pool_buffer_size() + .bits(), + ), + tx_len: usize::from( + self.regs().i2cc0c().read().tx_data_byte_count().bits() + 1, + ), }); } else if sts == constants::AST_I2CS_SLAVE_MATCH | constants::AST_I2CS_WAIT_TX_DMA { // S: Sw | wait_tx diff --git a/src/main.rs b/src/main.rs index 0b2bef6..f8296e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,9 @@ use aspeed_ddk::tests::functional::ecdsa_test::run_ecdsa_tests; use aspeed_ddk::tests::functional::hash_test::run_hash_tests; use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests; use aspeed_ddk::tests::functional::i2c_core_test::run_i2c_core_tests; -use aspeed_ddk::tests::functional::i2c_master_slave_test::run_master_slave_tests; +#[cfg(any(feature = "i2c_master", feature = "i2c_target"))] +use aspeed_ddk::tests::functional::i2c_master_slave_test; +#[cfg(any(feature = "i2c_master", feature = "i2c_target"))] use aspeed_ddk::tests::functional::i2c_test; #[cfg(any(feature = "i3c_master", feature = "i3c_target"))] use aspeed_ddk::tests::functional::i3c_test; @@ -386,27 +388,32 @@ fn main() -> ! { run_rsa_tests(&mut uart_controller, &mut rsa); gpio_test::test_gpioa(&mut uart_controller); - i2c_test::test_i2c_master(&mut uart_controller); - #[cfg(feature = "i2c_target")] - i2c_test::test_i2c_slave(&mut uart_controller); + let i2c_test_hw = false; + if i2c_test_hw { + //I2C test on real hardware + #[cfg(feature = "i2c_master")] + i2c_test::test_i2c_master(&mut uart_controller); + #[cfg(feature = "i2c_target")] + i2c_test::test_i2c_slave(&mut uart_controller); + } #[cfg(feature = "i3c_master")] i3c_test::test_i3c_master(&mut uart_controller); #[cfg(feature = "i3c_target")] i3c_test::test_i3c_target(&mut uart_controller); - // Run i2c_core functional tests - run_i2c_core_tests(&mut uart_controller); - { + let i2c_core_test_hw = false; + if i2c_core_test_hw { //I2C core test on real hardware i2c_core::init_i2c_global(); - //run_master_tests(&mut uart_controller); + #[cfg(feature = "i2c_master")] + i2c_master_slave_test::run_master_tests(&mut uart_controller); #[cfg(feature = "i2c_target")] - run_slave_tests(&mut uart_controller); + i2c_master_slave_test::run_slave_tests(&mut uart_controller); + } else { + // Run i2c_core functional tests + run_i2c_core_tests(&mut uart_controller); } - // Run I2C master-slave hardware integration tests - run_master_slave_tests(&mut uart_controller); - test_wdt(&mut uart_controller); run_timer_tests(&mut uart_controller); diff --git a/src/tests/functional/i2c_master_slave_test.rs b/src/tests/functional/i2c_master_slave_test.rs index ceca9ed..7075058 100644 --- a/src/tests/functional/i2c_master_slave_test.rs +++ b/src/tests/functional/i2c_master_slave_test.rs @@ -62,6 +62,8 @@ use embedded_io::Write; /// I2C controller for master tests (I2C1 - connected to ADT7490) const I2C_MASTER_CTRL_ID: u8 = 1; +/// I2C controller for master tests (I2C2 - connected to ast1060 i2c slave) +const I2C_MASTER2_CTRL_ID: u8 = 2; /// I2C controller for slave tests const I2C_SLAVE_CTRL_ID: u8 = 2; @@ -124,15 +126,24 @@ impl TestResults { /// Tests the `i2c_core` API by reading known registers from the on-board ADT7490. /// This mirrors the original `i2c_test.rs` functionality. pub fn run_master_tests(uart: &mut UartController<'_>) { - let _ = writeln!(uart, "\n========================================\r"); - let _ = writeln!(uart, "I2C MASTER Tests (i2c_core API)\r"); - let _ = writeln!(uart, "Using ADT7490 @ 0x{ADT7490_ADDRESS:02X}\r"); - let _ = writeln!(uart, "========================================\n\r"); - let mut results = TestResults::new(); - test_adt7490_register_reads(uart, &mut results); - test_adt7490_write_read(uart, &mut results); + if false { + let _ = writeln!(uart, "\n========================================\r"); + let _ = writeln!(uart, "I2C MASTER Tests (i2c_core API)\r"); + let _ = writeln!(uart, "Using ADT7490 @ 0x{ADT7490_ADDRESS:02X}\r"); + let _ = writeln!(uart, "========================================\n\r"); + + test_adt7490_register_reads(uart, &mut results); + test_adt7490_write_read(uart, &mut results); + } else { + let _ = writeln!(uart, "\n========================================\r"); + let _ = writeln!(uart, "I2C MASTER Tests (i2c_core API)\r"); + let _ = writeln!(uart, "Using i2c slave @ 0x{SLAVE_ADDRESS:02X}\r"); + let _ = writeln!(uart, "========================================\n\r"); + + test_ast1060_i2c_slave_write_read(uart, &mut results); + } let (passed, failed) = results.summary(); let _ = writeln!(uart, "\n========================================\r"); @@ -299,6 +310,96 @@ fn test_adt7490_write_read(uart: &mut UartController<'_>, results: &mut TestResu } } +/// Test write-read sequence to slave tests +fn test_ast1060_i2c_slave_write_read(uart: &mut UartController<'_>, results: &mut TestResults) { + let _ = writeln!(uart, "\n[TEST] Write-Read Sequence\r"); + + unsafe { + let peripherals = Peripherals::steal(); + pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_I2C2); + + // Get I2C2 registers + let i2c_regs = &peripherals.i2c2; + let buff_regs = &peripherals.i2cbuff2; + + let Some(controller_id) = Controller::new(I2C_MASTER2_CTRL_ID) else { + let _ = writeln!(uart, " [FAIL] Invalid controller ID\r"); + results.fail(); + return; + }; + + let controller = I2cController { + controller: controller_id, + registers: i2c_regs, + buff_registers: buff_regs, + }; + + let config = I2cConfig { + speed: I2cSpeed::Standard, + xfer_mode: I2cXferMode::BufferMode, + multi_master: true, + smbus_timeout: true, + smbus_alert: false, + clock_config: ClockConfig::ast1060_default(), + }; + + let mut i2c = match Ast1060I2c::new(&controller, config) { + Ok(m) => m, + Err(e) => { + let _ = writeln!(uart, " [FAIL] Init error: {e:?}\r"); + results.fail(); + return; + } + }; + + // write to address 0x3d + let write_buf = [0x3D, 0xAB]; + + let _ = writeln!(uart, " Writing to reg 0x3D...\r"); + + match i2c.write(SLAVE_ADDRESS, &write_buf) { + Ok(()) => {} + Err(e) => { + let _ = writeln!(uart, " [FAIL] Write address: {e:?}\r"); + results.fail(); + return; + } + } + + // Read Device address (0x3D) + let reg_addr = [0x3D]; + let mut read_buf = [0u8; 1]; + + let _ = writeln!(uart, " Reading reg 0x3D...\r"); + + match i2c.write(SLAVE_ADDRESS, ®_addr) { + Ok(()) => {} + Err(e) => { + let _ = writeln!(uart, " [FAIL] Write address: {e:?}\r"); + results.fail(); + return; + } + } + + //Small delay + for _ in 0..1000 { + core::hint::spin_loop(); + } + + match i2c.read(SLAVE_ADDRESS, &mut read_buf) { + Ok(()) => { + let _ = writeln!(uart, " read value: 0x{:02X}\r", read_buf[0]); + let _ = writeln!(uart, " [PASS] Write-Read sequence completed\r"); + results.pass(); + } + Err(e) => { + let _ = writeln!(uart, " [FAIL] Read: {e:?}\r"); + results.fail(); + } + } + } +} + // ============================================================================ // SLAVE Tests - External Master Required // ============================================================================ @@ -416,6 +517,19 @@ fn slave_event_loop(uart: &mut UartController<'_>, slave: &mut Ast1060I2c<'_>) { let _ = slave.slave_write(&TEST_PATTERN_READ); transaction_count += 1; } + SlaveEvent::DataReceivedAndSent { rx_len, tx_len } => { + let _ = writeln!( + uart, + "[SLAVE] Received {rx_len} bytes, Sent {tx_len} bytes\r" + ); + let mut buf = [0u8; 32]; + if let Ok(n) = slave.slave_read(&mut buf) { + let _ = writeln!(uart, " Data: {:02X?}\r", &buf[..n]); + } + let _ = writeln!(uart, "sending {:02X?}\r", &TEST_PATTERN_READ[..tx_len]); + let _ = slave.slave_write(&TEST_PATTERN_READ); + transaction_count += 1; + } SlaveEvent::Stop => { let _ = writeln!(uart, "[SLAVE] Stop condition\r"); } @@ -453,24 +567,27 @@ fn slave_event_loop(uart: &mut UartController<'_>, slave: &mut Ast1060I2c<'_>) { /// Print test setup information pub fn run_master_slave_tests(uart: &mut UartController<'_>) { - let _ = writeln!(uart, "\n========================================"); - let _ = writeln!(uart, "I2C Hardware Integration Tests (i2c_core)"); - let _ = writeln!(uart, "========================================"); + let _ = writeln!(uart, "\n========================================\r"); + let _ = writeln!(uart, "I2C Hardware Integration Tests (i2c_core)\r"); + let _ = writeln!(uart, "========================================\r"); let _ = writeln!(uart); - let _ = writeln!(uart, "MASTER TESTS: run_master_tests()"); + let _ = writeln!(uart, "MASTER TESTS: run_master_tests()\r"); let _ = writeln!( uart, - " - Uses on-board ADT7490 temp sensor @ 0x{ADT7490_ADDRESS:02X}" + " - Uses on-board ADT7490 temp sensor @ 0x{ADT7490_ADDRESS:02X}\r" ); - let _ = writeln!(uart, " - Reads known registers and verifies defaults"); - let _ = writeln!(uart, " - No external hardware needed"); + let _ = writeln!(uart, " - Reads known registers and verifies defaults\r"); + let _ = writeln!(uart, " - No external hardware needed\r"); let _ = writeln!(uart); - let _ = writeln!(uart, "SLAVE TESTS: run_slave_tests()"); + let _ = writeln!(uart, "SLAVE TESTS: run_slave_tests()\r"); + let _ = writeln!( + uart, + " - Configures AST1060 as I2C slave @ 0x{SLAVE_ADDRESS:02X}\r" + ); let _ = writeln!( uart, - " - Configures AST1060 as I2C slave @ 0x{SLAVE_ADDRESS:02X}" + " - Requires external master (AST2600, another EVB)\r" ); - let _ = writeln!(uart, " - Requires external master (AST2600, another EVB)"); - let _ = writeln!(uart, " - Start slave first, then master initiates"); - let _ = writeln!(uart, "========================================\n"); + let _ = writeln!(uart, " - Start slave first, then master initiates\r"); + let _ = writeln!(uart, "========================================\r\n"); } diff --git a/src/tests/functional/i2c_test.rs b/src/tests/functional/i2c_test.rs index 07a7f18..7a79752 100644 --- a/src/tests/functional/i2c_test.rs +++ b/src/tests/functional/i2c_test.rs @@ -235,7 +235,7 @@ static mut TEST_TARGET: DummyI2CTarget = DummyI2CTarget { pub fn test_i2c_slave(uart: &mut UartController<'_>) { writeln!(uart, "\r\n####### I2C slave test #######\r\n").unwrap(); - let peripherals = unsafe { Peripherals::steal() }; + let _peripherals = unsafe { Peripherals::steal() }; unsafe { let uart_regs = &*ast1060_pac::Uart::ptr(); let mut dbg_uart = UartController::new(uart_regs); From 4da0105d94323886a10fd3d14e7149016ba4da4b Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Wed, 8 Apr 2026 16:54:31 -0700 Subject: [PATCH 2/4] slave interrupt enable and clear fix. --- src/i2c_core/constants.rs | 2 ++ src/i2c_core/slave.rs | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/i2c_core/constants.rs b/src/i2c_core/constants.rs index 6027faa..d8c51f9 100644 --- a/src/i2c_core/constants.rs +++ b/src/i2c_core/constants.rs @@ -148,6 +148,8 @@ pub const AST_I2CS_RX_DONE: u32 = 1 << 2; pub const AST_I2CS_TX_NAK: u32 = 1 << 1; /// Slave TX got ACK pub const AST_I2CS_TX_ACK: u32 = 1 << 0; +/// Slave inactive timeout +pub const AST_I2CS_INACTIVE_TO: u32 = 1 << 15; /// Slave packet mode done pub const AST_I2CS_PKT_DONE: u32 = 1 << 16; /// Slave packet mode error diff --git a/src/i2c_core/slave.rs b/src/i2c_core/slave.rs index f85e9b1..a2066c0 100644 --- a/src/i2c_core/slave.rs +++ b/src/i2c_core/slave.rs @@ -168,11 +168,17 @@ impl Ast1060I2c<'_> { /// Enable slave mode interrupts fn enable_slave_interrupts(&mut self) { - let mask = constants::AST_I2CS_PKT_DONE - | constants::AST_I2CS_PKT_ERROR - | constants::AST_I2CS_RX_DONE - | constants::AST_I2CS_SLAVE_MATCH - | constants::AST_I2CS_STOP; + let mut mask = 0u32; + if self.xfer_mode == I2cXferMode::BufferMode { + mask = constants::AST_I2CS_PKT_DONE + | constants::AST_I2CS_INACTIVE_TO + | constants::AST_I2CM_ABNORMAL + | constants::AST_I2CM_NORMAL_STOP + | constants::AST_I2CM_RX_DONE + | constants::AST_I2CM_TX_ACK; + } else { + mask = constants::AST_I2CS_PKT_DONE | constants::AST_I2CS_INACTIVE_TO; + } unsafe { self.regs().i2cs20().write(|w| w.bits(mask)); @@ -183,6 +189,7 @@ impl Ast1060I2c<'_> { fn clear_slave_interrupts(&mut self) { unsafe { self.regs().i2cs24().write(|w| w.bits(0xFFFF_FFFF)); + let _ = self.regs().i2cs24().read().bits(); } } From 89a10af999f85176f20c6d1264466acc78696aa3 Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Wed, 8 Apr 2026 16:57:48 -0700 Subject: [PATCH 3/4] Add delay in i2c master polling --- src/i2c_core/controller.rs | 5 +++++ src/tests/functional/i2c_master_slave_test.rs | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/i2c_core/controller.rs b/src/i2c_core/controller.rs index 6925de4..d801b21 100644 --- a/src/i2c_core/controller.rs +++ b/src/i2c_core/controller.rs @@ -2,6 +2,9 @@ //! AST1060 I2C controller implementation +use crate::common::DummyDelay; +use embedded_hal::delay::DelayNs; + use super::timing::configure_timing; use super::types::{I2cConfig, I2cController, I2cXferMode}; use super::{constants, error::I2cError}; @@ -185,12 +188,14 @@ impl<'a> Ast1060I2c<'a> { /// Wait for completion with timeout (visible to master/transfer modules) pub(crate) fn wait_completion(&mut self, timeout_us: u32) -> Result<(), I2cError> { + let mut delay = DummyDelay {}; let mut timeout = timeout_us; self.completion = false; while timeout > 0 && !self.completion { self.handle_interrupt()?; timeout = timeout.saturating_sub(1); + delay.delay_ns(100_000); } if self.completion { diff --git a/src/tests/functional/i2c_master_slave_test.rs b/src/tests/functional/i2c_master_slave_test.rs index 7075058..b63eadd 100644 --- a/src/tests/functional/i2c_master_slave_test.rs +++ b/src/tests/functional/i2c_master_slave_test.rs @@ -380,12 +380,6 @@ fn test_ast1060_i2c_slave_write_read(uart: &mut UartController<'_>, results: &mu return; } } - - //Small delay - for _ in 0..1000 { - core::hint::spin_loop(); - } - match i2c.read(SLAVE_ADDRESS, &mut read_buf) { Ok(()) => { let _ = writeln!(uart, " read value: 0x{:02X}\r", read_buf[0]); From 8488085125a92b19ddf6e72b028b8916e6f1547e Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Wed, 8 Apr 2026 17:07:24 -0700 Subject: [PATCH 4/4] Fix clippy error. --- src/i2c_core/slave.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/i2c_core/slave.rs b/src/i2c_core/slave.rs index a2066c0..1d88ed5 100644 --- a/src/i2c_core/slave.rs +++ b/src/i2c_core/slave.rs @@ -168,16 +168,12 @@ impl Ast1060I2c<'_> { /// Enable slave mode interrupts fn enable_slave_interrupts(&mut self) { - let mut mask = 0u32; + let mut mask = constants::AST_I2CS_PKT_DONE | constants::AST_I2CS_INACTIVE_TO; if self.xfer_mode == I2cXferMode::BufferMode { - mask = constants::AST_I2CS_PKT_DONE - | constants::AST_I2CS_INACTIVE_TO - | constants::AST_I2CM_ABNORMAL + mask |= constants::AST_I2CM_ABNORMAL | constants::AST_I2CM_NORMAL_STOP | constants::AST_I2CM_RX_DONE | constants::AST_I2CM_TX_ACK; - } else { - mask = constants::AST_I2CS_PKT_DONE | constants::AST_I2CS_INACTIVE_TO; } unsafe {