FPGA开发--AT24C读写
文章摘要:
本文主要是用于对I2C模块的测试程序,实现对AT24C进行读测试;
重点内容: SingleTap应用,AT24C读写时序;
硬件平台:EP4CE6F17C8
开发环境:Quartus II 13.1
AT24C读写时序图
测试代码:
module at24c02(
clk, // 模块时钟
rst_n, // 模块复位(低电平有效)
scl, // 时钟引脚
sda, // 数据引脚(双向)
rdata // 接收到的数据
);
input clk; // 模块时钟
input rst_n; // 模块复位(低电平有效)
output scl; // 时钟引脚
inout sda; // 数据引脚(双向)
output[7:0] rdata;
//-----------------------------------------------
localparam T1SEC = 32'd50_000_000;
//-----------------------------------------------
reg i2c_start_req;
reg i2c_wr_req;
reg i2c_rd_req;
reg i2c_stop_req;
reg[7:0] i2c_wdata;
wire i2c_done;
reg[3:0] cstate;
reg[3:0] nstate;
reg init_flag;
//-----------------------------------------------
reg [31:0] timer;
// 计时时钟
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
timer <= 0;
end
else if(timer == T1SEC) begin
timer <= 0;
end
else begin
timer <= timer + 1'b1;
end
end
//-----------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
i2c_wr_req <= 0;
i2c_rd_req <= 0;
i2c_start_req <= 0;
i2c_stop_req <= 0;
cstate <= 0;
end
else begin
case(cstate)
0: begin
if(timer == T1SEC) begin
cstate <= cstate + 1'b1;
init_flag <= 0;
end
end
// 发送起始位及设备地址
1: begin
if(init_flag == 0) begin
i2c_wdata <= 8'b1010_000_0; // 设备地址
i2c_start_req <= 1'b1; // 启动发送
init_flag <= 1;
end
else if(i2c_done) begin
init_flag <= 0;
cstate <= cstate + 1'b1;
end
else begin
i2c_start_req <= 0;
end
end
// 发送字地址
2: begin
if(init_flag == 0) begin
init_flag <= 1;
i2c_wr_req <= 1'b1;
i2c_wdata <= 8'b0000_0000;
end
else if(i2c_done) begin
init_flag <= 0;
cstate <= cstate + 1'b1;
end
else begin
i2c_wr_req <= 0;
end
end
// 重启总线及发送设备地址
3: begin
if(init_flag == 0) begin
init_flag <= 1;
i2c_wdata <= 8'b1010_000_1;
i2c_start_req <= 1'b1;
end
else if(i2c_done) begin
init_flag <= 0;
cstate <= cstate + 1'b1;
end
else begin
i2c_start_req <= 0;
end
end
// 读操作
4: begin
if(init_flag == 0) begin
init_flag <= 1;
i2c_rd_req <= 1'b1; // 读操作
end
else if(i2c_done) begin
cstate <= cstate + 1'b1;
init_flag <= 0;
end
else begin
i2c_rd_req <= 0;
end
end
// 发送停止位
5: begin
if(init_flag == 0) begin
init_flag <= 1;
i2c_stop_req <= 1'b1; // 读操作
end
else if(i2c_done) begin
init_flag <= 0;
cstate <= 0;
end
else begin
i2c_stop_req <= 0;
end
end
default: begin
cstate <= 0;
end
endcase
end
end
// 例化模块
i2c_comm m1(
.clk(clk), // 模块时钟
.rst_n(rst_n), // 模块复位(低电平有效)
.scl(scl), // 时钟引脚
.sda(sda), // 数据引脚(双向)
.start_req(i2c_start_req), // 发送起始位及设备地址
.stop_req(i2c_stop_req), // 发送停止位
.wr_req(i2c_wr_req), // 发送数据命令
.rd_req(i2c_rd_req), // 读取数据命令
.rdata(rdata), // 读取数据
.wdata(i2c_wdata), // 待写数据
.done(i2c_done), // 单步操作完成标志
.busy() // 繁忙信号
);
endmodule
添加SingleTap测试文件:
1.采样时钟设置为timer[1],由于存储深度的问题,如果直接采用clk做为采样时钟,则存储不够一个完整的流程,所以需要降低采样频率来现;
2.添加SCL信号;
3.添加SDA信号,并设置SDA下降沿触发;
4.添加rdata信号;
测试结果:
点击Run Analysis进行采集,自动在SDA下降(起始位)沿进行触发;