iic协议通讯驱动

1 篇文章 0 订阅
1 篇文章 0 订阅

模块特点

  1. 利用状态机完成iic的驱动,将重复的状态进行合并,使代码更简单;
  2. 由于iic不能连续完成读写操作,在STOP状态后又加了一个DELAY (延迟)状态,延迟了5ms,可以保证程序不会卡死;
  3. 为体现iic的节能特点,使用了三态门,在空闲状态下,sda和scl线处于释放状态;
  4. 为了使一次通讯稳定运行,在通讯刚开始时对数据进行寄存,而且在通讯过程中不能发生变化;

iic协议读/写数据步骤

在这里插入图片描述

iic协议读数据时序图

在这里插入图片描述
在这里插入图片描述

iic协议写数据时序图

在这里插入图片描述
在这里插入图片描述

iic协议通讯驱动模块

下面展示一些 内联代码片

module i2c_driver(
input   wire            clk,
input   wire            rst_n,
input   wire            read,
input   wire            write,
input   wire    [7:0]   dataw,  //要写的数据
input   wire    [6:0]   add,    //从机地址
input   wire    [7:0]   add_reg,//寄存器地址

inout   wire            sda,
output  wire            scl,
output  reg             done,
output  reg     [7:0]   datar   //接收到的数据
);
//sda线的三态门,空闲时释放
reg     sda_sel;
reg     sda_buf;
assign  sda = sda_sel ? sda_buf : 1'bz ;
//scl线的三态门,空闲时释放
reg     scl_sel;
reg     scl_buf;
assign  scl = scl_sel ? scl_buf : 1'bz ;
//assign  scl_sel =  !done  ? 1'b1 : 1'b0;

reg     [7:0]       dataw_r;
reg     [6:0]       add_r;
reg     [7:0]       add_reg_r;
//数据缓存,只有空闲时可以缓存数据
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        begin
            dataw_r <=0;  
            add_r <=0;    
            add_reg_r <=0;
        end
    else if(( write || read ) && done==1)
        begin
            dataw_r     <=  dataw  ;  
            add_r       <=  add    ;    
            add_reg_r   <=  add_reg;
        end
    else 
        begin
            dataw_r     <=  dataw_r  ;  
            add_r       <=  add_r    ;    
            add_reg_r   <=  add_reg_r;
        end 
             
localparam      T_4_1   =   125 - 1 ;   //  1/4周期
localparam      T_4_2   =   250 - 1 ;   //  2/4周期
localparam      T_4_3   =   375 - 1 ;   //  3/4周期
localparam      T_4_4   =   500 - 1 ;   //  4/4周期
reg     [10:0]      cnt;
always@(posedge clk or negedge rst_n)
    if(rst_n==0)
        cnt<=0;
    else if((cnt==T_4_4) || (done==1))  //执行读写时计数,空闲时不计数
        cnt<=0;
    else
        cnt<=cnt+1;
//建立scl线,执行读写时开始为1,建立100k时钟线
always@(posedge clk or negedge rst_n)
    if(rst_n==0)
        scl_buf<=1;
    else if(done==1)
        scl_buf<=1;
    else if(cnt==T_4_2 || cnt==T_4_4)
        scl_buf <= ~scl_buf;
    else
        scl_buf <= scl_buf; 

