文章摘要:
本文主要是用于对I2C模块的测试程序,实现对AT24C进行读测试;

重点内容: SingleTap应用,AT24C读写时序;


硬件平台:EP4CE6F17C8
开发环境:Quartus II 13.1


AT24C读写时序图

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信号;

AT24C SingleTap


测试结果:

点击Run Analysis进行采集,自动在SDA下降(起始位)沿进行触发;

AT24C测试结果波形