Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/ultrasonic_sensor/debounce.sv
Original file line number Diff line number Diff line change
@@ -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

135 changes: 135 additions & 0 deletions src/ultrasonic_sensor/sensor_driver.sv
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions src/ultrasonic_sensor/tb/sensor_driver_tb.sv
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions src/ultrasonic_sensor/top_level.sv
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions src/ultrasonic_sensor/top_level_distance_sensor.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module top_level_distance_sensor #(
parameter CLOSE = 8'd50
) (
input CLOCK_50,
input enable,
input reset,
input echo,
output trigger,
output too_close
);

logic start;

// 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)
);

// 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