localparam      FSM_IDLE       =0;  //空闲状态
localparam      FSM_START      =1;  //发送start位
localparam      FSM_DATAW      =2;  //发送数据(从机地址+读/写,寄存器地址,数据)
localparam      FSM_ACK        =3;  //接收ack
localparam      FSM_RSTART     =4;  //发送restart位
localparam      FSM_DATAR      =5;  //接收数据
localparam      FSM_NACK       =6;  //发送nack
localparam      FSM_STOP       =7;  //发送停止位
localparam      FSM_DELAY      =8;  //延迟大约5ms
reg     [3:0]       cstate;
reg                 read_flag;
reg                 write_flag;
reg     [7:0]       datas;
reg     [2:0]       cs_flag;
reg     [8:0]       num;
reg                 flag;
always@(posedge clk or negedge rst_n)
    if(rst_n==0)
        begin
            cstate<=FSM_IDLE;
            read_flag<=0;
            write_flag<=0;
            cs_flag<=0;
            flag<=0; 
            sda_sel<=0;
            sda_buf<=1;
            num<=0; 
            datas<=0;
            scl_sel<=0;
            done<=1;          
        end
    else 
        case(cstate)
            FSM_IDLE    :       begin 
                                    sda_sel<=0;
                                    scl_sel<=0;
                                    if(read)
                                        begin
                                            cstate<=FSM_START;
                                            read_flag<=1;
                                        end
                                    else if(write)
                                        begin
                                            cstate<=FSM_START;
                                            write_flag<=1;
                                        end
                                    else
                                        cstate<=FSM_IDLE;
                                end
                                
            FSM_START   :       begin
                                    scl_sel<=1;
                                    done<=0;
                                    if(cnt==T_4_1)
                                        begin
                                            sda_sel <= 1;
                                            sda_buf <= 0;
                                            datas<={add_r,1'b0};
                                            cstate<=FSM_DATAW;
                                            cs_flag<=1;
                                        end 
                                end
                                
            FSM_DATAW   :       begin
                                    if(cnt==T_4_3)
                                        begin
                                            if(num<=7)
                                                begin
                                                    sda_sel <= 1;
                                                    sda_buf <= datas[7-num];
                                                    num <= num+1;
                                                end
                                            else
                                                begin
                                                    cstate<=FSM_ACK;
                                                    sda_sel <= 0;
                                                    num<=0;
                                                end
                                        end   
                                end
                                
            FSM_ACK     :       begin 
                                    if(cnt==T_4_1)
                                        if(sda==0)
                                            begin
                                                if(cs_flag==1)
                                                    begin
                                                        cstate<=FSM_DATAW;
                                                        datas<=add_reg_r;
                                                        cs_flag<=2;
                                                    end
                                                else if(cs_flag==2)
                                                    begin
                                                        if(read_flag==1)
                                                            begin
                                                                cstate<=FSM_RSTART;
                                                                read_flag<=0; 
                                                            end
                                                        else if(write_flag==1)
                                                            begin
                                                                cstate<=FSM_DATAW;
                                                                write_flag<=0;
                                                                datas<=dataw_r;
                                                                cs_flag<=3;
                                                            end
                                                    end
                                                else if(cs_flag==3)
                                                    cstate<=FSM_STOP;
                                                else if(cs_flag==4)
                                                    cstate<=FSM_DATAR;
                                            end
                                end
                                
            FSM_RSTART  :       begin 
                                    if(cnt==T_4_1)
                                        begin
                                            sda_sel<=1;
                                            sda_buf<=0;
                                            cstate<=FSM_DATAW;
                                            datas<={add_r,1'b1};
                                            cs_flag<=4;
                                        end 
                                end
                                
            FSM_DATAR   :       begin 
                                    if( cnt==T_4_1 )
                                        begin
                                            if(num<=7)
                                                begin
                                                    datar[7-num]<=sda;
                                                    num<=num+1;
                                                end
                                            else 
                                                begin
                                                    cstate<=FSM_NACK;
                                                    num<=0;
                                                end  
                                        end
                                end
                                
            FSM_NACK   :       begin 
                                  if( cnt == T_4_3 )          
                                        begin
                                            sda_sel<=1;
                                            sda_buf<=1;
                                            cstate<=FSM_STOP;
                                        end             
                                end                    
            FSM_STOP   :       begin 
                                    if(cnt == T_4_3)
                                        begin
                                            sda_sel<=1;
                                            sda_buf<=0;
                                            flag <= 1;
                                        end
                                    else if(cnt == T_4_1 && flag == 1)
                                        begin
                                            sda_buf<=0;
                                            flag <= 0;
                                            cstate<=FSM_DELAY;
                                        end
                               end 
                               
            FSM_DELAY   :       begin
                                    sda_sel<=0;
                                    scl_sel<=0;
                                    if(cnt == T_4_4 && num == 500)
                                        begin
                                            num<=0;
                                            cstate<=FSM_IDLE;
                                            done<=1;
                                        end
                                    else if(cnt == T_4_4)
                                        num<=num+1;
                                end
                                    
           default     :       begin
                                   cstate<=FSM_IDLE;
                                   read_flag<=0;
                                   write_flag<=0;
                                   cs_flag<=0;
                                   flag<=0; 
                                   sda_sel<=0;
                                   sda_buf<=1;
                                   num<=0; 
                                   datas<=0;
                                   scl_sel<=0;
                                   done<=1;     
                                end
        endcase
endmodule             

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值