野火FPGA进阶(2):基于I2C协议的EEPROM驱动控制

news/2024/4/30 2:07:07/文章来源:https://blog.csdn.net/qq_39236499/article/details/128105127

文章目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_228023.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

改革后IB数学该如何选?

IB数学&#xff0c;作为一个IB课程里必选科目&#xff0c;让无数IB学霸为之自豪&#xff0c;他们能解出外教都不会做的题。另一方面&#xff0c;也让很多同学&#xff08;自称“学渣”&#xff09;避之不及。 从2019年起&#xff0c;IB数学教学大纲发生重大改革。▲图源&#x…

C语言详细知识点(下)

⛄️上一篇⛄️C语言详细知识点&#xff08;上&#xff09; 文章目录五、数组1、一维数组的定义及使用2、二维数组的定义及使用3、字符数组的定义及使用六、函数1、函数的定义2、函数的调用3、函数的声明4、函数的嵌套调用5、函数的递归调用七、指针1、什么是指针2、指针变量3、…

链表之反转链表

文章目录链表之反转链表题目描述解题思路代码实现链表之反转链表 力扣链接 题目描述 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例&#xff1a; ​ 输入: 1->2->3->4->5->NULL ​ 输出: 5->4-&…

基于vue项目的代码优化

前言 项目上线后其整体性能的优良是用户也是研发人员所关注的。项目优化非常重要&#xff0c;一丝一毫的提升都是对用户的负责。因此我们在开发中就应该注重细节&#xff0c;优化工作从日常开发做起。本篇文章就分享一些在日常开发中代码层面的优化手段。 开发常用优化手段 …

达摩院快速动作识别TPS ECCV论文深入解读

一、论文&代码 论文&#xff1a;https://www.ecva.net/papers/eccv_2022/papers_ECCV/papers/136630615.pdf 模型&代码&#xff1a;ModelScope 魔搭社区 二、背景 高效的时空建模(Spatiotemporal modeling)是视频理解和动作识别的核心问题。相较于图像的Transforme…

开源共建 | TIS整合数据同步工具ChunJun,携手完善开源生态

TIS整合ChunJun实操 B站视频&#xff1a; https://www.bilibili.com/video/BV1QM411z7w5/?spm_id_from333.999.0.0 一、ChunJun 概述 ChunJun是一款易用、稳定、高效的批流统一的数据集成框架&#xff0c;可基于实时计算引擎Flink实现多种异构数据源之间的数据同步与计算&…

flink学习

Flink学习之路&#xff08;一&#xff09;Flink简介 - 走看看 Flink(一)-基本概念 - 知乎 Flink架构&#xff1a; Flink整个系统包含三个部分&#xff1a; 1、Client&#xff1a; 给用户提供向Flink系统提交用户任务&#xff08;流式作业&#xff09;的能力。用户提交一个F…

全球无人驾驶大洗牌,百度Apollo Day宣告Robotaxi进入2.0时代

作者 | 德新 编辑 | 王博1. 全球无人驾驶大洗牌&#xff0c;Robotaxi越发向头部聚集 全球无人驾驶落地正呈现两幅面孔。随着资本热潮褪去&#xff0c;一部分公司在资金和研发上已经难以为继&#xff0c;Robotaxi落地的资源和希望&#xff0c;正无限向头部公司聚集。 10月&#…

OVS DPDK VXLAN隧道处理

在学习OVS VXLAN实现之前&#xff0c;我们先回顾一下传统VTEP设备是如何处理VXLAN报文的。如下图所示&#xff1a; vxlan报文进入交换机端口后&#xff0c;根据报文头部信息进行vxlan隧道终结。隧道终结后&#xff0c;根据underlay信息进行overlay映射&#xff0c;得到overlay的…

鲲鹏devkit性能分析工具介绍(四)

