FPGA 学习小组
直播中

alexdos

6年用户 804经验值
擅长:可编程逻辑 电源/新能源 嵌入式技术 模拟技术
私信 关注

【FPGA】I²C协议位传输的实现--全程代码实现

i2c_master_bit_ctrl.v 完成位传输的功能。位传输的功能包括数据按位传输的实现和  I²C协议各个命令的实现两部分。
如图 4-5 所示开始和重复开始命令的产生包括 5 个阶段:idle 和 A、B、C、D 等。停止命令包括 4 个阶段:idle 和 A、B、C 等。读、写一个字节通过 8 次位操作完成。
实现代码如下:

  1. `include "timescale.v"
  2. `include "i2c_master_defines.v"
  3. //模块名称及 IO
  4. module i2c_master_bit_ctrl(
  5.                 clk, rst, nReset,
  6.                 clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout,
  7.                 scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen
  8.                 );

6.jpg
  1. // 输入、输出
  2. input clk;
  3. input rst;
  4. input nReset;
  5. input ena; // 模块使能信号
  6. input [15:0] clk_cnt; // 时钟分频系数
  7. input [3:0] cmd;
  8. output cmd_ack; // 命令完成应答
  9. reg cmd_ack;
  10. output busy; // 总线忙
  11. reg busy;
  12. output al; // 总线仲裁丢失
  13. reg al;
  14. input din;
  15. output dout;
  16. reg dout;
  17. //  I²C 连线
  18. input scl_i; //  I²C 时钟输入
  19. output scl_o; //  I²C 时钟输出
  20. output scl_oen; //  I²C 时钟输出使能
  21. reg scl_oen;
  22. input sda_i; // I²C 数据输入
  23. output sda_o; //  I²C 数据输出
  24. output sda_oen; //  I²C 数据输出使能
  25. reg sda_oen;
  26. // variable declarations
  27. reg sSCL, sSDA; // 同步后的 SCL 和 SDA 输入
  28. reg dscl_oen; // 延迟后的 scl_oen
  29. reg sda_chk; // 检 查 后 的 SDA output (Multi-master
  30. arbitration)
  31. reg clk_en; // 时钟产生信号
  32. wire slave_wait;
  33. reg [15:0] cnt; // 时钟分频计数器
  34. // 模块主体
  35. // 当从节点没有准备好时,下拉 SCL 来延迟周期
  36. // 延迟 scl_oen
  37. always @(posedge clk)
  38.         dscl_oen <= #1 scl_oen;
  39. assign slave_wait = dscl_oen && !sSCL;
  40. // 产生时钟使能信号
  41. always @(posedge clk or negedge nReset)
  42.         if(~nReset)
  43.                 begin
  44.                                 cnt <= #1 16'h0;
  45.                                 clk_en <= #1 1'b1;
  46.                 end
  47.         else if (rst)
  48.                 begin
  49.                                 cnt <= #1 16'h0;
  50.                                 clk_en <= #1 1'b1;
  51.                 end
  52.                 else if ( ~|cnt || ~ena)
  53.         if (~slave_wait)
  54.                 begin
  55.                                 cnt <= #1 clk_cnt;
  56.                                 clk_en <= #1 1'b1;
  57.                 end
  58.         else
  59.                 begin
  60.                                 cnt <= #1 cnt;
  61.                                 clk_en <= #1 1'b0;
  62.                 end
  63.         else
  64.                 begin
  65.                                 cnt <= #1 cnt - 16'h1;
  66.                                 clk_en <= #1 1'b0;
  67.                 end
  68. // 产生总线状态控制信号
  69. reg dSCL, dSDA;
  70. reg sta_condition;
  71. reg sto_condition;
  72. // 同步 SCL 和 SDA 输入信号,减少不稳定风险
  73. always @(posedge clk or negedge nReset)
  74.         if (~nReset)
  75.                 begin
  76.                                 sSCL <= #1 1'b1;
  77.                                 sSDA <= #1 1'b1;
  78.                                 dSCL <= #1 1'b1;
  79.                                 dSDA <= #1 1'b1;
  80.                 end
  81.         else if (rst)
  82.                 begin
  83.                                 sSCL <= #1 1'b1;
  84.                                 sSDA <= #1 1'b1;
  85.                                 dSCL <= #1 1'b1;
  86.                                 dSDA <= #1 1'b1;
  87.                 end
  88.         else
  89.                 begin
  90.                                 sSCL <= #1 scl_i;
  91.                                 sSDA <= #1 sda_i;
  92.                                 dSCL <= #1 sSCL;
  93.                                 dSDA <= #1 sSDA;
  94.                 end
  95. // SCL 处于高时检测到 SDA 的下降沿,即检测开始状态信号
  96. // SCL 处于高时检测到 SDA 的上升沿,即检测停止状态信号
  97. always @(posedge clk or negedge nReset)
  98.         if (~nReset)
  99.                 begin
  100.                                 sta_condition <= #1 1'b0;
  101.                                 sto_condition <= #1 1'b0;
  102.                 end
  103.         else if (rst)
  104.                 begin
  105.                                 sta_condition <= #1 1'b0;
  106.                                 sto_condition <= #1 1'b0;
  107.                 end
  108.         else
  109.                 begin
  110.                                 sta_condition <= #1 ~sSDA & dSDA & sSCL;
  111.                                 sto_condition <= #1 sSDA & ~dSDA & sSCL;
  112.                 end
  113. // 产生  I²C 总线忙信号
  114. always @(posedge clk or negedge nReset)
  115.         if(!nReset)
  116.                 busy <= #1 1'b0;
  117.         else if (rst)
  118.                 busy <= #1 1'b0;
  119.         else
  120.                 busy <= #1 (sta_condition | busy) & ~sto_condition;
  121. // 产生仲裁丢失信号 generate arbitration lost signal
  122. // 仲裁丢失发生在:
  123. // 1) 主节点驱动 SDA 处于高,但是  I²C 总线一直处于低
  124. // 2) 没有请求时却检测到停止状态信号
  125. reg cmd_stop, dcmd_stop;
  126. always @(posedge clk or negedge nReset)
  127.         if (~nReset)
  128.                 begin
  129.                                 cmd_stop <= #1 1'b0;
  130.                                 dcmd_stop <= #1 1'b0;
  131. al <= #1 1'b0;
  132.                 end
  133.         else if (rst)
  134.                 begin
  135.                                 cmd_stop <= #1 1'b0;
  136.                                 dcmd_stop <= #1 1'b0;
  137.                                 al <= #1 1'b0;
  138.                 end
  139.         else

更多回帖

发帖
×
20
完善资料,
赚取积分