当前位置:   article > 正文

基于FPGA的I2C协议实现_i2c的 fpga实现

i2c的 fpga实现

I²CInter-Integrated Circuit)即集成电路总线,它其实是I²C Bus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板嵌入式系统手机用以连接低速周边设备而发展。I²C的正确读法为“I平方C”("I-squared-C"),而“I二C”("I-two-C")则是另一种错误但被广泛使用的读法。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。--------维基百科

图1 I2C总线

 一、I2C总线的概念

I2C通过SCL和SDA在连接到总线的器件之间进行信息交流。每个器件都有一个唯一的地址识别(微处理器、lCD驱动器、存储器及键盘接口)。而且都可以作为一个发送器或接收器,由器件的功能决定。很明显 LCD驱动器只是一个接收器,而存储器则既可以接收又可以发送数据,除了发送器和接收器外器件在执行数据传输时也可以被看作是主机或从机 。见表 1主机是初始化总线的数据传输并产生允许传输的时钟信号的器件,此时任何被寻址的器件都被认为是从机。
1.1I2C总线的特征

I2C总线的两条线SCL和SDA都是双向线路,都通过一个电流源或上拉电阻连接到正的电源电压。实际使用中,通常将SCL定义为输出类型,SDA为输入输出类型。当总线空闲时,这两条线路都是高电平。I2C总线上的数据传输速率在标准模式下可达100Kbit/s,在快速模式下可达400kbit/s,在高速模式下可达3.4Mbit/s。连接到总线的接口数量只由总线电容400pF的限制决定。

 1.2 位传输

由于连接到I2C总线的器件有不同种类的工艺(CMOS、NMOS、双极性),逻辑0和1的电平不是固定的,它由V_D_D的相关电平决定。每传输一个数据位就产生一个时钟脉冲。

1.2.1 数据的有效性

SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态只有在SCL线的时钟信号是低电平时才能改变。

 

图2 IIC数据改变

 图2中给出了SDA上数据何时改变的示意图,由图可知,在SCL高电平期间,数据必须保持稳定;在SCL为低电平期间,才允许SDA上数据发生改变。

1.2.2 起始和停止条件

起始条件:在SCL为高电平器件,SDA由高电平跳变为低电平,此情况表示起始条件。

停止条件:在SCL为高电平期间,SDA由低电平跳变为高电平,此情况表示停止条件。

起始条件和停止条件一般由主机产生。起始条件和停止条件如图3所示:

图3 起始条件和停止条件

 图3中S表示起始条件,此时,SCL为高电平,SDA由高电平跳变为低电平;P表示结束条件,此时,SCL为高电平,由低电平跳变为高电平。

1.2.3 数据发送过程

在检测到起始条件后,接下来可以进行数据的发送,发送到SDA线上的每个字节必须为8位。每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应信号。首先传输的是数据的最高位。

响应:在一个字节发送完毕后后面必须跟一个响应信号。想关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,主机释放SDA线(此时SDA为输入类型),此时若从机发通过SDA数据线传入一个低电平,则从机响应;从机相应后可以继续进行数据的传输,若不在进行数据传输,此时只需要在从机响应后主机再产生一个停止信号即可。

图4 IIC 总线的数据发送过程

图4中通过是I2C 总线发送数据的过程,首先主控器产生起始信号(告诉从机主机要发送数据了),然后从机接收到起始信号后开始做好接收数据的准备,接下来主机就可以进行数据的发送,图4中首先发送的是被控器7位地址和一位读写选择信号,在主机发送完成后,主机会释放SDA总线(此时SDA由输出类型变为输入类型),同时从机在接收完数据信号后通过SDA线传输给主机一个应答信号ACK(SCL为高时,SDA为低),在主机检测到应答信号后主机继续发送下一个字节,待发送完成后主机释放SDA总线(SDA由输出变为输入类型),同时从机在接收完数据信号后通过SDA线传输给主机一个应答信号ACK(SCL为高时,SDA为低);从机应答后,若主机需要继续发送数据则重复上述过程;若主机不需要再进行数据的发送,主机需要发送一个停止信号告诉从机本轮数据发送完毕。

二、IIC总线数据发送的VERILOG描述

