i2c check 1
diff --git a/apps/i2c-slave-echo/src/main.rs b/apps/i2c-slave-echo/src/main.rs
index ef2d6b9..7fdc094 100644
--- a/apps/i2c-slave-echo/src/main.rs
+++ b/apps/i2c-slave-echo/src/main.rs
@@ -67,7 +67,9 @@
     let mut reg_ptr: u8 = 0;
 
     // Pre-load the initial read response.
-    let _ = client.slave_set_response(SLAVE_BUS, &[reg_map[reg_ptr as usize]]);
+    if let Err(_) = client.slave_set_response(SLAVE_BUS, &[reg_map[reg_ptr as usize]]) {
+        pw_log::error!("Initial slave_set_response failed");
+    }
 
     let mut rx_buf = [0u8; 32];
 
@@ -87,7 +89,9 @@
                              reg_ptr as u32,
                              val as u32,
                          );
-                        let _ = client.slave_set_response(SLAVE_BUS, &[val]);
+                        if let Err(_) = client.slave_set_response(SLAVE_BUS, &[val]) {
+                            pw_log::error!("slave_set_response failed");
+                        }
                     }
                     _ => {
                         // Write: byte 0 = register address, byte 1 = value.
@@ -100,7 +104,9 @@
                              val as u32,
                          );
                          //Update read response in case master reads back immediately.
-                        let _ = client.slave_set_response(SLAVE_BUS, &[val]);
+                        if let Err(_) = client.slave_set_response(SLAVE_BUS, &[val]) {
+                            pw_log::error!("slave_set_response failed");
+                        }
                     }
                 }
             }
diff --git a/services/i2c/backend-aspeed/src/lib.rs b/services/i2c/backend-aspeed/src/lib.rs
index 86a4343..46885f6 100644
--- a/services/i2c/backend-aspeed/src/lib.rs
+++ b/services/i2c/backend-aspeed/src/lib.rs
@@ -342,9 +342,37 @@
         if !self.is_bus_initialized(bus) {
             return Err(ResponseCode::ServerError);
         }
+        if (self.slave_configured & (1 << bus)) == 0 {
+            return Err(ResponseCode::NotInitialized);
+        }
+
         let len = data.len().min(SLAVE_TX_BUF_SIZE);
         self.slave_tx_bufs[bus as usize][..len].copy_from_slice(&data[..len]);
         self.slave_tx_lens[bus as usize] = len;
+
+        // Pre-load the hardware TX buffer and length register so it's ready for the next
+        // master read. We do NOT set AST_I2CS_TX_BUFF_EN here because that would put the
+        // slave into TX mode and prevent it from receiving writes. The TX_BUFF_EN flag
+        // will be set later when we detect a ReadRequest event.
+        let (regs, buffs) = self.controller_regs(bus)?;
+
+        // Manually pre-load TX buffer without triggering transmission.
+        // Only copy 1 byte to match the DDK's current limitation.
+        let to_write = 1.min(len);
+        if to_write > 0 {
+            // Write directly to hardware buffer register (first DWORD)
+            // The buffer is organized as 8 DWORDs, each holding up to 4 bytes
+            unsafe {
+                buffs.buff(0).write(|w| w.bits(data[0] as u32));
+
+                // Set transfer length register (tx_data_byte_count = len - 1)
+                regs.i2cc0c()
+                    .modify(|_, w| w.tx_data_byte_count().bits((to_write - 1) as u8));
+            }
+            // Note: We do NOT set AST_I2CS_TX_BUFF_EN here - that happens in slave_wait_event
+            // when ReadRequest is detected, to avoid blocking RX operations.
+        }
+
         Ok(())
     }
 
@@ -390,6 +418,8 @@
                     return Ok((SlaveEventKind::DataReceived, n));
                 }
                 Some(SlaveEvent::ReadRequest) => {
+                    // Hardware should already have the TX buffer armed from slave_set_response(),
+                    // but call slave_write() as a fallback in case the timing worked out.
                     let _ = i2c.slave_write(&tx_local[..tx_len]);
                     return Ok((SlaveEventKind::ReadRequest, 0));
                 }
diff --git a/target/ast1060-evb/harness/uart_test_exec.py b/target/ast1060-evb/harness/uart_test_exec.py
index 10bab93..e7ada83 100644
--- a/target/ast1060-evb/harness/uart_test_exec.py
+++ b/target/ast1060-evb/harness/uart_test_exec.py
@@ -13,6 +13,7 @@
 import base64
 import binascii
 import os
+import signal
 import subprocess
 import sys
 import time
@@ -302,17 +303,21 @@
         start_time = time.time()
         buffer = b""
 
-        while time.time() - start_time < timeout:
-            data = self.read_serial_data(0.1)
-            if data:
-                buffer += data
-                if not self.args.quiet:
-                    self.print_uart_data(data)
+        try:
+            while time.time() - start_time < timeout:
+                data = self.read_serial_data(0.1)
+                if data:
+                    buffer += data
+                    if not self.args.quiet:
+                        self.print_uart_data(data)
 
-                # Look for 'U' character
-                if b"U" in buffer:
-                    self.log("\nUART bootloader ready detected!")
-                    return True
+                    # Look for 'U' character
+                    if b"U" in buffer:
+                        self.log("\nUART bootloader ready detected!")
+                        return True
+        except KeyboardInterrupt:
+            self.log("\nInterrupted while waiting for UART ready")
+            raise
 
         self.log("\nTimeout waiting for UART ready signal")
         return False
