FPGA读写操作24lc64

FPGA读写操作常用的EEPROM芯片24lc64
速度250k,刚好400个时钟周期,容易计数。
代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/07/25 09:21:01
// Design Name:
// Module Name: iic_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description: eeprom 24lc64
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//

module iic_test(

Clk,
Rst_n,
En,
Wr_en,
Rd_en,
Addr,
Wdata,
Rdata,
Sclk,
Sdata,
Busy,
Done
);

input              Clk ;
input              Rst_n;
input              En;
input              Wr_en;
input              Rd_en;
input    [12:00]   Addr;
input    [07:00]   Wdata;
output   [07:00]   Rdata;
output             Sclk;
inout              Sdata;
output             Busy;
output             Done;

parameter          IDWADDR = 8'h42;
parameter          IDRADDR = 8'h43;
parameter          SCLK_TIME = 9'd400;
parameter          SCLK_HALF_TIME = 9'd200;
parameter          SCLK_W_TIME = 9'd100;
parameter          SCLK_R_TIME = 9'd300;

reg      [07:00]   Rdata;
reg                work_flag;
reg      [08:00]   cnt1;
wire               add_cnt1;
wire               end_cnt1;  
reg      [05:00]   cnt2;
wire               add_cnt2;
wire               end_cnt2;
reg      [01:00]   cnt3;
wire               add_cnt3;
wire               end_cnt3;
reg                rd_flag;
reg                wr_flag;  
reg    [12:00]     addr;
reg    [38:00]     wdata;
reg    [07:00]     wrdata;
reg    [05:00]     byte_num;
reg    [01:00]     step_num;
wire               rd_0_flag;
wire               rd_1_flag; 
wire               rd_get_flag; 
reg                Sclk;
wire               start_area;
wire               stop_area;
wire               sclk_h2l;
wire               sclk_l2h;  
reg                sio_out;   
reg    [07:00]     rdata;
wire               sio_get;
wire               sio_in;    
reg                sio_out_en;
reg                Done; 
wire               sio_send;  
 wire               Ack;
           
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         work_flag <= 1'b0;
       else if(En&&!Busy)
         work_flag <= 1'b1;
       else if(end_cnt3)
         work_flag <= 1'b0;
       else
         work_flag <= work_flag;
         
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         cnt1 <= 9'd0;
       else if(add_cnt1)
            if(end_cnt1)
              cnt1 <= 9'd0;
            else
              cnt1 <= cnt1+1'b1;
assign  add_cnt1 = work_flag == 1'b1;
assign  end_cnt1 = add_cnt1 && cnt1== SCLK_TIME-1;

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         cnt2 <= 6'd0 ;
       else if(add_cnt2)
            if(end_cnt2)
              cnt2 <= 6'd0 ;
            else 
              cnt2 <= cnt2 +1'b1 ;
assign  add_cnt2 = end_cnt1 ;
assign  end_cnt2 = add_cnt2 && cnt2 == byte_num-1'b1 ;

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         cnt3 <= 2'd0;
       else if(add_cnt3)
            if(end_cnt3)
              cnt3 <= 2'd0;
            else 
              cnt3 <= cnt3 + 1'b1;
assign  add_cnt3 = end_cnt2;
assign  end_cnt3 = add_cnt3 && cnt3 == step_num-1;  
                     
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         rd_flag <= 1'b0 ;
       else if(En)
         rd_flag <= Rd_en;
       else
         rd_flag <= rd_flag;
         
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         wr_flag <= 1'b0 ;
       else if(En)
         wr_flag <= Wr_en;
       else
         wr_flag <= wr_flag;  
         
 always@(posedge Clk or negedge Rst_n)
                if(!Rst_n)
                  addr <= 13'd0 ;
                else if(En)
                  addr <= Addr ;    
 always@(posedge Clk or negedge Rst_n)
                 if(!Rst_n)
                    wrdata <= 8'd0 ;
                 else if(En)
                    wrdata <= Wdata  ; 
           
