FPGA基于i2c的eeprom的读写uart串口通信验证
通过I2C实现对EEPROM读写操作
概述
IIC简介
IIC (I2C,Inter-Integrated Circuit)即集成电路总线,是一种两线式串行总线,由 PHILIPS公司开发,用于连接微控制器及其外围设备。多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。I2C 总线由数据线 SDA 和时钟线 SCL 构成通信线路,既可用于发送数据,也可接收数据,是一种半双工通信协议。总线上的主设备与从设备之间以字节(8 位)为单位进行双向的数据传输
标准模式:100Kbit/s
快速模式:400kbit/s
高速模式:3.4Mbit/s
iic器件和sdl、scl关系
空闲状态:
I2C 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
起始信号:
在 SCL 保持高电平期间,SDA 的电平被拉低,称为 I2C 总线总线的起始信号,标志着一次数据传输开始。起始信号由主机主动建立的,在建立该信号之前 I2C 总线必须处于空闲状态。
停止信号:
在 SCL 保持高电平期间,SDA 被释放,返回高电平,称为 I2C 总线的停止信号,标志着一次数据传输的终止。停止信号由主机主动建立的,建立该信号之后,I2C 总线将返回空闲状态。
在这张图表明I2C时钟频率MAX100 400 KHZ,高低电平保持时间,高低点电平转换时间
起始信号至少保持600-4000ns,停止信号至少保持600-4000ns
数据传输:
在 I2C 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,在 SDA 上逐位地串行传送每一位数据。进行数据传送时,在 SCL 的高电平期间, SDA 上的电平必须保持稳定,只有在 SCL 为低电平期间,才允许 SDA 上的电平改变状态。即数据在 SCL 的上升沿到来之前就必须准备好,并在在下降沿到来之前必须保持稳定。
在前面的表格图中表明I2C起始信号至少保持600-4000ns,停止信号至少保持600-4000ns,数据总线在I2C时钟低电平可以改变值,高电平数据总线保持
应答信号:
I2C 总线上的所有数据都是以字节传送的,发送端每发送一个字节,就必须在第 9 个SCL 脉冲期间释放 SDA,由接收端反馈一个应答信号。应答信号为低电平时,称为有效应答位(ACK),表示接收端成功接收了该字节;应答信号为高电平时,称为非应答位(NACK),表示接收端接收该字节失败。对于反馈有效应答位 ACK 的要求是,接收端在第 9 个时钟脉冲之前的低电平期间将 SDA 拉低,并且确保在该时钟周期的高电平期间保持低电平。如果接收端是主控端,则在它收到最后一个字节后,发送一个 NACK 信号,以通知被控发送端结束数据发送,并释放 SDA 线,以便主控接收器发送停止信号。
I2C应答位和数据读写想同,都是时钟高电平有效 ACK=0,NACK=1;
在EEPROM写操作时写完最后一字节数据时观察时序,发现应答位为应答有效,可能手册写了我没看到,这里我没有管它,直接从机应答结束后给的停止信号.
EEPROM 简介
写操作时序
写操作,发起始位->写写控制字->接收 ACK->写字节地址->接收 ACK->写数据接收ACK-> 发停止位。
写控制字:{7’b101000,1’b0}
读操作时序
发起始位->写读控制字->接收 ACK->写读地址->接收读数据->发NACK->发停止位。
读控制字:{7’b101000,1’b1}。
随机读
顺序读
一、状态图
1、I2C主机状态图
2、I2C读写控制状态图
二、程序讲解
1、工程讲解
uart串口写入数据到FIFO1储存,当key_in0按下从FIFO读取数据通过I2C写入EEPROM,当key_in1按下从EEPROM读取数据暂存在FIFO2再通过uart读取出来
2、全部代码
param
//参数定义
//i2c时钟参数
`define SCL_PERIOD 250
`define SCL_HALF 125
`define LOW_HLAF 65
`define HIGH_HALF 190
//i2c命令参数
`define CMD_START 4'b0001
`define CMD_WRITE 4'b0010
`define CMD_READ 4'b0100
`define CMD_STOP 4'b1000
//i2c write mode
//`define BYTE_WRITE //字写
`define PAGE_WRITE //页写
`ifdef BYTE_WRITE
`define WR_BYTE 3 //从机地址 1字节 + 数据写入地址 1字节 + 数据 1字节
`elsif PAGE_WRITE
`define WR_BYTE 18 //页写最大写入数据 16字节 从机地址 1字节 + 数据写入地址 1字节 + 数据 16字节
`endif
//i2c read mode
//`define RANDOM_READ //随机读
`define SEQUENTIAL_READ //顺序读
`ifdef RANDOM_READ
`define RE_BYTE 4 //从机地址 1字节 写命令 + 数据写入地址1字节 +从机地址1字节 读命令 + 数据 (顺序读多少字节看自己设置多少)
`elsif SEQUENTIAL_READ
`define RE_BYTE 19
`endif
//从机ID定义
`define WR_ID 6'b1010_00
`define RD_ID 6'b1010_00
//波特率
`define BAUD_9600 5208
`define BAUD_19200 2604
`define BAUD_38400 1302
`define BAUD_115200 434
`define STOP_BIT 1'b1 //数据停止位
`define START_BIT 1'b0 //数据开始位
test
module test(
input clk ,
input rst_n ,
input [2:0] key_in ,
input uart_rxd,
output uart_txd,
inout sda ,
output scl
);
//中间信号定义
wire [7:0] rx_byte ;
wire rx_byte_vld ;
wire [2:0] key_out ;
wire [7:0] dout_m ;
wire [7:0] dout_tx ;
wire dout_tx_vld ;
wire req ;
wire [3:0] cmd ;
wire dq_in ;
wire done ;
wire dq_out ;
wire dq_en ;
wire slave_ack ;
wire [7:0] dout ;
wire dout_vld ;
wire busy ;
//模块例化
uart_rx u_uart_rx
(
/*input */.clk (clk),
/*input */.rst_n (rst_n),
/*input */.rx_din (uart_rxd),
/*input [1:0] */.baud_sel (2'b0),
/*output [7:0] */.rx_byte (rx_byte),
/*output */.rx_byte_vld (rx_byte_vld)
);
key_filter_fsm # (.KEY_W(3),.TIME_20MS(1_000_000))u_key_filter_fsm
(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [KEY_W - 1:0] */.key_in (key_in ),
/*output [KEY_W - 1:0] */.key_out (key_out )
);
control u_control
(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [2:0] */.key_in (key_out ),
/*input */.slave_ack (slave_ack ),
/*input [7:0] */.rx_din (rx_byte ),
/*input */.rx_din_vld (rx_byte_vld ),
/*input [7:0] */.m_din (dout ),
/*input */.m_din_vld (dout_vld ),
/*input */.busy (busy ),
/*inout */.done (done ),
/*output [7:0] */.dout_m (dout_m ),
/*output [7:0] */.dout_tx (dout_tx ),
/*output */.dout_tx_vld (dout_tx_vld ),
/*output */.req (req ),
/*output [3:0] */.cmd (cmd )
);
i2c_master u_i2c_master
(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.req (req ),
/*input [3:0] */.cmd (cmd ),
/*input [7:0] */.din (dout_m ),
/*input */.dq_in (dq_in ),
/*output */.done (done ),
/*output reg */.dq_out (dq_out ),
/*output reg */.dq_en (dq_en ),
/*output */.scl (scl ),
/*output reg */.slave_ack (slave_ack ),
/*output [7:0] */.dout (dout ),
/*output */.dout_vld (dout_vld )
);
uart_tx u_uart_tx
(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [1:0] */.baud_sel (2'b0 ),
/*input [7:0] */.tx_byte (dout_tx ),
/*input */.tx_byte_vld (dout_tx_vld ),
/*output */.tx_dout (uart_txd ),
/*output */.busy (busy )
);
//三态门
assign sda = dq_en?dq_out:1'bz;
assign dq_in = sda;
endmodule
control
`include "param.v"
module control
(
input clk ,
input rst_n ,
input [2:0] key_in ,
input slave_ack ,
input [7:0] rx_din ,
input rx_din_vld ,
input [7:0] m_din ,
input m_din_vld ,
input busy ,
inout done ,
output [7:0] dout_m ,
output [7:0] dout_tx ,
output dout_tx_vld ,
output req ,
output [3:0] cmd
);
//参数定义
localparam IDLE = 6'b000_001,
WR_REQ = 6'b000_010,
WAIT_WR = 6'b000_100,
RE_REQ = 6'b001_000,
WAIT_RE = 6'b010_000,
DONE = 6'b100_000;
//信号定义
//状态机信号定义
reg [5:0] state_c ;
reg [5:0] state_n ;
reg [4:0] cnt_byte ;
wire add_cnt_byte ;
wire end_cnt_byte ;
//读写地址
reg [7:0] wr_add ;
reg [7:0] re_add ;
//task TX 请求、命令、输出数据
reg tx_req ;
reg [3:0] tx_cmd ;
reg [7:0] tx_data ;
reg flag ;
//rx_fifo
wire [7:0] rx_fdin ;
wire rx_frden ;
wire rx_fwren ;
wire rx_fempty ;
wire rx_ffull ;
wire [7:0] rx_fdout ;
wire [7:0] rx_fusedw ;
//fifo_tx
wire [7:0] f_txdin ;
wire f_txrden ;
wire f_txwren ;
wire f_txempty ;
wire f_txfull ;
wire [7:0] f_txdout ;
wire [7:0] f_txusedw ;
//状态机转换条件定义
wire idle2wr_req ;
wire idle2re_req ;
wire wr_req2wait_wr ;
wire re_req2wait_re ;
wire wait_wr2wr_req ;
wire wait_re2re_req ;
wire wait_wr2done ;
wire wait_re2done ;
wire done2idle ;
//状态机
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
casez (state_c)
IDLE :begin if (idle2wr_req) begin
state_n = WR_REQ;
end
else if (idle2re_req) begin
state_n = RE_REQ;
end
else begin
state_n = IDLE;
end
end
WR_REQ :begin if (wr_req2wait_wr) begin
state_n = WAIT_WR;
end
else begin
state_n = WR_REQ;
end
end
WAIT_WR :begin if (wait_wr2wr_req) begin
state_n = WR_REQ;
end
else if (wait_wr2done) begin
state_n = DONE;
end
else begin
state_n = WAIT_WR;
end
end
RE_REQ :begin if (re_req2wait_re) begin
state_n = WAIT_RE;
end
else begin
state_n = RE_REQ;
end
end
WAIT_RE :begin if (wait_re2re_req) begin
state_n = RE_REQ;
end
else
if (wait_re2done) begin
state_n = DONE;
end
else begin
state_n = WAIT_RE;
end
end
DONE :begin if (done2idle) begin
state_n = IDLE;
end
else begin
state_n = DONE;
end
end
default: state_n = state_c;
endcase
end
//状态机转换条件
assign idle2wr_req = state_c == IDLE && key_in[0] && rx_fusedw >= `WR_BYTE -2;
assign idle2re_req = state_c == IDLE && key_in[1];
assign wr_req2wait_wr = state_c == WR_REQ && 1'b1;
assign re_req2wait_re = state_c == RE_REQ && 1'b1;
assign wait_wr2wr_req = state_c == WAIT_WR && (done && cnt_byte < (`WR_BYTE-1));
assign wait_re2re_req = state_c == WAIT_RE && (done && cnt_byte < (`RE_BYTE-1));
assign wait_wr2done = state_c == WAIT_WR && (end_cnt_byte | done & slave_ack);
assign wait_re2done = state_c == WAIT_RE && (end_cnt_byte | done & slave_ack);
assign done2idle = state_c == DONE && 1'b1;
//计数器
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
else begin
cnt_byte <= cnt_byte;
end
end
assign add_cnt_byte = ((state_c == WAIT_RE) || (state_c == WAIT_WR)) && done;
assign end_cnt_byte = add_cnt_byte && cnt_byte == ((state_c == WAIT_RE)?(`RE_BYTE-1):(`WR_BYTE-1));
//assign end_cnt_byte = add_cnt_byte && cnt_byte == 18-1;
//输出
always @(*)begin
if(!rst_n)begin
TX(1'b0,4'b0,8'b0);
end
else if(state_c == WAIT_WR)begin
case (cnt_byte)
0 : TX(1'b1,{`CMD_START|`CMD_WRITE},{`WR_ID,wr_add[7],1'b0});
1 : TX(1'b1,`CMD_WRITE,wr_add);
`WR_BYTE-1 : TX(1'b1,{`CMD_WRITE|`CMD_STOP},rx_fdout);
default: TX(1'b1,`CMD_WRITE,rx_fdout);
endcase
end
else if (state_c == WAIT_RE) begin
case (cnt_byte)
0 : TX(1'b1,{`CMD_START|`CMD_WRITE},{`RD_ID,wr_add[7],1'b0});
1 : TX(1'b1,`CMD_WRITE,re_add);
2 : TX(1'b1,{`CMD_START|`CMD_WRITE},{`RD_ID,wr_add[7],1'b1});
`RE_BYTE-1 : TX(1'b1,{`CMD_READ|`CMD_STOP},0);
default: TX(1'b1,`CMD_READ,0);
endcase
end
else begin
TX(1'b0,tx_cmd,tx_data);
end
end
//task发送请求、命令、数据
task TX;
input req_r ;
input [3:0] command_r;
input [7:0] data_r ;
begin
tx_req = req_r;
tx_cmd = command_r;
tx_data = data_r;
end
endtask
//req cmd dout_m
assign req = tx_req;
assign cmd = tx_cmd;
assign dout_m = tx_data;
//wr_add & re_add
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
wr_add <= 8'b0;
end
else if(wait_wr2done && (state_c == WAIT_WR))begin
wr_add <= wr_add+`WR_BYTE-2;
end
else begin
wr_add <= wr_add;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
re_add <= 8'b0;
end
else if(wait_re2done && (state_c == WAIT_RE))begin
re_add <= re_add+`RE_BYTE-3;
end
else begin
re_add <= re_add;
end
end
//flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 0;
end
else if(f_txusedw >= (`RE_BYTE-3))begin
flag <= 1;
end
else if(f_txempty)begin
flag <= 0;
end
end
//rx_fifo
rx_fifo u_rx_fifo
(
.aclr ( ~rst_n ),
.clock ( clk ),
.data ( rx_fdin ),
.rdreq ( rx_frden ),
.wrreq ( rx_fwren ),
.empty ( rx_fempty ),
.full ( rx_ffull ),
.q ( rx_fdout ),
.usedw ( rx_fusedw )
);
assign rx_fdin = rx_din;
assign rx_frden = state_c == WAIT_WR && (cnt_byte>1) && done && (!rx_fempty);
assign rx_fwren = rx_din_vld && (!rx_ffull);
//fifo_tx
fifo_tx u_fifo_tx
(
.aclr ( ~rst_n ),
.clock ( clk ),
.data ( f_txdin ),
.rdreq ( f_txrden ),
.wrreq ( f_txwren ),
.empty ( f_txempty ),
.full ( f_txfull ),
.q ( f_txdout ),
.usedw ( f_txusedw )
);
assign f_txwren = !f_txfull && m_din_vld;
assign f_txrden = !f_txempty && (busy==0) && flag;
assign f_txdin = m_din;
//输出
assign dout_tx = f_txdout;
assign dout_tx_vld = f_txrden; //fifo_tx数据有效
endmodule
i2c_master
/**************************************功能介绍***********************************
Copyright:i2c_master
Date :2022/2/17
Author :li_lys
Version :
Description:
*********************************************************************************/
`include "param.v"
module i2c_master
(
input clk ,
input rst_n ,
input req ,
input [3:0] cmd ,
input [7:0] din ,
input dq_in ,
output done ,
output reg dq_out ,
output reg dq_en ,
output scl ,
output reg slave_ack ,
output [7:0] dout ,
output dout_vld
);
//参数定义
//状态机
localparam IDLE = 7'b000_0001,
START = 7'b000_0010,
WRITE = 7'b000_0100,
RACK = 7'b000_1000,
READ = 7'b001_0000,
SACK = 7'b010_0000,
STOP = 7'b100_0000;
//信号定义
reg [6:0] state_c ;
reg [6:0] state_n ;
reg clk_scl ;
reg [7:0] cnt_scl ;
wire add_cnt_scl ;
wire end_cnt_scl ;
reg [3:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] bit_num ;
reg master_ack ;
reg cnt_scl_flag ;
reg [7:0] dout_data ;
reg dout_data_vld ;
//状态机转换条件
wire idle2start ;
wire idle2write ;
wire idle2read ;
wire start2write ;
wire start2read ;
wire write2rack ;
wire read2sack ;
wire rack2stop ;
wire sack2stop ;
wire rack2idle ;
wire sack2idle ;
wire stop2idle ;
//状态机
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 @(posedge clk or negedge rst_n)begin
case (state_c)
IDLE : begin if (idle2start) begin
state_n = START;
end
else if (idle2write) begin
state_n = WRITE;
end
else if (idle2read) begin
state_n = READ;
end
else begin
state_n = state_c;
end
end
START : begin if (start2write) begin
state_n = WRITE;
end
else if (start2read) begin
state_n = READ;
end
else begin
state_n = state_c;
end
end
WRITE : begin if (write2rack) begin
state_n = RACK;
end
else begin
state_n = state_c;
end
end
RACK : begin if (rack2idle) begin
state_n = IDLE;
end
else if (rack2stop) begin
state_n = STOP;
end
else begin
state_n = state_c;
end
end
READ : begin if (read2sack) begin
state_n = SACK;
end
else begin
state_n = state_c;
end
end
SACK : begin if (sack2idle) begin
state_n = IDLE;
end
else if (sack2stop) begin
state_n = STOP;
end
else begin
state_n = state_c;
end
end
STOP : begin if (stop2idle) begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default: state_n = state_c;
endcase
end
assign idle2start = state_c == IDLE && req && (`CMD_START & cmd);
assign idle2write = state_c == IDLE && req && (`CMD_WRITE & cmd);
assign idle2read = state_c == IDLE && req && (`CMD_READ & cmd);
assign start2write = state_c == START && end_cnt_bit && (`CMD_WRITE & cmd);
assign start2read = state_c == START && end_cnt_bit && (`CMD_READ & cmd);
assign write2rack = state_c == WRITE && (end_cnt_bit);
assign read2sack = state_c == READ && (end_cnt_bit);
assign rack2stop = state_c == RACK && (end_cnt_bit && (`CMD_STOP & cmd));
assign sack2stop = state_c == SACK && (end_cnt_bit && (`CMD_STOP & cmd));
assign rack2idle = state_c == RACK && (end_cnt_bit && ((`CMD_STOP & cmd) ==0));
assign sack2idle = state_c == SACK && (end_cnt_bit && ((`CMD_STOP & cmd) ==0));
assign stop2idle = state_c == STOP && (end_cnt_bit);
//计数器
//cnt_scl计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_scl <= 0;
end
else if(add_cnt_scl)begin
if(end_cnt_scl)begin
cnt_scl <= 0;
end
else begin
cnt_scl <= cnt_scl + 1;
end
end
else begin
cnt_scl <= cnt_scl;
end
end
assign add_cnt_scl = cnt_scl_flag;
assign end_cnt_scl = add_cnt_scl && cnt_scl == `SCL_PERIOD-1;
//cnt_bit计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 0;
end
else begin
cnt_bit <= cnt_bit + 1;
end
end
else begin
cnt_bit <= cnt_bit;
end
end
assign add_cnt_bit = end_cnt_scl;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_num - 1;
//cnt_scl_flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_scl_flag <= 0;
end
else if(idle2start)begin
cnt_scl_flag <= 1;
end
else if(stop2idle)begin
cnt_scl_flag <= 0;
end
else begin
cnt_scl_flag <= cnt_scl_flag;
end
end
//clk_scl
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
clk_scl <= 1;
end
else if (idle2start | idle2write | idle2read ) begin
clk_scl <= 0;
end
else if(add_cnt_scl && cnt_scl == `HIGH_HALF-1)begin
clk_scl <= 1;
end
else if(end_cnt_scl && (!stop2idle))begin
clk_scl <= 0;
end
else begin
clk_scl <= clk_scl;
end
end
//bit_num
always @(*)begin
if(!rst_n) begin
bit_num = 0;
end
else if(state_c == WRITE || state_c == READ)begin
bit_num = 8;
end
else begin
bit_num = 1;
end
end
//dout_data
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dout_data <= 0;
end
else if((state_c == READ) && (cnt_scl == `HIGH_HALF))begin
dout_data[7-cnt_bit] <=dq_in;
end
end
//dout_data_vld
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dout_data_vld <= 0;
end
else if((state_c == READ) && (cnt_bit == 7) && (cnt_scl == `HIGH_HALF))begin
dout_data_vld <=1;
end
else begin
dout_data_vld <= 0;
end
end
//输出
//dq_out
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_out <= 1;
end
else if(state_c == START)begin //检测其实信号,将数据总线sdl拉高确保从机能检测到起始信号
if(cnt_scl == `LOW_HLAF) begin
dq_out <= 1;
end
else if(cnt_scl == `HIGH_HALF) begin //将数据总线拉低产生起始信号
dq_out <= 0;
end
end
else if((state_c == SACK) && (cnt_scl == `SCL_HALF))begin //scl 低电平改变传输数据 cnt_scl== `SCL_HALF || cnt_scl== `LOW_HLAF
dq_out <= master_ack; //主机应答信号
end
else if((state_c == WRITE) && (cnt_scl == `SCL_HALF))begin
dq_out <= din[7 - cnt_bit];
end
else if (state_c == STOP )begin //停止信号
if(cnt_scl == `LOW_HLAF)begin //低电平将数据总线sdl拉低确保从机能检测到停止信号
dq_out <= 0;
end
else if (cnt_scl == `HIGH_HALF) begin //将数据总线拉高产生停止信号
dq_out <= 1;
end
end
end
//master_ack 主机应答信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
master_ack <= 0;
end
else if(cmd &`CMD_STOP)begin
master_ack <= 1;
end
else if(cmd&`CMD_START)begin
master_ack <= 0;
end
end
//dq_en
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_en <= 0;
end
else if(idle2start || idle2write || read2sack || rack2stop || sack2stop)begin
dq_en <= 1;
end
else if(idle2read || start2read || write2rack || stop2idle)begin
dq_en <= 0;
end
end
//slave_ack 从机应答信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
slave_ack <= 1;
end
else if(state_c == RACK && cnt_scl == `HIGH_HALF)begin //高电平接收应答
slave_ack <=dq_in;
end
else begin
slave_ack <= slave_ack;
end
end
assign done = (stop2idle | rack2idle | sack2idle);
// scl dout dout_vld
assign scl=clk_scl;
assign dout=dout_data;
assign dout_vld=dout_data_vld;
endmodule
key_filter_fsm
https://blog.csdn.net/li_lys/article/details/121849916
uart
https://blog.csdn.net/li_lys/article/details/122887251?spm=1001.2014.3001.5502
三、验证
signal Tap 抓取结果
这里可以直观看出读写数据的正确性
工程链接:
https://blog.csdn.net/li_lys/article/details/124870664?utm_source=app&app_version=5.4.0&code=app_1562916241&uLinkId=usr1mkqgl919blen