文章目录
- 第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