EEPROM读写控制模块实现
- 一、模块功能分析
- 二、输入/输出信号
- 三、EEPROM读写控制模块状态机
- 四、EEPROM读写控制模块实现
- 五、仿真测试
写在前面:
FPGA实现IIC协议读写EEPROM相关文章:
IIC通信协议
【FPGA】FPGA实现IIC协议读写EEPROM(一) ----- IIC接口驱动实现
在上篇文章中已经对IIC协议和IIC接口驱动实现进行了详细介绍,本文介绍EEPROM读写控制模块的实现。
一、模块功能分析
EEPROM读写控制模块需要根据接收到的按键读写请求信号以及I2C接口模块返回的信号发送读写请求、控制指令、数据字节给I2C接口模块,以及接收I2C接口模块返回的数据。
二、输入/输出信号
EEPROM读写控制模块输入/输出信号如下:
信号说明:
信号 | I/O类型 | 说明 |
---|---|---|
rdin[7:0] | input | I2C接口模块读回的数据 |
rdin_vld | input | I2C接口模块读回的数据有效标志 |
rw_done | input | I2C接口读写一字节数据完成标志 |
rd_req | input | 读请求 |
wr_req | input | 写请求 |
req | output | 输出给I2C接口模块的读写请求 |
cmd[3:0] | output | 控制命令 |
wr_dout[7:0] | output | 要发送的数据/控制字节 |
三、EEPROM读写控制模块状态机
EEPROM读写控制模块状态转移图如下:
状态说明:
IDLE:空闲状态,等待读写请求。
SEND_WRREQ:发送写请求、控制指令、写控制字、地址、数据字节给I2C接口模块。
SEND_RDREQ :发送读请求、控制指令、写控制字、地址、读控制字给I2C接口模块。
WAIT_WRDONE:等待I2C接口模块写数据完成。
WAIT_RDDONE:等待I2C接口模块读数据完成。
WR_DONE:I2C接口模块写数据完成。
RD_DONE:I2C接口模块读数据完成。
四、EEPROM读写控制模块实现
EEPROM读写控制模块verilog代码如下:
// **************************************************************
// Author: Zhang JunYi
// Create Date: 2022.11.13
// Design Name: i2c_eeprom
// Module Name: eeprom_ctrl
// Target Device: Cyclone IV E (EP4CE6F17C8)
// Tool versions: Quartus Prime 18.1
// Description: 使用I2C协议读写EEPROM驱动控制模块
// **************************************************************
module eeprom_ctrl (input clk ,input rst_n ,// key_filterinput wr_req , // 读请求input rd_req , // 写请求// i2c_interfaceinput [7:0] rdin , // 从I2C接口读回的数据input rdin_vld ,input rw_done , // 读写一字节数据完成标志output req , // 读写请求output [7:0] wr_dout , // 要发送的数据output [3:0] cmd
);// 参数定义// 状态机参数定义localparam IDLE = 7'b000_0001 ,SEND_WRREQ = 7'b000_0010 , // 发送写请求SEND_RDREQ = 7'b000_0100 , // 发送读请求WAIT_WRDONE = 7'b000_1000 , // 等待写数据完成WAIT_RDDONE = 7'b001_0000 , // 等待读数据完成WR_DONE = 7'b010_0000 , // 写数据完成RD_DONE = 7'b100_0000 ; // 读数据完成// 信号定义reg [6:0] state_c ;reg [6:0] state_n ;reg [3:0] byte_num ; // 字节数reg [3:0] cnt_byte ; // 字节计数器wire add_cnt_byte ;wire end_cnt_byte ;reg [7:0] wrdata ; // 寄存将要发送的数据reg [3:0] command ; // 寄存将要发送的命令reg rw_req ;// 状态转移条件wire idle2sendwrreq ;wire idle2sendrdreq ;wire sendwrreq2waitwrdone ;wire sendrdreq2waitrddone ;wire waitwrdone2wrdone ;wire waitwrdone2sendwrreq ;wire waitrddone2rddone ;wire waitrddone2sendrdreq ;wire wrdone2idle ;wire rddone2idle ;// 状态机always @(posedge clk or negedge rst_n)beginif(!rst_n)beginstate_c <= IDLE ;endelse beginstate_c <= state_n ;endendalways @(*)begincase (state_c)IDLE: beginif(idle2sendwrreq)state_n = SEND_WRREQ ;else if(idle2sendrdreq)state_n = SEND_RDREQ ;elsestate_n = state_c ;endSEND_WRREQ: beginif(sendwrreq2waitwrdone)state_n = WAIT_WRDONE ;elsestate_n = state_c ;endSEND_RDREQ: beginif(sendrdreq2waitrddone)state_n = WAIT_RDDONE ;elsestate_n = state_c ;endWAIT_WRDONE: beginif(waitwrdone2wrdone)state_n = WR_DONE ;else if(waitwrdone2sendwrreq)state_n = SEND_WRREQ ;elsestate_n = state_c ;endWAIT_RDDONE: beginif(waitrddone2rddone)state_n = RD_DONE ;else if(waitrddone2sendrdreq)state_n = SEND_RDREQ ;elsestate_n = state_c ;endWR_DONE: beginif(wrdone2idle)state_n = IDLE ;elsestate_n = state_c ;endRD_DONE: beginif(rddone2idle)state_n = IDLE ;elsestate_n = state_c ;enddefault: state_n = IDLE ;endcaseend// 状态转移assign idle2sendwrreq = state_c == IDLE && wr_req ;assign idle2sendrdreq = state_c == IDLE && rd_req ; assign sendwrreq2waitwrdone= state_c == SEND_WRREQ && (1'b1) ;assign sendrdreq2waitrddone= state_c == SEND_RDREQ && (1'b1) ;assign waitwrdone2wrdone = state_c == WAIT_WRDONE && end_cnt_byte ;assign waitwrdone2sendwrreq= state_c == WAIT_WRDONE && (cnt_byte < 2) && rw_done ;assign waitrddone2rddone = state_c == WAIT_RDDONE && end_cnt_byte ;assign waitrddone2sendrdreq= state_c == WAIT_RDDONE && (cnt_byte < 3) && rw_done ;assign wrdone2idle = state_c == WR_DONE && (1'b1) ;assign rddone2idle = state_c == RD_DONE && (1'b1) ;// byte_numalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginbyte_num <= 0 ;endelse if(wr_req)beginbyte_num <= 3 ;endelse if(rd_req)beginbyte_num <= 4 ;endelse if(wrdone2idle | rddone2idle)beginbyte_num <= 0 ;endend// cnt_bytealways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_byte <= 0 ;endelse if(add_cnt_byte)beginif(end_cnt_byte)begincnt_byte <= 0 ;end else begin cnt_byte <= cnt_byte + 1 ;end endend assign add_cnt_byte = rw_done ;assign end_cnt_byte = add_cnt_byte && (cnt_byte == byte_num - 1) ;// rw_reqalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginrw_req <= 1'b0 ;endelse if(idle2sendwrreq | idle2sendrdreq | sendwrreq2waitwrdone | sendrdreq2waitrddone)beginrw_req <= 1'b1 ;endelse beginrw_req <= 1'b0 ;endend// wrdata commandalways @(*)beginif(state_c == SEND_WRREQ)begincase (cnt_byte)0: begin wrdata = 8'b1010_0000 ;command = 4'b1010 ; end // 写控制字1: begin wrdata = 8'b1101_1001 ;command = 4'b1000 ; end // 写地址2: begin wrdata = 8'b1111_1001 ;command = 4'b1001 ; end // 写数据default: begin wrdata = 8'b0 ;command = 4'b0 ;endendcaseendelse if(state_c == SEND_RDREQ)begincase (cnt_byte)0: begin wrdata = 8'b1010_0000 ;command = 4'b1010 ; end // 写控制字1: begin wrdata = 8'b1101_1001 ;command = 4'b1000 ; end // 读地址2: begin wrdata = 8'b1010_0001 ;command = 4'b1010 ; end // 写读控制字3: begin wrdata = 8'b0 ;command = 4'b0101 ; end // 读数据default: begin wrdata = 8'b0 ;command = 4'b0 ;end endcaseendend// 输出assign req = rw_req ;assign cmd = command ;assign wr_dout = wrdata ;endmodule
五、仿真测试
写数据:
读数据