@@ -343,20 +348,26 @@
             chunk_size = 1024
             bytes_sent = 0
 
-            for i in range(0, len(firmware_data), chunk_size):
-                chunk = firmware_data[i : i + chunk_size]
+            try:
+                for i in range(0, len(firmware_data), chunk_size):
+                    chunk = firmware_data[i : i + chunk_size]
 
-                if not self.write_serial_data(chunk):
-                    self.log("Failed to write firmware chunk")
-                    return False
+                    if not self.write_serial_data(chunk):
+                        self.log("Failed to write firmware chunk")
+                        return False
 
-                bytes_sent += len(chunk)
-                time.sleep(0.01)
+                    bytes_sent += len(chunk)
+                    time.sleep(0.01)
 
-                # Progress indicator
-                if not self.args.quiet and bytes_sent % (chunk_size * 10) == 0:
-                    progress = (bytes_sent * 100) // len(firmware_data)
-                    print(f"\rProgress: {progress}%", end="", flush=True)
+                    # Progress indicator
+                    if not self.args.quiet and bytes_sent % (chunk_size * 10) == 0:
+                        progress = (bytes_sent * 100) // len(firmware_data)
+                        print(f"\rProgress: {progress}%", end="", flush=True)
+            except KeyboardInterrupt:
+                if not self.args.quiet:
+                    print()
+                self.log("Firmware upload interrupted")
+                raise
 
             if not self.args.quiet:
                 print()
@@ -364,6 +375,8 @@
             self.log("Firmware upload completed")
             return True
 
+        except KeyboardInterrupt:
+            raise
         except Exception as e:
             self.log(f"Failed to upload firmware: {e}")
             return False
@@ -385,37 +398,41 @@
         line_buffer = ""
         test_results = {"passed": 0, "failed": 0, "skipped": 0}
 
-        while time.time() - start_time < actual_timeout:
-            data = self.read_serial_data(0.5)
-            if data:
-                if not self.args.quiet:
-                    self.print_uart_data(data)
+        try:
+            while time.time() - start_time < actual_timeout:
+                data = self.read_serial_data(0.5)
+                if data:
+                    if not self.args.quiet:
+                        self.print_uart_data(data)
 
-                line_buffer += data.decode("utf-8", errors="replace")
-                lines = line_buffer.split("\n")
-                # Keep the last (possibly incomplete) line in the buffer
-                line_buffer = lines[-1]
+                    line_buffer += data.decode("utf-8", errors="replace")
+                    lines = line_buffer.split("\n")
+                    # Keep the last (possibly incomplete) line in the buffer
+                    line_buffer = lines[-1]
 
-                for line in lines[:-1]:
-                    if "PASS" in line:
-                        test_results["passed"] += 1
-                    elif "FAIL" in line:
-                        test_results["failed"] += 1
-                    elif "SKIP" in line:
-                        test_results["skipped"] += 1
+                    for line in lines[:-1]:
+                        if "PASS" in line:
+                            test_results["passed"] += 1
+                        elif "FAIL" in line:
+                            test_results["failed"] += 1
+                        elif "SKIP" in line:
+                            test_results["skipped"] += 1
 
-                    # Check for completion
-                    for pattern in self.SUCCESS_PATTERNS:
-                        if pattern in line:
-                            self.log(f"\nTest execution completed!")
-                            self.log(f"Results: {test_results}")
-                            return test_results["failed"] == 0
+                        # Check for completion
+                        for pattern in self.SUCCESS_PATTERNS:
+                            if pattern in line:
+                                self.log(f"\nTest execution completed!")
+                                self.log(f"Results: {test_results}")
+                                return test_results["failed"] == 0
 
-                    # Check for failure
-                    for pattern in self.FAILURE_PATTERNS:
-                        if pattern.lower() in line.lower():
-                            self.log(f"\nFailure detected: {pattern}")
-                            return False
+                        # Check for failure
+                        for pattern in self.FAILURE_PATTERNS:
+                            if pattern.lower() in line.lower():
+                                self.log(f"\nFailure detected: {pattern}")
+                                return False
+        except KeyboardInterrupt:
+            self.log(f"\nMonitoring interrupted. Results so far: {test_results}")
+            raise
 
         self.log(f"\nTest monitoring timeout. Results so far: {test_results}")
         return test_results["failed"] == 0
@@ -424,6 +441,12 @@
         """Clean up resources."""
         self.close_serial()
 
+    def _install_signal_handler(self):
+        """Install SIGINT handler so Ctrl+C always triggers clean shutdown."""
+        def _handler(signum, frame):
+            raise KeyboardInterrupt
+        signal.signal(signal.SIGINT, _handler)
+
     def run_parse_only(self) -> int:
         """Read and print UART output indefinitely. Returns 0 on KeyboardInterrupt."""
         try:
@@ -640,6 +663,7 @@
         parser.error(f"UART device not found: {args.uart_device}")
 
     executor = UartTestExecutor(args)
+    executor._install_signal_handler()
 
     try:
         # Parse-only mode: read UART indefinitely
@@ -698,7 +722,8 @@
                 return 1
 
     except KeyboardInterrupt:
-        executor.log("\nInterrupted by user")
+        executor.log("\nInterrupted.")
+        executor.cleanup()
         return 130
     except Exception as e:
         executor.log(f"Error: {e}")