由图4可知,IIC发送数据的过程包括以下步骤:1、主控器发送开始信号—>2、主控器发送8位命令—>3、被控器应答—>4、主控器发送8位数据—>5、被控器应答—>6、主控器发送结束信号(如果还有数据要发送只需继续重复步骤4和5,待所有数据发送完后执行步骤6)。因此,IIC协议发送过程有明显的先后顺序关系,可以使用状态机来描述数据发送的整个过程。

对应的状态机如图5所示:

图5 IIC 发送过程状态机描述

 

 在复位信号rst有效时进入IDLE状态,在IDLE状态,初始化SCL、SDA以及SDA_link(控制SDA是输入还是输出);IIC发送数据开始信号wr_en有效时,进入START状态,在该状态产生IIC发送数据的起始条件start(SCL为高时,SDA由高变为低);start有效时,进入ADDR0,在该状态,加载待发送的8位地址,并将最高位发送出去,i用来计数发送几个地址的第几位(由于SCL是i计数器的时钟的2分频,因此这里使用ADDR1和ADDR2这两个状态来完成数据的发送,ADDR1发送数据,ADDR2无操作);当8个地址发送完毕后,进入ACK1 状态,此状态,主机释放SDA,从机给出应答信号,并加载下一次待发送的数据;DATA0和DATA1用来实现8位数据信号的发送,DATA0状态对数据无操作,DATA1状态发送数据,当数据发送完毕后即i=16,进入ACK2状态,此时,主机释放SDA,从机给出应答;i=0时,进入STOP状态,该状态用于产生IIC发送数据的结束条件stop(SCL 为高时,SDA由低跳变为高);stop信号有效时进入DONE状态,表示数据发送完成,拉高done信号,然后进入IDLE状态,等待下一次数据的发送。

verilog描述如下所示:

