From 32d1e48a4576c7403579bb8ad799592286f86a4f Mon Sep 17 00:00:00 2001 From: RossGazis Date: Thu, 17 Oct 2024 17:05:57 +1100 Subject: [PATCH 1/5] ultrasonic sensor --- src/ultrasonic_sensor/debounce.sv | 26 ++++ src/ultrasonic_sensor/sensor_driver.sv | 135 +++++++++++++++++++ src/ultrasonic_sensor/tb/sensor_driver_tb.sv | 70 ++++++++++ src/ultrasonic_sensor/top_level.sv | 40 ++++++ 4 files changed, 271 insertions(+) create mode 100644 src/ultrasonic_sensor/debounce.sv create mode 100644 src/ultrasonic_sensor/sensor_driver.sv create mode 100644 src/ultrasonic_sensor/tb/sensor_driver_tb.sv create mode 100644 src/ultrasonic_sensor/top_level.sv diff --git a/src/ultrasonic_sensor/debounce.sv b/src/ultrasonic_sensor/debounce.sv new file mode 100644 index 0000000..23b2e02 --- /dev/null +++ b/src/ultrasonic_sensor/debounce.sv @@ -0,0 +1,26 @@ +module debounce ( + input clk, button, + output logic button_edge +); + parameter delay_val = 2500; // 50us with clk period 20ns is 2500 counts + integer count = 0; + logic new_button_pressed=0; + logic button_pressed = 0; + + always_ff @(posedge clk) begin : debouncing + if (button != new_button_pressed) begin + new_button_pressed <= button; + count <= 0; + end + else if (count == delay_val) button_pressed <= new_button_pressed; + else count <= count + 1; + end + + logic button_q0; + + always_ff @(posedge clk) begin : edge_detect + button_q0 <= button_pressed; + end + assign button_edge = (button_pressed > button_q0); +endmodule + diff --git a/src/ultrasonic_sensor/sensor_driver.sv b/src/ultrasonic_sensor/sensor_driver.sv new file mode 100644 index 0000000..e8313c9 --- /dev/null +++ b/src/ultrasonic_sensor/sensor_driver.sv @@ -0,0 +1,135 @@ +// sensor_driver based on timing diagram: +// user sends a trigger signal which lasts 10us, and expects an echo signal back to the module +// The Echo is a distance object that is pulse width and the range in proportion. +// You can calculate the range through the time interval between sending trigger signal and receiving echo signal + +module sensor_driver#(parameter ten_us = 10'd500)( + input clk, + input rst, + input measure, + input echo, + output trig, + output [7:0] distance); + + localparam IDLE = 3'b000, + TRIGGER = 3'b010, + WAIT = 3'b011, + COUNTECHO = 3'b100, + DISPLAY_DISTANCE = 3'b101; + + wire inIDLE, inTRIGGER, inWAIT, inCOUNTECHO, inDISPLAY; + reg [9:0] counter; + reg [21:0] distanceRAW = 0; // cycles in COUNTECHO + reg [31:0] distanceRAW_in_cm = 0; + wire trigcountDONE, counterDONE; + + logic [2:0] state; + logic ready; + + //Ready + assign ready = inIDLE; + + //Decode states + assign inIDLE = (state == IDLE); + assign inTRIGGER = (state == TRIGGER); + assign inWAIT = (state == WAIT); + assign inCOUNTECHO = (state == COUNTECHO); + assign inDISPLAY = (state == DISPLAY_DISTANCE); + + //State transactions + always@(posedge clk or posedge rst) + begin + if(rst) + begin + state <= IDLE; + end + else + begin + case(state) + IDLE: + begin + state <= (measure & ready) ? TRIGGER : state; + end + TRIGGER: + begin + state <= (trigcountDONE) ? WAIT : state; + end + WAIT: + begin + state <= (echo) ? COUNTECHO : state; + end + COUNTECHO: + begin + state <= (echo) ? state : DISPLAY_DISTANCE; + end + DISPLAY_DISTANCE: + begin + state <= IDLE; + end + endcase + + end + end + + //Trigger + assign trig = inTRIGGER; + + //Counter + always@(posedge clk) + begin + if(inIDLE) + begin + counter <= 10'd0; + end + else + begin + counter <= counter + {9'd0, (|counter | inTRIGGER)}; + end + end + assign trigcountDONE = (counter == ten_us); + + //Get distance + always@(posedge clk) + begin + if(inWAIT) begin + distanceRAW <= 22'd0; + end else + distanceRAW <= distanceRAW + {21'd0, inCOUNTECHO}; + + end + + // to calculate distance in cm + // range = high level time * velocity (340M/S) / 2 + // 340m/s = 0.000034cm/ns = 0.00068cm/cycle + // range = 0.00068/2 = 0.00034cm/cycle + // using fixedpoint python library we can convert 0.000034 to fixed point binary with 8 int and 24 frac bits by writing the code below + // import fixedpoint + // print(fixedpoint.FixedPoint(0.00034, signed=True, m=8, n=24)) # Signed with 8 integer bits and 24 fractional bits + + always @(posedge clk) begin + if(inDISPLAY) begin + distanceRAW_in_cm <= distanceRAW * 32'h1648; + end + end + + assign distance = distanceRAW_in_cm[31:24]; + +endmodule + +// timer used to measure distance at 250ms intervals - not used in top level +module refresher250ms( + input clk, + input en, + output measure); + reg [24:0] counter; + + assign measure = (counter == 25'd1); + + always@(posedge clk) + begin + if(~en | (counter == 25'd12_500_000)) + counter <= 25'd0; + else + counter <= 25'd1 + counter; + end +endmodule diff --git a/src/ultrasonic_sensor/tb/sensor_driver_tb.sv b/src/ultrasonic_sensor/tb/sensor_driver_tb.sv new file mode 100644 index 0000000..6f26656 --- /dev/null +++ b/src/ultrasonic_sensor/tb/sensor_driver_tb.sv @@ -0,0 +1,70 @@ +module sensor_driver_tb(); + +parameter CLK_PERIOD = 20; + +logic clk; +logic echo; +logic trigger; +logic start; +logic reset; +logic [7:0] LEDR; + +sensor_driver u0( + .clk(clk), + .echo(echo), + .measure(start), + .rst(reset), + .trig(trigger), + .distance(LEDR) + +); + + +initial clk = 1'b0; + +always begin + #10 + clk = ~clk; +end + + initial begin + + #(1 * CLK_PERIOD) + reset = 1; + start = 0; + LEDR = 0; + + #(1 * CLK_PERIOD) + reset = 0; + start = 1; + + #(1 * CLK_PERIOD) + start = 0; + + #(500 * CLK_PERIOD) + echo = 1; + #(1000000 * CLK_PERIOD) + + #(1 * CLK_PERIOD) + echo = 0; + + #(10 * CLK_PERIOD) + + #(1 * CLK_PERIOD) + start = 1; + + #(1 * CLK_PERIOD) + start = 0; + + #(500 * CLK_PERIOD) + echo = 1; + #(1000000 * CLK_PERIOD) + + #(1 * CLK_PERIOD) + echo = 0; + + #(10 * CLK_PERIOD) + + $finish(); + end +endmodule diff --git a/src/ultrasonic_sensor/top_level.sv b/src/ultrasonic_sensor/top_level.sv new file mode 100644 index 0000000..e577bac --- /dev/null +++ b/src/ultrasonic_sensor/top_level.sv @@ -0,0 +1,40 @@ +module top_level( + input CLOCK_50, + inout [35:0] GPIO, + input [17:0] SW, + input [3:0] KEY, + output [9:0] LEDR +); + +logic start, reset; +logic echo, trigger; + +assign echo = GPIO[34]; +assign GPIO[35] = trigger; + +// Reset button (KEY[3]) +debounce reset_edge( + .clk(CLOCK_50), + .button(!KEY[3]), + .button_edge(reset) +); + +// Measure the distance every 250ms +refresher250ms refresher_250ms ( + .clk(CLOCK_50), + .en(SW[0]), + .measure(start) +); + +// Sends trigger and reads distance +sensor_driver u0( + .clk(CLOCK_50), + .rst(reset), + .measure(start), + .echo(echo), + .trig(trigger), + .distance(LEDR) +); + + +endmodule From 5caa2c3fbf914b422721e2fee40c870afbf1978c Mon Sep 17 00:00:00 2001 From: RossGazis Date: Thu, 17 Oct 2024 17:17:10 +1100 Subject: [PATCH 2/5] Create top_level_distance_sensor.sv --- .../top_level_distance_sensor.sv | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/ultrasonic_sensor/top_level_distance_sensor.sv diff --git a/src/ultrasonic_sensor/top_level_distance_sensor.sv b/src/ultrasonic_sensor/top_level_distance_sensor.sv new file mode 100644 index 0000000..a42b74e --- /dev/null +++ b/src/ultrasonic_sensor/top_level_distance_sensor.sv @@ -0,0 +1,32 @@ + +module top_level_distance_sensor ( + input CLOCK_50, + input enable, + input reset, + inout [35:0] GPIO, + output [7:0] distance +); + +logic start; +logic echo, trigger; + +assign echo = GPIO[34]; +assign GPIO[35] = trigger; + +// Measure the distance every 250ms +refresher250ms refresher_250ms ( + .clk(CLOCK_50), + .en(enable), + .measure(start) +); + +// Sends trigger and reads distance +sensor_driver u0( + .clk(CLOCK_50), + .rst(reset), + .measure(start), + .echo(echo), + .trig(trigger), + .distance(distance) +); +endmodule \ No newline at end of file From 875d6441712b5073b25d3c26629ff77bbe717b65 Mon Sep 17 00:00:00 2001 From: RossGazis Date: Thu, 17 Oct 2024 17:26:19 +1100 Subject: [PATCH 3/5] Update top_level_distance_sensor.sv --- src/ultrasonic_sensor/top_level_distance_sensor.sv | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ultrasonic_sensor/top_level_distance_sensor.sv b/src/ultrasonic_sensor/top_level_distance_sensor.sv index a42b74e..6e869dd 100644 --- a/src/ultrasonic_sensor/top_level_distance_sensor.sv +++ b/src/ultrasonic_sensor/top_level_distance_sensor.sv @@ -1,17 +1,13 @@ - module top_level_distance_sensor ( input CLOCK_50, input enable, input reset, - inout [35:0] GPIO, + input echo, + output trigger, output [7:0] distance ); logic start; -logic echo, trigger; - -assign echo = GPIO[34]; -assign GPIO[35] = trigger; // Measure the distance every 250ms refresher250ms refresher_250ms ( From 357b1b6784975a258cb701ad571d882729710dda Mon Sep 17 00:00:00 2001 From: RossGazis Date: Thu, 17 Oct 2024 18:00:36 +1100 Subject: [PATCH 4/5] too_close flag --- src/ultrasonic_sensor/top_level_distance_sensor.sv | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ultrasonic_sensor/top_level_distance_sensor.sv b/src/ultrasonic_sensor/top_level_distance_sensor.sv index 6e869dd..8142c20 100644 --- a/src/ultrasonic_sensor/top_level_distance_sensor.sv +++ b/src/ultrasonic_sensor/top_level_distance_sensor.sv @@ -4,9 +4,10 @@ module top_level_distance_sensor ( input reset, input echo, output trigger, - output [7:0] distance + output too_close ); +localparam CLOSE = 8'd50; logic start; // Measure the distance every 250ms @@ -25,4 +26,14 @@ sensor_driver u0( .trig(trigger), .distance(distance) ); + +// Always checks distance < 50cm, if true raises too_close +always_comb begin + if (distance < CLOSE) begin + too_close <= 1; + end + else begin + too_close <= 1; + end +end endmodule \ No newline at end of file From 98d10c5865223af3d5541a7d4e328f949c1515ef Mon Sep 17 00:00:00 2001 From: RossGazis Date: Thu, 17 Oct 2024 18:03:16 +1100 Subject: [PATCH 5/5] Update top_level_distance_sensor.sv --- src/ultrasonic_sensor/top_level_distance_sensor.sv | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ultrasonic_sensor/top_level_distance_sensor.sv b/src/ultrasonic_sensor/top_level_distance_sensor.sv index 8142c20..bc38d15 100644 --- a/src/ultrasonic_sensor/top_level_distance_sensor.sv +++ b/src/ultrasonic_sensor/top_level_distance_sensor.sv @@ -1,4 +1,6 @@ -module top_level_distance_sensor ( +module top_level_distance_sensor #( + parameter CLOSE = 8'd50 +) ( input CLOCK_50, input enable, input reset, @@ -7,7 +9,6 @@ module top_level_distance_sensor ( output too_close ); -localparam CLOSE = 8'd50; logic start; // Measure the distance every 250ms