    
- module iic(
- input clk ,
- input rst ,
- input [ 4:0] cmd ,
- input cmd_vld ,
- input [ 7:0] wr_data ,
- output [ 7:0] rd_data ,
- output rd_data_vld ,
- output reg rev_ack ,
- output done ,
- output reg scl ,
- inout sda
- );
- /*
- 模拟过程
- 1. cnt_num
- 2. 二阶状态机
- 3. scl的生成
- cmd和cmd_vld是一起过来的!!!
- */
- `define START_BIT 5'b00001
- `define WRITE_BIT 5'b00010
- `define READ_BIT 5'b00100
- `define STOP_BIT 5'b01000
- `define ACK_BIT 5'b10000
- `define ACK 0
- `define NO_ACK 1
- localparam STATUS_IDLE = 7'b000_0001;
- localparam STATUS_START = 7'b000_0010;
- localparam STATUS_WR_DATA = 7'b000_0100;
- localparam STATUS_RD_DATA = 7'b000_1000;
- localparam STATUS_T_ACK = 7'b001_0000;
- localparam STATUS_R_ACK = 7'b010_0000;
- localparam STATUS_STOP = 7'b100_0000;
- localparam T = 100_000;
- localparam SCL_MAX = 50_000_000/T; // 一个完整的SCL周期
- /*
- localparam和define放在最前面
- */
- reg [3:0]cnt_num ;
- reg [6:0]cstate;
- reg [6:0]nstate;
- reg [7:0]wr_data_r;
- reg sda_out;
- parameter SCL_LOW_HALF = (SCL_MAX * 1 / 4) - 1,
- SCL_HIGH_HALF = (SCL_MAX * 3 / 4) - 1;
- reg [25:0]cnt_bit;
- // 下面是关键的 状态转换的检测信号
- reg OE;
- reg[8*20-1:0]state_name;
- reg [7:0]rd_data_r;
- reg [4:0]num;
- wire end_cnt_num;
- /*下面是输入输出信号*/
- assign rd_data = rd_data_r; //读也从寄存器开始输出
- assign sda = OE?sda_out:1'bz;
- wire sda_in = sda;
- reg [4:0]cmd_r;
- wire IF_IDLE_START = (cstate == STATUS_IDLE ) && cmd_vld && (cmd & `START_BIT) ;
- wire IF_START_WR_DATA = (cstate == STATUS_START ) && end_cnt_num && (cmd_r & `WRITE_BIT) ;
- wire IF_WR_DATA_R_ACK = (cstate == STATUS_WR_DATA ) && end_cnt_num ;
- wire IF_R_ACK_IDLE = (cstate == STATUS_R_ACK ) && end_cnt_num && !(cmd_r & `STOP_BIT) ; // 可以接收到响应后停止(比如说在读数据之前)
- wire IF_IDLE_WR_DATA = (cstate == STATUS_IDLE ) && cmd_vld && (cmd & `WRITE_BIT) ;
- wire IF_R_ACK_STOP = (cstate == STATUS_R_ACK ) && end_cnt_num && (cmd_r & `STOP_BIT) ;
- wire IF_STOP_IDLE = (cstate == STATUS_STOP ) && end_cnt_num ;
- wire IF_IDLE_RD_DATA = (cstate == STATUS_IDLE ) && cmd_vld && (cmd & `READ_BIT) ;
- wire IF_RD_DATA_T_ACK = (cstate == STATUS_RD_DATA ) && end_cnt_num ;
- wire IF_T_ACK_IDLE = (cstate == STATUS_T_ACK ) && end_cnt_num && !(cmd_r & `STOP_BIT) ;
- wire IF_T_ACK_STOP = (cstate == STATUS_T_ACK ) && end_cnt_num && (cmd_r & `STOP_BIT) ;
- /*
- cmd_vld对应cmd 是由外界的cmd触发的
- end_cnt_num对应cmd_r 是由自动触发引起的
- */
- assign add_cnt_bit = cstate != STATUS_IDLE;
- assign end_cnt_bit = add_cnt_bit && cnt_bit == SCL_MAX - 1'd1;
- assign add_cnt_num = end_cnt_bit;
- assign end_cnt_num = add_cnt_num && cnt_num == num - 1;
- assign done = IF_R_ACK_IDLE || IF_STOP_IDLE || IF_T_ACK_IDLE;//都是回到IDLE 用来对应eeprom的cnt_byte
- assign rd_data_vld = IF_T_ACK_STOP || IF_T_ACK_IDLE;// 快发送ACK的时候
- /*
- cnt_bit的目的是组成完整的scl时钟周期
- */
- always @(posedge clk or negedge rst)
- if (!rst) begin
- cnt_bit <= 26'd0;
- end else if(add_cnt_bit)begin
- if(end_cnt_bit)
- cnt_bit <= 26'd0;
- else
- cnt_bit <= cnt_bit + 26'd1;
- end
- //IIC_SCL
- always @(posedge clk or negedge rst) begin
- if (!rst) begin
- scl <= 1'b1;
- end else if(cnt_bit == (SCL_MAX - 1'd1)>>1 || IF_STOP_IDLE)begin
- scl <= 1'b1;
- end else if(end_cnt_bit)begin
- scl <= 1'b0;//start信号 默认是1 过了第一个end_cnt_bit才把scl拉低 妙啊
- end
- end
- // 能用寄存器 都用寄存器
- always @(posedge clk or negedge rst)
- if (!rst) begin
- OE = 1'b1;
- end else if(IF_IDLE_START || IF_START_WR_DATA || IF_IDLE_WR_DATA || IF_RD_DATA_T_ACK || IF_T_ACK_STOP || IF_R_ACK_STOP)begin// !!!添加了IF_T_ACK_STOP
- OE = 1'b1;
- end else if(IF_WR_DATA_R_ACK || IF_IDLE_RD_DATA || IF_STOP_IDLE)begin
- OE = 1'b0;
- end
- always @(posedge clk or negedge rst) begin
- if (!rst) begin
- sda_out <= 1;
- end
- else begin
- case (cstate)
- STATUS_IDLE :sda_out <= 1;
- STATUS_START :begin
- if(cnt_bit == SCL_LOW_HALF)
- sda_out <= 1;
- else if(cnt_bit == SCL_HIGH_HALF)
- sda_out <= 0;
- end
- STATUS_WR_DATA :begin
- if(cnt_bit == SCL_LOW_HALF)
- sda_out <= wr_data_r[7-cnt_num];
- end
- STATUS_T_ACK :begin//
- if(cnt_bit == SCL_LOW_HALF)
- if(cmd_r & `ACK_BIT)
- sda_out <= `NO_ACK;
- else
- sda_out <= `ACK;
- end
- STATUS_STOP :begin
- if(cnt_bit == SCL_LOW_HALF)
- sda_out <= 0;
- else if(cnt_bit == SCL_HIGH_HALF)
- sda_out <= 1;
- end
- default: sda_out <= 'b1;
- endcase
- end
- end
- always@(*)
- case(cstate)
- STATUS_IDLE : state_name = "IDLE ";
- STATUS_START : state_name = "START ";
- STATUS_WR_DATA : state_name = "WR_DATA";
- STATUS_RD_DATA : state_name = "RD_DATA";
- STATUS_T_ACK : state_name = "T_ACK ";
- STATUS_R_ACK : state_name = "R_ACK ";
- STATUS_STOP : state_name = "STOP ";
- default : state_name = "IDLE ";
- endcase
- always @(posedge clk or negedge rst) begin
- if (!rst) begin
- rev_ack <= 0;
- rd_data_r <= 8'b0;
- end else case (cstate)
- STATUS_RD_DATA:
- if(cnt_bit == SCL_HIGH_HALF)
- rd_data_r[7 - cnt_num] <= sda;
- STATUS_R_ACK:
- if(cnt_bit == SCL_HIGH_HALF)
- rev_ack <= sda_in;
- default:;
- endcase
- end
- /*
- 在scl的1/4发送数据,在3/4处接受数据
- */
- always @(*) begin
- case (cstate)
- STATUS_IDLE : num = 1;
- STATUS_START : num = 1;
- STATUS_WR_DATA : num = 8;
- STATUS_RD_DATA : num = 8;
- STATUS_R_ACK : num = 1;
- STATUS_T_ACK : num = 1;
- STATUS_STOP : num = 1;
- default : num = 1;
- endcase
- end
- // 把输入的东西先存放在寄存器里面 确保在状态机运行期间,这些信号的值保持稳定
- always @(posedge clk or negedge rst) begin
- if (!rst) begin
- wr_data_r <= 'd0;
- cmd_r <= 'd0;
- end
- else if (cmd_vld) begin
- wr_data_r <= wr_data;
- cmd_r <= cmd;
- end
- end
- always@(posedge clk or negedge rst)
- if(!rst)begin
- cstate <= STATUS_IDLE;
- end else begin
- cstate <= nstate;
- end
- always @(*) begin
- case(cstate)
- STATUS_IDLE : begin
- if (IF_IDLE_START) begin
- nstate = STATUS_START;
- end
- else if (IF_IDLE_WR_DATA) begin
- nstate = STATUS_WR_DATA;
- end
- else if (IF_IDLE_RD_DATA) begin
- nstate = STATUS_RD_DATA;
- end
- else begin
- nstate = cstate; //这个要注意
- end
- end
- STATUS_START : begin
- if (IF_START_WR_DATA) begin
- nstate = STATUS_WR_DATA;
- end
- else begin
- nstate = cstate;
- end
- end
- STATUS_WR_DATA : begin
- if (IF_WR_DATA_R_ACK) begin
- nstate = STATUS_R_ACK;
- end
- else begin
- nstate = cstate;
- end
- end
- STATUS_RD_DATA : begin
- if (IF_RD_DATA_T_ACK) begin
- nstate = STATUS_T_ACK;
- end
- else begin
- nstate = cstate;
- end
- end
- STATUS_R_ACK : begin
- if (IF_R_ACK_STOP) begin
- nstate = STATUS_STOP;
- end
- else if (IF_R_ACK_IDLE) begin
- nstate = STATUS_IDLE;
- end
- else begin
- nstate = cstate;
- end
- end
- STATUS_T_ACK : begin
- if (IF_T_ACK_STOP) begin
- nstate = STATUS_STOP;
- end
- else if (IF_T_ACK_IDLE) begin
- nstate = STATUS_IDLE;
- end
- else begin
- nstate = cstate;
- end
- end
- STATUS_STOP : begin
- if (IF_STOP_IDLE) begin
- nstate = STATUS_IDLE;
- end
- else begin
- nstate = cstate;
- end
- end
- default : nstate = cstate;
- endcase
- end
- always @(posedge clk or negedge rst)begin
- if(!rst)begin
- cnt_num <= 'd0;
- end
- else if(add_cnt_num)begin
- if(end_cnt_num)begin
- cnt_num <= 'd0;
- end
- else begin
- cnt_num <= cnt_num + 1'd1;
- end
- end
- end
- endmodule
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |