| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- `timescale 1ns/1ps
- module axis_travel_monitor #(
- // How far beyond the target is considered a serious overrun.
- parameter integer OVERRUN_LIMIT = 20
- )(
- input wire clk,
- input wire reset_n,
- // Start a new travel segment.
- input wire start,
- // Current measured position.
- input wire signed [31:0] current_position,
- // Relative requested travel.
- // +500 = positive travel
- // -500 = negative travel
- input wire signed [31:0] target_travel,
- // Allowed target error.
- input wire [31:0] tolerance,
- // Physical limits.
- input wire limit_pos,
- input wire limit_neg,
- // Position captured when START occurs.
- output reg signed [31:0] start_position,
- // start_position + target_travel
- output reg signed [31:0] target_position,
- // current_position - start_position
- output wire signed [31:0] travel,
- // Travel state.
- output reg busy,
- // Current position is inside target tolerance.
- output wire in_position,
- // Normal completion.
- output reg done,
- // Limit status.
- output reg limit_hit,
- output reg limit_pos_hit,
- output reg limit_neg_hit,
- // Target was crossed without entering tolerance window.
- output reg overshoot,
- // Position went too far beyond target.
- output reg travel_overrun
- );
- reg signed [31:0] latched_target_travel;
- // ------------------------------------------------------------
- // Travel calculation
- // ------------------------------------------------------------
- assign travel =
- current_position - start_position;
- // ------------------------------------------------------------
- // Extend positions to 33 bits before subtraction/comparison.
- // ------------------------------------------------------------
- wire signed [32:0] current_ext;
- wire signed [32:0] target_ext;
- wire signed [32:0] tolerance_ext;
- wire signed [32:0] overrun_limit_ext;
- wire signed [32:0] position_error;
- wire [32:0] abs_position_error;
- assign current_ext =
- {current_position[31], current_position};
- assign target_ext =
- {target_position[31], target_position};
- assign tolerance_ext =
- {1'b0, tolerance};
- assign overrun_limit_ext =
- OVERRUN_LIMIT;
- assign position_error =
- current_ext - target_ext;
- assign abs_position_error =
- position_error[32]
- ? -position_error
- : position_error;
- // ------------------------------------------------------------
- // Current position is inside allowed target window.
- // ------------------------------------------------------------
- assign in_position =
- (busy || done) &&
- (abs_position_error <= tolerance_ext);
- // ------------------------------------------------------------
- // Overshoot detection
- //
- // Positive movement:
- //
- // target = 1500
- // tolerance = 5
- //
- // >1505 means target window was passed.
- //
- // Negative movement is the opposite.
- // ------------------------------------------------------------
- wire positive_overshoot_now;
- wire negative_overshoot_now;
- assign positive_overshoot_now =
- (latched_target_travel > 0) &&
- (current_ext > (target_ext + tolerance_ext));
- assign negative_overshoot_now =
- (latched_target_travel < 0) &&
- (current_ext < (target_ext - tolerance_ext));
- // ------------------------------------------------------------
- // Serious travel-overrun detection.
- //
- // Default OVERRUN_LIMIT = 20.
- //
- // target=1500:
- // positive overrun at >=1520
- //
- // target=2500:
- // negative overrun at <=2480
- // ------------------------------------------------------------
- wire positive_overrun_now;
- wire negative_overrun_now;
- assign positive_overrun_now =
- (latched_target_travel > 0) &&
- (current_ext >=
- (target_ext + overrun_limit_ext));
- assign negative_overrun_now =
- (latched_target_travel < 0) &&
- (current_ext <=
- (target_ext - overrun_limit_ext));
- // ------------------------------------------------------------
- // Main state logic
- // ------------------------------------------------------------
- always @(posedge clk or negedge reset_n) begin
- if (!reset_n) begin
- start_position <= 32'sd0;
- target_position <= 32'sd0;
- latched_target_travel <= 32'sd0;
- busy <= 1'b0;
- done <= 1'b0;
- limit_hit <= 1'b0;
- limit_pos_hit <= 1'b0;
- limit_neg_hit <= 1'b0;
- overshoot <= 1'b0;
- travel_overrun <= 1'b0;
- end else begin
- // ====================================================
- // New travel segment
- // ====================================================
- if (start) begin
- start_position <=
- current_position;
- target_position <=
- current_position + target_travel;
- latched_target_travel <=
- target_travel;
- done <= 1'b0;
- limit_hit <= 1'b0;
- limit_pos_hit <= 1'b0;
- limit_neg_hit <= 1'b0;
- overshoot <= 1'b0;
- travel_overrun <= 1'b0;
- // Zero-distance command is complete immediately.
- if (target_travel == 0) begin
- busy <= 1'b0;
- done <= 1'b1;
- end else begin
- busy <= 1'b1;
- end
- end else begin
- // =================================================
- // Continue monitoring overrun even after the normal
- // travel state has stopped.
- //
- // This allows:
- //
- // reach target normally
- // ↓
- // external mechanics keep moving
- // ↓
- // travel_overrun becomes 1
- // =================================================
- if (
- (
- busy ||
- done ||
- overshoot ||
- limit_hit
- ) &&
- !travel_overrun
- ) begin
- if (
- positive_overrun_now ||
- negative_overrun_now
- ) begin
- travel_overrun <= 1'b1;
- end
- end
- // =================================================
- // Active travel monitoring
- // =================================================
- if (busy) begin
- // ---------------------------------------------
- // Positive physical limit has highest priority.
- // ---------------------------------------------
- if (
- (latched_target_travel > 0) &&
- limit_pos
- ) begin
- busy <= 1'b0;
- done <= 1'b0;
- limit_hit <= 1'b1;
- limit_pos_hit <= 1'b1;
- end
- // ---------------------------------------------
- // Negative physical limit.
- // ---------------------------------------------
- else if (
- (latched_target_travel < 0) &&
- limit_neg
- ) begin
- busy <= 1'b0;
- done <= 1'b0;
- limit_hit <= 1'b1;
- limit_neg_hit <= 1'b1;
- end
- // ---------------------------------------------
- // Normal arrival inside tolerance window.
- // ---------------------------------------------
- else if (
- abs_position_error <= tolerance_ext
- ) begin
- busy <= 1'b0;
- done <= 1'b1;
- end
- // ---------------------------------------------
- // Target was skipped.
- //
- // This is NOT a normal completion.
- // ---------------------------------------------
- else if (
- positive_overshoot_now ||
- negative_overshoot_now
- ) begin
- busy <= 1'b0;
- done <= 1'b0;
- overshoot <= 1'b1;
- end
- end
- end
- end
- end
- endmodule
|