always@(*)
       if(!Rst_n)
         begin

         	 wdata    <= 39'd0;
         	 byte_num <= 6'd0;
         	 step_num <= 2'd0;
         end  
       else if(wr_flag)
         begin
         	 wdata    <= {1'b0,8'b1010_0000,1'b1,3'd0,addr[12:8],1'b1,addr[7:0],1'b1,wrdata[7:0],1'b1,1'b0,1'b1};
         	 byte_num <= 6'd39;
         	 step_num <= 1;
         end
       else if(rd_0_flag)
         begin
         	 wdata    <= {1'b0,8'b1010_0000,1'b0,3'd0,addr[12:8],1'b0,addr[7:0],1'b0,2'b11,9'd0};
         	 byte_num <= 6'd30;
         	 step_num <= 2;
         end                              
       else if(rd_1_flag)
         begin
         	 wdata    <= {1'b0,8'b10100001,1'b0,8'b0,1'b1,1'b0,1'b1,18'd0};
         	 byte_num <= 6'd21;
         	 step_num <= 2;
         end
        else
         begin
             wdata    <= 39'd0;
             byte_num <= 6'd0;
             step_num <= 2'd0;
        end                 
assign  rd_0_flag = rd_flag && cnt3 == 0;
assign  rd_1_flag = rd_flag && cnt3 == 1;
assign  rd_get_flag   = rd_1_flag && (cnt2>=10 && cnt2<18);

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         Sclk <= 1'b1;
       else if(sclk_h2l)
         Sclk <= 1'b0;
       else if(sclk_l2h)
         Sclk <= 1'b1;
assign  start_area = work_flag && cnt2 == 1'b0;
assign  stop_area  = work_flag && cnt2 == byte_num-1;
assign  sclk_h2l   = work_flag && ((!start_area)&&(!stop_area))&&cnt1==0;
assign  sclk_l2h   = work_flag && ((!start_area)&&(!stop_area))&&cnt1==SCLK_HALF_TIME-1;

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         sio_out <= 1'b1 ;
       else if (sio_send)
         sio_out <= wdata[38-cnt2];
assign  sio_send = work_flag && (cnt1 == SCLK_W_TIME-1'b1) && rd_get_flag == 1'b0; 

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         rdata <= 8'd0;
		  else if (work_flag && end_cnt3)
		    rdata <= 8'd0;
       else if(sio_get)
         rdata <= {rdata[6:0],sio_in};
assign  sio_get = work_flag && (cnt1 == SCLK_R_TIME-1'b1) && rd_get_flag == 1'b1;

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         sio_out_en <= 1'b0;
		  else if(Ack)
		    sio_out_en <= 1'b0;
       else if(work_flag && (rd_get_flag == 1'b0))
         sio_out_en <=1'b1;
       else if(work_flag && (rd_get_flag == 1'b1))
         sio_out_en <= 1'b0;
 assign  Ack = ((rd_0_flag && ((cnt2==9)||(cnt2==18)||(cnt2==27))))||((rd_1_flag && ((cnt2==9)||(cnt2==18))));
 
 reg     [05:00]   ack_data_reg;
 wire              ack_get;
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
		    ack_data_reg <=6'd0;
		  else if(ack_get)	
		    ack_data_reg <= {ack_data_reg[04:00],sio_in} ;
			 
 assign  ack_get=Ack&& (cnt1 == SCLK_R_TIME-1'b1);   
assign  Sdata  = sio_out_en ? sio_out: 1'bz;
assign  sio_in = Sdata;
 
always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
		    Rdata <= 8'd0;  
		  else if(rd_1_flag && end_cnt3)	
		    Rdata <= rdata;
 
assign  Busy  = work_flag;

always@(posedge Clk or negedge Rst_n)
       if(!Rst_n)
         Done <= 1'b0; 
       else if(work_flag && end_cnt3)
         Done <= 1'b1;
       else
         Done <= 1'b0;
endmodule

手册时序要求如下:
FPGA读写操作24lc64_第1张图片
设计时序如下:
FPGA读写操作24lc64_第2张图片
1处为开始信号,在时钟为高时,数据线由高拉低。
2处为数据传输要求,在时钟拉低的时候数据才可以进行跳变,不能在为高时变化,否则可能会出错。
3处为ACK信号,要求主机释放数据线,所以变为高阻态,这时候采集数据,如果EEPROM相应,则读取值为0.
4处为开始信号,读取模式下,手册要求共有两次开始信号。
5处为停止信号,在时钟为高时将数据线由低拉高,表示结束。
仿真结果如下:
图一:
在这里插入图片描述
图二:
在这里插入图片描述
图一为写入数据时的时序。
图二为读出数据时的时序,注意图中蓝色为释放数据线后的高阻态,可以读数据。
可以看到仿真结果是与设计时序图一致的。
图三:
FPGA读写操作24lc64_第3张图片
板子实验程序如下:
顶层模块由串口模块与iic_test_top模块组成,当串口发送任意字符,接受完成的信号Rx_Done作为iic_test_top的起始信号,将在EEPROM中指定的地址中写入指定的值,并将其读出,将读出的值用来驱动LED灯发光。
module uart_iic(

Clk,
Rst_n,
Rs232_rx,	
Sclk,
Sdata,
Led

);

input               Clk;
input               Rst_n;
input               Rs232_rx;

output Sclk;
inout Sdata;
output [03:00] Led;
wire Start;
iic_test_top u1
(
.Clk (Clk),
.Rst_n(Rst_n),
.Sclk (Sclk),
.Sdata(Sdata),
.Start(Start),
.Led (Led)
);
uart_byte_rx u2(
.Clk (Clk),
.Rst_n (Rst_n),
.Rs232_rx (Rs232_rx),
.baud_set (3’d4),
.Data_Byte(),
.Rx_Done (Start)

);

endmodule
实验效果:
FPGA读写操作24lc64_第4张图片

FPGA读写操作24lc64_第5张图片
代码中要求读取地址1中的值,地址1中预先写入了值1。

FPGA读写操作24lc64_第6张图片
可以看到LED0灭掉,与预期结果一致。
工程如下,需要的可以下载指教讨论:

  1. vivado与modelsim联合仿真工程
    工程链接:https://pan.baidu.com/s/1DuYMVYnYq7Ek1ApawCjrVg
    提取码:1234
    2.quartus与signal tap在线仿真实验
    工程链接:https://pan.baidu.com/s/18b6AtRuIlj03I-1E0Lnxsg
    提取码:1234

你可能感兴趣的:(FPGA,fpga)