axis_travel_monitor.v 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. `timescale 1ns/1ps
  2. module axis_travel_monitor (
  3. input wire clk,
  4. input wire reset_n,
  5. // Start a new travel segment.
  6. // On start, current_position becomes the new start_position.
  7. input wire start,
  8. // Current position, for example encoder pulse count.
  9. input wire signed [31:0] current_position,
  10. // Relative travel command.
  11. // +500 = move positive by 500
  12. // -500 = move negative by 500
  13. input wire signed [31:0] target_travel,
  14. // Allowed target-position error.
  15. input wire [31:0] tolerance,
  16. // Physical limit inputs.
  17. input wire limit_pos,
  18. input wire limit_neg,
  19. // Latched position where this travel started.
  20. output reg signed [31:0] start_position,
  21. // start_position + target_travel
  22. output reg signed [31:0] target_position,
  23. // current_position - start_position
  24. output wire signed [31:0] travel,
  25. // Travel state
  26. output reg busy,
  27. // Current position is inside target tolerance window.
  28. output wire in_position,
  29. // Latched completion flag.
  30. // Cleared by next start or reset.
  31. output reg done,
  32. // Latched limit status.
  33. output reg limit_hit,
  34. output reg limit_pos_hit,
  35. output reg limit_neg_hit
  36. );
  37. // Keep the direction of the current travel command.
  38. reg signed [31:0] latched_target_travel;
  39. // ------------------------------------------------------------
  40. // Actual travelled distance
  41. // ------------------------------------------------------------
  42. assign travel =
  43. current_position - start_position;
  44. // ------------------------------------------------------------
  45. // Position error
  46. //
  47. // Use 33 bits so subtraction itself does not overflow when
  48. // comparing two signed 32-bit positions.
  49. // ------------------------------------------------------------
  50. wire signed [32:0] current_ext;
  51. wire signed [32:0] target_ext;
  52. wire signed [32:0] position_error;
  53. wire [32:0] abs_position_error;
  54. assign current_ext =
  55. {current_position[31], current_position};
  56. assign target_ext =
  57. {target_position[31], target_position};
  58. assign position_error =
  59. current_ext - target_ext;
  60. assign abs_position_error =
  61. position_error[32]
  62. ? -position_error
  63. : position_error;
  64. // ------------------------------------------------------------
  65. // In-position window
  66. //
  67. // Example:
  68. //
  69. // target = 1500
  70. // tolerance = 5
  71. //
  72. // 1495 ... 1505 => in_position = 1
  73. // ------------------------------------------------------------
  74. assign in_position =
  75. (busy || done) &&
  76. (abs_position_error <= {1'b0, tolerance});
  77. // ------------------------------------------------------------
  78. // Main travel state logic
  79. // ------------------------------------------------------------
  80. always @(posedge clk or negedge reset_n) begin
  81. if (!reset_n) begin
  82. start_position <= 32'sd0;
  83. target_position <= 32'sd0;
  84. latched_target_travel <= 32'sd0;
  85. busy <= 1'b0;
  86. done <= 1'b0;
  87. limit_hit <= 1'b0;
  88. limit_pos_hit <= 1'b0;
  89. limit_neg_hit <= 1'b0;
  90. end else begin
  91. // ----------------------------------------------------
  92. // New travel command
  93. //
  94. // A new start always creates a new measurement segment.
  95. // ----------------------------------------------------
  96. if (start) begin
  97. start_position <= current_position;
  98. target_position <=
  99. current_position + target_travel;
  100. latched_target_travel <=
  101. target_travel;
  102. done <= 1'b0;
  103. limit_hit <= 1'b0;
  104. limit_pos_hit <= 1'b0;
  105. limit_neg_hit <= 1'b0;
  106. // Zero-distance request is already complete.
  107. if (target_travel == 0) begin
  108. busy <= 1'b0;
  109. done <= 1'b1;
  110. end else begin
  111. busy <= 1'b1;
  112. end
  113. end
  114. // ----------------------------------------------------
  115. // Monitor active travel
  116. // ----------------------------------------------------
  117. else if (busy) begin
  118. // Positive motion:
  119. // positive limit is relevant.
  120. if (
  121. (latched_target_travel > 0) &&
  122. limit_pos
  123. ) begin
  124. busy <= 1'b0;
  125. done <= 1'b0;
  126. limit_hit <= 1'b1;
  127. limit_pos_hit <= 1'b1;
  128. end
  129. // Negative motion:
  130. // negative limit is relevant.
  131. else if (
  132. (latched_target_travel < 0) &&
  133. limit_neg
  134. ) begin
  135. busy <= 1'b0;
  136. done <= 1'b0;
  137. limit_hit <= 1'b1;
  138. limit_neg_hit <= 1'b1;
  139. end
  140. // Reached requested position.
  141. else if (
  142. abs_position_error <=
  143. {1'b0, tolerance}
  144. ) begin
  145. busy <= 1'b0;
  146. done <= 1'b1;
  147. end
  148. end
  149. end
  150. end
  151. endmodule