Verilog IIC驱动| FPGA驱动

打印 上一主题 下一主题

主题 989|帖子 989|积分 2967


  1. module iic(
  2.     input                               clk                        ,
  3.     input                               rst                       ,
  4.     input              [   4:0]         cmd                        ,
  5.     input                               cmd_vld                    ,
  6.     input              [   7:0]         wr_data                    ,
  7.     output             [   7:0]         rd_data                    ,
  8.     output                              rd_data_vld                ,
  9.     output reg                          rev_ack                    ,
  10.     output                              done                       ,
  11.     output reg                          scl                        ,
  12.     inout                               sda                        
  13. );
  14. /*
  15. 模拟过程
  16. 1. cnt_num
  17. 2. 二阶状态机
  18. 3. scl的生成
  19. cmd和cmd_vld是一起过来的!!!
  20. */
  21. `define     START_BIT   5'b00001
  22. `define     WRITE_BIT   5'b00010
  23. `define     READ_BIT    5'b00100
  24. `define     STOP_BIT    5'b01000
  25. `define     ACK_BIT     5'b10000
  26. `define     ACK         0
  27. `define     NO_ACK      1
  28. localparam STATUS_IDLE      = 7'b000_0001;
  29. localparam STATUS_START     = 7'b000_0010;
  30. localparam STATUS_WR_DATA   = 7'b000_0100;
  31. localparam STATUS_RD_DATA   = 7'b000_1000;
  32. localparam STATUS_T_ACK     = 7'b001_0000;
  33. localparam STATUS_R_ACK     = 7'b010_0000;
  34. localparam STATUS_STOP      = 7'b100_0000;
  35. localparam T = 100_000;
  36. localparam SCL_MAX = 50_000_000/T; // 一个完整的SCL周期
  37. /*
  38. localparam和define放在最前面
  39. */
  40. reg        [3:0]cnt_num                   ;
  41. reg [6:0]cstate;
  42. reg [6:0]nstate;
  43. reg [7:0]wr_data_r;
  44. reg sda_out;
  45. parameter   SCL_LOW_HALF  = (SCL_MAX * 1 / 4) - 1,
  46.             SCL_HIGH_HALF = (SCL_MAX * 3 / 4) - 1;  
  47. reg [25:0]cnt_bit;
  48. // 下面是关键的 状态转换的检测信号
  49. reg OE;
  50. reg[8*20-1:0]state_name;
  51. reg [7:0]rd_data_r;
  52. reg [4:0]num;
  53. wire end_cnt_num;
  54. /*下面是输入输出信号*/
  55. assign rd_data = rd_data_r; //读也从寄存器开始输出
  56. assign sda = OE?sda_out:1'bz;
  57. wire sda_in = sda;
  58. reg [4:0]cmd_r;
  59. wire IF_IDLE_START       = (cstate == STATUS_IDLE       )    && cmd_vld      && (cmd & `START_BIT)    ;
  60. wire IF_START_WR_DATA    = (cstate == STATUS_START      )    && end_cnt_num  && (cmd_r & `WRITE_BIT)    ;
  61. wire IF_WR_DATA_R_ACK    = (cstate == STATUS_WR_DATA    )    && end_cnt_num                             ;
  62. wire IF_R_ACK_IDLE       = (cstate == STATUS_R_ACK      )    && end_cnt_num  && !(cmd_r & `STOP_BIT)    ; // 可以接收到响应后停止(比如说在读数据之前)
  63. wire IF_IDLE_WR_DATA     = (cstate == STATUS_IDLE       )    && cmd_vld      && (cmd & `WRITE_BIT)    ;
  64. wire IF_R_ACK_STOP       = (cstate == STATUS_R_ACK      )    && end_cnt_num  && (cmd_r & `STOP_BIT)     ;
  65. wire IF_STOP_IDLE        = (cstate == STATUS_STOP       )    && end_cnt_num                             ;
  66. wire IF_IDLE_RD_DATA     = (cstate == STATUS_IDLE       )    && cmd_vld      && (cmd & `READ_BIT)     ;
  67. wire IF_RD_DATA_T_ACK    = (cstate == STATUS_RD_DATA    )    && end_cnt_num                             ;
  68. wire IF_T_ACK_IDLE       = (cstate == STATUS_T_ACK      )    && end_cnt_num  && !(cmd_r & `STOP_BIT)    ;
  69. wire IF_T_ACK_STOP       = (cstate == STATUS_T_ACK      )    && end_cnt_num  && (cmd_r & `STOP_BIT)     ;
  70. /*
  71. cmd_vld对应cmd                                   是由外界的cmd触发的
  72. end_cnt_num对应cmd_r                        是由自动触发引起的
  73. */
  74. assign add_cnt_bit = cstate != STATUS_IDLE;
  75. assign end_cnt_bit = add_cnt_bit && cnt_bit == SCL_MAX - 1'd1;
  76. assign add_cnt_num = end_cnt_bit;
  77. assign end_cnt_num = add_cnt_num && cnt_num == num - 1;
  78. assign done = IF_R_ACK_IDLE || IF_STOP_IDLE || IF_T_ACK_IDLE;//都是回到IDLE  用来对应eeprom的cnt_byte
  79. assign rd_data_vld = IF_T_ACK_STOP || IF_T_ACK_IDLE;// 快发送ACK的时候
  80. /*
  81.     cnt_bit的目的是组成完整的scl时钟周期
  82. */
  83. always @(posedge clk or negedge rst)
  84.         if (!rst) begin
  85.         cnt_bit <= 26'd0;
  86.     end else if(add_cnt_bit)begin
  87.         if(end_cnt_bit)
  88.             cnt_bit <= 26'd0;
  89.         else
  90.             cnt_bit <= cnt_bit + 26'd1;
  91.     end
  92. //IIC_SCL
  93. always @(posedge clk or negedge rst) begin
  94.         if (!rst) begin
  95.                 scl <= 1'b1;
  96.     end else if(cnt_bit == (SCL_MAX - 1'd1)>>1 || IF_STOP_IDLE)begin
  97.         scl <= 1'b1;
  98.     end else if(end_cnt_bit)begin
  99.         scl <= 1'b0;//start信号  默认是1 过了第一个end_cnt_bit才把scl拉低  妙啊
  100.     end
  101. end
  102. // 能用寄存器   都用寄存器
  103. always @(posedge clk or negedge rst)
  104.         if (!rst) begin
  105.         OE = 1'b1;
  106.     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
  107.         OE = 1'b1;
  108.     end else if(IF_WR_DATA_R_ACK || IF_IDLE_RD_DATA || IF_STOP_IDLE)begin
  109.         OE = 1'b0;
  110.     end
  111. always @(posedge clk or negedge rst) begin
  112.         if (!rst) begin
  113.                 sda_out <= 1;
  114.                 end
  115.         else begin
  116.                 case (cstate)
  117.                         STATUS_IDLE    :sda_out <= 1;
  118.                         STATUS_START   :begin
  119.                 if(cnt_bit == SCL_LOW_HALF)
  120.                     sda_out <= 1;
  121.                 else if(cnt_bit == SCL_HIGH_HALF)
  122.                     sda_out <= 0;
  123.                                 end
  124.                         STATUS_WR_DATA :begin
  125.                 if(cnt_bit == SCL_LOW_HALF)
  126.                     sda_out <= wr_data_r[7-cnt_num];
  127.                                 end
  128.                         STATUS_T_ACK   :begin//
  129.                 if(cnt_bit == SCL_LOW_HALF)
  130.                     if(cmd_r & `ACK_BIT)
  131.                         sda_out <= `NO_ACK;
  132.                     else
  133.                         sda_out <= `ACK;
  134.                                 end
  135.                         STATUS_STOP    :begin
  136.                 if(cnt_bit == SCL_LOW_HALF)
  137.                     sda_out <= 0;
  138.                 else if(cnt_bit == SCL_HIGH_HALF)
  139.                     sda_out <= 1;
  140.                                 end
  141.                         default: sda_out <= 'b1;
  142.                 endcase
  143.         end
  144. end
  145. always@(*)
  146.     case(cstate)
  147.         STATUS_IDLE    :   state_name  = "IDLE   ";
  148.         STATUS_START   :   state_name  = "START  ";
  149.         STATUS_WR_DATA :   state_name  = "WR_DATA";
  150.         STATUS_RD_DATA :   state_name  = "RD_DATA";
  151.         STATUS_T_ACK   :   state_name  = "T_ACK  ";
  152.         STATUS_R_ACK   :   state_name  = "R_ACK  ";
  153.         STATUS_STOP    :   state_name  = "STOP   ";
  154.         default            :   state_name  = "IDLE   ";
  155.     endcase
  156. always @(posedge clk or negedge rst) begin
  157.         if (!rst) begin
  158.                 rev_ack <= 0;
  159.                 rd_data_r <= 8'b0;
  160.         end else case (cstate)
  161.         STATUS_RD_DATA:
  162.             if(cnt_bit == SCL_HIGH_HALF)
  163.                     rd_data_r[7 - cnt_num] <= sda;
  164.         STATUS_R_ACK:
  165.             if(cnt_bit == SCL_HIGH_HALF)
  166.                 rev_ack <= sda_in;   
  167.         default:;
  168.     endcase
  169. end
  170. /*
  171. 在scl的1/4发送数据,在3/4处接受数据
  172. */
  173. always @(*) begin
  174.         case (cstate)
  175.                 STATUS_IDLE    : num = 1;
  176.                 STATUS_START   : num = 1;
  177.                 STATUS_WR_DATA : num = 8;
  178.                 STATUS_RD_DATA : num = 8;
  179.                 STATUS_R_ACK   : num = 1;
  180.                 STATUS_T_ACK   : num = 1;
  181.                 STATUS_STOP    : num = 1;
  182.                 default : num = 1;
  183.         endcase
  184. end
  185. // 把输入的东西先存放在寄存器里面  确保在状态机运行期间,这些信号的值保持稳定
  186. always @(posedge clk or negedge rst) begin
  187.         if (!rst) begin
  188.                 wr_data_r <= 'd0;
  189.                 cmd_r <= 'd0;
  190.                 end
  191.         else if (cmd_vld) begin
  192.                 wr_data_r <= wr_data;
  193.                 cmd_r <= cmd;
  194.                 end
  195. end
  196. always@(posedge clk or negedge rst)
  197.     if(!rst)begin
  198.         cstate <= STATUS_IDLE;
  199.     end else begin
  200.         cstate <= nstate;
  201.     end
  202. always @(*) begin
  203.         case(cstate)
  204.                 STATUS_IDLE    : begin
  205.                         if (IF_IDLE_START) begin
  206.                                 nstate = STATUS_START;
  207.                                 end
  208.                         else if (IF_IDLE_WR_DATA) begin
  209.                                 nstate = STATUS_WR_DATA;
  210.                                 end
  211.                         else if (IF_IDLE_RD_DATA) begin
  212.                                 nstate = STATUS_RD_DATA;
  213.                                 end
  214.                         else begin
  215.                                 nstate = cstate;    //这个要注意
  216.                                 end
  217.                         end
  218.                 STATUS_START   : begin
  219.                         if (IF_START_WR_DATA) begin
  220.                                 nstate = STATUS_WR_DATA;
  221.                                 end
  222.                         else begin
  223.                                 nstate = cstate;
  224.                                 end
  225.                         end
  226.                 STATUS_WR_DATA : begin
  227.                         if (IF_WR_DATA_R_ACK) begin
  228.                                 nstate = STATUS_R_ACK;
  229.                                 end
  230.                         else begin
  231.                                 nstate = cstate;
  232.                                 end
  233.                         end
  234.                 STATUS_RD_DATA : begin
  235.                         if (IF_RD_DATA_T_ACK) begin
  236.                                 nstate = STATUS_T_ACK;
  237.                                 end
  238.                         else begin
  239.                                 nstate = cstate;
  240.                                 end
  241.                         end
  242.                 STATUS_R_ACK   : begin
  243.                         if (IF_R_ACK_STOP) begin
  244.                                 nstate = STATUS_STOP;
  245.                                 end
  246.                         else if (IF_R_ACK_IDLE) begin
  247.                                 nstate = STATUS_IDLE;
  248.                                 end
  249.                         else begin
  250.                                 nstate = cstate;
  251.                                 end
  252.                         end
  253.                 STATUS_T_ACK   : begin
  254.                         if (IF_T_ACK_STOP) begin
  255.                                 nstate = STATUS_STOP;
  256.                                 end
  257.                         else if (IF_T_ACK_IDLE) begin
  258.                                 nstate = STATUS_IDLE;
  259.                                 end
  260.                         else begin
  261.                                 nstate = cstate;
  262.                                 end
  263.                         end
  264.                 STATUS_STOP    : begin
  265.                         if (IF_STOP_IDLE) begin
  266.                                 nstate = STATUS_IDLE;
  267.                                 end
  268.                         else begin
  269.                                 nstate = cstate;
  270.                                 end
  271.                         end
  272.                 default : nstate = cstate;
  273.         endcase
  274. end
  275. always @(posedge clk or negedge rst)begin
  276.         if(!rst)begin
  277.                 cnt_num <= 'd0;
  278.                 end
  279.         else if(add_cnt_num)begin
  280.                 if(end_cnt_num)begin
  281.                         cnt_num <= 'd0;
  282.                         end
  283.                 else begin
  284.                         cnt_num <= cnt_num + 1'd1;
  285.                 end
  286.         end
  287. end
  288. endmodule
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

半亩花草

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表