top_ef2l45_motor_hil_trace.v 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. `timescale 1ns/1ps
  2. `include "trace_build_id.vh"
  3. // -----------------------------------------------------------------------------
  4. // Single-CP2102 motor HIL + Trace top-level.
  5. //
  6. // One UART carries BOTH:
  7. // * control/HIL packets while the virtual motor is running
  8. // * Trace packets after the motor test finishes
  9. //
  10. // The PC program is the virtual motor and Trace receiver at the same time.
  11. // -----------------------------------------------------------------------------
  12. module top_ef2l45_motor_hil_trace #(
  13. parameter integer CLK_HZ = 25000000,
  14. parameter integer BAUD = 115200,
  15. parameter integer TRACE_DEPTH = 1024,
  16. parameter integer TRACE_ADDR_W = 10,
  17. parameter integer STEP_MS = 10,
  18. parameter integer FEEDBACK_TIMEOUT_CYCLES = 50000000,
  19. parameter integer LED_HOLD_CYCLES = 6250000
  20. )(
  21. input wire sys_clk,
  22. input wire reset_n,
  23. output wire uart_tx,
  24. input wire uart_rx,
  25. output wire led_heartbeat_n,
  26. output wire led_reset_n,
  27. output wire led_activity_n,
  28. output wire led_tx_n,
  29. output wire led_error_n
  30. );
  31. localparam [7:0] PKT_STATUS = 8'h81;
  32. localparam [7:0] PKT_TRACE = 8'h82;
  33. localparam [7:0] PKT_SUMMARY = 8'h83;
  34. localparam [7:0] PKT_MOTOR_CMD = 8'h90;
  35. localparam [15:0] STATUS_EVENT_ID = 16'hB17D;
  36. localparam [3:0] T_IDLE = 4'd0;
  37. localparam [3:0] T_SEND_STATUS = 4'd1;
  38. localparam [3:0] T_WAIT_STATUS = 4'd2;
  39. localparam [3:0] T_SEND_MOTOR = 4'd3;
  40. localparam [3:0] T_WAIT_MOTOR = 4'd4;
  41. localparam [3:0] T_WAIT_FB = 4'd5;
  42. localparam [3:0] T_APPLY_FB = 4'd6;
  43. localparam [3:0] T_CHECK = 4'd7;
  44. localparam [3:0] T_PREP = 4'd8;
  45. localparam [3:0] T_READ = 4'd9;
  46. localparam [3:0] T_SEND_TRACE = 4'd10;
  47. localparam [3:0] T_WAIT_TRACE = 4'd11;
  48. localparam [3:0] T_SEND_SUMMARY = 4'd12;
  49. localparam [3:0] T_WAIT_SUMMARY = 4'd13;
  50. wire rst_n;
  51. wire [7:0] rx_data;
  52. wire rx_valid;
  53. wire rx_framing_error;
  54. wire fb_packet_valid;
  55. wire [15:0] fb_packet_seq;
  56. wire [15:0] fb_packet_flags;
  57. wire [31:0] fb_packet_timestamp;
  58. wire [15:0] fb_packet_rpm;
  59. wire [15:0] fb_packet_current_ma;
  60. wire fb_crc_error;
  61. reg motor_start;
  62. reg motor_feedback_valid;
  63. reg [15:0] motor_feedback_rpm;
  64. reg [15:0] motor_feedback_current_ma;
  65. reg motor_feedback_fault;
  66. reg motor_feedback_encoder_ok;
  67. reg [15:0] motor_feedback_time_ms;
  68. wire motor_busy;
  69. wire motor_done;
  70. wire [6:0] motor_pwm;
  71. wire motor_enable;
  72. wire motor_direction;
  73. wire [15:0] motor_state_id;
  74. wire [7:0] motor_fault_code;
  75. wire motor_trace_valid;
  76. wire [15:0] motor_trace_id;
  77. wire [15:0] motor_trace_timestamp;
  78. wire [31:0] motor_trace_data;
  79. reg capture_reset;
  80. wire [15:0] captured_count;
  81. wire [31:0] drop_count;
  82. wire overflow;
  83. reg rd_en;
  84. reg [TRACE_ADDR_W-1:0] rd_addr;
  85. wire [63:0] rd_data;
  86. reg pkt_send;
  87. reg [7:0] pkt_type;
  88. reg [15:0] pkt_seq;
  89. reg [15:0] pkt_event_id;
  90. reg [31:0] pkt_timestamp;
  91. reg [31:0] pkt_data;
  92. wire pkt_busy;
  93. wire pkt_done;
  94. reg [3:0] top_state;
  95. reg [15:0] hil_seq;
  96. reg [31:0] sim_time_ms;
  97. reg [31:0] feedback_timeout_counter;
  98. reg [15:0] total_to_dump;
  99. reg [15:0] dump_index;
  100. reg [31:0] sim_time_latched;
  101. reg [31:0] drop_count_latched;
  102. reg hil_link_error;
  103. // Latch one validated feedback packet before applying it to the controller.
  104. reg [15:0] fb_seq_l;
  105. reg [15:0] fb_flags_l;
  106. reg [31:0] fb_time_l;
  107. reg [15:0] fb_rpm_l;
  108. reg [15:0] fb_current_l;
  109. reg [31:0] heartbeat_counter;
  110. reg heartbeat_phase;
  111. reg [31:0] activity_hold_counter;
  112. reg [31:0] tx_hold_counter;
  113. reg error_latched;
  114. wire start_cmd = rx_valid && (rx_data == 8'h53) && (top_state == T_IDLE); // 'S'
  115. wire ping_cmd = rx_valid && (rx_data == 8'h50) && (top_state == T_IDLE); // 'P'
  116. wire transaction_busy = (top_state != T_IDLE) &&
  117. (top_state != T_SEND_STATUS) &&
  118. (top_state != T_WAIT_STATUS);
  119. reset_sync u_reset_sync (
  120. .clk(sys_clk),
  121. .reset_n_ext(reset_n),
  122. .reset_n(rst_n)
  123. );
  124. uart_rx #(
  125. .CLK_HZ(CLK_HZ),
  126. .BAUD(BAUD)
  127. ) u_uart_rx (
  128. .clk(sys_clk),
  129. .reset_n(rst_n),
  130. .rx(uart_rx),
  131. .data(rx_data),
  132. .valid(rx_valid),
  133. .framing_error(rx_framing_error)
  134. );
  135. motor_feedback_rx u_feedback_rx (
  136. .clk(sys_clk),
  137. .reset_n(rst_n),
  138. .rx_data(rx_data),
  139. .rx_valid(rx_valid),
  140. .feedback_valid(fb_packet_valid),
  141. .feedback_seq(fb_packet_seq),
  142. .feedback_flags(fb_packet_flags),
  143. .feedback_timestamp(fb_packet_timestamp),
  144. .feedback_rpm(fb_packet_rpm),
  145. .feedback_current_ma(fb_packet_current_ma),
  146. .crc_error(fb_crc_error)
  147. );
  148. motor_controller_hil u_motor_controller (
  149. .clk(sys_clk),
  150. .reset_n(rst_n),
  151. .start(motor_start),
  152. .feedback_valid(motor_feedback_valid),
  153. .feedback_rpm(motor_feedback_rpm),
  154. .feedback_current_ma(motor_feedback_current_ma),
  155. .feedback_fault(motor_feedback_fault),
  156. .feedback_encoder_ok(motor_feedback_encoder_ok),
  157. .feedback_time_ms(motor_feedback_time_ms),
  158. .busy(motor_busy),
  159. .done(motor_done),
  160. .pwm_duty(motor_pwm),
  161. .motor_enable(motor_enable),
  162. .direction(motor_direction),
  163. .state_id(motor_state_id),
  164. .fault_code(motor_fault_code),
  165. .trace_valid(motor_trace_valid),
  166. .trace_id(motor_trace_id),
  167. .trace_timestamp(motor_trace_timestamp),
  168. .trace_data(motor_trace_data)
  169. );
  170. trace_capture_ram #(
  171. .TRACE_DEPTH(TRACE_DEPTH),
  172. .TRACE_ADDR_W(TRACE_ADDR_W)
  173. ) u_trace_ram (
  174. .clk(sys_clk),
  175. .reset_n(rst_n),
  176. .capture_reset(capture_reset),
  177. .trace_valid(motor_trace_valid && (top_state == T_APPLY_FB)),
  178. .trace_id(motor_trace_id),
  179. .trace_timestamp(motor_trace_timestamp),
  180. .trace_data(motor_trace_data),
  181. .captured_count(captured_count),
  182. .drop_count(drop_count),
  183. .overflow(overflow),
  184. .rd_en(rd_en),
  185. .rd_addr(rd_addr),
  186. .rd_data(rd_data)
  187. );
  188. trace_packet_tx #(
  189. .CLK_HZ(CLK_HZ),
  190. .BAUD(BAUD)
  191. ) u_packet_tx (
  192. .clk(sys_clk),
  193. .reset_n(rst_n),
  194. .send(pkt_send),
  195. .pkt_type(pkt_type),
  196. .seq(pkt_seq),
  197. .event_id(pkt_event_id),
  198. .timestamp(pkt_timestamp),
  199. .data(pkt_data),
  200. .uart_tx_o(uart_tx),
  201. .busy(pkt_busy),
  202. .done(pkt_done)
  203. );
  204. assign led_heartbeat_n = heartbeat_phase ? 1'b0 : 1'b1;
  205. assign led_reset_n = reset_n;
  206. assign led_activity_n = (activity_hold_counter != 0) ? 1'b0 : 1'b1;
  207. assign led_tx_n = (tx_hold_counter != 0) ? 1'b0 : 1'b1;
  208. assign led_error_n = error_latched ? 1'b0 : 1'b1;
  209. always @(posedge sys_clk or negedge rst_n) begin
  210. if (!rst_n) begin
  211. heartbeat_counter <= 32'd0;
  212. heartbeat_phase <= 1'b0;
  213. activity_hold_counter <= 32'd0;
  214. tx_hold_counter <= 32'd0;
  215. error_latched <= 1'b0;
  216. end else begin
  217. if (heartbeat_counter >= (CLK_HZ / 2) - 1) begin
  218. heartbeat_counter <= 32'd0;
  219. heartbeat_phase <= ~heartbeat_phase;
  220. end else begin
  221. heartbeat_counter <= heartbeat_counter + 1'b1;
  222. end
  223. if (start_cmd || transaction_busy)
  224. activity_hold_counter <= LED_HOLD_CYCLES;
  225. else if (activity_hold_counter != 0)
  226. activity_hold_counter <= activity_hold_counter - 1'b1;
  227. if (pkt_busy || pkt_send)
  228. tx_hold_counter <= LED_HOLD_CYCLES;
  229. else if (tx_hold_counter != 0)
  230. tx_hold_counter <= tx_hold_counter - 1'b1;
  231. if (start_cmd)
  232. error_latched <= 1'b0;
  233. if (rx_framing_error || fb_crc_error || overflow || hil_link_error || (motor_fault_code != 0))
  234. error_latched <= 1'b1;
  235. end
  236. end
  237. // Combinational control for one-cycle pulses and the shared packet transmitter.
  238. always @(*) begin
  239. motor_start = 1'b0;
  240. motor_feedback_valid = 1'b0;
  241. motor_feedback_rpm = fb_rpm_l;
  242. motor_feedback_current_ma = fb_current_l;
  243. motor_feedback_fault = fb_flags_l[0];
  244. motor_feedback_encoder_ok = fb_flags_l[1];
  245. motor_feedback_time_ms = fb_time_l[15:0];
  246. capture_reset = 1'b0;
  247. rd_en = 1'b0;
  248. rd_addr = dump_index[TRACE_ADDR_W-1:0];
  249. pkt_send = 1'b0;
  250. pkt_type = PKT_TRACE;
  251. pkt_seq = dump_index;
  252. pkt_event_id = rd_data[47:32];
  253. pkt_timestamp = {16'd0, rd_data[63:48]};
  254. pkt_data = rd_data[31:0];
  255. case (top_state)
  256. T_IDLE: begin
  257. if (start_cmd) begin
  258. capture_reset = 1'b1;
  259. motor_start = 1'b1;
  260. end
  261. end
  262. T_SEND_STATUS: begin
  263. pkt_type = PKT_STATUS;
  264. pkt_seq = 16'd0;
  265. pkt_event_id = STATUS_EVENT_ID;
  266. pkt_timestamp = 32'd0;
  267. pkt_data = `TRACE_BUILD_ID;
  268. if (!pkt_busy)
  269. pkt_send = 1'b1;
  270. end
  271. T_SEND_MOTOR: begin
  272. pkt_type = PKT_MOTOR_CMD;
  273. pkt_seq = hil_seq;
  274. pkt_event_id = motor_state_id;
  275. pkt_timestamp = sim_time_ms;
  276. pkt_data = {1'b0, motor_pwm, motor_enable, motor_direction, 22'd0};
  277. if (!pkt_busy)
  278. pkt_send = 1'b1;
  279. end
  280. T_APPLY_FB: begin
  281. motor_feedback_valid = 1'b1;
  282. end
  283. T_READ: begin
  284. rd_en = 1'b1;
  285. rd_addr = dump_index[TRACE_ADDR_W-1:0];
  286. end
  287. T_SEND_TRACE: begin
  288. if (!pkt_busy)
  289. pkt_send = 1'b1;
  290. end
  291. T_SEND_SUMMARY: begin
  292. pkt_type = PKT_SUMMARY;
  293. pkt_seq = total_to_dump;
  294. pkt_event_id = hil_link_error ? 16'hFFFE : 16'hFFFF;
  295. pkt_timestamp = sim_time_latched;
  296. pkt_data = drop_count_latched;
  297. if (!pkt_busy)
  298. pkt_send = 1'b1;
  299. end
  300. default: begin end
  301. endcase
  302. end
  303. always @(posedge sys_clk or negedge rst_n) begin
  304. if (!rst_n) begin
  305. top_state <= T_IDLE;
  306. hil_seq <= 16'd0;
  307. sim_time_ms <= 32'd0;
  308. feedback_timeout_counter <= 32'd0;
  309. total_to_dump <= 16'd0;
  310. dump_index <= 16'd0;
  311. sim_time_latched <= 32'd0;
  312. drop_count_latched <= 32'd0;
  313. hil_link_error <= 1'b0;
  314. fb_seq_l <= 16'd0;
  315. fb_flags_l <= 16'd0;
  316. fb_time_l <= 32'd0;
  317. fb_rpm_l <= 16'd0;
  318. fb_current_l <= 16'd0;
  319. end else begin
  320. case (top_state)
  321. T_IDLE: begin
  322. hil_seq <= 16'd0;
  323. sim_time_ms <= 32'd0;
  324. feedback_timeout_counter <= 32'd0;
  325. dump_index <= 16'd0;
  326. if (start_cmd) begin
  327. hil_link_error <= 1'b0;
  328. top_state <= T_SEND_MOTOR;
  329. end else if (ping_cmd) begin
  330. top_state <= T_SEND_STATUS;
  331. end
  332. end
  333. T_SEND_STATUS: begin
  334. if (!pkt_busy)
  335. top_state <= T_WAIT_STATUS;
  336. end
  337. T_WAIT_STATUS: begin
  338. if (pkt_done)
  339. top_state <= T_IDLE;
  340. end
  341. T_SEND_MOTOR: begin
  342. if (!pkt_busy)
  343. top_state <= T_WAIT_MOTOR;
  344. end
  345. T_WAIT_MOTOR: begin
  346. if (pkt_done) begin
  347. feedback_timeout_counter <= 32'd0;
  348. top_state <= T_WAIT_FB;
  349. end
  350. end
  351. T_WAIT_FB: begin
  352. if (fb_packet_valid) begin
  353. if (fb_packet_seq == hil_seq) begin
  354. fb_seq_l <= fb_packet_seq;
  355. fb_flags_l <= fb_packet_flags;
  356. fb_time_l <= fb_packet_timestamp;
  357. fb_rpm_l <= fb_packet_rpm;
  358. fb_current_l <= fb_packet_current_ma;
  359. top_state <= T_APPLY_FB;
  360. end else begin
  361. hil_link_error <= 1'b1;
  362. top_state <= T_PREP;
  363. end
  364. end else if (feedback_timeout_counter >= FEEDBACK_TIMEOUT_CYCLES - 1) begin
  365. hil_link_error <= 1'b1;
  366. top_state <= T_PREP;
  367. end else begin
  368. feedback_timeout_counter <= feedback_timeout_counter + 1'b1;
  369. end
  370. end
  371. T_APPLY_FB: begin
  372. top_state <= T_CHECK;
  373. end
  374. T_CHECK: begin
  375. hil_seq <= hil_seq + 1'b1;
  376. sim_time_ms <= sim_time_ms + STEP_MS;
  377. if (motor_done)
  378. top_state <= T_PREP;
  379. else
  380. top_state <= T_SEND_MOTOR;
  381. end
  382. T_PREP: begin
  383. total_to_dump <= captured_count;
  384. sim_time_latched <= sim_time_ms;
  385. drop_count_latched <= drop_count;
  386. dump_index <= 16'd0;
  387. if (captured_count == 0)
  388. top_state <= T_SEND_SUMMARY;
  389. else
  390. top_state <= T_READ;
  391. end
  392. T_READ: begin
  393. top_state <= T_SEND_TRACE;
  394. end
  395. T_SEND_TRACE: begin
  396. if (!pkt_busy)
  397. top_state <= T_WAIT_TRACE;
  398. end
  399. T_WAIT_TRACE: begin
  400. if (pkt_done) begin
  401. if ((dump_index + 1'b1) >= total_to_dump) begin
  402. top_state <= T_SEND_SUMMARY;
  403. end else begin
  404. dump_index <= dump_index + 1'b1;
  405. top_state <= T_READ;
  406. end
  407. end
  408. end
  409. T_SEND_SUMMARY: begin
  410. if (!pkt_busy)
  411. top_state <= T_WAIT_SUMMARY;
  412. end
  413. T_WAIT_SUMMARY: begin
  414. if (pkt_done)
  415. top_state <= T_IDLE;
  416. end
  417. default: top_state <= T_IDLE;
  418. endcase
  419. end
  420. end
  421. endmodule