| 
									
										
										
										
											2025-05-07 10:27:17 +02:00
										 |  |  | module ultrasonic_fpga #( | 
					
						
							|  |  |  |     parameter integer CLK_FREQ = 27_000_000  // Fréquence d'horloge en Hz | 
					
						
							|  |  |  | )( | 
					
						
							|  |  |  |     input  wire clk, | 
					
						
							|  |  |  |     input  wire start, | 
					
						
							|  |  |  |     inout  wire sig,             // Broche bidirectionnelle vers le capteur | 
					
						
							|  |  |  |     output reg [15:0] distance,  // Distance mesurée en cm | 
					
						
							|  |  |  |     output reg busy, | 
					
						
							|  |  |  |     output reg done | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  |     reg [15:0] trig_counter = 0; | 
					
						
							|  |  |  |     reg [31:0] echo_counter = 0; | 
					
						
							|  |  |  |     reg [31:0] echo_div_counter = 0; | 
					
						
							|  |  |  |     reg [15:0] distance_counter = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reg sig_out; | 
					
						
							|  |  |  |     reg sig_dir;                  // 1: output, 0: input | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assign sig = sig_dir ? sig_out : 1'bz; // bz pour dire que le fpga laisse le fils libre et n'oblige pas de valeur | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reg sig_int, sig_ok; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reg [2:0] state = IDLE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     localparam IDLE         = 3'd0, | 
					
						
							|  |  |  |                TRIG_HIGH    = 3'd1, | 
					
						
							|  |  |  |                TRIG_LOW     = 3'd2, | 
					
						
							|  |  |  |                WAIT_ECHO    = 3'd3, | 
					
						
							|  |  |  |                MEASURE_ECHO = 3'd4, | 
					
						
							|  |  |  |                COMPUTE      = 3'd5, | 
					
						
							|  |  |  |                DONE         = 3'd6, | 
					
						
							|  |  |  |                WAIT_NEXT    = 3'd7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse | 
					
						
							|  |  |  |     localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm | 
					
						
							|  |  |  |     localparam integer MAX_CM = 350; | 
					
						
							|  |  |  |     localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reg [31:0] wait_counter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     always @(posedge clk) begin | 
					
						
							|  |  |  |         sig_int <= sig; | 
					
						
							|  |  |  |         sig_ok  <= sig_int; | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     always @(posedge clk) begin | 
					
						
							|  |  |  |         busy <= (state != IDLE); | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     always @(posedge clk) begin // FSM | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         case (state) | 
					
						
							|  |  |  |             IDLE: begin | 
					
						
							| 
									
										
										
										
											2025-05-07 10:39:52 +02:00
										 |  |  |                 done <= 1; | 
					
						
							| 
									
										
										
										
											2025-05-07 10:27:17 +02:00
										 |  |  |                 sig_out <= 0; | 
					
						
							|  |  |  |                 sig_dir <= 0; | 
					
						
							|  |  |  |                 distance <= 0; | 
					
						
							|  |  |  |                 if (start) begin | 
					
						
							|  |  |  |                     state <= TRIG_HIGH; | 
					
						
							|  |  |  |                     trig_counter <= 0; | 
					
						
							|  |  |  |                     done <= 0; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             TRIG_HIGH: begin | 
					
						
							|  |  |  |                 sig_out <= 1; | 
					
						
							|  |  |  |                 sig_dir <= 1; | 
					
						
							|  |  |  |                 if (trig_counter < TRIG_PULSE_CYCLES) begin | 
					
						
							|  |  |  |                     trig_counter <= trig_counter + 1; | 
					
						
							|  |  |  |                 end else begin | 
					
						
							|  |  |  |                     trig_counter <= 0; | 
					
						
							|  |  |  |                     state <= TRIG_LOW; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             TRIG_LOW: begin | 
					
						
							|  |  |  |                 sig_out <= 0; | 
					
						
							|  |  |  |                 sig_dir <= 0; // Mettre en entrée | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (sig_ok) begin | 
					
						
							|  |  |  |                     state <= TRIG_LOW; | 
					
						
							|  |  |  |                 end else | 
					
						
							|  |  |  |                     state <= WAIT_ECHO; | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             WAIT_ECHO: begin | 
					
						
							|  |  |  |                 if (sig_ok) begin | 
					
						
							|  |  |  |                     echo_counter <= 0; | 
					
						
							|  |  |  |                     state <= MEASURE_ECHO; | 
					
						
							|  |  |  |                 end else if (echo_counter >= TIMEOUT_CYCLES) begin | 
					
						
							|  |  |  |                     distance <= 0;  | 
					
						
							|  |  |  |                     state <= DONE; | 
					
						
							|  |  |  |                 end else begin | 
					
						
							|  |  |  |                     echo_counter <= echo_counter + 1; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             MEASURE_ECHO: begin | 
					
						
							|  |  |  |                 if (sig_ok) begin | 
					
						
							|  |  |  |                     if (echo_counter < TIMEOUT_CYCLES) begin | 
					
						
							|  |  |  |                         echo_counter <= echo_counter + 1; | 
					
						
							|  |  |  |                     end else begin  | 
					
						
							|  |  |  |                         state <= DONE; | 
					
						
							|  |  |  |                     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 end else begin  | 
					
						
							|  |  |  |                     state <= COMPUTE; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             COMPUTE: begin | 
					
						
							|  |  |  |                 if (echo_counter >= DIST_DIVISOR) begin | 
					
						
							|  |  |  |                     echo_counter <= echo_counter - DIST_DIVISOR; | 
					
						
							|  |  |  |                     distance_counter <= distance_counter + 1; | 
					
						
							|  |  |  |                     state <= COMPUTE; | 
					
						
							|  |  |  |                 end else begin | 
					
						
							|  |  |  |                     distance <= distance_counter; | 
					
						
							|  |  |  |                     state <= DONE; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             DONE: begin | 
					
						
							|  |  |  |                 if (start) begin | 
					
						
							|  |  |  |                     wait_counter <= 0; | 
					
						
							|  |  |  |                     state <= WAIT_NEXT; | 
					
						
							|  |  |  |                 end else begin | 
					
						
							|  |  |  |                     state <= IDLE; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |                 done <= 1;  | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             WAIT_NEXT: begin | 
					
						
							|  |  |  |                 wait_counter <= wait_counter + 1; | 
					
						
							|  |  |  |                 if (wait_counter >= WAIT_NEXT_CYCLES) begin | 
					
						
							|  |  |  |                     state <= TRIG_HIGH; | 
					
						
							|  |  |  |                     trig_counter <= 0; | 
					
						
							|  |  |  |                     distance_counter <= 0; | 
					
						
							|  |  |  |                     echo_counter <= 0; | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             default: begin | 
					
						
							|  |  |  |                 state <= IDLE; // Reset to IDLE state in case of an error | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |         endcase | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | endmodule |