文章目录

  • 第49讲:基于I2C协议的EEPROM驱动控制
    • 理论部分
    • 设计与实现
    • i2c_ctrl
    • i2c_rw_data
    • eeprom_byte_rd_wr
    • tb_eeprom_byte_rd_wr

第49讲:基于I2C协议的EEPROM驱动控制

理论部分

I2C通讯协议(Inter-Integrated Circuit)是由Philips公司开发的一种简单、双向二线制同步串行总线,只需要两根线即可在连接于总线上的器件之间传送信息。

I2C通讯协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行AD,图像处理领域的摄像头配置,工业控制领域的X射线管配置等等。除此之外,由于I2C协议占用引脚特别少,硬件实现简单,可扩展性强,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。





设计与实现

实验目标:01-10的写入和读取



i2c_ctrl

`timescale  1ns/1nsmodule  i2c_ctrl
#(parameter   DEVICE_ADDR     =   7'b1010_000     ,   //i2c设备地址parameter   SYS_CLK_FREQ    =   26'd50_000_000  ,   //输入系统时钟频率parameter   SCL_FREQ        =   18'd250_000         //i2c设备scl时钟频率
)
(input   wire            sys_clk     ,   //输入系统时钟,50MHzinput   wire            sys_rst_n   ,   //输入复位信号,低电平有效input   wire            wr_en       ,   //输入写使能信号input   wire            rd_en       ,   //输入读使能信号input   wire            i2c_start   ,   //输入i2c触发信号input   wire            addr_num    ,   //输入i2c字节地址字节数input   wire    [15:0]  byte_addr   ,   //输入i2c字节地址input   wire    [7:0]   wr_data     ,   //输入i2c设备数据output  reg             i2c_clk     ,   //i2c驱动时钟output  reg             i2c_end     ,   //i2c一次读/写操作完成output  reg     [7:0]   rd_data     ,   //输出i2c设备读取数据output  reg             i2c_scl     ,   //输出至i2c设备的串行时钟信号sclinout   wire            i2c_sda         //输出至i2c设备的串行数据信号sda
);// parameter define
parameter   CNT_CLK_MAX     =   (SYS_CLK_FREQ/SCL_FREQ) >> 2'd3   ;   //cnt_clk计数器计数最大值parameter   CNT_START_MAX   =   8'd100; //cnt_start计数器计数最大值parameter   IDLE            =   4'd00,  //初始状态START_1         =   4'd01,  //开始状态1SEND_D_ADDR     =   4'd02,  //设备地址写入状态 + 控制写ACK_1           =   4'd03,  //应答状态1SEND_B_ADDR_H   =   4'd04,  //字节地址高八位写入状态ACK_2           =   4'd05,  //应答状态2SEND_B_ADDR_L   =   4'd06,  //字节地址低八位写入状态ACK_3           =   4'd07,  //应答状态3WR_DATA         =   4'd08,  //写数据状态ACK_4           =   4'd09,  //应答状态4START_2         =   4'd10,  //开始状态2SEND_RD_ADDR    =   4'd11,  //设备地址写入状态 + 控制读ACK_5           =   4'd12,  //应答状态5RD_DATA         =   4'd13,  //读数据状态N_ACK           =   4'd14,  //非应答状态STOP            =   4'd15;  //结束状态// wire  define
wire            sda_in          ;   //sda输入数据寄存
wire            sda_en          ;   //sda数据写入使能信号// reg   define
reg     [7:0]   cnt_clk         ;   //系统时钟计数器,控制生成clk_i2c时钟信号
reg     [3:0]   state           ;   //状态机状态
reg             cnt_i2c_clk_en  ;   //cnt_i2c_clk计数器使能信号
reg     [1:0]   cnt_i2c_clk     ;   //clk_i2c时钟计数器,控制生成cnt_bit信号
reg     [2:0]   cnt_bit         ;   //sda比特计数器
reg             ack             ;   //应答信号
reg             i2c_sda_reg     ;   //sda数据缓存
reg     [7:0]   rd_data_reg     ;   //自i2c设备读出数据// cnt_clk:系统时钟计数器,控制生成clk_i2c时钟信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  8'd0;else    if(cnt_clk == CNT_CLK_MAX - 1'b1)cnt_clk <=  8'd0;elsecnt_clk <=  cnt_clk + 1'b1;// i2c_clk:i2c驱动时钟
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_clk <=  1'b1;else    if(cnt_clk == CNT_CLK_MAX - 1'b1)i2c_clk <=  ~i2c_clk;// cnt_i2c_clk_en:cnt_i2c_clk计数器使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_i2c_clk_en  <=  1'b0;else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))cnt_i2c_clk_en  <=  1'b0;else    if(i2c_start == 1'b1)cnt_i2c_clk_en  <=  1'b1;// cnt_i2c_clk:i2c_clk时钟计数器,控制生成cnt_bit信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_i2c_clk <=  2'd0;else    if(cnt_i2c_clk_en == 1'b1)cnt_i2c_clk <=  cnt_i2c_clk + 1'b1;// cnt_bit:sda比特计数器
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_bit <=  3'd0;else    if((state == IDLE) || (state == START_1) || (state == START_2)|| (state == ACK_1) || (state == ACK_2) || (state == ACK_3)|| (state == ACK_4) || (state == ACK_5) || (state == N_ACK))cnt_bit <=  3'd0;else    if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))cnt_bit <=  3'd0;else    if((cnt_i2c_clk == 2'd3) && (state != IDLE))cnt_bit <=  cnt_bit + 1'b1;// state:状态机状态跳转
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)state   <=  IDLE;else    case(state)IDLE:if(i2c_start == 1'b1)state   <=  START_1;elsestate   <=  state;START_1:if(cnt_i2c_clk == 3)state   <=  SEND_D_ADDR;elsestate   <=  state;SEND_D_ADDR:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_1;elsestate   <=  state;ACK_1:if((cnt_i2c_clk == 3) && (ack == 1'b0))beginif(addr_num == 1'b1)state   <=  SEND_B_ADDR_H;elsestate   <=  SEND_B_ADDR_L;endelsestate   <=  state;SEND_B_ADDR_H:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_2;elsestate   <=  state;ACK_2:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  SEND_B_ADDR_L;elsestate   <=  state;SEND_B_ADDR_L:if((cnt_bit == 3'd7) && (cnt_i2c_clk == 3))state   <=  ACK_3;elsestate   <=  state;ACK_3:if((cnt_i2c_clk == 3) && (ack == 1'b0))beginif(wr_en == 1'b1)state   <=  WR_DATA;else    if(rd_en == 1'b1)state   <=  START_2;elsestate   <=  state;endelsestate   <=  state;WR_DATA:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_4;elsestate   <=  state;ACK_4:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  STOP;elsestate   <=  state;START_2:if(cnt_i2c_clk == 3)state   <=  SEND_RD_ADDR;elsestate   <=  state;SEND_RD_ADDR:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_5;elsestate   <=  state;ACK_5:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  RD_DATA;elsestate   <=  state;RD_DATA:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  N_ACK;elsestate   <=  state;N_ACK:if(cnt_i2c_clk == 3)state   <=  STOP;elsestate   <=  state;STOP:if((cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))state   <=  IDLE;elsestate   <=  state;default:    state   <=  IDLE;endcase// ack:应答信号
always@(*)case    (state)IDLE,START_1,SEND_D_ADDR,SEND_B_ADDR_H,SEND_B_ADDR_L,WR_DATA,START_2,SEND_RD_ADDR,RD_DATA,N_ACK:ack <=  1'b1;ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:if(cnt_i2c_clk == 2'd0)ack <=  sda_in;elseack <=  ack;default:    ack <=  1'b1;endcase// i2c_scl:输出至i2c设备的串行时钟信号scl
always@(*)case    (state)IDLE:i2c_scl <=  1'b1;START_1:if(cnt_i2c_clk == 2'd3)i2c_scl <=  1'b0;elsei2c_scl <=  1'b1;SEND_D_ADDR,ACK_1,SEND_B_ADDR_H,ACK_2,SEND_B_ADDR_L,ACK_3,WR_DATA,ACK_4,START_2,SEND_RD_ADDR,ACK_5,RD_DATA,N_ACK:if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))i2c_scl <=  1'b1;elsei2c_scl <=  1'b0;STOP:if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0))i2c_scl <=  1'b0;elsei2c_scl <=  1'b1;default:    i2c_scl <=  1'b1;endcase// i2c_sda_reg:sda数据缓存
always@(*)case    (state)IDLE:begini2c_sda_reg <=  1'b1;rd_data_reg <=  8'd0;endSTART_1:if(cnt_i2c_clk <= 2'd0)i2c_sda_reg <=  1'b1;elsei2c_sda_reg <=  1'b0;SEND_D_ADDR:if(cnt_bit <= 3'd6)i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];elsei2c_sda_reg <=  1'b0;ACK_1:i2c_sda_reg <=  1'b1;SEND_B_ADDR_H:i2c_sda_reg <=  byte_addr[15 - cnt_bit];ACK_2:i2c_sda_reg <=  1'b1;SEND_B_ADDR_L:i2c_sda_reg <=  byte_addr[7 - cnt_bit];ACK_3:i2c_sda_reg <=  1'b1;WR_DATA:i2c_sda_reg <=  wr_data[7 - cnt_bit];ACK_4:i2c_sda_reg <=  1'b1;START_2:if(cnt_i2c_clk <= 2'd1)i2c_sda_reg <=  1'b1;elsei2c_sda_reg <=  1'b0;SEND_RD_ADDR:if(cnt_bit <= 3'd6)i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];elsei2c_sda_reg <=  1'b1;ACK_5:i2c_sda_reg <=  1'b1;RD_DATA:if(cnt_i2c_clk  == 2'd2)rd_data_reg[7 - cnt_bit]    <=  sda_in;elserd_data_reg <=  rd_data_reg;N_ACK:i2c_sda_reg <=  1'b1;STOP:if((cnt_bit == 3'd0) && (cnt_i2c_clk < 2'd3))i2c_sda_reg <=  1'b0;elsei2c_sda_reg <=  1'b1;default:begini2c_sda_reg <=  1'b1;rd_data_reg <=  rd_data_reg;endendcase// rd_data:自i2c设备读出数据
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_data <=  8'd0;else    if((state == RD_DATA) && (cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))rd_data <=  rd_data_reg;// i2c_end:一次读/写结束信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_end <=  1'b0;else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))i2c_end <=  1'b1;elsei2c_end <=  1'b0;// sda_in:sda输入数据寄存
assign  sda_in = i2c_sda;
// sda_en:sda数据写入使能信号
assign  sda_en = ((state == RD_DATA) || (state == ACK_1) || (state == ACK_2)|| (state == ACK_3) || (state == ACK_4) || (state == ACK_5))? 1'b0 : 1'b1;
// i2c_sda:输出至i2c设备的串行数据信号sda
assign  i2c_sda = (sda_en == 1'b1) ? i2c_sda_reg : 1'bz;endmodule

i2c_rw_data

`timescale  1ns/1nsmodule  i2c_rw_data
(input   wire            sys_clk     ,   //输入系统时钟,频率50MHzinput   wire            i2c_clk     ,   //输入i2c驱动时钟,频率1MHzinput   wire            sys_rst_n   ,   //输入复位信号,低有效input   wire            write       ,   //输入写触发信号input   wire            read        ,   //输入读触发信号input   wire            i2c_end     ,   //一次i2c读/写结束信号input   wire    [7:0]   rd_data     ,   //输入自i2c设备读出的数据output  reg             wr_en       ,   //输出写使能信号output  reg             rd_en       ,   //输出读使能信号output  reg             i2c_start   ,   //输出i2c读/写触发信号output  reg     [15:0]  byte_addr   ,   //输出i2c设备读/写地址output  reg     [7:0]   wr_data     ,   //输出写入i2c设备的数据output  wire    [7:0]   fifo_rd_data    //输出自fifo中读出的数据
);// parameter  define
parameter   DATA_NUM        =   8'd10       ,   //读/写操作读出或写入的数据个数CNT_START_MAX   =   16'd4000    ,   //cnt_start计数器计数最大值CNT_WR_RD_MAX   =   8'd200      ,   //cnt_wr/cnt_rd计数器计数最大值CNT_WAIT_MAX    =   28'd500_000 ;   //cnt_wait计数器计数最大值
// wire  define
wire    [7:0]   data_num    ;   //fifo中数据个数// reg   define
reg     [7:0]   cnt_wr          ;   //写触发有效信号保持时间计数器
reg             write_valid     ;   //写触发有效信号
reg     [7:0]   cnt_rd          ;   //读触发有效信号保持时间计数器
reg             read_valid      ;   //读触发有效信号
reg     [15:0]  cnt_start       ;   //单字节数据读/写时间间隔计数
reg     [7:0]   wr_i2c_data_num ;   //写入i2c设备的数据个数
reg     [7:0]   rd_i2c_data_num ;   //读出i2c设备的数据个数
reg             fifo_rd_valid   ;   //fifo读有效信号
reg     [27:0]  cnt_wait        ;   //fifo读使能信号间时间间隔计数
reg             fifo_rd_en      ;   //fifo读使能信号
reg     [7:0]   rd_data_num     ;   //读出fifo数据个数//cnt_wr:写触发有效信号保持时间计数器,计数写触发有效信号保持时钟周期数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wr    <=  8'd0;else    if(write_valid == 1'b0)cnt_wr    <=  8'd0;else    if(write_valid == 1'b1)cnt_wr    <=  cnt_wr + 1'b1;//write_valid:写触发有效信号
//由于写触发信号保持时间为一个系统时钟周期(20ns),
//不能被i2c驱动时钟i2c_scl正确采集,延长写触发信号生成写触发有效信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)write_valid    <=  1'b0;else    if(cnt_wr == (CNT_WR_RD_MAX - 1'b1))write_valid    <=  1'b0;else    if(write == 1'b1)write_valid    <=  1'b1;//cnt_rd:读触发有效信号保持时间计数器,计数读触发有效信号保持时钟周期数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_rd    <=  8'd0;else    if(read_valid == 1'b0)cnt_rd    <=  8'd0;else    if(read_valid == 1'b1)cnt_rd    <=  cnt_rd + 1'b1;//read_valid:读触发有效信号
//由于读触发信号保持时间为一个系统时钟周期(20ns),
//不能被i2c驱动时钟i2c_scl正确采集,延长读触发信号生成读触发有效信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)read_valid    <=  1'b0;else    if(cnt_rd == (CNT_WR_RD_MAX - 1'b1))read_valid    <=  1'b0;else    if(read == 1'b1)read_valid    <=  1'b1;//cnt_start:单字节数据读/写操作时间间隔计数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_start   <=  16'd0;else    if((wr_en == 1'b0) && (rd_en == 1'b0))cnt_start   <=  16'd0;else    if(cnt_start == (CNT_START_MAX - 1'b1))cnt_start   <=  16'd0;else    if((wr_en == 1'b1) || (rd_en == 1'b1))cnt_start   <=  cnt_start + 1'b1;//i2c_start:i2c读/写触发信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_start   <=  1'b0;else    if((cnt_start == (CNT_START_MAX - 1'b1)))i2c_start   <=  1'b1;elsei2c_start   <=  1'b0;//wr_en:输出写使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_en   <=  1'b0;else    if((wr_i2c_data_num == DATA_NUM - 1) && (i2c_end == 1'b1) && (wr_en == 1'b1))wr_en   <=  1'b0;else    if(write_valid == 1'b1)wr_en   <=  1'b1;//wr_i2c_data_num:写入i2c设备的数据个数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_i2c_data_num <=  8'd0;else    if(wr_en == 1'b0)wr_i2c_data_num <=  8'd0;else    if((wr_en == 1'b1) && (i2c_end == 1'b1))wr_i2c_data_num <=  wr_i2c_data_num + 1'b1;//rd_en:输出读使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_en   <=  1'b0;else    if((rd_i2c_data_num == DATA_NUM - 1) && (i2c_end == 1'b1) && (rd_en == 1'b1))rd_en   <=  1'b0;else    if(read_valid == 1'b1)rd_en   <=  1'b1;//rd_i2c_data_num:写入i2c设备的数据个数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_i2c_data_num <=  8'd0;else    if(rd_en == 1'b0)rd_i2c_data_num <=  8'd0;else    if((rd_en == 1'b1) && (i2c_end == 1'b1))rd_i2c_data_num <=  rd_i2c_data_num + 1'b1;//byte_addr:输出读/写地址
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)byte_addr   <=  16'h00_5A;else    if((wr_en == 1'b0) && (rd_en == 1'b0))byte_addr   <=  16'h00_5A;else    if(((wr_en == 1'b1) || (rd_en == 1'b1)) && (i2c_end == 1'b1))byte_addr   <=  byte_addr + 1'b1;//wr_data:输出待写入i2c设备数据
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_data <=  8'h01;else    if(wr_en == 1'b0)wr_data <=  8'h01;else    if((wr_en == 1'b1) && (i2c_end == 1'b1))wr_data <=  wr_data + 1'b1;//fifo_rd_valid:fifo读有效信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_rd_valid  <=  1'b0;else    if((rd_data_num == DATA_NUM)&& (cnt_wait == (CNT_WAIT_MAX - 1'b1)))fifo_rd_valid  <=  1'b0;else    if(data_num == DATA_NUM)fifo_rd_valid  <=  1'b1;//cnt_wait:fifo读使能信号间时间间隔计数,计数两fifo读使能间的时间间隔
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wait    <=  28'd0;else    if(fifo_rd_valid == 1'b0)cnt_wait    <=  28'd0;else    if(cnt_wait == (CNT_WAIT_MAX - 1'b1))cnt_wait    <=  28'd0;else    if(fifo_rd_valid == 1'b1)cnt_wait    <=  cnt_wait + 1'b1;//fifo_rd_en:fifo读使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_rd_en <=  1'b0;else    if((cnt_wait == (CNT_WAIT_MAX - 1'b1))&& (rd_data_num < DATA_NUM))fifo_rd_en <=  1'b1;elsefifo_rd_en <=  1'b0;//rd_data_num:自fifo中读出数据个数计数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_data_num <=  8'd0;else    if(fifo_rd_valid == 1'b0)rd_data_num <=  8'd0;else    if(fifo_rd_en == 1'b1)rd_data_num <=  rd_data_num + 1'b1;//------------- fifo_read_inst -------------
fifo_data   fifo_read_inst
(.clock  (i2c_clk            ),  //输入时钟信号,频率1MHz,1bit.data   (rd_data            ),  //输入写入数据,1bit.rdreq  (fifo_rd_en         ),  //输入数据读请求,1bit.wrreq  (i2c_end && rd_en   ),  //输入数据写请求,1bit.q      (fifo_rd_data       ),  //输出读出数据,1bit.usedw  (data_num           )   //输出fifo内数据个数,1bit
);endmodule

eeprom_byte_rd_wr

`timescale  1ns/1nsmodule  eeprom_byte_rd_wr
(input   wire            sys_clk     ,   //输入工作时钟,频率50MHzinput   wire            sys_rst_n   ,   //输入复位信号,低电平有效input   wire            key_wr      ,   //按键写input   wire            key_rd      ,   //按键读inout   wire            sda         ,   //串行数据output  wire            scl         ,   //串行时钟output  wire            stcp        ,   //输出数据存储器时钟output  wire            shcp        ,   //移位寄存器的时钟输入output  wire            ds          ,   //串行数据输入output  wire            oe              //使能信号
);//wire  define
wire            read        ;   //读数据
wire            write       ;   //写数据
wire    [7:0]   po_data     ;   //fifo输出数据
wire    [7:0]   rd_data     ;   //eeprom读出数据
wire            wr_en       ;
wire            rd_en       ;
wire            i2c_end     ;
wire            i2c_start   ;
wire    [7:0]   wr_data     ;
wire    [15:0]  byte_addr   ;
wire            i2c_clk     ;//------------- key_wr_inst -------------
key_filter  key_wr_inst
(.sys_clk    (sys_clk    ),  //系统时钟50Mhz.sys_rst_n  (sys_rst_n  ),  //全局复位.key_in     (key_wr     ),  //按键输入信号.key_flag   (write      )   //key_flag为1时表示按键有效,0表示按键无效
);//------------- key_rd_inst -------------
key_filter  key_rd_inst
(.sys_clk    (sys_clk    ),  //系统时钟50Mhz.sys_rst_n  (sys_rst_n  ),  //全局复位.key_in     (key_rd     ),  //按键输入信号.key_flag   (read       )   //key_flag为1时表示按键有效,0表示按键无效
);//------------- i2c_rw_data_inst -------------
i2c_rw_data i2c_rw_data_inst
(.sys_clk     (sys_clk   ),  //输入系统时钟,频率50MHz.i2c_clk     (i2c_clk   ),  //输入i2c驱动时钟,频率1MHz.sys_rst_n   (sys_rst_n ),  //输入复位信号,低有效.write       (write     ),  //输入写触发信号.read        (read      ),  //输入读触发信号.i2c_end     (i2c_end   ),  //一次i2c读/写结束信号.rd_data     (rd_data   ),  //输入自i2c设备读出的数据.wr_en       (wr_en     ),  //输出写使能信号.rd_en       (rd_en     ),  //输出读使能信号.i2c_start   (i2c_start ),  //输出i2c读/写触发信号.byte_addr   (byte_addr ),  //输出i2c设备读/写地址.wr_data     (wr_data   ),  //输出写入i2c设备的数据.fifo_rd_data(po_data   )   //输出自fifo中读出的数据
);//------------- i2c_ctrl_inst -------------
i2c_ctrl
#(.DEVICE_ADDR    (7'b1010_011     ), //i2c设备器件地址.SYS_CLK_FREQ   (26'd50_000_000  ), //i2c_ctrl模块系统时钟频率.SCL_FREQ       (18'd250_000     )  //i2c的SCL时钟频率
)
i2c_ctrl_inst
(.sys_clk     (sys_clk   ),   //输入系统时钟,50MHz.sys_rst_n   (sys_rst_n ),   //输入复位信号,低电平有效.wr_en       (wr_en     ),   //输入写使能信号.rd_en       (rd_en     ),   //输入读使能信号.i2c_start   (i2c_start ),   //输入i2c触发信号.addr_num    (1'b1      ),   //输入i2c字节地址字节数.byte_addr   (byte_addr ),   //输入i2c字节地址.wr_data     (wr_data   ),   //输入i2c设备数据.rd_data     (rd_data   ),   //输出i2c设备读取数据.i2c_end     (i2c_end   ),   //i2c一次读/写操作完成.i2c_clk     (i2c_clk   ),   //i2c驱动时钟.i2c_scl     (scl       ),   //输出至i2c设备的串行时钟信号scl.i2c_sda     (sda       )    //输出至i2c设备的串行数据信号sda
);//------------- seg7_dynamic_inst -------------
seg_595_dynamic seg_595_dynamic_inst
(.sys_clk     (sys_clk   ), //系统时钟,频率50MHz.sys_rst_n   (sys_rst_n ), //复位信号,低有效.data        (po_data   ), //数码管要显示的值.point       (          ), //小数点显示,高电平有效.seg_en      (1'b1      ), //数码管使能信号,高电平有效.sign        (          ), //符号位,高电平显示负号.stcp        (stcp      ), //数据存储器时钟.shcp        (shcp      ), //移位寄存器时钟.ds          (ds        ), //串行数据输入.oe          (oe        )  //使能信号
);endmodule

tb_eeprom_byte_rd_wr

`timescale  1ns/1nsmodule  tb_eeprom_byte_rd_wr();
//wire define
wire            scl ;
wire            sda ;
wire            stcp;
wire            shcp;
wire            ds  ;
wire            oe  ;//reg define
reg           clk   ;
reg           rst_n ;
reg           key_wr;
reg           key_rd;//时钟、复位信号
initialbeginclk     =   1'b1  ;rst_n   <=  1'b0  ;key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#200rst_n   <=  1'b1  ;#1000key_wr  <=  1'b0  ;key_rd  <=  1'b1  ;#400key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#20000000key_wr  <=  1'b1  ;key_rd  <=  1'b0  ;#400key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#40000000$stop;endalways  #10 clk = ~clk;defparam eeprom_byte_rd_wr_inst.key_wr_inst.CNT_MAX = 5;
defparam eeprom_byte_rd_wr_inst.key_rd_inst.CNT_MAX = 5;
defparam eeprom_byte_rd_wr_inst.i2c_rw_data_inst.CNT_WAIT_MAX = 1000;//-------------eeprom_byte_rd_wr_inst-------------
eeprom_byte_rd_wr   eeprom_byte_rd_wr_inst
(.sys_clk        (clk    ),    //输入工作时钟,频率50MHz.sys_rst_n      (rst_n  ),    //输入复位信号,低电平有效.key_wr         (key_wr ),    //按键写.key_rd         (key_rd ),    //按键读.sda            (sda    ),    //串行数据.scl            (scl    ),    //串行时钟.stcp           (stcp   ),   //输出数据存储寄时钟.shcp           (shcp   ),   //移位寄存器的时钟输入.ds             (ds     ),   //串行数据输入.oe             (oe     )
);//-------------eeprom_inst-------------
M24LC64  M24lc64_inst
(.A0     (1'b0       ),  //器件地址.A1     (1'b0       ),  //器件地址.A2     (1'b0       ),  //器件地址.WP     (1'b0       ),  //写保护信号,高电平有效.RESET  (~rst_n     ),  //复位信号,高电平有效.SDA    (sda        ),  //串行数据.SCL    (scl        )   //串行时钟
);endmodule

FPGA进阶(2):基于I2C协议的EEPROM驱动控制相关推荐

  1. 基于I2C协议的EEPROM驱动控制

    基于I2C协议的EEPROM驱动控制 `timescale 1ns / 1ps module i2c_ctrl #(parameter DEVICE_ADDR = 7'b1010_000,//i2c设 ...

  2. 基于I2C协议的EEPROM驱动控制(笔记整理)

    一.目标 要求:设计一个使用I2C通讯协议的EEPROM读写控制器.使用写按键向EEPROM中写入1~10共10字节数据:使用读按键读出之前写入的数据并显示在数码管上. 分析:①首先按键控制读写操作按 ...

  3. 基于SPI协议的Flash驱动控制-数据普通读操作

    目录 Flash数据普通读操作 实现原理 verilog设计代码 verilog测试代码 Flash数据普通读操作 实现原理 将片选信号拉低,写入读操作指令,最少读取一个字节的数据,写入读指令后要写入 ...

  4. 基于SPI协议的Flash驱动控制-扇区擦除

    目录 Flash扇区擦除 实现原理 verilog设计代码 verilog测试代码 Flash扇区擦除 实现原理 扇区的概念 Flash型号的数字代表容量,单位兆bit,如M25P16,此Flash的 ...

  5. STM32F103基于I2C协议的AHT20温湿度传感器的数据采集

    目录 一.I2C 1.I2C 协议简介 2.I2C 物理层 3.协议层 通讯的起始和停止信号 数据有效性 响应 4. 软件I2C"和"硬件I2C 二.实现AHT20采集程序 1.A ...

  6. STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

    文章目录 一.I2C总线通讯协议 1.I2C总线简介 2.I2C 协议的物理层和协议层 2.1物理层 2.2协议层 3.I2C的两种方式--硬件I2C和软件I2C 3.1硬件I2C 3.2软件I2C ...

  7. STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出

    文章目录 前言 一.I2C总线通信协议 1.I2C总线 2.工作原理 3.I2C特点 4.I2C模式选择 5.软件I2C和硬件I2C 二.串口输出温湿度传感器的数据 1.核心代码分析 2.硬件实操连接 ...

  8. 基于I2C协议利用STM32进行温湿度传感器的数据采集

    目录 一.I2C总线通信协议的介绍 1.I2C简介 2.I2C总线时序图 3.五种速率 4.四种信号 5.I2C的优缺点 6.软件IIC和硬件IIC 二.创建工程 1.实验目的 2.工具的选择 3.相 ...

  9. firefly-rk3288j开发板--linux I2C实验之eeprom驱动

    firefly-rk3288j开发板–linux I2C实验之eeprom驱动 1 准备工作 开发板:aio-rk3288j SDK版本:rk3288_linux_release_20210304 下 ...

最新文章

  1. SQL 注入真是防不胜防!
  2. Linq to xml:使用 XSLT 转换 XML 树
  3. 开源OSS.Social微信项目解析
  4. Android 秒级编译FreeLine
  5. 华为开发者大会上,鸿蒙问世、方舟编译器开源、还有 EMUI 10;壕置100万美元,苹果推出漏洞攻击报告赏金计划……...
  6. c语言分配飞机10个座位,leetcode1227(飞机座位分配)--C语言实现
  7. 解决拼音汉字混合搜索,由于同音字导致搜出不相干的内容
  8. Latex给表格加脚注
  9. 用友u852找不到本地服务器,用友U852安装常见问题
  10. android框架百大排行榜
  11. “动真格”的垃圾分类,需要你我容忍其中的不便
  12. 产品销售份额数据统计流程图模板分享
  13. 如何保养笔记本的电池
  14. Ubuntu 下编写C程序
  15. android钢琴软件和弦,‎App Store 上的“判断和弦以钢琴演奏 Piano Chord Judge”
  16. 什么是Hadoop的HA机制?
  17. pandas学习笔记:pandas.Dataframe.rename()函数用法
  18. 获取图片的EXIF信息如此困难?
  19. python-字符串连接
  20. Windows 微秒级 延时

热门文章

  1. VLC Plugin JS 方法
  2. C语言入门 九九乘法表
  3. 多项式 商环 域(群论笔记)
  4. 崩三类卡通渲染解析及制作规范
  5. 《信息系统安全》第二章 信息安全模型 作业
  6. 黑盒测试的原理及内容
  7. Pose for Everything: Towards Category-Agnostic Pose Estimation 阅读笔记
  8. Python 的 AIML
  9. 无线通信学习笔记(一)
  10. 孤尽班第22天 -- 系统安全规约