当前位置:   article > 正文

I2C协议FPGA verilog开发_i2c fpga verilog hdl

i2c fpga verilog hdl

说在前头

前两天老师布置了一个I2C协议的手绘图,我心想这么简单的协议我就用verilog写一个呗。
初步设想是双机,能够实现主从机相互转换,可以相互读写,但是现在只实现了主机写从机读从机,手头上目前还没有FPGA,主从任意转换就没有写了,今天就把目前做到的写下来,以后有机会就填坑。

I2C协议

瞌睡的洋葱博客
这位博主说的十分清楚了,再结合一下百度百科基本上就能搞清楚了。

时序图

时序图

寄存器的标准流程为:

  1. Master发起START
  2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
  3. Slave发送ACK
  4. Master发送reg addr(8bit),等待ACK
  5. Slave发送ACK
  6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
  7. Slave发送ACK
  8. 第6步和第7步可以重复多次,即顺序写多个寄存器
  9. Master发起STOP

读寄存器的标准流程为:

  1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
  2. Slave发送ACK
  3. Master发送reg addr(8bit),等待ACK
  4. Slave发送ACK
  5. Master发起START
  6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
  7. Slave发送ACK
  8. Slave发送data(8bit),即寄存器里的值
  9. Master发送ACK
  10. 第8步和第9步可以重复多次,即顺序读多个寄存器

大家不懂的可以看看上面那一篇博客。

编程思路

既然了解了I2C协议的过程下面就是要解决问题了。
I2C协议的步骤如此清晰,我们自然而然想到使用状态机,状态机可以用FPGA系统时钟,这里为了方便我使用的是1Mhz的FPGA时钟I2C_SCL时钟为系统时钟的10分频.
状态机我分为6个状态:

  1. wait状态,完成部分初始化,SDA与SCL不工作时都为高;
  2. start状态,主机在SCL为高时将SDA拉低
  3. adder状态,主机输出7位设备地址和读写控制符
  4. adder2状态,主机输出数据存放地址
  5. doing状态,主机读写数据
  6. ask状态,每写完地址或者数据从机都需要应答
  7. stop状态,结束,回到等待状态
parameter s_wait=3'b000,s_start=3'b001,s_adder1=3'b010,s_adder2=3'b011,s_doing=3'b100,s_ask=3'b101,s_stop=3'b110;
  • 1