I2C_MODULE:使用三段式状态机描述IIC数据发送过程,主要生成控制信号;同时例化实现过程中所需要的电路。

  1. module I2C_MODULE(input clk_50m,
  2. input clk_in,/用来同步SDA,使其在SCL低电平改变
  3. input rst_n,
  4. input wr_en,
  5. input [7:0]addr_in,
  6. input [7:0]data_in,
  7. output reg done,
  8. inout SDA,
  9. output SCL,
  10. output reg ack1,///仿真信号
  11. output reg ack2仿真信号
  12. );
  13. wire [4:0] i;
  14. wire sda_r;
  15. reg load_a;/SCl空闲时加载数据
  16. reg en_a;/产生SCL
  17. reg load_b;///加载待发送地址
  18. reg en_b;///地址移位寄存器使能
  19. reg load_c;///计数器加载数据
  20. reg en_c;计数器计数
  21. reg load_d;///加载待发送数据
  22. reg en_d;
  23. reg SDA_link;//1时SDA为输出,0时为输入
  24. reg sad_load;///sda_r空闲时加载数据
  25. reg sda_en_addr;//将地址赋值给sda_r
  26. reg sda_en_data;//将数据赋值给sda_r
  27. reg start;
  28. reg stop;
  29. //reg ack1;应答信号给ack1
  30. //reg ack2;///应答信号给ack2
  31. reg SDA_R = 'd0;
  32. assign SDA = SDA_link?SDA_R:1'b0/*Z*/;///实际应为z,为仿真方便设置为0
  33. always @(posedge clk_in)
  34. SDA_R <= sda_r;
  35. parameter [10:0]IDLE = 11'b000_0000_0001;
  36. parameter [10:0]STRAT = 11'b000_0000_0010;
  37. parameter [10:0]ADDR0 = 11'b000_0000_0100;加载待发送地址
  38. parameter [10:0]ADDR1 = 11'b000_0000_1000;/发送地址
  39. parameter [10:0]ADDR2 = 11'b000_0001_0000;/保持地址
  40. parameter [10:0]ACK1 = 11'b000_0010_0000;
  41. parameter [10:0]DATA0 = 11'b000_0100_0000;///加载待发送数据
  42. parameter [10:0]DATA1 = 11'b000_1000_0000;///发送数据
  43. parameter [10:0]ACK2 = 11'b001_0000_0000;///应答
  44. parameter [10:0]STOP = 11'b010_0000_0000;
  45. parameter [10:0]DONE = 11'b100_0000_0000;
  46. //parameter [11:0]DATA2 = 'b0001_0000_0000;///保持数据
  47. //parameter [11:0]ACK2 = 'b0010_0000_0000;
  48. //parameter [11:0]STOP = 'b0100_0000_0000;
  49. //parameter [11:0]DONE = 'b1000_0000_0000;
  50. reg [10:0]current_state = 'd0;
  51. reg [10:0]next_state = 'd0;
  52. 次态转移
  53. always @(posedge clk_50m or negedge rst_n)
  54. if(!rst_n)
  55. current_state <= IDLE;
  56. else
  57. current_state <= next_state;
  58. 状态跳变
  59. always @(*)
  60. case(current_state)
  61. IDLE: begin
  62. if(wr_en)
  63. next_state = STRAT;
  64. else
  65. next_state = IDLE;
  66. end
  67. STRAT: begin
  68. if(start)
  69. next_state = ADDR0;
  70. else
  71. next_state = STRAT;
  72. end
  73. ADDR0: begin
  74. if(i == 'd1)
  75. next_state = ADDR1;
  76. else
  77. next_state = ADDR0;
  78. end
  79. ADDR1: begin
  80. if(i == 'd16)
  81. next_state = ACK1;
  82. else if(i[0] == 'b0)//i为偶数
  83. next_state = ADDR2;
  84. else
  85. next_state = ADDR1;
  86. end
  87. ADDR2: begin
  88. if(i[0] == 'b1)
  89. next_state = ADDR1;
  90. else
  91. next_state = ADDR2;
  92. end
  93. ACK1: begin//ack1应答,同时将待发送的数据加载进移位寄存器
  94. if(i == 'd0)
  95. next_state = DATA0;
  96. else
  97. next_state = ACK1;
  98. end
  99. DATA0: begin
  100. if(i[0] == 'd1)
  101. next_state = DATA1;
  102. else
  103. next_state = DATA0;
  104. end
  105. DATA1: begin
  106. if(i == 'd16)
  107. next_state = ACK2;
  108. else if(i[0] == 'b0)
  109. next_state = DATA0;
  110. else
  111. next_state = DATA1;
  112. end
  113. ACK2: begin
  114. if(i == 'd0)
  115. next_state = STOP;
  116. else
  117. next_state = ACK2;
  118. end
  119. STOP: begin
  120. if(stop)
  121. next_state = DONE;
  122. else
  123. next_state = STOP;
  124. end
  125. DONE: begin
  126. if(done)
  127. next_state = IDLE;
  128. else
  129. next_state = DONE;
  130. end
  131. default: begin
  132. next_state = IDLE;
  133. end
  134. endcase
  135. //输出赋值
  136. always @(*)
  137. case(current_state)
  138. IDLE: begin
  139. load_a = 'd1;/SCl空闲时加载数据,初始化SCL
  140. en_a = 'd0;
  141. load_b = 'd0;///加载待发送地址
  142. en_b = 'd0;
  143. load_c = 'd1;///计数器加载数据
  144. en_c = 'd0;
  145. load_d = 'd0;///加载待发送地址
  146. en_d = 'd0;
  147. SDA_link = 'd1;//1时SDA为输出,0时为输入
  148. sad_load = 'd1;///sda_r空闲时加载数据,初始化SDA
  149. sda_en_addr = 'd0;//将地址赋值给sda_r
  150. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  151. sda_en_data = 'd0;//将数据赋值给sda_r
  152. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  153. start = 'd0;
  154. stop = 'd0;
  155. done = 'd0;
  156. ack1 = 'd0;
  157. ack2 = 'd0;
  158. end
  159. STRAT: begin
  160. load_a = 'd1;/SCl空闲时加载数据
  161. en_a = 'd0;
  162. load_b = 'd0;///加载待发送地址
  163. en_b = 'd0;
  164. load_c = 'd1;///计数器加载数据
  165. en_c = 'd0;
  166. load_d = 'd0;///加载待发送地址
  167. en_d = 'd0;
  168. SDA_link = 'd1;//1时SDA为输出,0时为输入
  169. sad_load = 'd1;///sda_r空闲时加载数据
  170. sda_en_addr = 'd0;//将地址赋值给sda_r
  171. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  172. sda_en_data = 'd0;//将数据赋值给sda_r
  173. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  174. start = 'd1;
  175. stop = 'd0;
  176. done = 'd0;
  177. ack1 = 'd0;
  178. ack2 = 'd0;
  179. end
  180. ADDR0: begin
  181. load_a = 'd0;/SCl空闲时加载数据
  182. en_a = 'd1;
  183. load_b = 'd1;///加载待发送地址
  184. en_b = 'd0;
  185. load_c = 'd0;///计数器加载数据
  186. en_c = 'd1;
  187. load_d = 'd0;///加载待发送地址
  188. en_d = 'd0;
  189. SDA_link = 'd1;//1时SDA为输出,0时为输入
  190. sad_load = 'd0;///sda_r空闲时加载数据
  191. sda_en_addr = 'd1;//将地址赋值给sda_r
  192. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  193. sda_en_data = 'd0;//将数据赋值给sda_r
  194. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  195. start = 'd0;
  196. stop = 'd0;
  197. done = 'd0;
  198. ack1 = 'd0;
  199. ack2 = 'd0;
  200. end
  201. ADDR1: begin
  202. load_a = 'd0;/SCl空闲时加载数据
  203. en_a = 'd1;/产生SCL
  204. load_b = 'd0;///加载待发送地址
  205. en_b = 'd1;///地址移位寄存器使能
  206. load_c = 'd0;///计数器加载数据
  207. en_c = 'd1;计数器计数
  208. load_d = 'd0;///加载待发送地址
  209. en_d = 'd0;
  210. SDA_link = 'd1;//1时SDA为输出,0时为输入
  211. sad_load = 'd0;///sda_r空闲时加载数据
  212. sda_en_addr = 'd1;//将地址赋值给sda_r
  213. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  214. sda_en_data = 'd0;//将数据赋值给sda_r
  215. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  216. start = 'd0;
  217. stop = 'd0;
  218. done = 'd0;
  219. ack1 = 'd0;
  220. ack2 = 'd0;
  221. end
  222. ADDR2: begin
  223. load_a = 'd0;/SCl空闲时加载数据
  224. en_a = 'd1;/产生SCL
  225. load_b = 'd0;///加载待发送地址
  226. en_b = 'd0;///地址移位寄存器使能
  227. load_c = 'd0;///计数器加载数据
  228. en_c = 'd1;计数器计数
  229. load_d = 'd0;///加载待发送地址
  230. en_d = 'd0;
  231. SDA_link = 'd1;//1时SDA为输出,0时为输入
  232. sad_load = 'd0;///sda_r空闲时加载数据
  233. sda_en_addr = 'd1;//将地址赋值给sda_r
  234. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  235. sda_en_data = 'd0;//将数据赋值给sda_r
  236. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  237. start = 'd0;
  238. stop = 'd0;
  239. done = 'd0;
  240. ack1 = 'd0;
  241. ack2 = 'd0;
  242. end
  243. ACK1: begin
  244. load_a = 'd0;/SCl空闲时加载数据
  245. en_a = 'd1;/产生SCL
  246. load_b = 'd0;///加载待发送地址
  247. en_b = 'd0;///地址移位寄存器使能
  248. load_c = 'd0;///计数器加载数据
  249. en_c = 'd1;计数器计数
  250. load_d = 'd1;///加载待发送数据
  251. en_d = 'd0;
  252. SDA_link = 'd0;//1时SDA为输出,0时为输入
  253. sad_load = 'd0;///sda_r空闲时加载数据
  254. sda_en_addr = 'd0;//将地址赋值给sda_r
  255. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  256. sda_en_data = 'd0;//将数据赋值给sda_r
  257. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  258. start = 'd0;
  259. stop = 'd0;
  260. done = 'd0;
  261. ack1 = !SDA;应答信号给ack1
  262. ack2 = 'd0;
  263. end
  264. DATA0: begin
  265. load_a = 'd0;/SCl空闲时加载数据
  266. en_a = 'd1;/产生SCL
  267. load_b = 'd0;///加载待发送地址
  268. en_b = 'd0;///地址移位寄存器使能
  269. load_c = 'd0;///计数器加载数据
  270. en_c = 'd1;计数器计数
  271. load_d = 'd0;///加载待发送数据
  272. en_d = 'd0;
  273. SDA_link = 'd1;//1时SDA为输出,0时为输入
  274. sad_load = 'd0;///sda_r空闲时加载数据
  275. sda_en_addr = 'd0;//将地址赋值给sda_r
  276. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  277. sda_en_data = 'd1;//将数据赋值给sda_r
  278. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  279. start = 'd0;
  280. stop = 'd0;
  281. done = 'd0;
  282. ack1 = 'd0;应答信号给ack1
  283. ack2 = 'd0;
  284. end
  285. DATA1: begin
  286. load_a = 'd0;/SCl空闲时加载数据
  287. en_a = 'd1;/产生SCL
  288. load_b = 'd0;///加载待发送地址
  289. en_b = 'd0;///地址移位寄存器使能
  290. load_c = 'd0;///计数器加载数据
  291. en_c = 'd1;计数器计数
  292. load_d = 'd0;///加载待发送数据
  293. en_d = 'd1;
  294. SDA_link = 'd1;//1时SDA为输出,0时为输入
  295. sad_load = 'd0;///sda_r空闲时加载数据
  296. sda_en_addr = 'd0;//将地址赋值给sda_r
  297. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  298. sda_en_data = 'd1;//将数据赋值给sda_r
  299. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  300. start = 'd0;
  301. stop = 'd0;
  302. done = 'd0;
  303. ack1 = 'd0;应答信号给ack1
  304. ack2 = 'd0;
  305. end
  306. ACK2: begin/应答后由于之后产生stop信号,所以此时应该就让SCL处于空闲状态;
  307. load_a = 'd1;/SCl空闲时加载数据
  308. en_a = 'd0;/产生SCL
  309. load_b = 'd0;///加载待发送地址
  310. en_b = 'd0;///地址移位寄存器使能
  311. load_c = 'd0;///计数器加载数据
  312. en_c = 'd1;计数器计数
  313. load_d = 'd0;///加载待发送数据
  314. en_d = 'd0;
  315. SDA_link = 'd0;//1时SDA为输出,0时为输入
  316. sad_load = 'd0;///sda_r空闲时加载数据
  317. sda_en_addr = 'd0;//将地址赋值给sda_r
  318. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  319. sda_en_data = 'd1;//将数据赋值给sda_r
  320. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  321. start = 'd0;
  322. stop = 'd0;
  323. done = 'd0;
  324. ack1 = 'd0;应答信号给ack1
  325. ack2 = !SDA;///应答信号给ack2
  326. end
  327. STOP: begin
  328. load_a = 'd1;/SCl空闲时加载数据
  329. en_a = 'd0;/产生SCL
  330. load_b = 'd0;///加载待发送地址
  331. en_b = 'd0;///地址移位寄存器使能
  332. load_c = 'd1;///计数器加载数据
  333. en_c = 'd0;计数器计数
  334. load_d = 'd0;///加载待发送数据
  335. en_d = 'd0;
  336. SDA_link = 'd1;//1时SDA为输出,0时为输入
  337. sad_load = 'd1;///sda_r空闲时加载数据
  338. sda_en_addr = 'd0;//将地址赋值给sda_r
  339. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  340. sda_en_data = 'd0;//将数据赋值给sda_r
  341. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  342. start = 'd0;
  343. stop = 'd1;
  344. done = 'd0;
  345. ack1 = 'd0;应答信号给ack1
  346. ack2 = 'd0;///应答信号给ack2
  347. end
  348. DONE: begin
  349. load_a = 'd1;/SCl空闲时加载数据
  350. en_a = 'd0;/产生SCL
  351. load_b = 'd0;///加载待发送地址
  352. en_b = 'd0;///地址移位寄存器使能
  353. load_c = 'd1;///计数器加载数据
  354. en_c = 'd0;计数器计数
  355. load_d = 'd0;///加载待发送数据
  356. en_d = 'd0;
  357. SDA_link = 'd1;//1时SDA为输出,0时为输入
  358. sad_load = 'd1;///sda_r空闲时加载数据
  359. sda_en_addr = 'd0;//将地址赋值给sda_r
  360. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  361. sda_en_data = 'd0;//将数据赋值给sda_r
  362. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  363. start = 'd0;
  364. stop = 'd0;
  365. done = 'd1;
  366. ack1 = 'd0;应答信号给ack1
  367. ack2 = 'd0;///应答信号给ack2
  368. end
  369. default: begin
  370. load_a = 'd1;/SCl空闲时加载数据
  371. en_a = 'd0;
  372. load_b = 'd0;///加载待发送地址
  373. en_b = 'd0;
  374. load_c = 'd1;///计数器加载数据
  375. en_c = 'd0;
  376. load_d = 'd0;///加载待发送地址
  377. en_d = 'd0;
  378. SDA_link = 'd1;//1时SDA为输出,0时为输入
  379. sad_load = 'd1;///sda_r空闲时加载数据
  380. sda_en_addr = 'd0;//将地址赋值给sda_r
  381. // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
  382. sda_en_data = 'd0;//将数据赋值给sda_r
  383. // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
  384. start = 'd0;
  385. stop = 'd0;
  386. done = 'd0;
  387. ack1 = 'd0;
  388. ack2 = 'd0;
  389. end
  390. endcase
  391. // Instantiate the module
  392. scl_generate scl_generate (
  393. .clk_50m(clk_50m),
  394. .load_a(load_a),
  395. .en_a(en_a),
  396. .scl(SCL)
  397. );
  398. // Instantiate the module
  399. ad_left_shifter ad_left_shifter (
  400. .clk_50m(clk_50m),
  401. .addr_in(addr_in),
  402. .load_b(load_b),
  403. .en_b(en_b),
  404. .addr_o(addr_o)
  405. );
  406. // Instantiate the module
  407. count_num count_num (
  408. .clk_50m(clk_50m),
  409. .load_c(load_c),
  410. .en_c(en_c),
  411. .count(i)
  412. );
  413. // Instantiate the module
  414. data_left_shifter data_left_shifter (
  415. .clk_50m(clk_50m),
  416. .data_in(data_in),
  417. .en_d(en_d),
  418. .load_d(load_d),
  419. .data_o(data_o)
  420. );
  421. // Instantiate the module
  422. SDA_strat_stop SDA_strat_stop (
  423. .clk_50m(clk_50m),
  424. .start(start),
  425. .stop(stop),
  426. .edge_detect(edge_detect)
  427. );
  428. // Instantiate the module
  429. sdar_signal sdar_signal (
  430. .clk_50m(clk_50m),
  431. .sad_load(sad_load),
  432. .start(start),
  433. .edge_detect(edge_detect),
  434. .sda_en_addr(sda_en_addr),
  435. .addr_o(addr_o),
  436. .sda_en_data(sda_en_data),
  437. .data_o(data_o),
  438. .stop(stop),
  439. .sda_r(sda_r)
  440. );
  441. endmodule

 scl_generate:用于产生SCL

  1. module scl_generate(input clk_50m,
  2. input load_a,
  3. input en_a,
  4. output reg scl
  5. );
  6. always @(posedge clk_50m)
  7. if(load_a)
  8. scl <= 'd1;
  9. else if(en_a)
  10. scl <= ~scl;
  11. else
  12. scl <= scl;
  13. endmodule

 ad_left_shifter:用于将并行的8位地址转换成串行的一位一位的发送出去

  1. module ad_left_shifter(input clk_50m,
  2. input [7:0]addr_in,
  3. input load_b,
  4. input en_b,
  5. output addr_o
  6. );
  7. reg [7:0]addr_reg = 'd0;
  8. always @(posedge clk_50m)
  9. if(load_b)
  10. addr_reg <= addr_in;
  11. else if(en_b=='b1)
  12. addr_reg <= {addr_reg[6:0],1'b0};
  13. else
  14. addr_reg <= addr_reg;
  15. assign addr_o = addr_reg[7];
  16. endmodule

 count_num:计数器,用于计数发送地址或者数据的个数

  1. module count_num(input clk_50m,
  2. input load_c,
  3. input en_c,
  4. output reg[4:0]count
  5. );
  6. always @(posedge clk_50m)
  7. if(load_c)
  8. count <= 'd0;
  9. else if(en_c) begin
  10. if(count == 'd17)
  11. count <= 'd0;
  12. else
  13. count <= count + 'd1;
  14. end
  15. else
  16. count <= count;
  17. endmodule

 data_left_shifter:用于将并行的8位数据转换成串行的一位一位的发送出去

  1. module data_left_shifter(input clk_50m,
  2. input [7:0]data_in,
  3. input en_d,
  4. input load_d,
  5. output data_o
  6. );
  7. reg [7:0]data_reg = 'd0;
  8. always @(posedge clk_50m)
  9. if(load_d)
  10. data_reg <= data_in;
  11. else if(en_d)
  12. data_reg <= {data_reg[6:0],1'b0};
  13. else
  14. data_reg <= data_reg;
  15. assign data_o = data_reg[7];
  16. endmodule

 SDA_strat_stop:用于生成起始信号和结束信号

  1. module SDA_strat_stop(input clk_50m,
  2. input start,
  3. input stop,
  4. output reg edge_detect = 'd0
  5. );
  6. always @(posedge clk_50m)
  7. case({stop,start})
  8. 2'b01: edge_detect <= 'd0;
  9. 2'b10: edge_detect <= 'd1;
  10. default: edge_detect <= 'd0;
  11. endcase
  12. endmodule

 sdar_signal:用于控制SDA发送的是地址信号、数据信号、开始信号还是结束信号

  1. module sdar_signal(input clk_50m,
  2. input sad_load,
  3. input start,
  4. input edge_detect,
  5. input sda_en_addr,
  6. input addr_o,
  7. input sda_en_data,
  8. input data_o,
  9. input stop,
  10. output reg sda_r
  11. );
  12. always @(*)
  13. if(sad_load)
  14. sda_r <= 'd1;
  15. else begin
  16. case({stop,sda_en_data,sda_en_addr,start})
  17. 4'b0001: sda_r <= edge_detect;
  18. 4'b0010: sda_r <= addr_o;
  19. 4'b0100: sda_r <= data_o;
  20. 4'b1000: sda_r <= edge_detect;
  21. default: sda_r <= 'd1;
  22. endcase
  23. end
  24. endmodule

 仿真激励文件:

  1. module tb;
  2. // Inputs
  3. reg clk_50m;
  4. reg clk_in;
  5. reg rst_n;
  6. reg wr_en;
  7. reg [7:0] addr_in;
  8. reg [7:0] data_in;
  9. // Outputs
  10. wire done;
  11. wire SCL;
  12. wire ack1;
  13. wire ack2;
  14. // Bidirs
  15. wire SDA;
  16. // Instantiate the Unit Under Test (UUT)
  17. I2C_MODULE uut (
  18. .clk_50m(clk_50m),
  19. .clk_in(clk_in),
  20. .rst_n(rst_n),
  21. .wr_en(wr_en),
  22. .addr_in(addr_in),
  23. .data_in(data_in),
  24. .done(done),
  25. .SDA(SDA),
  26. .SCL(SCL),
  27. .ack1(ack1),
  28. .ack2(ack2)
  29. );
  30. initial begin
  31. // Initialize Inputs
  32. clk_50m = 0;
  33. clk_in = 0;
  34. rst_n = 0;
  35. wr_en = 0;
  36. addr_in = 0;
  37. data_in = 0;
  38. // Wait 100 ns for global reset to finish
  39. #100;
  40. // Add stimulus here
  41. end
  42. always #10 clk_50m = ~clk_50m;
  43. always #5 clk_in = ~clk_in;
  44. ///rst_n
  45. reg [3:0] cnt = 'd0;
  46. always @(posedge clk_50m)
  47. if(cnt == 'd10)
  48. cnt <= 'd10;
  49. else
  50. cnt <= cnt + 'd1;
  51. always @(posedge clk_50m)
  52. if(cnt=='d10)
  53. rst_n <= 'd1;
  54. else
  55. rst_n <= 'd0;
  56. ///
  57. reg[4:0]count = 'd0;
  58. always @(posedge clk_50m)
  59. if(done)
  60. count <= 'd0;
  61. else if(count == 'd30)
  62. count <= 'd30;
  63. else
  64. count <= count + 'd1;
  65. always @(posedge clk_50m)
  66. if(count == 'd29)
  67. wr_en <= 'd1;
  68. else
  69. wr_en <= 'd0;
  70. always @(posedge clk_50m)
  71. if(count == 'd30) begin
  72. addr_in <= 8'b10101010;
  73. data_in <= 8'b10101010;
  74. end
  75. else begin
  76. addr_in <= 'd0;
  77. data_in <= 'd0;
  78. end
  79. //always @(posedge clk_50m)
  80. // if(ack1||ack2)
  81. // SDA <= 'd0;
  82. // else
  83. // SDA <= SDA;
  84. endmodule

 仿真波形:

 从图中可以看出:空闲时SCL和SDA均处于高电平;在SCL有效时,SDA由高变为低(开始信号)后开始进行数据的发送,数据只在SCL的低电平发生变化;在ack时,SCL为高时,SDA为低,表示从机发送应答信号,当数据发送完毕后,在SCL有效时,SDA由低变为高(结束信号),之后done信号拉高,表示IIC发送一次数据完毕。

 

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

闽ICP备14008679号