Added trigger to scope
This commit is contained in:
@@ -20,11 +20,19 @@ module signal_scope_q15 #(
|
|||||||
localparam [31:0] reg_base_addr = 32'h8000_0000;
|
localparam [31:0] reg_base_addr = 32'h8000_0000;
|
||||||
localparam [3:0] reg_control = 4'h0;
|
localparam [3:0] reg_control = 4'h0;
|
||||||
localparam [3:0] reg_status = 4'h1;
|
localparam [3:0] reg_status = 4'h1;
|
||||||
|
localparam [3:0] reg_trig_val = 4'h2;
|
||||||
|
|
||||||
(* ram_style = "block" *) reg [16*4-1:0] mem[depth-1:0];
|
(* ram_style = "block" *) reg [16*4-1:0] mem[depth-1:0];
|
||||||
reg [aw-1:0] counter;
|
reg [aw-1:0] counter;
|
||||||
reg count_enable;
|
reg count_enable;
|
||||||
reg arm_req;
|
reg arm_req;
|
||||||
|
reg trigger_enable;
|
||||||
|
reg scope_armed;
|
||||||
|
reg scope_triggered;
|
||||||
|
reg capture_done;
|
||||||
|
reg [15:0] trig_val;
|
||||||
|
reg [15:0] signal_a_prev;
|
||||||
|
reg signal_a_prev_valid;
|
||||||
|
|
||||||
reg [15:0] signal_a;
|
reg [15:0] signal_a;
|
||||||
reg [15:0] signal_b;
|
reg [15:0] signal_b;
|
||||||
@@ -69,8 +77,15 @@ module signal_scope_q15 #(
|
|||||||
counter <= {aw{1'b0}};
|
counter <= {aw{1'b0}};
|
||||||
count_enable <= 1'b0;
|
count_enable <= 1'b0;
|
||||||
arm_req <= 1'b0;
|
arm_req <= 1'b0;
|
||||||
|
trigger_enable <= 1'b0;
|
||||||
|
scope_armed <= 1'b0;
|
||||||
|
scope_triggered <= 1'b0;
|
||||||
|
capture_done <= 1'b0;
|
||||||
wb_ack <= 1'b0;
|
wb_ack <= 1'b0;
|
||||||
wb_rdt <= 32'b0;
|
wb_rdt <= 32'b0;
|
||||||
|
trig_val <= 16'h0000;
|
||||||
|
signal_a_prev <= 16'h0000;
|
||||||
|
signal_a_prev_valid <= 1'b0;
|
||||||
signal_a <= 0;
|
signal_a <= 0;
|
||||||
signal_b <= 0;
|
signal_b <= 0;
|
||||||
signal_c <= 0;
|
signal_c <= 0;
|
||||||
@@ -85,6 +100,18 @@ module signal_scope_q15 #(
|
|||||||
if(i_signal_valid_a) begin
|
if(i_signal_valid_a) begin
|
||||||
signal_a <= i_signal_a;
|
signal_a <= i_signal_a;
|
||||||
signal_a_pending <= 1'b1;
|
signal_a_pending <= 1'b1;
|
||||||
|
|
||||||
|
// Trigger on signal_a rising across trig_val.
|
||||||
|
if(scope_armed && trigger_enable && !count_enable) begin
|
||||||
|
if(signal_a_prev_valid &&
|
||||||
|
($signed(signal_a_prev) < $signed(trig_val)) &&
|
||||||
|
($signed(i_signal_a) >= $signed(trig_val))) begin
|
||||||
|
count_enable <= 1'b1;
|
||||||
|
scope_triggered <= 1'b1;
|
||||||
|
end
|
||||||
|
signal_a_prev <= i_signal_a;
|
||||||
|
signal_a_prev_valid <= 1'b1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if(i_signal_valid_b) begin
|
if(i_signal_valid_b) begin
|
||||||
signal_b <= i_signal_b;
|
signal_b <= i_signal_b;
|
||||||
@@ -99,10 +126,14 @@ module signal_scope_q15 #(
|
|||||||
signal_d_pending <= 1'b1;
|
signal_d_pending <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
// Arm/rearm capture on control-register command pulse.
|
// Arm/rearm capture. If trigger is disabled, start capture immediately.
|
||||||
if(arm_req) begin
|
if(arm_req) begin
|
||||||
counter <= {aw{1'b0}};
|
counter <= {aw{1'b0}};
|
||||||
count_enable <= 1'b1;
|
count_enable <= !trigger_enable;
|
||||||
|
scope_armed <= 1'b1;
|
||||||
|
scope_triggered <= !trigger_enable;
|
||||||
|
capture_done <= 1'b0;
|
||||||
|
signal_a_prev_valid <= 1'b0;
|
||||||
signal_a_pending <= 1'b0;
|
signal_a_pending <= 1'b0;
|
||||||
signal_b_pending <= 1'b0;
|
signal_b_pending <= 1'b0;
|
||||||
signal_c_pending <= 1'b0;
|
signal_c_pending <= 1'b0;
|
||||||
@@ -114,10 +145,15 @@ module signal_scope_q15 #(
|
|||||||
if(counter <= depth_last) begin
|
if(counter <= depth_last) begin
|
||||||
mem[counter] <= {signal_a, signal_b, signal_c, signal_d};
|
mem[counter] <= {signal_a, signal_b, signal_c, signal_d};
|
||||||
counter <= counter + {{(aw-1){1'b0}}, 1'b1};
|
counter <= counter + {{(aw-1){1'b0}}, 1'b1};
|
||||||
if(counter == depth_last)
|
if(counter == depth_last) begin
|
||||||
count_enable <= 1'b0;
|
count_enable <= 1'b0;
|
||||||
|
scope_armed <= 1'b0;
|
||||||
|
capture_done <= 1'b1;
|
||||||
|
end
|
||||||
end else begin
|
end else begin
|
||||||
count_enable <= 1'b0;
|
count_enable <= 1'b0;
|
||||||
|
scope_armed <= 1'b0;
|
||||||
|
capture_done <= 1'b1;
|
||||||
end
|
end
|
||||||
signal_a_pending <= 1'b0;
|
signal_a_pending <= 1'b0;
|
||||||
signal_b_pending <= 1'b0;
|
signal_b_pending <= 1'b0;
|
||||||
@@ -136,9 +172,17 @@ module signal_scope_q15 #(
|
|||||||
// can be added without touching memory-path logic.
|
// can be added without touching memory-path logic.
|
||||||
case(wb_reg_idx)
|
case(wb_reg_idx)
|
||||||
reg_control: begin
|
reg_control: begin
|
||||||
// Bit 0: write-1 to arm/rearm scope (pulse).
|
if(wb_sel[0]) begin
|
||||||
if(wb_sel[0] && wb_dat[0])
|
// Bit 0: write-1 pulse to arm/rearm scope.
|
||||||
arm_req <= 1'b1;
|
if(wb_dat[0])
|
||||||
|
arm_req <= 1'b1;
|
||||||
|
// Bit 1: trigger enable.
|
||||||
|
trigger_enable <= wb_dat[1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
reg_trig_val: begin
|
||||||
|
if(wb_sel[0]) trig_val[7:0] <= wb_dat[7:0];
|
||||||
|
if(wb_sel[1]) trig_val[15:8] <= wb_dat[15:8];
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
end
|
end
|
||||||
@@ -147,10 +191,11 @@ module signal_scope_q15 #(
|
|||||||
end else begin
|
end else begin
|
||||||
if(wb_is_reg) begin
|
if(wb_is_reg) begin
|
||||||
case(wb_reg_idx)
|
case(wb_reg_idx)
|
||||||
// Write-pulse register: reads as zero.
|
// [1]=trigger_enable, [0]=arm bit is write-pulse only.
|
||||||
reg_control: wb_rdt <= 32'b0;
|
reg_control: wb_rdt <= {30'b0, trigger_enable, 1'b0};
|
||||||
// Basic status for polling/debug.
|
// [0]=triggered, [1]=capturing, [2]=armed, [3]=done
|
||||||
reg_status: wb_rdt <= {30'b0, count_enable, (counter == depth_last)};
|
reg_status: wb_rdt <= {28'b0, capture_done, scope_armed, count_enable, scope_triggered};
|
||||||
|
reg_trig_val: wb_rdt <= {16'b0, trig_val};
|
||||||
default: wb_rdt <= 32'b0;
|
default: wb_rdt <= 32'b0;
|
||||||
endcase
|
endcase
|
||||||
end else if(wb_mem_idx <= depth_last) begin
|
end else if(wb_mem_idx <= depth_last) begin
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ MEM_BASE = 0x00000000
|
|||||||
REG_BASE = 0x80000000
|
REG_BASE = 0x80000000
|
||||||
REG_CONTROL = REG_BASE + 0x00
|
REG_CONTROL = REG_BASE + 0x00
|
||||||
REG_STATUS = REG_BASE + 0x04
|
REG_STATUS = REG_BASE + 0x04
|
||||||
|
REG_TRIG_VAL = REG_BASE + 0x08
|
||||||
|
|
||||||
|
|
||||||
def _add_bridge_module_path() -> None:
|
def _add_bridge_module_path() -> None:
|
||||||
@@ -46,6 +47,12 @@ def parse_args() -> argparse.Namespace:
|
|||||||
default=0.05,
|
default=0.05,
|
||||||
help="Seconds to wait after arm/dearm before reading",
|
help="Seconds to wait after arm/dearm before reading",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--trigger-value",
|
||||||
|
type=lambda x: int(x, 0),
|
||||||
|
default=None,
|
||||||
|
help="Optional trigger threshold (16-bit, signal_a rising crossing). If omitted, triggering is disabled.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--unsigned",
|
"--unsigned",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@@ -63,14 +70,38 @@ def parse_args() -> argparse.Namespace:
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Keep running: press Enter to recapture/replot in the same window",
|
help="Keep running: press Enter to recapture/replot in the same window",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--continuous",
|
||||||
|
action="store_true",
|
||||||
|
help="Keep running and recapture continuously without waiting for Enter",
|
||||||
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def capture_once(bridge, args: argparse.Namespace) -> list[tuple[int, int, int, int]]:
|
def capture_once(bridge, args: argparse.Namespace) -> list[tuple[int, int, int, int]]:
|
||||||
samples = []
|
samples = []
|
||||||
frame_count = args.depth
|
frame_count = args.depth
|
||||||
print("[signal_scope] Arming scope (write REG_CONTROL bit0=1)...")
|
if args.trigger_value is None:
|
||||||
bridge.write32(REG_CONTROL, 0x1)
|
print("[signal_scope] Arming scope with trigger disabled...")
|
||||||
|
bridge.write32(REG_CONTROL, 0x1) # bit0: arm pulse, bit1: trigger enable=0
|
||||||
|
else:
|
||||||
|
trig_val = args.trigger_value & 0xFFFF
|
||||||
|
print(f"[signal_scope] Config trigger: trig_val=0x{trig_val:04x}, source=signal_a rising")
|
||||||
|
bridge.write32(REG_TRIG_VAL, trig_val)
|
||||||
|
print("[signal_scope] Arming scope with trigger enabled...")
|
||||||
|
bridge.write32(REG_CONTROL, 0x3) # bit0: arm pulse, bit1: trigger enable
|
||||||
|
|
||||||
|
# Wait until the new arm command is active, then wait for its trigger event.
|
||||||
|
while (bridge.read32(REG_STATUS) & 0x4) == 0:
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
|
print("[signal_scope] Waiting for trigger...")
|
||||||
|
while True:
|
||||||
|
status = bridge.read32(REG_STATUS)
|
||||||
|
if status & 0x1:
|
||||||
|
break
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
if args.wait_s > 0:
|
if args.wait_s > 0:
|
||||||
print(f"[signal_scope] Waiting {args.wait_s:.3f}s for capture to complete...")
|
print(f"[signal_scope] Waiting {args.wait_s:.3f}s for capture to complete...")
|
||||||
time.sleep(args.wait_s)
|
time.sleep(args.wait_s)
|
||||||
@@ -93,7 +124,6 @@ def capture_once(bridge, args: argparse.Namespace) -> list[tuple[int, int, int,
|
|||||||
samples.append((ch_a, ch_b, ch_c, ch_d))
|
samples.append((ch_a, ch_b, ch_c, ch_d))
|
||||||
if idx and (idx % max(1, frame_count // 10) == 0):
|
if idx and (idx % max(1, frame_count // 10) == 0):
|
||||||
pct = (100 * idx) // frame_count
|
pct = (100 * idx) // frame_count
|
||||||
print(f"[signal_scope] Read progress: {pct}% ({idx}/{frame_count})")
|
|
||||||
print(f"[signal_scope] Read complete: {len(samples)} frames")
|
print(f"[signal_scope] Read complete: {len(samples)} frames")
|
||||||
return samples
|
return samples
|
||||||
|
|
||||||
@@ -116,10 +146,10 @@ def plot_samples(ax, samples: list[tuple[int, int, int, int]], args: argparse.Na
|
|||||||
series[3].append(ch_d)
|
series[3].append(ch_d)
|
||||||
|
|
||||||
ax.cla()
|
ax.cla()
|
||||||
ax.plot(series[0], linewidth=1, label="ch_a")
|
ax.plot(series[0], linewidth=1, label="ch_d")
|
||||||
ax.plot(series[1], linewidth=1, label="ch_b")
|
ax.plot(series[1], linewidth=1, label="ch_c")
|
||||||
ax.plot(series[2], linewidth=1, label="ch_c")
|
ax.plot(series[2], linewidth=1, label="ch_b")
|
||||||
ax.plot(series[3], linewidth=1, label="ch_d")
|
ax.plot(series[3], linewidth=1, label="ch_a")
|
||||||
ax.set_title(f"signal_scope_q15 capture #{capture_idx} (depth={args.depth}, chain={args.chain})")
|
ax.set_title(f"signal_scope_q15 capture #{capture_idx} (depth={args.depth}, chain={args.chain})")
|
||||||
ax.set_xlabel("Sample")
|
ax.set_xlabel("Sample")
|
||||||
ax.set_ylabel("Value")
|
ax.set_ylabel("Value")
|
||||||
@@ -178,10 +208,13 @@ def main() -> int:
|
|||||||
fig.savefig(out_path, dpi=150)
|
fig.savefig(out_path, dpi=150)
|
||||||
print(f"Wrote plot: {out_path}")
|
print(f"Wrote plot: {out_path}")
|
||||||
|
|
||||||
if not args.interactive:
|
if not args.interactive and not args.continuous:
|
||||||
break
|
break
|
||||||
|
|
||||||
plt.show(block=False)
|
plt.show(block=False)
|
||||||
|
if args.continuous:
|
||||||
|
capture_idx += 1
|
||||||
|
continue
|
||||||
answer = input("[signal_scope] Press Enter to recapture, or 'q' + Enter to quit: ")
|
answer = input("[signal_scope] Press Enter to recapture, or 'q' + Enter to quit: ")
|
||||||
if answer.strip().lower().startswith("q"):
|
if answer.strip().lower().startswith("q"):
|
||||||
break
|
break
|
||||||
|
|||||||
Reference in New Issue
Block a user