完整代码如下

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/05/13 17:34:09
// Design Name: 
// Module Name: I2Cpro_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module I2Cpro_top(
    input clk,
    input rst_n,
    input enable, //使能I2C模块
    input wr_cont,//0写,1读
    input [6:0]Device_addr,//设备地址
    input [7:0]Store_addr,//储存地址
    input [7:0]data_in,
    output [7:0]data_out,
    inout SDA,
    inout SCL);
    parameter s_wait=3'b000,s_start=3'b001,s_adder1=3'b010,s_adder2=3'b011,s_doing=3'b100,s_ask=3'b101,s_stop=3'b110;
    parameter data_size=8;
   

    reg doing=1'b0;         //SDA数据有效,开始到结束
    reg ready=1'b0;         //进行数据读写

    reg [7:0]data_reg[7:0];                 //暂存输入的所有数据
    reg [7:0]data_wr=8'h00,data_rd=8'h00;             //暂存收发数据
    reg [7:0]rDevice_wr_addr=8'b000;  //设备地址和读写控制
    reg [7:0]rStore_addr=8'h00;       //读写地址


    reg rSDA=1'b1;                          //SDA
    reg [2:0]rState=s_wait;                 //I2C控制状态机
    reg [2:0]bit_cnt=3'b000;                //读写bit计数器
    reg [7:0]data_cnt=data_size+2;          //读写byte计数器
    reg [4:0]buffer=5'b00001;               //在clk驱动的状态机中与SCL时钟规则匹配

    reg s_cnt=1'b0;                         //用于控制两次数据传输间隙

    //调用偶分频div模块
    //SCL时钟由clk系统时钟10分频产生
    sysclk2I2CSCL #(
        .N(10)      //分频数为10
    )sysclk2I2CSCL2(
        .clk(clk),
        .rst_n(rst_n),
        .SCL(SCL)
    );

    //  如果SCL高电平的时候检测到了SDA的高转低说明开始
    always@(negedge SDA)begin
        if(SCL==1)
        doing<=1'b1;
    end
    //  如果SCL高电平的时候检测到SDA的低转高说明结束
    always@(posedge SDA)begin
        if(SCL==1)
        doing<=1'b0;
    end

    always@(posedge clk)begin
        if(enable)begin
            if(!rst_n)begin
                rSDA<=1;
                rState<=s_wait;
                buffer<=5'b00001;
                data_cnt<=data_size+2;
                bit_cnt<=3'b000;                
            end
            else begin
                case(rState)
                s_wait:begin
                if(SCL)begin
                    buffer<={buffer[3:0],buffer[4]};
                    if(buffer[2])begin
                        if(s_cnt==1)begin
                        rSDA<=1'b1;
                        rState<=s_start;
                        rDevice_wr_addr<={Device_addr,wr_cont};
                        rStore_addr<=Store_addr;
                        data_wr<=data_in;
                        data_cnt<=data_size+2;
                        bit_cnt<=3'b000;
                        end
                        buffer<=5'b00001;  
                        s_cnt<=s_cnt+1; 
                    end
                end  
                end
                s_start:begin
                if(SCL)begin
                    buffer<={buffer[3:0],buffer[4]};
                    if(buffer[2])
                    begin
                    rSDA<=1'b0;
                    rState<=s_adder1;
                    buffer<=5'b00001;
                    end
                end
                end
                s_adder1:begin
                if(!SCL)begin
                    buffer<={buffer[3:0],buffer[4]};
                    if(buffer[2])
                    begin
                    rSDA<=rDevice_wr_addr[0];
                    rDevice_wr_addr<={rDevice_wr_addr[0],rDevice_wr_addr[7:1]};
                    bit_cnt<=bit_cnt+1'b1;
                    if(bit_cnt==7)
                    begin
                    data_cnt<=data_cnt-1;
                    rState<=s_ask;
                    buffer<=5'b00001;
                    end
                    end
                end                

                end
                s_adder2:begin
                if(!SCL)begin
                    buffer<={buffer[3:0],buffer[4]};
                    if(buffer[2])
                    begin
                    rSDA<=rStore_addr[0];
                    rStore_addr<={rStore_addr[0],rStore_addr[7:1]};
                    bit_cnt<=bit_cnt+1'b1;
                    if(bit_cnt==7)
                    begin
                    data_cnt<=data_cnt-1;
                    rState<=s_ask;
                    buffer<=5'b00001;     
                    end               
                    end
                end       
                end
                s_doing:begin
                    if(wr_cont==0)begin//如果是写,写入数据改变SDA
                        if(!SCL)begin
                            buffer<={buffer[3:0],buffer[4]};
                            if(buffer[2])begin
                            rSDA<=data_wr[0];
                            data_wr<={data_wr[0],data_wr[7:1]};
                            bit_cnt<=bit_cnt+1'b1;
                            if(bit_cnt==7)begin
                                data_cnt<=data_cnt-1;
                                rState<=s_ask;
                                buffer<=5'b00001;   
                            end               
                            end
                        end                   
                    end
                    else begin
                        if(SCL)begin
                            buffer<={buffer[3:0],buffer[4]};
                            if(buffer[2])begin
                                data_rd[0]<=SDA;
                                data_rd<={data_rd[0],data_rd[7:1]};
                                bit_cnt<=bit_cnt+1;
                                if(bit_cnt==7)begin
                                    data_reg[data_cnt]<=data_rd;
                                    data_cnt<=data_cnt+1;
                                end
                            end
                        end
                    end
                end
                s_ask:begin
                    if(wr_cont==0)begin //等待回复ask
                        if(SCL && !SDA)begin
                            buffer<={buffer[3:0],buffer[4]};
                            if(buffer[2])begin
                                if(data_cnt==data_size+1)
                                rState<=s_adder2;
                                else if(data_cnt==0)
                                rState<=s_stop;
                                else
                                rState<=s_doing;
                            end                       
                        end
                    end/*
                    else begin          //主动回复ask  从机时候
                        if(!SCL)begin
                            buffer<={buffer[3:0],buffer[4]};
                            if(buffer[2])begin
                            rSDA<=1'b0;
                            buffer<=5'b00001;
                            if(data_cnt==data_size+1)
                                rState<=s_adder2;
                            else if(data_cnt==0)
                                rState<=s_stop;
                            else
                                rState<=s_doing;
                            end
                        end   
                    end */                  
                end
                s_stop:begin            //结束
                if(SCL)begin
                    buffer<={buffer[3:0],buffer[4]};
                    if(buffer[2])
                    begin
                    if(s_cnt==1)begin
                    rSDA<=1'b1;
                    rState<=s_wait;
                    end
                    s_cnt<=s_cnt+1;
                    buffer<=5'b00001; 
                    end
                end
                end
                endcase
            end
        end
    end
//  读数据
    assign SDA=rSDA;
    assign data_out=data_rd;

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235

tsetbench

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/05/11 15:07:11
// Design Name: 
// Module Name: I2Ctb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module I2Ctb();
reg clk;
reg rst_n;
reg enable;
reg wr_cont;
reg[6:0]Device_addr;//设备地址
reg[7:0]Store_addr;//储存地址
reg[7:0]data_in;
wire [7:0]data_out;
wire SDA;
wire SCL;


I2Cpro_top I2C_top1(
    .clk(clk),
    .rst_n(rst_n),
    .enable(enable),
    .wr_cont(wr_cont),
    .Device_addr(Device_addr),
    .Store_addr(Store_addr),
    .data_in(data_in),
    .data_out(data_out),
    .SDA(SDA),
    .SCL(SCL)
);

always #5 clk=~clk;
initial 
begin
    clk=0;
    rst_n=0;
    enable=0;
    wr_cont=0;
    Device_addr=7'h78;
    Store_addr=8'haa;
    data_in=8'hff;
    #10 
    enable=1;
    #10
    rst_n=1;
    #20000
    wr_cont=1;
end

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

有人读的话再继续完善

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/599717
推荐阅读
相关标签
  

闽ICP备14008679号