CW312T-A35 (SS2) Trigger Detection Issue - Signal Present but Husky Scope Times Out

I’ve implemented custom arithmetic registers on a CW312T-A35 target using the SS2 wrapper and successfully verified the computation works correctly. However, the ChipWhisperer Husky scope
consistently fails to detect the trigger signal on TIO4, even though I’ve confirmed the signal is physically present using an external oscilloscope. The arithmetic operations complete
successfully (verified via register reads), but trace capture always times out.

Hardware Setup

  • Scope: ChipWhisperer Husky
  • Target: CW312T-A35 (Artix-7 35T FPGA)
  • Platform: SS2 wrapper (ss2_a35)
  • Clock: 7.37 MHz
  • Bitstream: Custom arithmetic testing implementation based on ChipWhisperer AES example
  • Connection: 20-pin cable between Husky and CW312T-A35

Implementation Details

Custom Arithmetic Registers

I added six custom registers to the standard CW305 register bank:

Input Registers:

* REG_NUM_1 = 0x0c (128-bit operand 1)
* REG_NUM_2 = 0x0d (128-bit operand 2)
* REG_NUM_3 = 0x0e (128-bit operand 3)

Output Registers:

* REG_ADD_OUT = 0x0f (addition result)
* REG_MUL_OUT = 0x10 (multiplication result)
* REG_DIV_OUT = 0x11 (division result)

Verilog FSM Modifications

Modified the FSM to generate a trigger signal on tio_trigger (routed to TIO4/IO4):

// core.v - FSM excerpt
localparam ARITH_CYCLES = 100;       // Arithmetic completion cycles
localparam BUSY_HOLD_CYCLES = 5000;  // Busy signal hold duration (\~680us)

S_WAIT: begin
// Perform arithmetic operations
add_o <= {64’h0, num_1\[63:0\]} + {64’h0, num_2\[63:0\]} + {64’h0, num_3\[63:0\]};
mul_o <= {64’h0, num_1\[63:0\]} \* {64’h0, num_2\[63:0\]};
div_o <= (num_2\[63:0\] != 0) ? ({64’h0, num_1\[63:0\]} / {64’h0, num_2\[63:0\]}) : 128’hFFFF…;

  // Decrement counters
  if (arith_counter > 0) arith_counter <= arith_counter - 1;
  if (busy_counter > 0) busy_counter <= busy_counter - 1;

  // Complete after arithmetic finishes
  if (arith_counter == 0) begin
      done_seen <= 1'b1;
      state <= S_CAPTURE;
  end

end

S_CAPTURE: begin
// Hold busy_o high for extended period
if (busy_counter == 0) begin
busy_o <= 1’b0;
state <= S_IDLE;
end else begin
busy_counter <= busy_counter - 1;
end
end

Signal routing in ss2_aes_wrapper.v:
wire tio_trigger_signal;

assign led2 = tio_trigger_signal;  // For visual verification
assign io4 = tio_trigger_signal;   // For scope trigger

cw305_top U_cw305_dut (
// … other ports …
.tio_trigger(tio_trigger_signal)
);

Wiring in cw305_top.v:
assign tio_trigger = aes_busy;  // aes_busy comes from arithmetic_testing module

What Works

  1. Arithmetic Computation ✓

Register read/write and arithmetic operations work perfectly:

Test code

scope = cw.scope()
scope.clock.clkgen_freq = 7.37e6
scope.io.tio1 = “serial_rx”
scope.io.tio2 = “serial_tx”
scope.io.hs2 = ‘clkgen’

target = cw.target(scope, cw.targets.CW305, platform=‘ss2_a35’, program=False)

Write operands

def write_operand(target, reg_addr, value):
data = value.to_bytes(16, byteorder=‘little’)
target.fpga_write(reg_addr, list(data))

write_operand(target, 0x0c, 100)  # NUM_1
write_operand(target, 0x0d, 200)  # NUM_2
write_operand(target, 0x0e, 300)  # NUM_3

Trigger computation

target.fpga_write(0x05, \[1\])  # REG_CRYPT_GO
time.sleep(0.01)

Read results

add_data = target.fpga_read(0x0f, 16)
add_result = int.from_bytes(bytes(add_data), byteorder=‘little’)

print(f"Result: {add_result}")  # Output: 600 ✓

Result: Addition correctly computes 100+200+300=600. All arithmetic operations verified working.

  1. Trigger Signal Physically Present ✓

I confirmed the trigger signal with an external oscilloscope:

  • Probe point: GPIO4 (IO4 pin on the 20-pin connector)
  • Test: Sent 10 GO commands, observed 10 corresponding pulses
  • Pulse width: Approximately 680 microseconds (matches BUSY_HOLD_CYCLES)
  • Signal level: Valid logic levels detected

