野火FPGA进阶(2):基于I2C协议的EEPROM驱动控制
创始人
2024-03-06 05:53:39
0

文章目录

    • 第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

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...