第49讲:基于I2C协议的EEPROM驱动控制
理论部分
I2C通讯协议(Inter-Integrated Circuit)是由Philips公司开发的一种简单、双向二线制同步串行总线,只需要两根线即可在连接于总线上的器件之间传送信息。
I2C通讯协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行AD,图像处理领域的摄像头配置,工业控制领域的X射线管配置等等。除此之外,由于I2C协议占用引脚特别少,硬件实现简单,可扩展性强,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
设计与实现
实验目标:01-10的写入和读取
i2c_ctrl
`timescale 1ns/1ns module 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 , //输入系统时钟,50MHz input 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设备的串行时钟信号scl inout 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, //开始状态1 SEND_D_ADDR = 4'd02, //设备地址写入状态 + 控制写 ACK_1 = 4'd03, //应答状态1 SEND_B_ADDR_H = 4'd04, //字节地址高八位写入状态 ACK_2 = 4'd05, //应答状态2 SEND_B_ADDR_L = 4'd06, //字节地址低八位写入状态 ACK_3 = 4'd07, //应答状态3 WR_DATA = 4'd08, //写数据状态 ACK_4 = 4'd09, //应答状态4 START_2 = 4'd10, //开始状态2 SEND_RD_ADDR = 4'd11, //设备地址写入状态 + 控制读 ACK_5 = 4'd12, //应答状态5 RD_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; else cnt_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; else state <= state; START_1: if(cnt_i2c_clk == 3) state <= SEND_D_ADDR; else state <= state; SEND_D_ADDR: if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3)) state <= ACK_1; else state <= state; ACK_1: if((cnt_i2c_clk == 3) && (ack == 1'b0)) begin if(addr_num == 1'b1) state <= SEND_B_ADDR_H; else state <= SEND_B_ADDR_L; end else state <= state; SEND_B_ADDR_H: if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3)) state <= ACK_2; else state <= state; ACK_2: if((cnt_i2c_clk == 3) && (ack == 1'b0)) state <= SEND_B_ADDR_L; else state <= state; SEND_B_ADDR_L: if((cnt_bit == 3'd7) && (cnt_i2c_clk == 3)) state <= ACK_3; else state <= state; ACK_3: if((cnt_i2c_clk == 3) && (ack == 1'b0)) begin if(wr_en == 1'b1) state <= WR_DATA; else if(rd_en == 1'b1) state <= START_2; else state <= state; end else state <= state; WR_DATA: if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3)) state <= ACK_4; else state <= state; ACK_4: if((cnt_i2c_clk == 3) && (ack == 1'b0)) state <= STOP; else state <= state; START_2: if(cnt_i2c_clk == 3) state <= SEND_RD_ADDR; else state <= state; SEND_RD_ADDR: if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3)) state <= ACK_5; else state <= state; ACK_5: if((cnt_i2c_clk == 3) && (ack == 1'b0)) state <= RD_DATA; else state <= state; RD_DATA: if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3)) state <= N_ACK; else state <= state; N_ACK: if(cnt_i2c_clk == 3) state <= STOP; else state <= state; STOP: if((cnt_bit == 3'd3) &&(cnt_i2c_clk == 3)) state <= IDLE; else state <= 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; else ack <= 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; else i2c_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; else i2c_scl <= 1'b0; STOP: if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0)) i2c_scl <= 1'b0; else i2c_scl <= 1'b1; default: i2c_scl <= 1'b1; endcase // i2c_sda_reg:sda数据缓存 always@(*) case (state) IDLE: begin i2c_sda_reg <= 1'b1; rd_data_reg <= 8'd0; end START_1: if(cnt_i2c_clk <= 2'd0) i2c_sda_reg <= 1'b1; else i2c_sda_reg <= 1'b0; SEND_D_ADDR: if(cnt_bit <= 3'd6) i2c_sda_reg <= DEVICE_ADDR[6 - cnt_bit]; else i2c_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; else i2c_sda_reg <= 1'b0; SEND_RD_ADDR: if(cnt_bit <= 3'd6) i2c_sda_reg <= DEVICE_ADDR[6 - cnt_bit]; else i2c_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; else rd_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; else i2c_sda_reg <= 1'b1; default: begin i2c_sda_reg <= 1'b1; rd_data_reg <= rd_data_reg; end endcase // 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; else i2c_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/1ns module i2c_rw_data ( input wire sys_clk , //输入系统时钟,频率50MHz input wire i2c_clk , //输入i2c驱动时钟,频率1MHz input 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; else i2c_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; else fifo_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/1ns module eeprom_byte_rd_wr ( input wire sys_clk , //输入工作时钟,频率50MHz input 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/1ns module 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; //时钟、复位信号 initial begin clk = 1'b1 ; rst_n <= 1'b0 ; key_wr <= 1'b1 ; key_rd <= 1'b1 ; #200 rst_n <= 1'b1 ; #1000 key_wr <= 1'b0 ; key_rd <= 1'b1 ; #400 key_wr <= 1'b1 ; key_rd <= 1'b1 ; #20000000 key_wr <= 1'b1 ; key_rd <= 1'b0 ; #400 key_wr <= 1'b1 ; key_rd <= 1'b1 ; #40000000 $stop; end always #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