FPGA IIC 协议
主控芯片不能设置SDA高电平,能用高阻态,外部上拉电阻拉上去。可以直接设置高电平。
三态门
oe为0:
开关断开作为输入,i2c_id=i2c_SDA ;
oe为1:
若od为1,做输出,高阻态,外部上拉电阻拉高。
若od为0,做输出,输出为低电平。
I2C 协议起始位: SCL 为高电平时, SDA 出现下降沿,产生一个起始位;
I2C 协议结束位: SCL 为高电平时, SDA 出现上升沿,产生一个结束位;
I2C器件地址,I2C存储器地址
当主机像从机写入数据时,SDA 上的每一位数据在 SCL 的高电平期间被写入从机中。从主机角度来看,需要在 SCL 低电平期间改变要写入的数据。
而当主机读取从机中数据时,从机在 SCL 低电平期间将数据输出到 SDA总线上,在 SCL 的高电平期间保持数据稳定,从主机角度来看,需要在SCL 的高电平期间将 SDA 线上的数据读取并存储。
不管对于从机还是主机, SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在 SCL 的低电平期间发生。
SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在SCL 的低电平期间发生。
I2C_CLK高低电平计数器计数。高电平开始计数。
状态图
IIC文件
module IIC(
Clk,
Rst_n,
Wr,
Read,
Wdata_num,
Rdata_num,
Address_num,
Device_adress,
Word_adrr,
Wr_data,
Rd_data,
Wr_data_vaule,
Rd_data_vaule,
Done,
Sda,
Iic_clk
);
input Clk;
input Rst_n;
input Wr;
input Read;
input [5:0]Wdata_num; //连续写数据存储单元个数
input [5:0]Rdata_num; //连续读存储单元个数
input [1:0]Address_num; //单字节/双字节地址段选择
input [2:0]Device_adress; //器件片选地址
input [15:0]Word_adrr; //存储单元地址
input [7:0]Wr_data;//写入的数据
output reg[7:0]Rd_data;//读出的数据
output Wr_data_vaule;//读数据有效标志信号
output reg Rd_data_vaule;//写数据有效标志信号
inout Sda;
output reg Done;
output reg Iic_clk;
parameter CLK_FREQUENCY = 50_000_000;
parameter IIC_CLK_FREQUENCY = 400_000; //I2c clk时钟频率400KHZ
localparam COUNT_MAX = CLK_FREQUENCY/IIC_CLK_FREQUENCY;
//独热码
localparam IDLE = 9'b000_000_001,
WR_START = 9'b000_000_010,
WR_CTRL = 9'b000_000_100,//写控制 写器件地址
WR_ADDRE = 9'b000_001_000,//写地址
WR_DATA = 9'b000_010_000,//写数据
RD_START = 9'b000_100_000,//读开始
RD_CTRL = 9'b001_000_000,//读控制
RD_DATA = 9'b010_000_000,//读数据
STOP = 9'b100_000_000;
reg iic_free_n;//i2c空闲标志位,低电平有效
wire [7:0]waddress_data;//器件地址数据写
wire [7:0]raddress_data;//器件地址数据读
reg [7:0]iic_count; //产生i2C_CLK信号计数寄存器
reg iic_high;
reg iic_low;
reg [4:0]half_clk_cnt;//计数一个状态中高低电平计数器
reg [8:0]main_state;//主状态机状态寄存器
reg ack;//数据接收方对发送方的响应标志位
reg send_en;//控制Sda线输入输出开关
reg sda_reg;//sda信号线寄存器
reg task_en_n;//任务开始结束控制寄存器
reg [7:0]sda_data_out;//sda待输出的数据
reg [7:0]sda_data_in;//sda待写入的数据
reg [5:0]wdata_cnt;//连续写个数计数器
reg [5:0]rdata_cnt;//连续读个数计数器
reg [1:0]adress_cnt;//器件地址个数计数器 1/2
wire be_rd_data_vaule;//读数据有效前寄存器
reg w_flag;
reg r_flag;
//写/读器件地址8位
assign waddress_data = {4'b1010 , Device_adress , 1'b0};
assign raddress_data = {4'b1010 , Device_adress , 1'b1};
assign Sda = send_en?sda_reg:1'bz;
//iic_free_n状态判断
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
iic_free_n <= 1'b0;
else if(Wr|Read)
iic_free_n <= 1'b1;
else if(Done)
iic_free_n <= 1'b0;
else
iic_free_n <= iic_free_n;
//iic_count计数
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
iic_count <= 1'b0;
else if(iic_free_n)
begin
if(iic_count == COUNT_MAX - 1'b1)
iic_count <= 1'b0;
else
iic_count <= iic_count + 1'b1;
end
else
iic_count <= 1'b0;
//Iic_clk产生
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Iic_clk <= 1'b1;
else if(iic_count == COUNT_MAX >> 1)
Iic_clk <= 1'b0;
else if(iic_count == 1'b0)
Iic_clk <= 1'b1;
else
Iic_clk <= Iic_clk;
//标志Iic_clk高电平 iic_high产生
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
iic_high <= 1'b0;
else if(iic_count == (COUNT_MAX >> 2) )
iic_high <= 1'b1;
else
iic_high <= 1'b0;
//标志Iic_clk低电平 iic_low产生
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
iic_low <= 1'b0;
else if(iic_count == (COUNT_MAX >> 2 )+ (COUNT_MAX >> 1) )
iic_low <= 1'b1;
else
iic_low <= 1'b0;
//sda串行收发Iic_clk高低电平计数器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
half_clk_cnt <= 5'b0;
else
if((main_state == WR_CTRL) || (main_state ==WR_ADDRE)|| (main_state ==WR_DATA) || (main_state ==RD_CTRL) ||(main_state ==RD_DATA))
begin
if(iic_high || iic_low)
begin
if(half_clk_cnt == 5'd17)
half_clk_cnt <= 5'b0;
else
half_clk_cnt <= half_clk_cnt + 1'b1;
end
else
half_clk_cnt <= half_clk_cnt;
end
else
half_clk_cnt <= 1'b0;
//数据接收方对发送方的响应标志位ACK
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
ack <= 1'b0;
else
if((half_clk_cnt == 5'd16) && iic_high && (Sda == 1'b0))
ack <= 1'b1;
else
if(half_clk_cnt == 5'd17 && iic_low)
ack <= 1'b0;
else
ack <= ack;
//输出串行数据任务
task send_eight_data;
if(iic_high && (half_clk_cnt == 5'd16))
task_en_n <= 1'b1;
else
if(half_clk_cnt < 5'd17)
begin
sda_reg <= sda_data_out[7];
if(iic_low)
sda_data_out <= {sda_data_out[6:0],1'b0};
else
sda_data_out <= sda_data_out;
end
endtask
//输入串行任务
task get_eight_data;
if(iic_low && (half_clk_cnt == 5'd15))
task_en_n <= 1'b1;
else
if(half_clk_cnt < 5'd15)
begin
if(iic_high)
sda_data_in <= {sda_data_in[6:0],Sda};
else
sda_data_in <= sda_data_in;
end
endtask
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
sda_reg <= 1'b1;
wdata_cnt <= 1'b1;
rdata_cnt <= 1'b1;
adress_cnt <= 1'b1;
Done <= 1'b0;
w_flag <= 1'b0;
r_flag <= 1'b0;
end
else
begin
case(main_state)
IDLE :
begin
sda_reg <= 1'b1;
rdata_cnt <= 1'b1;
wdata_cnt <= 1'b1;
adress_cnt <=1'b1;
w_flag <= 1'b0;
r_flag <= 1'b0;
Done <= 1'b0;
if(Wr)
begin
main_state <= WR_START;
w_flag <= 1'b1;
end
else if(Read)
begin
main_state <= WR_START;
r_flag <= 1'b1;
end
end
WR_START: //10
begin
if(iic_low)
begin
main_state <= WR_CTRL;
sda_data_out <= waddress_data;
task_en_n <= 1'b0;
end
else if(iic_high)
begin
sda_reg <= 1'b0;
main_state <= WR_START;
end
else
main_state <= WR_START;
end
WR_CTRL: //100
begin
if(task_en_n == 1'b0)
send_eight_data;
else
if(ack == 1'b1)
begin
if(iic_low)
begin
main_state <= WR_ADDRE;
task_en_n <= 1'b0;
if(adress_cnt == Address_num)
sda_data_out <= Word_adrr[7:0];
else
sda_data_out <= Word_adrr[15:8];
end
else
main_state <= WR_CTRL;
end
else
main_state <= IDLE;
end
WR_ADDRE: //1000
begin
if(task_en_n == 1'b0)
send_eight_data;
else
if(ack == 1'b1)
begin
if(adress_cnt == Address_num)
begin
if(iic_low && w_flag)
begin
main_state <= WR_DATA;
adress_cnt <= 1'b1;
task_en_n <= 1'b0;
sda_data_out <= Wr_data;
end
else
if(iic_low && r_flag)
begin
main_state <= RD_START;
sda_reg <= 1'b1;
end
else
main_state <= WR_ADDRE;
end
else
begin
main_state <= WR_ADDRE;
sda_data_out <= Word_adrr[7:0];
task_en_n <= 1'b0;
adress_cnt <= adress_cnt + 1'b1;
end
end
else
main_state <= IDLE;
end
WR_DATA: //10_000
begin
if(task_en_n == 1'b0)
send_eight_data;
else
if(ack == 1'b1)
begin
if(wdata_cnt == Wdata_num)
begin
if(iic_low)
begin
wdata_cnt <= 1'b1;
main_state <= STOP;
sda_reg <= 1'b0; //上升沿停止
end
else
main_state <= WR_DATA;
end
else
if(iic_low)
begin
wdata_cnt <= wdata_cnt + 1'b1;
main_state <= WR_DATA;
sda_data_out <= Wr_data;
task_en_n <= 1'b0;
end
else
main_state <= WR_DATA;
end
else
main_state <= IDLE;
end
RD_START:
begin
if(iic_low)
begin
main_state <= RD_CTRL;
task_en_n <= 1'b0;
sda_data_out <= raddress_data;
end
else
if(iic_high)
begin
main_state <= RD_START;
sda_reg <= 1'b0;
end
else
main_state <= RD_START;
end
RD_CTRL:
begin
if(task_en_n == 1'b0)
send_eight_data;
else
if(ack == 1'b1)
begin
if(iic_low)
begin
main_state <= RD_DATA;
task_en_n <= 1'b0;
end
else
main_state <= RD_CTRL;
end
else
main_state <= IDLE;
end
RD_DATA:
begin
if(task_en_n == 1'b0)
get_eight_data;
else
if(rdata_cnt == Rdata_num)
begin
sda_reg <= 1'b1; //产生NOack信号表示不读
if(iic_low)
begin
main_state <= STOP;
sda_reg <= 1'b0; //产生上升沿停止位
end
else
main_state <= RD_DATA;
end
else
begin
sda_reg <= 1'b0; //产生ack信表示再读
if(iic_low)
begin
main_state <= RD_DATA;
rdata_cnt <= rdata_cnt + 1'b1;
task_en_n <= 1'b0;
end
else
main_state <= RD_DATA;
end
end
STOP:
begin
if(iic_high)
begin
sda_reg <= 1'b1; //产生上升沿停止态
main_state <= IDLE;
Done <= 1'b1;
end
else
main_state <= STOP;
end
default : main_state <= IDLE;
endcase
end
//控制sda开关闭合关闭
always @(*) //描述组合逻辑电路
begin
case(main_state)
IDLE:
send_en = 1'b0;
RD_START,WR_START,STOP: //写/读开始 停止位
send_en = 1'b1;
RD_CTRL,WR_CTRL,WR_ADDRE,WR_DATA:
if(half_clk_cnt < 16)
send_en = 1'b1;
else
send_en = 1'b0;
RD_DATA:
if(half_clk_cnt < 16)
send_en = 1'b0;
else
send_en = 1'b1;
default:send_en = 1'b0;
endcase
end
//写输入有效标志位
assign Wr_data_vaule = ((main_state == WR_ADDRE) && (w_flag && iic_low) && (ack == 1'b1) && (adress_cnt == Address_num))||((main_state == WR_DATA) && (ack == 1'b1) && (iic_low)&&(wdata_cnt != Wdata_num));
//读数据有效标志位前寄存器
assign be_rd_data_vaule = ((main_state == RD_DATA) && (half_clk_cnt == 5'd15) && (iic_low));
//读数据有效标志位
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rd_data_vaule <= 1'b0;
else if(be_rd_data_vaule)
Rd_data_vaule <= 1'b1;
else
Rd_data_vaule <= 1'b0;
//读出的有效数据
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rd_data <= 8'd0;
else if(be_rd_data_vaule)
Rd_data <= sda_data_in;
else
Rd_data <= Rd_data;
endmodule
IIC仿真文件
`timescale 1ns/1ns
`define CLK_CYCLE 20
//`define TEST_M24LC64 //24LC64 1字节存储器地址
`define TEST_M24LC04 //24LC04B 2字节存储器地址
module IIC_tb;
localparam NUM = 6'd4; //连续读写数据个数
reg Clk;
reg Rst_n;
reg Wr;
reg Read;
reg [15:0]Word_adrr;
reg [7:0]Wr_data;
wire [7:0]Rd_data;
wire Wr_data_vaule;
wire Rd_data_vaule;
wire Done;
wire Sda;
wire Iic_clk;
`ifdef TEST_M24LC64
localparam Device_adress = 3'b000;//器件地址
localparam Address_num = 2'd2; //存储器地址字节数
`elsif TEST_M24LC04
localparam Device_adress = 3'b001;
localparam Address_num = 2'd1;
`endif
IIC IIC(
.Clk(Clk),
.Rst_n(Rst_n),
.Wr(Wr),
.Read(Read),
.Wdata_num(NUM),
.Rdata_num(NUM),
.Address_num(Address_num),
.Device_adress(Device_adress),
.Word_adrr(Word_adrr),
.Wr_data(Wr_data),
.Rd_data(Rd_data),
.Wr_data_vaule(Wr_data_vaule),
.Rd_data_vaule(Rd_data_vaule),
.Done(Done),
.Sda(Sda),
.Iic_clk(Iic_clk)
);
`ifdef TEST_M24LC64
M24LC64 M24LC64(
.A0(1'b0),
.A1(1'b0),
.A2(1'b0),
.WP(1'b0),
.SDA(Sda),
.SCL(Iic_clk),
.RESET(!Rst_n)
);
`elsif TEST_M24LC04
M24LC04B M24LC04(
.A0(1'b1),
.A1(1'b0),
.A2(1'b0),
.WP(1'b0),
.SDA(Sda),
.SCL(Iic_clk),
.RESET(!Rst_n)
);
`endif
initial Clk = 1;
always #(`CLK_CYCLE/2) Clk = ~Clk;
initial
begin
Rst_n = 0;
Wr = 0;
Read = 0;
Word_adrr = 0;
Wr_data = 0;
#(`CLK_CYCLE*200 + 1);
Rst_n = 1;
#200;
`ifdef TEST_M24LC64//仿真24LC64模型
Word_adrr = 0;
Wr_data = 0;
repeat(20)
begin
Wr = 1'b1;
#(`CLK_CYCLE);
Wr = 1'b0;
repeat(NUM)
begin
@(posedge Wr_data_vaule)
Wr_data = Wr_data + 1;
end
@(posedge Done)
#1000;
Word_adrr = Word_adrr + NUM;
end
#2000;
//读出数据
Word_adrr = 0;
repeat(20)
begin
Read = 1'b1;
#(`CLK_CYCLE);
Read = 1'b0;
@(posedge Done)
#1000;
Word_adrr = Word_adrr + NUM; //?????
end
`elsif TEST_M24LC04
Word_adrr = 100;
Wr_data = 100;
repeat(20)
begin
Wr = 1;
#(`CLK_CYCLE);
Wr = 0;
repeat(NUM)
begin
@(posedge Wr_data_vaule)
Wr_data = Wr_data + 1;
end
@(posedge Done);
#1000;
Word_adrr = Word_adrr + NUM;
end
#2000;
//读出数据
Word_adrr = 100;
repeat(20)
begin
Read = 1;
#(`CLK_CYCLE);
Read = 0;
@(posedge Done);
#1000;
Word_adrr = Word_adrr + NUM;
end
`endif
#4000;
$stop;
end
endmodule
仿真结果第一个读取的数据为01100101,刚好是十进制数101也是第一个存储的数据。
UART串口读写EEPROM存储器任意地址数据
编写RX接收数据分析模块
规定电脑端发送的数据格式为
其中,器件地址包括器件的地址字节数和 3 位的器件地址,具体分配如图所示。
使用左移循环动态判断数据的帧头,判断功能码(功能码为0xf1 表示写数据操作,0xf2 表示读数据操作)。
module DATA_ANALYSIS(
Clk,
Rst_n
Rx_data,
Rx_done,
Wfifo_reg,
Wfifo_data,
Rdata_num,
Wdata_num,
Address_num,
Device_address,
Word_adrr,
Rd, //EEPROM读请求信号
);
input Clk;
input Rst_n;
input [7:0]Rx_data;
input Rx_done;
output Wfifo_reg;
output [7:0]Wfifo_data;
output [5:0]Rdata_num;
output [5:0]Wdata_num;
output [1:0]Address_num;
output [2:0]Device_address;
output [7:0]Word_adrr;
output Rd; //EEPROM读请求信号
reg [7:0]an_cnt;//串口数据接收个数计数器
reg[7:0] buff_data[5:0];
reg analysis_done;
//串口接收数据计数器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
an_cnt <= 8'd0;
else
if((an_cnt==8'd4)&&Rx_done)
begin
if(buff_data[1] == 8'hf2)//读操作命令
an_cnt <= 8'd0;
else
if(buff_data[1] == 8'hf1)//写操作命令
an_cnt <= an_cnt + 1'b1;
else
an_cnt <= 1'b0; //错误指令
end
else
if(Rx_done)
begin
if(an_cnt == (8'd4 + buff_data[4]))
an_cnt <= 8'd0;
else
an_cnt <= an_cnt + 1'b1;
end
else an_cnt <= an_cnt ;
//串口缓冲寄存器
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
buff_data[0] <= 8'd0;
buff_data[1] <= 8'd0;
buff_data[2] <= 8'd0;
buff_data[3] <= 8'd0;
buff_data[4] <= 8'd0;
end
else
if((an_cnt < 8'd5) && Rx_done)
buff_data[an_cnt] <= Rx_data;
else ;
//WFIFO写请求使能信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Wfifo_reg <= 1'b0;
else
if((an_cnt > 8'd4)&& Rx_done)
Wfifo_reg <= 1'b1;
else
Wfifo_reg <= 1'b0;
//WFIFO写入的数据
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Wfifo_data <= 1'b0;
else
if((an_cnt > 8'd4)&& Rx_done)
Wfifo_data <= Rx_data;
else
Wfifo_data <= Wfifo_data;
//IIC读使能信号
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rd <= 1'b0;
else
if((an_cnt == 8'd4) && (buff_data[1] == 8'hf2) && Rx_done)
Rd <= 1'b1;
else
Rd <= 1'b0;
//指令完成标志
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
analysis_done <= 1'b0;
else
if((an_cnt == 8'd4)&& Rx_done)
analysis_done <= 1'd1;
else
analysis_done <= 1'd0;
//EEPROM存储器地址
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
begin
Rdata_num <= 1'b0;
Wdata_num <= 1'b0;
Address_num <= 1'b0;
Device_address <= 3'b0;
Word_adrr <= 16'b0;
end
else
if(analysis_done == 1'b1)
begin
Rdata_num <= buff_data[4][5:0];
Wdata_num <= buff_data[4][5:0];
Address_num <= buff_data[0][5:4];
Device_address <= buff_data[0][2:0];
Word_adrr <= {buff_data[2],buff_data[3]};
end
else
;
endmodule
串口读写EEPROM系统设计
编写系统文件
module UART_EEPROM(
Clk,
Rst_n,
Rx,
Tx,
Iic_clk,
Sda
);
input Clk;
input Rst_n;
input Rx;
output Tx;
output Iic_clk;
inout Sda;
parameter BPS_SET = 3'd4;
wire [7:0]rx_data;
wire Done_rx;
wire Wfifo_reg;
wire [7:0]wfifo_data;
wire [5:0]rdata_num;//连续读存储单元个数
wire [5:0]wdata_num;//连续写数据存储单元个数
wire [1:0]address_num;//单字节/双字节地址段选择
wire [2:0]device_address;//器件片选地址
wire [15:0]word_adrr;//存储单元地址
wire rd; //EEPROM读请求信号
wire [7:0]q_wfifo;
wire [7:0]q_rfifo;
wire [5:0]wfifo_usedw;
wire wr;
wire [7:0]rd_data;//读出的数据
wire wr_data_vaule;//写数据有效标志信号
wire rd_data_vaule;//读数据有效标志信号
wire done;
wire en_tx;
wire [6:0]rfifo_usedw;
wire rfifo_req;
wire done_tx;
uart_data_rx uart_data_rx( //串口接收模块
.Clk(Clk),
.Rst_n(Rst_n),
.Rs232_rx(Rx),
.Bps_set(BPS_SET),
.Data_out(rx_data),
.Rx_done(Done_rx)
);
DATA_ANALYSIS DATA_ANALYSIS(
.Clk(Clk),
.Rst_n(Rst_n),
.Rx_data(rx_data),
.Rx_done(Done_rx),
.Wfifo_reg(Wfifo_reg),
.Wfifo_data(wfifo_data),
.Rdata_num(rdata_num),
.Wdata_num(wdata_num),
.Address_num(address_num),
.Device_address(device_address),
.Word_adrr(word_adrr),
.Rd(rd) //EEPROM读请求信号
);
//写缓存FIFO
Wfifo Wfifo(
.clock(Clk),
.data(wfifo_data),
.rdreq(wr_data_vaule),
.wrreq(Wfifo_reg),
.empty(),
.full(),
.q(q_wfifo),
.usedw(wfifo_usedw)
);
assign wr = ((wdata_num == wfifo_usedw) && (wfifo_usedw != 1'b0));
//IIC
IIC IIC(
.Clk(Clk),
.Rst_n(Rst_n),
.Wr(wr),
.Read(rd),
.Wdata_num(wdata_num),
.Rdata_num(rdata_num),
.Address_num(address_num),
.Device_adress(device_address),
.Word_adrr(word_adrr),
.Wr_data(q_wfifo),
.Rd_data(rd_data),
.Wr_data_vaule(wr_data_vaule),
.Rd_data_vaule(rd_data_vaule),
.Done(done),
.Sda(Sda),
.Iic_clk(Iic_clk)
);
//读FIFO
Rfifo Rfifo(
.clock(Clk),
.data(rd_data),
.rdreq(rfifo_req),
.wrreq(rd_data_vaule),
.empty(),
.full(),
.q(q_rfifo),
.usedw(rfifo_usedw)
);
//串口发送使能
assign en_tx = ((rdata_num == rfifo_usedw) && done) || ((rdata_num > rfifo_usedw) && (rfifo_usedw > 1'b0)&& done_tx );
//读FIFO使能
assign rfifo_req = en_tx;
//tx模组
UART_TX UART_TX(
.Clk(Clk),
.Rst_n(Rst_n),
.Bps_set(BPS_SET),
.Con_en(en_tx),
.Data_in(q_rfifo),
.Rs232_tx(Tx),
.Done_tx(done_tx),
.Uart_state()
);
endmodule
编写系统仿真文件tb
`timescale 1ns/1ns
`define Clk_period 20
module UART_EEPROM_tb;
localparam DEV_ADDRESS = 3'b000; //器件地址
localparam BPS_SET = 3'd4; //波特率
localparam ADDRESS_NUM = 2'd2;
reg Clk;
reg Rst_n;
wire rx;
wire tx;
wire iic_clk;
wire sda;
reg con_en;
reg [7:0]data_in_tx;
wire done_tx;
reg [15:0]addr;
reg [7:0]data_num;
reg [39:0]wdata_cmd;
reg [39:0]rdata_cmd;
reg [7:0]tx_data;
//数据发送TX
UART_TX UART_TX(
.Clk(Clk),
.Rst_n(Rst_n),
.Bps_set(BPS_SET),
.Con_en(con_en),
.Data_in(tx_data),
.Rs232_tx(rx),
.Done_tx(done_tx),
.Uart_state()
);
UART_EEPROM #(.BPS_SET(BPS_SET))
UART_EEPROM(
.Clk(Clk),
.Rst_n(Rst_n),
.Rx(rx),
.Tx(tx),
.Iic_clk(iic_clk),
.Sda(sda)
);
//EEPROM模型例化
M24LC64 M24LC64(
.A0(1'b0),
.A1(1'b0),
.A2(1'b0),
.WP(1'b0),
.SDA(sda),
.SCL(iic_clk),
.RESET(!Rst_n)
);
initial Clk = 1;
always #(`Clk_period/2) Clk = ~Clk;
initial
begin
Rst_n = 0;
addr = 0;
data_num = 0;
wdata_cmd = 0;
rdata_cmd = 0;
con_en = 0;
data_in_tx = 0;
tx_data = 0;
#(`Clk_period*20 + 1);
Rst_n = 1;
#200;
addr= 0;
data_num = 4;
data_in_tx = 0;
send_write_bite;
@(posedge UART_EEPROM.IIC.Done);
#500;
send_read_bite;
@(posedge UART_EEPROM.IIC.Done);
#500;
addr= 0;
data_num = 8;
data_in_tx = 20;
send_write_bite;
@(posedge UART_EEPROM.IIC.Done);
#300;
send_read_bite;
@(posedge UART_EEPROM.IIC.Done);
repeat (data_num)
begin
@(posedge UART_EEPROM.done_tx);
end
#500;
$stop;
end
task send_write_bite;
begin
wdata_cmd = {{2'b00,ADDRESS_NUM,1'b0,DEV_ADDRESS},8'hf1,addr[15:8],addr[7:0],data_num};
//传入待写入的命令数据
repeat(5)
begin
tx_data = wdata_cmd[39:32];
con_en = 1;
#(`Clk_period)
con_en = 0;
@(posedge done_tx)
#100;
wdata_cmd = {wdata_cmd[31:0],8'h00};
end
//数据
tx_data = data_in_tx;
repeat(data_num)
begin
con_en = 1;
tx_data = tx_data + 1'b1;
#(`Clk_period)
con_en = 0;
@(posedge done_tx)
#200;
end
end
endtask
task send_read_bite;
begin
rdata_cmd = {{2'b00,ADDRESS_NUM,1'b0,DEV_ADDRESS},8'hf2,addr[15:8],addr[7:0],data_num};
repeat(5)
begin
tx_data = rdata_cmd[39:32];
con_en = 1;
#(`Clk_period)
con_en = 0;
@(posedge done_tx)
#100;
rdata_cmd = {rdata_cmd[31:0],8'h00};
end
end
endtask
endmodule
仿真波形
tx信号成功输出。