axis_travel_monitor.v 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. `timescale 1ns/1ps
  2. module axis_travel_monitor #(
  3. // How far beyond the target is considered a serious overrun.
  4. parameter integer OVERRUN_LIMIT = 20
  5. )(
  6. input wire clk,
  7. input wire reset_n,
  8. // Start a new travel segment.
  9. input wire start,
  10. // Current measured position.
  11. input wire signed [31:0] current_position,
  12. // Relative requested travel.
  13. // +500 = positive travel
  14. // -500 = negative travel
  15. input wire signed [31:0] target_travel,
  16. // Allowed target error.
  17. input wire [31:0] tolerance,
  18. // Physical limits.
  19. input wire limit_pos,
  20. input wire limit_neg,
  21. // Position captured when START occurs.
  22. output reg signed [31:0] start_position,
  23. // start_position + target_travel
  24. output reg signed [31:0] target_position,
  25. // current_position - start_position
  26. output wire signed [31:0] travel,
  27. // Travel state.
  28. output reg busy,
  29. // Current position is inside target tolerance.
  30. output wire in_position,
  31. // Normal completion.
  32. output reg done,
  33. // Limit status.
  34. output reg limit_hit,
  35. output reg limit_pos_hit,
  36. output reg limit_neg_hit,
  37. // Target was crossed without entering tolerance window.
  38. output reg overshoot,
  39. // Position went too far beyond target.
  40. output reg travel_overrun
  41. );
  42. reg signed [31:0] latched_target_travel;
  43. // ------------------------------------------------------------
  44. // Travel calculation
  45. // ------------------------------------------------------------
  46. assign travel =
  47. current_position - start_position;
  48. // ------------------------------------------------------------
  49. // Extend positions to 33 bits before subtraction/comparison.
  50. // ------------------------------------------------------------
  51. wire signed [32:0] current_ext;
  52. wire signed [32:0] target_ext;
  53. wire signed [32:0] tolerance_ext;
  54. wire signed [32:0] overrun_limit_ext;
  55. wire signed [32:0] position_error;
  56. wire [32:0] abs_position_error;
  57. assign current_ext =
  58. {current_position[31], current_position};
  59. assign target_ext =
  60. {target_position[31], target_position};
  61. assign tolerance_ext =
  62. {1'b0, tolerance};
  63. assign overrun_limit_ext =
  64. OVERRUN_LIMIT;
  65. assign position_error =
  66. current_ext - target_ext;
  67. assign abs_position_error =
  68. position_error[32]
  69. ? -position_error
  70. : position_error;
  71. // ------------------------------------------------------------
  72. // Current position is inside allowed target window.
  73. // ------------------------------------------------------------
  74. assign in_position =
  75. (busy || done) &&
  76. (abs_position_error <= tolerance_ext);
  77. // ------------------------------------------------------------
  78. // Overshoot detection
  79. //
  80. // Positive movement:
  81. //
  82. // target = 1500
  83. // tolerance = 5
  84. //
  85. // >1505 means target window was passed.
  86. //
  87. // Negative movement is the opposite.
  88. // ------------------------------------------------------------
  89. wire positive_overshoot_now;
  90. wire negative_overshoot_now;
  91. assign positive_overshoot_now =
  92. (latched_target_travel > 0) &&
  93. (current_ext > (target_ext + tolerance_ext));
  94. assign negative_overshoot_now =
  95. (latched_target_travel < 0) &&
  96. (current_ext < (target_ext - tolerance_ext));
  97. // ------------------------------------------------------------
  98. // Serious travel-overrun detection.
  99. //
  100. // Default OVERRUN_LIMIT = 20.
  101. //
  102. // target=1500:
  103. // positive overrun at >=1520
  104. //
  105. // target=2500:
  106. // negative overrun at <=2480
  107. // ------------------------------------------------------------
  108. wire positive_overrun_now;
  109. wire negative_overrun_now;
  110. assign positive_overrun_now =
  111. (latched_target_travel > 0) &&
  112. (current_ext >=
  113. (target_ext + overrun_limit_ext));
  114. assign negative_overrun_now =
  115. (latched_target_travel < 0) &&
  116. (current_ext <=
  117. (target_ext - overrun_limit_ext));
  118. // ------------------------------------------------------------
  119. // Main state logic
  120. // ------------------------------------------------------------
  121. always @(posedge clk or negedge reset_n) begin
  122. if (!reset_n) begin
  123. start_position <= 32'sd0;
  124. target_position <= 32'sd0;
  125. latched_target_travel <= 32'sd0;
  126. busy <= 1'b0;
  127. done <= 1'b0;
  128. limit_hit <= 1'b0;
  129. limit_pos_hit <= 1'b0;
  130. limit_neg_hit <= 1'b0;
  131. overshoot <= 1'b0;
  132. travel_overrun <= 1'b0;
  133. end else begin
  134. // ====================================================
  135. // New travel segment
  136. // ====================================================
  137. if (start) begin
  138. start_position <=
  139. current_position;
  140. target_position <=
  141. current_position + target_travel;
  142. latched_target_travel <=
  143. target_travel;
  144. done <= 1'b0;
  145. limit_hit <= 1'b0;
  146. limit_pos_hit <= 1'b0;
  147. limit_neg_hit <= 1'b0;
  148. overshoot <= 1'b0;
  149. travel_overrun <= 1'b0;
  150. // Zero-distance command is complete immediately.
  151. if (target_travel == 0) begin
  152. busy <= 1'b0;
  153. done <= 1'b1;
  154. end else begin
  155. busy <= 1'b1;
  156. end
  157. end else begin
  158. // =================================================
  159. // Continue monitoring overrun even after the normal
  160. // travel state has stopped.
  161. //
  162. // This allows:
  163. //
  164. // reach target normally
  165. // ↓
  166. // external mechanics keep moving
  167. // ↓
  168. // travel_overrun becomes 1
  169. // =================================================
  170. if (
  171. (
  172. busy ||
  173. done ||
  174. overshoot ||
  175. limit_hit
  176. ) &&
  177. !travel_overrun
  178. ) begin
  179. if (
  180. positive_overrun_now ||
  181. negative_overrun_now
  182. ) begin
  183. travel_overrun <= 1'b1;
  184. end
  185. end
  186. // =================================================
  187. // Active travel monitoring
  188. // =================================================
  189. if (busy) begin
  190. // ---------------------------------------------
  191. // Positive physical limit has highest priority.
  192. // ---------------------------------------------
  193. if (
  194. (latched_target_travel > 0) &&
  195. limit_pos
  196. ) begin
  197. busy <= 1'b0;
  198. done <= 1'b0;
  199. limit_hit <= 1'b1;
  200. limit_pos_hit <= 1'b1;
  201. end
  202. // ---------------------------------------------
  203. // Negative physical limit.
  204. // ---------------------------------------------
  205. else if (
  206. (latched_target_travel < 0) &&
  207. limit_neg
  208. ) begin
  209. busy <= 1'b0;
  210. done <= 1'b0;
  211. limit_hit <= 1'b1;
  212. limit_neg_hit <= 1'b1;
  213. end
  214. // ---------------------------------------------
  215. // Normal arrival inside tolerance window.
  216. // ---------------------------------------------
  217. else if (
  218. abs_position_error <= tolerance_ext
  219. ) begin
  220. busy <= 1'b0;
  221. done <= 1'b1;
  222. end
  223. // ---------------------------------------------
  224. // Target was skipped.
  225. //
  226. // This is NOT a normal completion.
  227. // ---------------------------------------------
  228. else if (
  229. positive_overshoot_now ||
  230. negative_overshoot_now
  231. ) begin
  232. busy <= 1'b0;
  233. done <= 1'b0;
  234. overshoot <= 1'b1;
  235. end
  236. end
  237. end
  238. end
  239. end
  240. endmodule