FPGA 学习小组
直播中

alexdos

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

【FPGA】I²C 协议的字节传输的实现

字节传输的具体实现流程如图 4-6 所示。


7.jpg
图 4-6 字节传输控制模块流程图

字节传输控制模块控制以字节为单位的数据传输。它根据命令寄存器的设置将数据传输寄存器中的内容传输到外部节点,将外部节点的数据接收到数据接收寄存器中。

实现代码如下:

  1. `include "timescale.v"
  2. `include "i2c_master_defines.v"
  3. //模块
  4. module i2c_master_byte_ctrl (
  5. clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din,
  6. cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen );
  7. // 输入、输出
  8. input clk; // 主时钟
  9. input rst; // 同步 RESET,高有效
  10. input nReset; // 异步 RESET,低有效
  11. input ena; // 模块使能信号
  12. input [15:0] clk_cnt; // 4 倍 SCL 信号
  13. // 控制信号输入
  14. input start;
  15. input stop;
  16. input read;
  17. input write;
  18. input ack_in;
  19. input [7:0] din;
  20. // 状态信号输出
  21. output cmd_ack;
  22. reg cmd_ack;
  23. output ack_out;
  24. reg ack_out;
  25. output i2c_busy;
  26. output i2c_al;
  27. output [7:0] dout;
  28. //  I²C 信号
  29. input scl_i;
  30. output scl_o;
  31. output scl_oen;
  32. input sda_i;
  33. output sda_o;
  34. output sda_oen;
  35. // 变量申明
  36. // 状态机
  37. parameter [4:0] ST_IDLE = 5'b0_0000;
  38. parameter [4:0] ST_START = 5'b0_0001;
  39. parameter [4:0] ST_READ = 5'b0_0010;
  40. parameter [4:0] ST_WRITE = 5'b0_0100;
  41. parameter [4:0] ST_ACK = 5'b0_1000;
  42. parameter [4:0] ST_STOP = 5'b1_0000;
  43. // 位控制模块的信号
  44. reg [3:0] core_cmd;
  45. reg core_txd;
  46. wire core_ack, core_rxd;
  47. // 移位寄存器信号
  48. reg [7:0] sr; //8 位移位寄存器
  49. reg shift, ld;
  50. // 状态机信号
  51. wire go;
  52. reg [2:0] dcnt;
  53. wire cnt_done;
  54. // 模块主体
  55. // 连接位控制模块
  56. i2c_master_bit_ctrl bit_controller (
  57. .clk ( clk ),
  58. .rst ( rst ),
  59. .nReset ( nReset ),
  60. .ena ( ena ),
  61. .clk_cnt ( clk_cnt ),
  62. .cmd ( core_cmd ),
  63. .cmd_ack ( core_ack ),
  64. .busy ( i2c_busy ),
  65. .al ( i2c_al ),
  66. .din ( core_txd ),
  67. .dout ( core_rxd ),
  68. .scl_i ( scl_i ),
  69. .scl_o ( scl_o ),
  70. .scl_oen ( scl_oen ),
  71. .sda_i ( sda_i ),
  72. .sda_o ( sda_o ),
  73. .sda_oen ( sda_oen )
  74. );
  75. // 产生 GO 信号,当读/写/停止/应答时发生
  76. assign go = (read | write | stop) & ~cmd_ack;
  77. // 分配输出到移位寄存器
  78. assign dout = sr;
  79. // 产生移位寄存器
  80. always @(posedge clk or negedge nReset)
  81. if (!nReset)
  82. sr <= #1 8'h0;
  83. else if (rst)
  84. sr <= #1 8'h0;
  85. else if (ld)
  86. sr <= #1 din;
  87. else if (shift)
  88. sr <= #1 {sr[6:0], core_rxd};
  89. // 产生计数器
  90. always @(posedge clk or negedge nReset)
  91. if (!nReset)
  92. dcnt <= #1 3'h0;
  93. else if (rst)
  94. dcnt <= #1 3'h0;
  95. else if (ld)
  96. dcnt <= #1 3'h7;
  97. else if (shift)
  98. dcnt <= #1 dcnt - 3'h1;
  99. assign cnt_done = ~(|dcnt);
  100. // 状态机
  101. reg [4:0] c_state;
  102. always @(posedge clk or negedge nReset)
  103. if (!nReset)
  104. begin
  105. core_cmd <= #1 `I2C_CMD_NOP;
  106. core_txd <= #1 1'b0;
  107. shift <= #1 1'b0;
  108. ld <= #1 1'b0;
  109. cmd_ack <= #1 1'b0;
  110. c_state <= #1 ST_IDLE;
  111. ack_out <= #1 1'b0;
  112. end
  113. else if (rst | i2c_al)
  114. begin
  115. core_cmd <= #1 `I2C_CMD_NOP;
  116. core_txd <= #1 1'b0;
  117. shift <= #1 1'b0;
  118. ld <= #1 1'b0;
  119. cmd_ack <= #1 1'b0;
  120. c_state <= #1 ST_IDLE;
  121. ack_out <= #1 1'b0;
  122. end
  123. else
  124. begin
  125. // 初始化所有信号
  126. core_txd <= #1 sr[7];
  127. shift <= #1 1'b0;
  128. ld <= #1 1'b0;
  129. cmd_ack <= #1 1'b0;
  130. case (c_state)
  131. //IDLE 状态
  132. ST_IDLE:
  133. if (go)
  134. begin
  135. if (start)
  136. begin
  137. c_state <= #1 ST_START;
  138. core_cmd <= #1 `I2C_CMD_START;
  139. end
  140. else if (read)
  141. begin
  142. c_state <= #1 ST_READ;
  143. core_cmd <= #1 `I2C_CMD_READ;
  144. end
  145. else if (write)
  146. begin
  147. c_state <= #1 ST_WRITE;
  148. core_cmd <= #1 `I2C_CMD_WRITE;
  149. end
  150. else // 缺省的是 stop 状态
  151. begin
  152. c_state <= #1 ST_STOP;
  153. core_cmd <= #1 `I2C_CMD_STOP;
  154. // 产生应答信号
  155. cmd_ack <= #1 1'b1;
  156. end
  157. ld <= #1 1'b1;
  158. end
  159. //开始状态
  160. ST_START:
  161. if (core_ack)
  162. begin
  163. if (read)
  164. begin
  165. c_state <= #1 ST_READ;
  166. core_cmd <= #1 `I2C_CMD_READ;
  167. end
  168. else
  169. begin
  170. c_state <= #1 ST_WRITE;
  171. core_cmd <= #1 `I2C_CMD_WRITE;
  172. end
  173. ld <= #1 1'b1;
  174. end
  175. //写数据状态
  176. ST_WRITE:
  177. if (core_ack)
  178. if (cnt_done)
  179. begin
  180. c_state <= #1 ST_ACK;
  181. core_cmd <= #1 `I2C_CMD_READ;
  182. end
  183. else
  184. begin
  185. c_state <= #1 ST_WRITE; // 保持在原来状态
  186. core_cmd <= #1 `I2C_CMD_WRITE; // 写下一位数据
  187. shift <= #1 1'b1;
  188. end
  189. //读信号状态
  190. ST_READ:
  191. if (core_ack)
  192. begin
  193. if (cnt_done)
  194. begin
  195. c_state <= #1 ST_ACK;
  196. core_cmd <= #1 `I2C_CMD_WRITE;
  197. end
  198. else
  199. begin
  200. c_state <= #1 ST_READ; // 保留在原来状态
  201. core_cmd <= #1 `I2C_CMD_READ; // 读下一位数据
  202. end
  203. shift <= #1 1'b1;
  204. core_txd <= #1 ack_in;
  205. end
  206. //应答数据状态
  207. ST_ACK:
  208. if (core_ack)
  209. begin
  210. if (stop)
  211. begin
  212. c_state <= #1 ST_STOP;
  213. core_cmd <= #1 `I2C_CMD_STOP;
  214. end
  215. else
  216. begin
  217. c_state <= #1 ST_IDLE;
  218. core_cmd <= #1 `I2C_CMD_NOP;
  219. end
  220. // 把应答信号输出连接到位控制模块
  221. ack_out <= #1 core_rxd;
  222. // 产生应答信号
  223. cmd_ack <= #1 1'b1;
  224. core_txd <= #1 1'b1;
  225. end
  226. else
  227. core_txd <= #1 ack_in;
  228. //停止状态
  229. ST_STOP:
  230. if (core_ack)
  231. begin
  232. c_state <= #1 ST_IDLE;
  233. core_cmd <= #1 `I2C_CMD_NOP;
  234. end
  235. endcase
  236. end
  237. endmodule

更多回帖

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