• FPGA IIC SLAVE 实现


    1.整体逻辑

    1.模块声明

    1. module I2CslaveWith8bitsIO(SDA, SCL, IOout);
    2. inout SDA;
    3. input SCL;
    4. output [7:0] IOout;

     IOout 用于输出接收到数据

    指定从设备的节点地址

    parameter I2C_ADR = 7'h27;

    判断IIC 的开始或结束条件

    1. wire SDA_shadow /* synthesis keep = 1 */;
    2. wire start_or_stop /* synthesis keep = 1 */;
    3. assign SDA_shadow = (~SCL | start_or_stop) ? SDA : SDA_shadow;
    4. assign start_or_stop = ~SCL ? 1'b0 : (SDA ^ SDA_shadow);
    5. reg incycle;
    6. always @(negedge SCL or posedge start_or_stop)
    7. if(start_or_stop) incycle <= 1'b0; else if(~SDA) incycle <= 1'b1;

    变量声明

    1. reg [3:0] bitcnt; // counts the I2C bits from 7 downto 0, plus an ACK bit
    2. wire bit_DATA = ~bitcnt[3]; // the DATA bits are the first 8 bits sent
    3. wire bit_ACK = bitcnt[3]; // the ACK bit is the 9th bit sent
    4. reg data_phase;

    bit cnt 计数或者dataphase转换

    1. always @(negedge SCL or negedge incycle)
    2. if(~incycle)
    3. begin
    4. bitcnt <= 4'h7; // the bit 7 is received first
    5. data_phase <= 0;
    6. end
    7. else
    8. begin
    9. if(bit_ACK)
    10. begin
    11. bitcnt <= 4'h7;
    12. data_phase <= 1;
    13. end
    14. else
    15. bitcnt <= bitcnt - 4'h1;
    16. end

    匹配从机地址

    wire adr_phase = ~data_phase;
    reg adr_match, op_read, got_ACK;
    // sample SDA on posedge since the I2C spec specifies as low as 0µs hold-time on negedge
    reg SDAr;  always @(posedge SCL) SDAr<=SDA;
    reg [7:0] mem;
    wire op_write = ~op_read;
    
    always @(negedge SCL or negedge incycle)
    if(~incycle)
    begin
        got_ACK <= 0;
        adr_match <= 1;
        op_read <= 0;
    end
    else
    begin
        if(adr_phase & bitcnt==7 & SDAr!=I2C_ADR[6]) adr_match<=0;
        if(adr_phase & bitcnt==6 & SDAr!=I2C_ADR[5]) adr_match<=0;
        if(adr_phase & bitcnt==5 & SDAr!=I2C_ADR[4]) adr_match<=0;
        if(adr_phase & bitcnt==4 & SDAr!=I2C_ADR[3]) adr_match<=0;
        if(adr_phase & bitcnt==3 & SDAr!=I2C_ADR[2]) adr_match<=0;
        if(adr_phase & bitcnt==2 & SDAr!=I2C_ADR[1]) adr_match<=0;
        if(adr_phase & bitcnt==1 & SDAr!=I2C_ADR[0]) adr_match<=0;
        if(adr_phase & bitcnt==0) op_read <= SDAr;
        // we monitor the ACK to be able to free the bus when the master doesn't ACK during a read operation
        if(bit_ACK) got_ACK <= ~SDAr;
    
        if(adr_match & bit_DATA & data_phase & op_write) mem[bitcnt] <= SDAr;  // memory write
    end

     

    整体代码如下

    1. module I2CslaveWith8bitsIO(SDA, SCL, IOout);
    2. inout SDA;
    3. input SCL;
    4. output [7:0] IOout;
    5. // The 7-bits address that we want for our I2C slave
    6. parameter I2C_ADR = 7'h27;
    7. //
    8. // I2C start and stop conditions detection logic
    9. // That's the "black magic" part of this design...
    10. // We use two wires with a combinatorial loop to detect the start and stop conditions
    11. // ... making sure these two wires don't get optimized away
    12. `ifdef Xilinx
    13. BUF mybuf(.O(SDA_shadow), .I((~SCL | start_or_stop) ? SDA : SDA_shadow));
    14. BUF SOS_BUF(.O(start_or_stop), .I(~SCL ? 1'b0 : (SDA ^ SDA_shadow)));
    15. `else
    16. wire SDA_shadow = (~SCL | start_or_stop) ? SDA : SDA_shadow /* synthesis keep = 1 */;
    17. wire start_or_stop = ~SCL ? 1'b0 : (SDA ^ SDA_shadow) /* synthesis keep = 1 */;
    18. `endif
    19. reg incycle; always @(negedge SCL or posedge start_or_stop) if(start_or_stop) incycle <= 1'b0; else if(~SDA) incycle <= 1'b1;
    20. //
    21. // Now we are ready to count the I2C bits coming in
    22. reg [3:0] bitcnt; // counts the I2C bits from 7 downto 0, plus an ACK bit
    23. wire bit_DATA = ~bitcnt[3]; // the DATA bits are the first 8 bits sent
    24. wire bit_ACK = bitcnt[3]; // the ACK bit is the 9th bit sent
    25. reg data_phase;
    26. always @(negedge SCL or negedge incycle)
    27. if(~incycle)
    28. begin
    29. bitcnt <= 4'h7; // the bit 7 is received first
    30. data_phase <= 1'b0;
    31. end
    32. else
    33. begin
    34. if(bit_ACK)
    35. begin
    36. bitcnt <= 4'h7;
    37. data_phase <= 1'b1;
    38. end
    39. else
    40. bitcnt <= bitcnt - 4'h1;
    41. end
    42. // and detect if the I2C address matches our own
    43. wire adr_phase = ~data_phase;
    44. reg adr_match, op_read, got_ACK;
    45. reg SDAr; always @(posedge SCL) SDAr<=SDA; // sample SDA on posedge since the I2C spec specifies as low as 0祍 hold-time on negedge
    46. reg [7:0] mem;
    47. wire op_write = ~op_read;
    48. always @(negedge SCL or negedge incycle)
    49. if(~incycle)
    50. begin
    51. got_ACK <= 1'b0;
    52. adr_match <= 1'b1;
    53. op_read <= 1'b0;
    54. end
    55. else
    56. begin
    57. if(adr_phase & bitcnt==7 & SDAr!=I2C_ADR[6]) adr_match<=1'b0;
    58. if(adr_phase & bitcnt==6 & SDAr!=I2C_ADR[5]) adr_match<=1'b0;
    59. if(adr_phase & bitcnt==5 & SDAr!=I2C_ADR[4]) adr_match<=1'b0;
    60. if(adr_phase & bitcnt==4 & SDAr!=I2C_ADR[3]) adr_match<=1'b0;
    61. if(adr_phase & bitcnt==3 & SDAr!=I2C_ADR[2]) adr_match<=1'b0;
    62. if(adr_phase & bitcnt==2 & SDAr!=I2C_ADR[1]) adr_match<=1'b0;
    63. if(adr_phase & bitcnt==1 & SDAr!=I2C_ADR[0]) adr_match<=1'b0;
    64. if(adr_phase & bitcnt==0) op_read <= SDAr;
    65. if(bit_ACK) got_ACK <= ~SDAr; // we monitor the ACK to be able to free the bus when the master doesn't ACK during a read operation
    66. if(adr_match & bit_DATA & data_phase & op_write) mem[bitcnt] <= SDAr; // memory write
    67. end
    68. // and drive the SDA line when necessary.
    69. wire mem_bit_low = ~mem[bitcnt[2:0]];
    70. wire SDA_assert_low = adr_match & bit_DATA & data_phase & op_read & mem_bit_low & got_ACK;
    71. wire SDA_assert_ACK = adr_match & bit_ACK & (adr_phase | op_write);
    72. wire SDA_low = SDA_assert_low | SDA_assert_ACK;
    73. assign SDA = SDA_low ? 1'b0 : 1'bz;
    74. assign IOout = mem;
    75. endmodule

  • 相关阅读:
    JS中的事件循环eventloop
    树状数组&线段树总结
    Visual Studio复制、拷贝C++项目与第三方库配置信息到新的项目中
    网球场地预约
    Springboot实现多数据源
    Move 合约漏洞,Move 合约中最常见的 10 种 Bug
    java面试笔试题
    资源 | Python可视化系列文章资源(源码+数据)
    《Go Web 编程》之第4章 处理请求
    一条SQL语句执行的顺序
  • 原文地址:https://blog.csdn.net/xinshuwei/article/details/126160973