FPGA Basys 3 State Machine Logic with PMOD ALS Sensor - verilog

For a lab I must create the logic to use on a Digilent PMOD ALS. In the lab requirenment I cannot use the sclk signal on the sensitivity list and therefore use a state machine to create the 2.5 MHz clk signal to send to the PMOD ALS. See the code below:
module sens_interface(
input clk, //clk 10Mhz
input reset_n,
input [15:0] delay,
input datain,
output reg sclk,
output reg cs_n,
output reg [3:0] Cout,
output reg [3:0] Dout,
output reg [5:0] cnt
);
//params
//state machine 1
parameter SA0 = 3'b000;
parameter SA1 = 3'b001;
parameter SA2 = 3'b010;
parameter SA3 = 3'b011;
parameter SD0 = 3'b100;
parameter SD1 = 3'b101;
//state machine 2
parameter SR0 = 2'b00;
parameter SR1 = 2'b01;
parameter SR2 = 2'b10;
parameter SR3 = 2'b11;
//pmod als registers
//reg sclk; //2.5Mhz clk
//reg cs_n; //
reg [14:0] data_reg;
//count registers
//reg [5:0] cnt;
reg [15:0] cnt_d;
reg [5:0] cnt_r;
//state registers
reg [2:0] state_sclk;
reg [1:0] state_data;
//State Machine 1
always # (posedge clk)begin
if(reset_n == 1'b0)begin
cs_n <= 1'b1;
sclk <= 0;
cnt <= 6'd0;
cnt_d <= 16'd0;
end
else
case(state_sclk)
SA0:begin
sclk <= 1'b1;
state_sclk <= SA1;
if (cnt <= 6'd17)
cs_n <= 1'b0;
else
cs_n <= 1'b1;
end
SA1:begin
state_sclk <= SA2;
end
SA2:begin
sclk <= 1'b0;
cnt <= cnt + 1;
state_sclk <= SA3;
end
SA3:begin
if(cnt == 6'd21)begin
cnt <= 0;
state_sclk <= SD0;
end
else
state_sclk <= SA0;
end
SD0:begin
cnt_d <= delay;
state_sclk <= SD1;
end
SD1:begin
if (cnt_d == 0)
state_sclk <= SA0;
else
cnt_d <= cnt_d - 1;
end
default:begin
state_sclk <= SA0;
end
endcase
end
always # (posedge clk)begin
if (reset_n == 1'b0)begin
cnt_r <= 0;
data_reg <= 0;
end
else begin
case (state_data)
SR0:begin
if (cs_n == 1'b1 && sclk == 1'b1)
state_data <= SR1;
end
SR1: begin
if (cs_n == 1'b1)begin
state_data <= SR0;
cnt_r <= 0;
end
else if (sclk == 1'b0)
state_data <= SR2;
end
SR2:begin
if (cs_n == 1'b1)begin
state_data <= SR0;
cnt_r <= 0;
end
else if (cnt_r == 15)
state_data <= SR3;
else if (sclk == 1'b1)begin
data_reg [14-cnt_r] <= datain;
cnt_r <= cnt_r + 1;
state_data <= SR1;
end
end
SR3:begin
if (cs_n == 1) begin
Cout <= data_reg [11:8];
Dout <= data_reg [7:4];
state_data <= SR0;
end
end
default:begin
state_data <= SR0;
end
endcase
end
end
endmodule
I tried to make a simulation of it and the simulation indicates that after my cnt register reaches 15 it just cuts out and goes to 0.
simulation

That behavior is caused by your SA3 state.
SA3:begin
if(cnt == 6'd21)begin
cnt <= 0;
state_sclk <= SD0;
end
else
state_sclk <= SA0;
end
end
When your cnt == 6'd21 (which is 6'h15) the cnt is set to zero.
The generic variable names and lack of comments makes it difficult to see why this is not the expected behavior.

Related

Verilog If statement -Appears to be triggering before Condition

Why does r_D <= 8'h40 execute before w_Rx_DV == 1'b1 according to below code and waveform? R_D should not be assigned any value until w_Rx_DV goes high.
Thank you for any comments
Joe
module main(
input i_Clock,
input i_Rx_Serial,
output o_PWM
);
reg r_Load ;
reg [7:0] r_D =0;
wire w_Rx_DV;
wire [7:0] w_RX_Byte;
reg [7:0] r_RX_Byte;
PWM PWM(
.i_Clock(i_Clock),
.i_Load(r_Load),
.i_D (r_D),
.o_PWM(o_PWM)
);
rx rx(
.i_Clock (i_Clock),
.i_Rx_Serial (i_Rx_Serial),
.o_Rx_DV (w_Rx_DV),
.o_Rx_Byte (w_RX_Byte)
);
always # (posedge i_Clock)
begin
r_Load <= 0;
if(w_Rx_DV == 1'b1) ;
begin
r_RX_Byte <= w_RX_Byte;
if(r_RX_Byte ==8'h0)
begin
r_D <= 0;
r_Load <= 1;
end
if(r_RX_Byte == 8'h3F)
begin
r_D <= 8'h40;
r_Load <= 1;
end
else
begin
r_Load <= 0;
end
end
end
endmodule
waveform
Why does r_D <= 8'h40 execute before w_Rx_DV == 1'b1
Because you have a semicolon after the if here:
if(w_Rx_DV == 1'b1) ;
// ^ End of if statement.

Vivado just points out that there is an exception

I'm trying to write a module which performs convolution on 24 by 24 bitmap image.
And here is the DUT and testbench.
Maybe there are some problems and I spend couple of hours to find what is problem but I can't figure it out.
Additionally, RTL Anaylsis works well without any error which makes me think that there is no problem on DUT.
Is there anyone who can help me?
module top_conv(clk,resetn,start,load_image_0,load_image_1,load_image_2,done,result);
input clk,resetn,load_image_0,load_image_1,load_image_2,start;
output done,result;
reg [1:0] st;
reg [1:0] nst;
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
wire [7:0] load_image_0;
wire [7:0] load_image_1;
wire [7:0] load_image_2;
reg [7:0] result;
reg done;
integer load_cnt, row_cnt, col_cnt , result_cnt ;
parameter IDLE = 2'b00, LOAD = 2'b01, MAC = 2'b10, DONE = 2'b11;
always#(posedge clk or negedge resetn)begin
case(st)
LOAD:begin
input_buffer_0[load_cnt] <= load_image_0;
input_buffer_1[load_cnt] <= load_image_1;
input_buffer_2[load_cnt] <= load_image_2;
end
MAC:begin
input_buffer_0[0] <= input_buffer_0[1];
input_buffer_1[0] <= input_buffer_1[1];
input_buffer_2[0] <= input_buffer_2[1];
input_buffer_0[1] <= input_buffer_0[2];
input_buffer_1[1] <= input_buffer_0[2];
input_buffer_2[1] <= input_buffer_0[2];
input_buffer_0[2] <= load_image_0;
input_buffer_1[2] <= load_image_1;
input_buffer_2[2] <= load_image_2;
end
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) load_cnt <= 0;
else if(st == LOAD) load_cnt <= load_cnt + 1;
else load_cnt <= 0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= 0;
row_cnt <= 0;
end
else if(st == MAC) begin
if(col_cnt == 21) begin
col_cnt <= 0;
row_cnt <= row_cnt +1;
end
end
else begin
col_cnt <= 0;
row_cnt <= 0;
end
end
always#(posedge clk or negedge resetn)begin
if( st == MAC ) begin
result <= (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 + (input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 + (input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16;
done <= 1'b1;
end
else done <=1'b0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) st <= 0;
else st <= nst;
end
always#(*)begin
case(st)
IDLE:begin
if(start) nst = LOAD;
else nst = IDLE;
end
LOAD:begin
if(load_cnt == 2)nst = MAC;
else nst = LOAD;
end
MAC:begin
if((row_cnt == 21)&&(col_cnt == 21)) nst = DONE;
else if(col_cnt == 21) nst = LOAD;
else nst = MAC;
end
DONE:begin
nst = IDLE;
end
endcase
end
endmodule
module testbench;
reg clk,resetn,start;
reg[7:0] val;
reg [7:0] b_load_image_0,g_load_image_0,r_load_image_0;
reg [7:0] b_load_image_1,g_load_image_1,r_load_image_1;
reg [7:0] b_load_image_2,g_load_image_2,r_load_image_2;
wire [2:0] done;
wire [7:0] b_result,g_result,r_result;
integer index;
top_conv blue_result (clk,resetn,start,b_load_image_0,b_load_image_1,b_load_image_2,done[0],b_result);
top_conv green_result (clk,resetn,start,g_load_image_0,g_load_image_1,g_load_image_2,done[1],g_result);
top_conv red_result (clk,resetn,start,r_load_image_0,r_load_image_1,r_load_image_2,done[2],r_result);
parameter read_fileName1 = "D:/blur_filter_unit/test.bmp" ;
localparam ARRAY_LEN = 24*24*3 + 54;
reg [7:0] data1 [0:ARRAY_LEN-1];
integer size,start_pos,width,height,bitcount;
task readBMP;
integer fileID1;
begin
fileID1 = $fopen(read_fileName1, "rb");
$display("%d" ,fileID1);
if(fileID1 == 0) begin
$display("Error: please check file path");
$finish;
end
else begin
$fread(data1, fileID1);
$fclose(fileID1);
size = {data1[5],data1[4],data1[3],data1[2]};
$display("size - %d", size);
start_pos = {data1[13],data1[12],data1[11],data1[10]};
$display("startpos : %d", start_pos);
width = {data1[21],data1[20],data1[19],data1[18]};
height = {data1[25],data1[24],data1[23],data1[22]};
$display("width - %d; height - %d",width,height);
bitcount = {data1[29],data1[28]};
if(bitcount != 24) begin
$display("Error: Please check the image file. It may be corrupted");
end
if(width%4)begin
$display("width is not suitable");
$finish;
end
end
end
endtask
integer i,j;
localparam RESULT_ARRAY_LEN = 24*24*3;
reg[7:0] result[0:RESULT_ARRAY_LEN - 1];
always #(posedge clk or negedge resetn)begin
if(!resetn)begin
j <= 8'b0;
end
else begin
if(&done[2:0]) begin
result[j] <= b_result;
result[j+1] <= g_result;
result[j+2] <= r_result;
j <= j+3;
end
end
end
parameter write_fileName1 = "D:/blur_filter_unit/result.bmp";
task writeBMP;
integer fileID, k;
begin
fileID = $fopen(write_fileName1,"wb");
for(k = 0; k < start_pos; k=k+1)begin
$fwrite(fileID, "%c",data1[k]);
end
for(k = start_pos; k<size; k=k+1)begin
$fwrite(fileID,"%c",result[k-start_pos]);
end
$fclose(fileID);
$display("Result.bmp is generated \n");
end
endtask
always begin
#1 clk = ~clk;
end
initial begin
clk = 1;
resetn = 0;
start = 0;
index = 1;
b_load_image_0 = 0;
g_load_image_0 = 0;
r_load_image_0 = 0;
b_load_image_1 = 0;
g_load_image_1 = 0;
r_load_image_1 = 0;
b_load_image_2 = 0;
g_load_image_2 = 0;
r_load_image_2 = 0;
readBMP;
#10;
resetn = 1;
start = 1;
for(i = start_pos; i<size; i=i+3)begin
{r_load_image_0, r_load_image_1, r_load_image_2} ={data1[i+2],data1[i+2+width*3],data1[i+2+width*6]};
{g_load_image_0, g_load_image_1, g_load_image_2} = {data1[i+1],data1[i+1+width*3],data1[i+1+width*6]};
{b_load_image_0, b_load_image_1, b_load_image_2} = {data1[i],data1[i+width*3],data1[i+width*6]};
#1;
end
#10;
#writeBMP;
#10
$stop;
end
endmodule
Even though this is not a complete answer, for figuring out the error you can use the below code which is revised version of your code for ease of debugging.
i think when synthesizing your design you might have faced this issue
Due to line numbers 25 & 71 in your code.You are declaring edge sensitive signal in sensitivity list and u are not using it in the always block. so tool cannot understand how to map it and throwing an error.
module top_conv(
input clk,resetn,start,
input [7:0] load_image_0,load_image_1,load_image_2,
output reg done,
output reg [7:0] result
);
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
reg [4:0] row_cnt, col_cnt;
reg [1:0] load_cnt;
parameter IDLE = 2'b00,
LOAD = 2'b01,
MAC = 2'b10,
DONE = 2'b11;
reg [1:0] state,next;
always#(posedge clk or negedge resetn)begin
if(!resetn) state <= #10 IDLE ;
else state <= #10 next ;
end
always#(*)begin
next = 'bx; // default undefined state
case(state)
IDLE: next = start ? LOAD : IDLE ;
LOAD: next = (load_cnt == 2) ? MAC : LOAD ;
MAC : next = ((row_cnt == 21)&&(col_cnt == 21)) ? DONE :
(col_cnt == 21) ? LOAD : MAC ;
DONE: next = IDLE ;
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
end else begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
case(next)
LOAD:load_cnt <= #10 load_cnt + 1'b1 ;
MAC :begin
col_cnt <= #10 (col_cnt == 21) ? 0 : col_cnt + 1'b1 ;
row_cnt <= #10 (col_cnt == 21) ? row_cnt : row_cnt + 1'b1 ;
end
DONE:begin
result <= #10 (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 +
(input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 +
(input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16 ;
done <= #10 1'b1;
end
endcase
end
end
always#(posedge clk)begin
case(next)
LOAD:begin
input_buffer_0[load_cnt] <= #10 load_image_0;
input_buffer_1[load_cnt] <= #10 load_image_1;
input_buffer_2[load_cnt] <= #10 load_image_2;
end
MAC:begin
input_buffer_0[0] <= #10 input_buffer_0[1];
input_buffer_1[0] <= #10 input_buffer_1[1];
input_buffer_2[0] <= #10 input_buffer_2[1];
input_buffer_0[1] <= #10 input_buffer_0[2];
input_buffer_1[1] <= #10 input_buffer_0[2];
input_buffer_2[1] <= #10 input_buffer_0[2];
input_buffer_0[2] <= #10 load_image_0;
input_buffer_1[2] <= #10 load_image_1;
input_buffer_2[2] <= #10 load_image_2;
end
endcase
end
endmodule

Rising Edge Counter

I'm new to fpgas in general. I want to make counter that iterates each time SCK sees a rising edge. The issue i'm having with my code is that it seems to count twice. Two leds are lit each time there is a rising edge transition - as opposed to just one led. Any idea where this may be coming from?
module spi_slave(pcEn, LED, clk, SCK);
input clk, SCK;
output reg pcEn;
output reg [7:0] LED = 8'h00;
reg r1 = 0;
reg r2 = 0;
reg r3 = 0;
reg [3:0] cnt = 4'b0000;
always #(posedge clk)
begin
r1 <= SCK;
r2 <= r1;
pcEn <= r1 && !r3;
if (pcEn == 1) begin
cnt = cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] = 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] = 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] = 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] = 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] = 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] = 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] = 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] = 1'b1;
end
else
LED = 8'h00;
end
else
#100;
r3 <= r2;
end
endmodule
The counter is counting twice because you are comparing r1 & !r3.
r1->r2->r3 .it takes 2 clocks for r3 to be set after r1 equal 1. This implies that r1&!r3 condition will remain valid for 2 clocks. The pcEn will be generated for 2 clocks , Hence the counter will count twice.
r1 && !r2 or if you want a delay r2 && !r3 should work fine.
you should be able to see this behavior in a waveform to debug.Use $dumpvars; in your simulation to view the waveform.
Also there are couple of change to improve the code.
use of reset.
consistently use non-blocking assignment .
there is no need for #100 delay.
module spi_slave(pcEn, LED, clk, SCK,rst_n);
input clk, SCK,rst_n;
output reg pcEn;
output reg [7:0] LED ;
reg r1 ;
reg r2 ;
reg r3 ;
reg [3:0] cnt ;
always #(posedge clk or negedge rst_n)
begin
if ( rst_n == 0 )
begin
r1 <=0 ;
r2 <= 0 ;
r3 <= 0 ;
cnt <= 0 ;
LED <=0 ;
pcEn <=0 ;
end
else
begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
if (pcEn == 1) begin
cnt <= cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] <= 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] <= 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] <= 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] <= 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] <= 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] <= 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] <= 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] <= 1'b1;
end
else
LED <= 8'h00;
end
end
end
endmodule
First of # delays are not synthesizable, they are delays for simulation only.
Generally is considered best practice to separate block and non-blocking logic into different always blocks. always #* for combinational (blocking assignments), and always #(posedge clk) for sequential (non-blocking assignments). FYI : Verilog supports case-statements which make coding value compare easier then nesting else-if.
I thing you may want to use r2 && !r3 instead of r1 && !r3 as Rahul also pointed out
always #* begin
if (pcEn == 1'b0) begin
next_cnt = cnt;
next_LED = LED;
else begin
next_cnt = cnt + 4'b0001;
next_LED = 8'h00; // Rest all to 0s
if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles
case(cnt)
4'b0000 : next_LED[0] = 1'b1;
4'b0001 : next_LED[1] = 1'b1;
// ...
4'b0111 : next_LED[7] = 1'b1;
endcase
end
end
always #(posedge clk) begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
cnt <= next_cnt;
LED <= next_LED;
end

inout verilog protocol I2C

I'm creating the I2C protocol in verilog to read data from a sensor (BMP180), AS you know, the sensor sends me a bit of ack recognition. How do I use the inout i2c_sda port to send and how do I receive.
As delivery and receipt i2c_sda the same line, if my variable is declared of type inout.
module stepPrueba(
input wire clk1,
input wire reset,
input wire start,
inout i2c_sda,
inout i2c_scl,
output wire ready,
output reg led1,
output reg led2
);
reg i2c_scl_out;
assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_scl_in = i2c_scl;
assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : clk1;
reg clk;
assign clk1 = (clk == 1)? 1'bz:1'b0;
reg i2c_sda_out;
assign i2c_sda = (i2c_sda_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_sda_in = i2c_sda ;
reg [6:0] addr;
reg [7:0] data;
reg enable; //(read=1, write=0)
reg datas;
reg enable2; //(read=1, write = 0)
reg [7:0] state;
reg [7:0] count;
reg i2c_scl_enable = 0;
reg [6:0] saved_addr;
reg [7:0] saved_data;
//goal es escribir al dispositivo direccion 0X55, 0Xaa
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR =2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_WACK2 = 6;
localparam STATE_STOP = 7;
always#(posedge clk)
begin
//enable2 <= 0; //i2c_scl==zetas & c_lectura=z;
if(reset == 1)
begin
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
if((state == STATE_IDLE) || (state == STATE_START) )
begin
//i2c_scl_enable <= 0; //dats == 1 --> ztas == z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
i2c_scl_enable <= 1; // dats==clk;
clk<=clk1;
end
end
end
always#(posedge clk)
begin
if(reset == 1)
begin
led1 <=0;
led2 <=0;
state <=0;
i2c_sda_out <= 1;// i2c_sda ==z;
addr <= 7'b1110111; // direccion del sensor
count <= 8'd0;
data <= 8'b11110100; //direccion interna PRESION
end
else //reset ==0
begin
case (state)
STATE_IDLE:
begin //idle
//datas <= 1; //zetas==z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
i2c_sda_out <= 1;
if(start)
begin
state <= STATE_START;
saved_addr <= addr;
saved_data <= data;
// reg i2c_scl_out;
// assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
// wire i2c_scl_in = i2c_scl;
// assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : ~clk;
end
else
begin
state <= STATE_IDLE;
end
end
STATE_START:
begin // start
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= 0;
//datas <= 0; // zetas==0
state<= STATE_ADDR;
count <= 6;
end
STATE_ADDR:
begin //msb addres bit
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= saved_addr[count]; // datas ==0 --> zetas==0 || datas==1 --> zetas==z
if (count == 0)
begin
state <= STATE_RW;
end
else
begin
count <= count - 1;
end
end
STATE_RW:
begin
//enable <= 0; //enable==0 --> i2c_sda==zetas
i2c_sda_out <= 0;//datas <= 0;
state <= STATE_WACK;
end
STATE_WACK:
begin
//enable <= 1; //enable==1 lee i2c_sda==z & lectura==i2c_sda
//enable <= 0;
//if(APA)
if(i2c_sda_in==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_DATA;
led1 <= 1;
end
count <= 7;
end
STATE_DATA:
begin
//enable <= 0;
i2c_sda_out <= saved_data[count];
if(count ==0)
begin
state <= STATE_WACK2;
end
else
begin
count <= count - 1;
end
end
STATE_WACK2:
begin
//enable <= 1;
if(i2c_sda_in ==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_STOP;
led2 <= 1;
end
end
STATE_STOP:
begin
//enable <= 0;
i2c_sda_out <= 0;
state <= STATE_IDLE;
end
endcase
end
end
endmodule
If you have a module pin defined as
inout wire pin
then you can access it like so
wire pin_input = pin;
assign pin = pin_oe ? pin_output : 1'bz;
this should infer a tristate buffer.
However, I would be careful when doing this, as if you infer a tristate buffer too early, it can limit what you can do with the module. For example, it would be possible to connect multiple internal I2C components together, such as allowing multiple masters inside the FPGA access to the same pins. However, tristate signals cannot be routed inside the FPGA, so if you implement the tristate inside the I2C master module, this becomes impossible. Instead, what you might consider is implementing each pin as three module pins: input, output, and output enable/tristate. This allows multiple modules to be connected with an emulated tristate bus, and allows them to share one set of tristate buffers to the actual I/O pin on the chip.
For a good example of how this works, see the comments in https://github.com/alexforencich/verilog-i2c/blob/master/rtl/i2c_master.v .

Creating pulses of different width

I have written following code which produces pulse of different width.I want the code to produce a single pulse according to select line.
If select line is
00 pulse width = 1 us ,
01 pulse width = 10 us
. .
11 pulse width = 1000 us
The input clock is of 10 Mhz.
But according to code I am getting continuous pulse if I don't provide any other value of selection line.How can I achieve only one pulse?
module pulse(input wire [1:0] sel , //selection lines s1 s0
input clk,
input rst_n,
output reg flag, //for checking conditions
output reg [13:0] Q, // output of 14 bit counter
output reg pulse, //output pulse
output reg count); //also for checking conditions
wire flag_d , count_d;
assign flag_d = ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0)? 1'b1 : flag;
assign count_d = ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0)? 1'b1 : count;
always #(posedge clk , negedge rst_n)
begin
if(!rst_n)
begin
Q <= 14'h0;
count <= 1'b0;
pulse <= 1'b0;
flag <= 1'b0;
end
else
begin
flag <= flag_d;
count <= count_d;
if(flag)
begin
case(sel)
2'b00: Q <= 14'd11;//count from 11 to 1
2'b01: Q <= 14'd101;//count from 101 to 1
2'b10: Q <= 14'd1001;//count from 1001 to 1
2'b11: Q <= 14'd10001;//count from 10001 to 1
default: Q <= 14'd0;
endcase
flag <= 1'b0;
end
else
begin
if(Q != 14'h1 && Q != 14'h0)
begin
Q <= Q - 14'h1;
pulse <= 1'b1;
end
else
begin
pulse <= 1'b0;
count <= 1'b0;
end
end
end
end
endmodule
Is this code in a good coding style considering the synthesis and hardware of the circuit? if not than what changes I should apply?..
I couldn't figure out the point of flag_d and count_d. Also ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0) simplifies to (count == 1'b0). sel should not be Xs or Zs.
I think you want something more like the following:
reg [13:0] next_Q;
always #* begin
if (Q==0) begin
case(sel)
2'b00 : next_Q = 14'd10;
2'b01 : next_Q = 14'd100;
2'b10 : next_Q = 14'd1000;
2'b11 : next_Q = 14'd10000;
endcase
end
else begin
next_Q = Q - 1;
end
end
always #(posedge clk, negedge rst_n) begin
if (!rst_n) begin
pulse <= 1'b0;
Q <= 14'd0;
end
else begin
// if (Q==0) pulse <= !pulse; // high and low pulse will have equal if sel is constant
pulse <= (Q!=0); // or high pulse based on sel, low is one clk
Q <= next_Q;
end
end
working example: http://www.edaplayground.com/x/GRv
module pulse(input wire [1:0] sel, // No need for the sel to be wire
input clk,
input rst_n,
output reg [13:0] Q,
output reg pulse,
input input_stb, // Input is valid
input output_ack,
output output_stb,
output input_ack); // 2 Flag model
reg s_input_ack ;
reg s_output_stb;
parameter get_inputs = 4'd0,
counter = 4'd1;
always #(posedge clk , negedge rst_n)
begin
case (state)
get_inputs:
s_input_ack <= 1;
if (s_input_ack && input_a_stb)
begin
s_input_ack <= 0;
case(sel)
00: Q <= 14'd11;//00000000001010;
01: Q <= 14'd101;//00000001100100;
10: Q <= 14'd1001;//00001111101000;
11: Q <= 14'd10001;//10011100010000;
default: Q <= 14'd0;
endcase
state <= counter;
end
counter:
begin
s_output_stb <= 1;
if (s_output_stb && output_z_ack)
begin
s_output_stb <= 0;
if(Q != 14'h1 && Q != 14'h0)
begin
Q <= Q - 1'b1;
pulse <= 1'b1;
end
else
begin
pulse <= 1'b0;
end
end
state <= get_inputs;
end
endcase
if(!rst_n)
begin
Q <= 14'h0;
pulse <= 1'b0;
s_input_ack <= 0;
s_output_stb <= 0;
end
assign input_ack = s_input_ack;
assign output_stb = s_output_stb;
end
endmodule
*Still needs work , add registers and necessary signals accordingly. Will edit at a later point in time

Resources