IIC协议的Verilog代码(1)——主机写模块开发
程序员文章站
2024-02-22 21:39:10
...
Verilog代码
//Module Name:IIC Write
//Author:Yang Cheng Yu
//Date:2020/4/21
//==================defines=====================
`define SIM
module iic_write(
//================System Signal================
input clk ,
input rst_n ,
//================Interface====================
output reg scl ,
inout sda ,
output reg flag_wr ,
input wr_req ,
output reg flag_wr_done ,
input[6:0] dev_addr ,
input[7:0] data_wr ,
output reg[5:0] state
);
//================parameters===================
parameter SYS_FRE =50_000_000;
parameter IIC_FRE =10_000;
`ifndef SIM
localparam CNT_BAUD =SYS_FRE/IIC_FRE;
localparam CNT_BAUD_HALF =CNT_BAUD/2;
`else
localparam CNT_BAUD = 500;
localparam CNT_BAUD_HALF = 250;
`endif
//state machine
localparam S_IDLE =6'b0000_01;
localparam S_START =6'b0000_10;
localparam S_DEV_ADDR =6'b0001_00;
localparam S_ACK_DEV_ADDR =6'b0010_00;
localparam S_DATA =6'b0100_00;
localparam S_ACK_DATA =6'b1000_00;
//================System regs==================
reg[15:0] cnt_baud;
reg[2:0] cnt_bit;
wire flag_bit;
reg flag_start_bit;
reg SDA;
reg wr_req_t0;
reg wr_req_t1;
wire wr_req_trig;
reg flag_get_ack;
reg[6:0] dev_addr_reg;
reg[7:0] data_wr_reg;
//================Main Codes===================
//scl
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
scl <= 1'b1;
else if(flag_start_bit==1'b1&&flag_wr==1'b1)
scl <= 1'b1;
else if(flag_start_bit==1'b0&&flag_wr==1'b1)
if(cnt_baud<=CNT_BAUD_HALF-1)
scl <= 1'b0;
else if(cnt_baud>CNT_BAUD_HALF-1)
scl <= 1'b1;
else
scl <= 1'b1;
end
//flag_wr
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_wr <= 1'b0;
else if(flag_wr==1'b0&&wr_req_trig==1'b1)
flag_wr <= 1'b1;
else if(state==S_ACK_DATA&&flag_bit==1'b1)
flag_wr <= 1'b0;
end
//sda
assign sda = (state==S_ACK_DATA||state==S_ACK_DEV_ADDR)?1'bz:SDA;
//cnt_baud
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_baud <= 'd0;
else if(flag_start_bit==1'b1&&flag_wr==1'b1)
if(cnt_baud==CNT_BAUD_HALF-1)
cnt_baud <= 'd0;
else
cnt_baud <= cnt_baud + 1'b1;
else if(flag_start_bit==1'b0&&flag_wr==1'b1)
if(cnt_baud==CNT_BAUD-1)
cnt_baud <= 'd0;
else
cnt_baud <= cnt_baud + 1'b1;
else
cnt_baud <= 'd0;
end
//cnt_bit
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_bit <= 'd0;
else case(state)
S_IDLE:cnt_bit <= 'd0;
S_START:cnt_bit <= 'd0;
S_DEV_ADDR:begin
if(cnt_bit==3'd7&&flag_bit==1'b1)
cnt_bit <= 'd0;
else if(flag_bit==1'b1)
cnt_bit <= cnt_bit + 1'b1;
end
S_ACK_DEV_ADDR:cnt_bit <= 'd0;
S_DATA:begin
if(cnt_bit==3'd7&&flag_bit==1'b1)
cnt_bit <= 'd0;
else if(flag_bit==1'b1)
cnt_bit <= cnt_bit + 1'b1;
end
S_ACK_DATA:cnt_bit <= 'd0;
endcase
end
//flag_bit
assign flag_bit = (cnt_baud==CNT_BAUD-1)?1'b1:1'b0;
//flag_start_bit
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_start_bit <= 1'b0;
else if(flag_wr==1'b0&&wr_req_trig==1'b1)
flag_start_bit <= 1'b1;
else if(flag_start_bit==1'b1&&cnt_baud==CNT_BAUD_HALF-1)
flag_start_bit <= 1'b0;
end
//state machine
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
state <= S_IDLE;
else case(state)
S_IDLE:begin
if(wr_req_trig==1'b1)
state <= S_START;
else
state <= S_IDLE;
end
S_START:begin
if(cnt_baud==CNT_BAUD_HALF-1)
state <= S_DEV_ADDR;
else
state <= S_START;
end
S_DEV_ADDR:begin
if(cnt_bit==3'd7&&flag_bit==1'b1)
state <= S_ACK_DEV_ADDR;
else
state <= S_DEV_ADDR;
end
S_ACK_DEV_ADDR:begin
if(cnt_baud<CNT_BAUD-1&&flag_get_ack==1'b0)
state <= S_ACK_DEV_ADDR;
else if(cnt_baud==CNT_BAUD-1&&flag_get_ack==1'b1)
state <= S_DATA;
else if(cnt_baud==CNT_BAUD-1&&flag_get_ack==1'b0)
state <= S_IDLE;
end
S_DATA:begin
if(cnt_bit==3'd7&&flag_bit==1'b1)
state <= S_ACK_DATA;
else
state <= S_DATA;
end
S_ACK_DATA:begin
if(cnt_baud==CNT_BAUD-1)
state <= S_IDLE;
else
state <= S_ACK_DATA;
end
default:state <= S_IDLE;
endcase
end
//SDA
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
SDA <= 1'b1;
else case(state)
S_IDLE:SDA <= 1'b1;
S_START:SDA <= 1'b0;
S_DEV_ADDR:begin
if(cnt_baud==CNT_BAUD_HALF/2-1)
case(cnt_bit)
0:SDA <= dev_addr_reg[6];
1:SDA <= dev_addr_reg[5];
2:SDA <= dev_addr_reg[4];
3:SDA <= dev_addr_reg[3];
4:SDA <= dev_addr_reg[2];
5:SDA <= dev_addr_reg[1];
6:SDA <= dev_addr_reg[0];
7:SDA <= 1'b1;
default:SDA <= 1'b1;
endcase
end
S_ACK_DEV_ADDR:SDA <= 1'b1;
S_DATA:begin
if(cnt_baud==CNT_BAUD_HALF/2-1)
case(cnt_bit)
0:SDA <= data_wr_reg[7];
1:SDA <= data_wr_reg[6];
2:SDA <= data_wr_reg[5];
3:SDA <= data_wr_reg[4];
4:SDA <= data_wr_reg[3];
5:SDA <= data_wr_reg[2];
6:SDA <= data_wr_reg[1];
7:SDA <= data_wr_reg[0];
default:SDA <= 1'b1;
endcase
end
S_ACK_DATA:SDA <= 1'b1;
default:SDA <= 1'b1;
endcase
end
//wr_req and wr_req_trig
always @(posedge clk)begin
wr_req_t0 <= wr_req;
wr_req_t1 <= wr_req_t0;
end
assign wr_req_trig = wr_req_t0&(~wr_req_t1);
//flag_get_ack
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_get_ack <= 1'b0;
else case(state)
S_ACK_DEV_ADDR:begin
if(cnt_baud==CNT_BAUD_HALF+CNT_BAUD_HALF/2-2&&sda==1'b1)
flag_get_ack <= 1'b1;
end
S_ACK_DATA:begin
if(cnt_baud==CNT_BAUD_HALF+CNT_BAUD_HALF/2-2&&sda==1'b1)
flag_get_ack <= 1'b1;
end
default:flag_get_ack <= 1'b0;
endcase
end
//flag_wr_done
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_wr_done <= 1'b0;
else if(state==S_ACK_DATA&&flag_get_ack==1'b1)
flag_wr_done <= 1'b1;
else
flag_wr_done <= 1'b0;
end
//dev_addr_reg
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
dev_addr_reg <= 'd0;
else if(flag_wr==1'b0&&wr_req_trig==1'b1)
dev_addr_reg <= dev_addr;
end
//data_wr_reg
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
data_wr_reg <= 'd0;
else if(flag_wr==1'b0&&wr_req_trig==1'b1)
data_wr_reg <= data_wr;
end
endmodule
Test Bench
`timescale 1ns/1ns //时间精度
`define clock_period 20 //时钟周期
module tb_iic_write; //实体名称
//state machine
localparam S_IDLE =6'b0000_01;
localparam S_START =6'b0000_10;
localparam S_DEV_ADDR =6'b0001_00;
localparam S_ACK_DEV_ADDR =6'b0010_00;
localparam S_DATA =6'b0100_00;
localparam S_ACK_DATA =6'b1000_00;
//=====================<系统端口>=============================
reg clk ;
reg rst_n ;
//=====================<外设端口>=============================
wire scl ;
wire sda ;
wire flag_wr ;
reg wr_req ;
wire flag_wr_done ;
reg[6:0] dev_addr ;
reg[7:0] data_wr ;
wire[5:0] state ;
assign sda = (state==S_ACK_DATA||state==S_ACK_DEV_ADDR)?1'b1:1'bz;
iic_write iic_write_inst(
//================System Signal================
.clk (clk),
.rst_n (rst_n),
//================Interface====================
.scl (scl),
.sda (sda),
.flag_wr (flag_wr),
.wr_req (wr_req),
.flag_wr_done (flag_wr_done),
.dev_addr (dev_addr),
.data_wr (data_wr),
.state (state)
);
//=====================<时钟信号>=============================
initial begin
clk = 1;
forever
#(`clock_period/2) clk = ~clk;
end
//=====================<复位信号>=============================
initial begin
rst_n = 0;#(`clock_period*20+1);
rst_n = 1;
end
//=====================<激励信号>=============================
initial begin
dev_addr = 7'b011_0101;
data_wr = 8'h00;
wr_req = 0;
#(`clock_period*20+1);//初始化
data_wr = 8'h56;
#20;
wr_req = 1;
#20;
wr_req = 0;
#20_0000;
data_wr = 8'h78;
dev_addr = 7'b100_1010;
#20;
wr_req = 1;
#20;
wr_req = 0;
end
endmodule