鲲鹏devkit性能分析工具介绍&#xff08;四&#xff09; 前面我们已经介绍了鲲鹏devkit性能分析工具的全景分析、热点函数分析、进程/线程分析、微架构分析、和访存分析&#xff0c;由此可见进行性能调优绝对不能够仅仅去进行一方面的考察而是需要全方面的数据分析进行一定的舍…

8、多进程之间的通信

多进程之间的常用通信方法有两种&#xff0c;及Queue和Pipe 一、Queue Queue([maxsize])&#xff1a;创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数&#xff0c;则无大小限制。底层队列使用管道和锁定实现。另外&#xff0c;还需要运行支持线程以便队列中…

[附源码]计算机毕业设计springboot基于Web的软考题库平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[论文阅读] Curriculum Semi-supervised Segmentation

[论文地址] [代码] [MICCAI 19] Abstract 本研究调查了半监督CNN分割的课程式策略&#xff0c;它设计了一个回归网络来学习图像级信息&#xff0c;如目标区域的大小。这些回归被用来有效地规范分割网络&#xff0c;约束未标记图像的softmax预测&#xff0c;使其与推断的标签分…

16-JavaSE基础巩固项目:拼图小游戏

阶段项目-拼图小游戏 一、项目介绍 1、目的 锻炼逻辑思维能力&#xff0c;让我们知道前面学习的知识点在实际开发中的应用场景。 1、为了学习一个新知识&#xff1a;GUI GUI全称&#xff1a;Graphical User Interface&#xff08;又称图形用户接口&#xff09;是指采用图形化…

【Android进阶之旅】内存泄漏的危害有哪些?(案例分析)

随着计算机应用需求的日益增加&#xff0c;应用程序的设计与开发也相应的日趋复杂&#xff1b; 开发人员在程序实现的过程中处理的变量也大量增加&#xff0c;如何有效进行内存分配和释放&#xff0c;防止内存泄漏的问题变得越来越突出 例如&#xff1a; 服务器应用软件&#x…

Redis 内存淘汰和过期删除策略

提起使用Redis的优点&#xff0c;大家可以列举出许多&#xff0c;比如&#xff1a;数据存储在内存&#xff0c;读写速度快&#xff0c;性能优异。比如数据持久化&#xff0c;便于数据备份及恢复等等。 分布式服务系统平台发展至今&#xff0c;Redis活跃在平台的各个领域&#…

RabbitMQ事务消息

通过对信道的设置实现 channel.txSelect()&#xff1b;通知服务器开启事务模式&#xff1b;服务端会返回Tx.Select-Ok channel.basicPublish&#xff1b;发送消息&#xff0c;可以是多条&#xff0c;可以是消费消息提交ackchannel.txCommit() &#xff1b;提交事务&#xff1b;…

mmdetection3d SUN RGB-D数据集预处理

SUN RGB-D是普林斯顿大学发布的一种关于室内场景理解的数据集&#xff0c;共包含了10335个样本&#xff0c;其中训练样本和验证测试样本数量分别为5285和5050。每个样本包含了彩色图像&#xff08;RGB&#xff09;和深度&#xff08;D&#xff09;信息&#xff0c;并且分别进行…

基于BDD的接口自动化框架开箱即用

1、背景说明 项目思想&#xff1a;BDD 行为驱动开发的思想褒贬不一&#xff0c;这里不多说。遵循的宗旨能解决业务痛点的思想就是好思想。 接口测试工具在实际的业务测试场景中往往会遇到一些使用上的局限性&#xff0c;自定义扩展要求技术较高&#xff0c;如果二次开发工具…

小程序瀑布流实现

什么是瀑布流布局 瀑布流布局&#xff0c;一般等宽&#xff0c;不等高的列表排列 原理是找出高度之和最小的那一列&#xff0c;在高度最小列继续添加元素 可以通过 absolute 定位实现&#xff0c;动态计算每一项的 top 和 left 封装瀑布流方法 function getAllRect(context…