EEPROM读写控制模块实现
写在前面:
FPGA实现IIC协议读写EEPROM相关文章:
IIC通信协议
【FPGA】FPGA实现IIC协议读写EEPROM(一) ----- IIC接口驱动实现
【FPGA】FPGA实现IIC协议读写EEPROM(二) -----EEPROM读写控制模块实现
【FPGA】FPGA实现IIC协议读写EEPROM(三) ----- 汇总篇
在上篇文章中已经对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_filter
input wr_req , // 读请求
input rd_req , // 写请求
// i2c_interface
input [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)begin
if(!rst_n)begin
state_c <= IDLE ;
end
else begin
state_c <= state_n ;
end
end
always @(*)begin
case (state_c)
IDLE: begin
if(idle2sendwrreq)
state_n = SEND_WRREQ ;
else if(idle2sendrdreq)
state_n = SEND_RDREQ ;
else
state_n = state_c ;
end
SEND_WRREQ: begin
if(sendwrreq2waitwrdone)
state_n = WAIT_WRDONE ;
else
state_n = state_c ;
end
SEND_RDREQ: begin
if(sendrdreq2waitrddone)
state_n = WAIT_RDDONE ;
else
state_n = state_c ;
end
WAIT_WRDONE: begin
if(waitwrdone2wrdone)
state_n = WR_DONE ;
else if(waitwrdone2sendwrreq)
state_n = SEND_WRREQ ;
else
state_n = state_c ;
end
WAIT_RDDONE: begin
if(waitrddone2rddone)
state_n = RD_DONE ;
else if(waitrddone2sendrdreq)
state_n = SEND_RDREQ ;
else
state_n = state_c ;
end
WR_DONE: begin
if(wrdone2idle)
state_n = IDLE ;
else
state_n = state_c ;
end
RD_DONE: begin
if(rddone2idle)
state_n = IDLE ;
else
state_n = state_c ;
end
default: state_n = IDLE ;
endcase
end
// 状态转移
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_num
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
byte_num <= 0 ;
end
else if(wr_req)begin
byte_num <= 3 ;
end
else if(rd_req)begin
byte_num <= 4 ;
end
else if(wrdone2idle | rddone2idle)begin
byte_num <= 0 ;
end
end
// cnt_byte
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_byte <= 0 ;
end
else if(add_cnt_byte)begin
if(end_cnt_byte)begin
cnt_byte <= 0 ;
end
else begin
cnt_byte <= cnt_byte + 1 ;
end
end
end
assign add_cnt_byte = rw_done ;
assign end_cnt_byte = add_cnt_byte && (cnt_byte == byte_num - 1) ;
// rw_req
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rw_req <= 1'b0 ;
end
else if(idle2sendwrreq | idle2sendrdreq | sendwrreq2waitwrdone | sendrdreq2waitrddone)begin
rw_req <= 1'b1 ;
end
else begin
rw_req <= 1'b0 ;
end
end
// wrdata command
always @(*)begin
if(state_c == SEND_WRREQ)begin
case (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 ;end
endcase
end
else if(state_c == SEND_RDREQ)begin
case (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
endcase
end
end
// 输出
assign req = rw_req ;
assign cmd = command ;
assign wr_dout = wrdata ;
endmodule
五、仿真测试
写数据:

读数据


4万+

被折叠的 条评论
为什么被折叠?