The trigger signal IS being generated and is physically present on the IO4 pin.

What Doesn’t Work

Scope Trigger Detection ✗

Despite the signal being present, the Husky scope consistently fails to detect the trigger:

Standard trigger configuration

scope.adc.samples = 1000
scope.adc.offset = 0
scope.adc.basic_mode = “rising_edge”
scope.trigger.triggers = “tio4”
scope.gain.db = 30

Write operands

write_operand(target, 0x0c, 100)
write_operand(target, 0x0d, 200)
write_operand(target, 0x0e, 300)

Arm and trigger

scope.arm()
time.sleep(0.001)
target.fpga_write(0x05, \[1\])

# Wait for capture

ret = scope.capture()  # Returns False - TIMEOUT

Result: Timeout every time. No trace captured.

Debugging Attempts

  1. Verified Scope Configuration

print(f"scope.trigger.triggers = {scope.trigger.triggers}“)  # tio4
print(f"scope.adc.basic_mode = {scope.adc.basic_mode}”)      # rising_edge
print(f"scope.io.tio4 = {scope.io.tio4}“)                    # high_z
print(f"scope.trigger.module = {scope.trigger.module}”)      # basic

All settings appear correct.

  1. Tried Multiple Trigger Configurations
  • Rising edge trigger (default)
  • Low-level trigger mode
  • Extended timeout (5 seconds)
  • Pre-trigger delay (100ms between arm and GO)
  • Manual trigger mode
  • Stream mode capture

All failed with timeout.

  1. Direct ADC Capture Test

Attempted to bypass trigger entirely and capture ADC samples directly:

scope.arm()
time.sleep(0.001)
target.fpga_write(0x05, \[1\])
time.sleep(0.05)  # Wait for samples

trace = scope.get_last_trace()  # Returns None

Result: scope.get_last_trace() returns None, suggesting the scope isn’t capturing ANY samples at all, even without trigger logic.

  1. LED Visual Verification

Routed trigger to LED2 - LED blinks as expected when GO commands sent, confirming FPGA-side trigger generation works.

Current Status

  • ✓ Arithmetic computation: WORKING
  • ✓ Trigger signal generation (FPGA): WORKING
  • ✓ Trigger signal physical presence (oscilloscope): CONFIRMED
  • ✗ Husky trigger detection: FAILING
  • ✗ Trace capture: FAILING

Questions

  1. Is there a known issue with trigger detection on SS2 targets? The standard parallel USB CW305 may handle triggers differently than the SS2 wrapper.
  2. Could UART latency affect trigger detection? The sequence is: Python sends FPGA write via UART → FPGA processes command → trigger asserts. Could the ~300-500μs UART transmission delay cause
    the scope to miss the trigger even with a 680μs pulse?
  3. Are there alternative trigger methods for SS2 targets? Since external trigger detection fails, are there recommended approaches like:
    • ADC-based triggering on power consumption changes
    • Software triggering based on timing
    • Post-capture trigger point identification
  4. Is TIO4 the correct pin for SS2 platform triggers? I’m using:
    scope.trigger.triggers = “tio4”
  5. Is this correct for SS2 targets, or should I use a different trigger source?
  6. Could this be a Husky-specific configuration issue? Are there additional Husky settings needed for SS2 target triggering that differ from standard CW305?

Request

Could someone provide guidance on:

  • Proper trigger configuration for SS2 wrapped targets
  • Why scope.get_last_trace() returns None even without trigger logic
  • Alternative capture methods that might work better for this use case
  • Whether this is a known limitation of SS2 targets with Husky

I can provide the complete Verilog source, Python test scripts, synthesis reports, or any other information needed to diagnose this issue.

Thank you for any assistance!

I won’t answer all your questions right away but I want to highlight the most important points:

  1. The TIO4 trigger line is a distinct line that has nothing to do with the rest of the target communication. So, SS2 wrapper or not, CW305 or not, has no effect on it. TIO4 works in the same manner for all of our target boards.
  2. scope.get_last_trace() won’t give you anything unless a capture actually occurred.

If you can answer the following questions, it will help me diagnose the issue.

  1. You say that you measure a pulse width of 680 us, this is TIO4, correct? What is the voltage level when it is high? It must be 3.3V. It’s possible to configure the target FPGA’s I/O banks to use a different voltage, but Husky only works with 3.3V (it won’t “see” the trigger if it’s a different voltage).
  2. What is the full output of print(scope)?
  3. What causes the trigger output line to go high? Is it target.fpga_write(0x05, [1])?