前言:接着上一篇的I2C写操作,今天要实现一个I2C的读操作。虽然在ADV7181B配置内部寄存器时没有必要使用到读操作,但是为了进一步确认寄存器是否在I2C写模块下被正确配置,这一步是必不可少的。

设计思路:由于最终的应用里I2C读模块在调试结束后还是要被剔除,因此决定还是另外建一个读的状态机独立于之前的写状态机。读状态机的思路基本和写状态机的思路一样,需要注意的是一次写操作需要两次的START信号和最后一字节传输结束后的NON-ACKNOWLEDGE。

改进和注意点:相比之前的写模块,读模块完善了以下这些

      (a)时钟信号在一系列写操作完毕之后拉高,不再跳变;

      (b)添加了使能信号,便于安排模块在写模块完成一些了写操作后才开始被激励工作;

      (c)三态口:修改了SDAT_R,使之在LINK为0,即三态口读方向时候SDAR_T保持1。以及LINK信号在空闲状态下释放总线;

未解决的问题:因为读写两个独立的模块各自用到一个三态口,即各自有一对I2C_SCLK和I2C_SDAT,因此在顶层就驱动同一个芯片的引脚之前,还需要一个复用的逻辑开关分时切换这两个驱动源。因为之前没有这样用多个三态口驱动一个同一个三态口,综合是否可行将在下一篇I2C测试里给出答案。p.s.当然如果整合两个状态机到同一个模块下就不存在这样的问题。

源码:

  1. `timescale ns / ps
  2. `define SIM
  3. `define SYS_CLK
  4. `define I2C_CLK
  5. `define I2C_DIV `SYS_CLK/`I2C_CLK
  6. `define ADV7180
  7. `define SCLK_CNT_WIDTH
  8. //version:v1.0
  9. //mend bug: WHEN IN IDLE SET SCLK HIGH;
  10. module i2c_read_controller(
  11. sys_clk,
  12. sys_rst_n,
  13. sys_rreq_i,
  14. sys_rd_en,
  15. rd_reg_addr_i,
  16. sys_data_o,
  17. i2c_rd_idle_o,
  18. i2c_rd_ack_o,
  19. i2c_sclk,
  20. i2c_sdat
  21. );
  22.  
  23. input sys_clk;
  24. input sys_rst_n;
  25. input sys_rreq_i;
  26. input sys_rd_en; //由其他信号激励使能
  27. input [:] rd_reg_addr_i; //从机寄存器地址
  28. output [:] sys_data_o; //待写的数据
  29. output i2c_rd_idle_o; //模块空闲
  30. output i2c_rd_ack_o; //非I2C的ACK,模块的ack
  31. output i2c_sclk;
  32. inout i2c_sdat;
  33. `ifdef ADV7180
  34. parameter DEVICE_READ = 'h40; //器件读操作地址
  35. parameter DEVICE_WRITE = 'h41; //器件写操作地址
  36. `endif
  37.  
  38. `ifdef SIM
  39. parameter ST_WIDTH = ;
  40. parameter IDLE = "IDLE...",
  41. START1 = "START1.",
  42. WR_SLAVE = "WR_SLAV",
  43. ACK1 = "ACK1...",
  44. SET_REG = "SET_REG",
  45. ACK2 = "ACK2...",
  46. START2 = "START2",
  47. RD_SLAVE = "RD_SLAV",
  48. ACK3 = "ACK3...",
  49. DATA = "DATA...",
  50. NACK4 = "NACK4..",
  51. STOP = "STOP...";
  52.  
  53. `else
  54. `define FSM
  55. parameter ST_WIDTH = ;
  56. parameter IDLE = `FSM'b0000_0000_0001,
  57. START1 = `FSM'b0000_0000_0010, //写操作一共有1个start,读操作一共2个start
  58. WR_SLAVE = `FSM'b0000_0000_0100,
  59. ACK1 = `FSM'b0000_0000_1000,
  60. SET_REG = `FSM'b0000_0001_0000,
  61. ACK2 = `FSM'b0000_0010_0000,
  62. START2 = `FSM'b0000_0100_0000,
  63. RD_SLAVE = `FSM'b0000_1000_0000,
  64. ACK3 = `FSM'b0001_0000_0000,
  65. DATA = `FSM'b0010_0000_0000,
  66. NACK4 = `FSM'b0100_0000_0000,
  67. STOP = `FSM'b1000_0000_0000;
  68. `endif
  69. //caputre the posedge of sys_rreq_i;
  70. reg sys_rreq_r0 = ;
  71. always @ (posedge sys_clk) begin
  72. if(sys_rst_n == 'b0) sys_rreq_r0 <= 0;
  73. else sys_rreq_r0 <= sys_rreq_i;
  74. end
  75. wire do_rreq = sys_rreq_i & ~sys_rreq_r0 & sys_rd_en;
  76. //generate the rd_start;
  77. reg rd_start = ;
  78. always @ (posedge sys_clk) begin
  79. if(sys_rst_n == 'b0) rd_start <= 0;
  80. else if(i2c_rd_ack_o == 'b1) rd_start <= 0;
  81. else if(do_rreq) rd_start <= ;
  82. else rd_start <= rd_start;
  83. end
  84. //GENERATE SCLK_R
  85. reg [`SCLK_CNT_WIDTH-:] sclk_cnt = ;
  86. always @ (posedge sys_clk) begin
  87. if('b0 == sys_rst_n) sclk_cnt <= 0;
  88. else if((sclk_cnt < `I2C_DIV-)&&(sys_rd_en == 'b1)&&(rd_start == 1'b1)) sclk_cnt <= sclk_cnt + 'd1;
  89. else sclk_cnt <= ;
  90. end
  91.  
  92. `define SCLK_POS (sclk_cnt == `SCLK_CNT_WIDTH'd499)
  93. `define SCLK_HIGH (sclk_cnt == `SCLK_CNT_WIDTH'd124)
  94. `define SCLK_NEG (sclk_cnt == `SCLK_CNT_WIDTH'd249)
  95. `define SCLK_LOW (sclk_cnt == `SCLK_CNT_WIDTH'd374)
  96. wire i2c_sclk_w;
  97. assign i2c_sclk_w = ((sys_rd_en == 'b1)&&(sclk_cnt <= `SCLK_CNT_WIDTH'd249))?'b1:1'b0;
  98.  
  99. //FSM
  100. reg [:] data2host = ;
  101. reg [:] sys_data_o = ;
  102. reg sdat_r = ;
  103. reg link = ; //控制三态口读写方向,默认为读方向0,写时为1
  104. reg [:] bit_cnt = 'd0;
  105. reg [ST_WIDTH-:] c_st = IDLE;
  106. reg [ST_WIDTH-:] n_st = IDLE;
  107. //FSM-1
  108. always @ (posedge sys_clk) begin
  109. if('b0 == sys_rst_n) c_st <= IDLE;
  110. else c_st <= n_st;
  111. end
  112. //fsm-2
  113. //实际的状态转移中ack[2:0]比物理等待的ack少四分之一
  114. always @ (*) begin
  115. n_st = IDLE;
  116. case(c_st)
  117. IDLE:begin
  118. n_st = (rd_start == 'b1)?START1:IDLE;end
  119. START1:begin
  120. n_st = (`SCLK_LOW)?WR_SLAVE:START1;end //sclk为高电平中心时转移
  121. WR_SLAVE:begin
  122. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
  123. ACK1:begin
  124. n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
  125. SET_REG:begin
  126. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK2:SET_REG;end//数据在低电平是更新
  127. ACK2:begin
  128. n_st = (`SCLK_NEG)?START2:ACK2;end
  129. START2:begin
  130. n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
  131. RD_SLAVE:begin
  132. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK3:RD_SLAVE;end
  133. //为保证下一步设置寄存器,提前1/4进入下一个状态
  134. ACK3:begin
  135. n_st = (`SCLK_NEG)?DATA:ACK3;end
  136. DATA:begin
  137. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?NACK4:DATA;end
  138. NACK4:begin
  139. n_st = (`SCLK_NEG)?STOP:NACK4;end
  140. STOP:begin
  141. n_st = (`SCLK_NEG)?IDLE:STOP;end
  142. default:begin
  143. n_st = IDLE;end
  144. endcase
  145. end
  146. //FSM-3
  147. always @ (posedge sys_clk) begin
  148. if(sys_rst_n == 'b0) begin
  149. link <= 'd0; //释放总线
  150. data2host <= 'd0;
  151. bit_cnt <= 'd0;
  152. sdat_r <= 'd1;
  153. sys_data_o <= ;
  154. end
  155. else begin
  156. case(c_st)
  157. IDLE:begin
  158. link <= 'd0;
  159. data2host <= DEVICE_WRITE;
  160. bit_cnt <= 'd0;
  161. sdat_r <= 'd1;
  162. sys_data_o <= sys_data_o;
  163. end
  164. START1:begin
  165. link <= 'd1;
  166. sys_data_o <= sys_data_o;
  167. bit_cnt <= 'd1;
  168. data2host <= (`SCLK_LOW)?data2host<<:data2host;
  169. if(`SCLK_HIGH) begin
  170. sdat_r <= 'b0;end
  171. else if(`SCLK_LOW) begin
  172. sdat_r <= data2host[];end //pull down,由于data2host缓存一级的缘故,需要提前在START里输出第MSB位
  173. else begin
  174. sdat_r <= sdat_r;end
  175. end
  176. WR_SLAVE:begin
  177. sys_data_o <= sys_data_o;
  178. if(`SCLK_LOW) begin
  179. link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
  180. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  181. data2host <= {data2host[:],'d0};//左移一位
  182. sdat_r <= (bit_cnt == 'd8)?1'd1:data2host[];end
  183. else begin
  184. link <= link;
  185. bit_cnt <= bit_cnt;
  186. data2host <= data2host;
  187. sdat_r <= sdat_r;end
  188. end
  189. ACK1:begin
  190. link <= 'd0;
  191. sys_data_o <= sys_data_o;
  192. data2host <= (`SCLK_POS)?rd_reg_addr_i:data2host; //读入待写的寄存器地址
  193. bit_cnt <= 'd0;
  194. sdat_r <= 'd1;
  195. end
  196. SET_REG:begin
  197. sys_data_o <= sys_data_o;
  198. if(`SCLK_LOW) begin
  199. link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
  200. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  201. data2host <= {data2host[:],'d0};//左移一位
  202. sdat_r <= (bit_cnt == 'd8)?1'd1:data2host[];end
  203. else begin
  204. link <= link;
  205. bit_cnt <= bit_cnt;
  206. data2host <= data2host;
  207. sdat_r <= sdat_r;end
  208. end
  209. ACK2:begin
  210. link <= 'd0;
  211. sys_data_o <= sys_data_o;
  212. data2host <= (`SCLK_POS)?DEVICE_READ:data2host; //读入待写的寄存器地址
  213. bit_cnt <= 'd0;
  214. sdat_r <= 'd1;
  215. end
  216. START2:begin
  217. link <= (`SCLK_LOW)?'b1:link;
  218. sys_data_o <= sys_data_o;
  219. data2host <= data2host;
  220. bit_cnt <= bit_cnt;
  221. sdat_r <= (`SCLK_HIGH)?'b0:sdat_r;
  222. end
  223. RD_SLAVE:begin
  224. sys_data_o <= sys_data_o;
  225. if(`SCLK_LOW) begin
  226. link <= (bit_cnt == 'd8)?1'b0:'b1;
  227. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  228. data2host <= {data2host[:],'d0};//左移一位
  229. sdat_r <= (bit_cnt == 'd8)?1'd1:data2host[];end
  230. else begin
  231. link <= link;
  232. bit_cnt <= bit_cnt;
  233. data2host <= data2host;
  234. sdat_r <= sdat_r;end
  235. end
  236. ACK3:begin
  237. link <= 'b0;
  238. bit_cnt <= 'd0;
  239. sys_data_o <= sys_data_o;
  240. data2host <= ;
  241. sdat_r <= 'd1;end
  242. DATA:begin
  243. sys_data_o <= sys_data_o;
  244. if(`SCLK_HIGH) begin
  245. link <= (bit_cnt == 'd8)?1'b1:'b0; //为主设备产生NACK准备
  246. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  247. data2host[:] <= data2host[:];//左移一位
  248. data2host[] <= sdat_r;end
  249. else begin
  250. link <= link;
  251. bit_cnt <= bit_cnt;
  252. data2host <= data2host;
  253. sdat_r <= sdat_r;end
  254. end
  255. NACK4:begin
  256. link <= 'd1;
  257. sdat_r <= 'd1;//预先拉低
  258. bit_cnt <= bit_cnt;
  259. sys_data_o <= data2host;end
  260. STOP:begin
  261. link <= 'b1;
  262. bit_cnt <= bit_cnt;
  263. sys_data_o <= sys_data_o;
  264. data2host <= data2host;
  265. if(`SCLK_LOW) begin
  266. sdat_r <= 'b0;end
  267. else if(`SCLK_HIGH) begin
  268. sdat_r <= 'b1;end
  269. else begin
  270. sdat_r <= sdat_r;end
  271. end
  272. default:begin
  273. link <= 'd0;
  274. data2host <= 'd0;
  275. sys_data_o <= sys_data_o;
  276. bit_cnt <= 'd0;
  277. sdat_r <= 'd1;
  278. end
  279. endcase
  280. end
  281. end
  282. //assign
  283. assign i2c_sdat = (link == 'b1)?sdat_r:8'hzz;
  284. assign i2c_rd_idle_o = (c_st == IDLE)?'b1:1'b0;
  285. assign i2c_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG))?'b1:1'b0;
  286. assign i2c_sclk = (c_st != IDLE)?i2c_sclk_w:'b1;
  287.  
  288. endmodule

控制读模块源码2:

  1. `timescale ns / ps
  2. `define LUT_WIDTH
  3. module adv7181_read_back(
  4. sys_clk,
  5. sys_rst_n,
  6. i2c_rd_ack_i,
  7. rd_back_done_o,
  8. sys_rreq_o,
  9. rd_reg_addr_o
  10. );
  11. input sys_clk;
  12. input sys_rst_n;
  13. input i2c_rd_ack_i;
  14. output rd_back_done_o;
  15. output sys_rreq_o;
  16. output [:] rd_reg_addr_o;
  17.  
  18. //generate rreq_o
  19. reg sys_rreq_o = ;
  20. reg [`LUT_WIDTH-:] lut_index = ;
  21. reg [:] lut_data = ;
  22. always @ (posedge sys_clk) begin
  23. if('b0 == sys_rst_n) begin
  24. sys_rreq_o <= ;
  25. lut_index <= ;end
  26. else if((i2c_rd_ack_i == 'b1)&&(rd_back_done_o == 1'b0)) begin
  27. sys_rreq_o <= ;
  28. lut_index <= lut_index + 'd1;end
  29. else begin
  30. sys_rreq_o <= ;
  31. lut_index <= lut_index;end
  32. end
  33. //assign
  34. assign rd_back_done_o = (lut_index == `LUT_WIDTH'd15)?1'b1:'b0;
  35. assign rd_reg_addr_o = lut_data;
  36. //lut
  37. always @ (*) begin
  38. case(lut_index)
  39. `LUT_WIDTH'd0:lut_data <= 8'h23;
  40. `LUT_WIDTH'd1:lut_data <= 8'h41;
  41. `LUT_WIDTH'd2:lut_data <= 8'hf2;
  42. `LUT_WIDTH'd3:lut_data <= 8'ha3;
  43. `LUT_WIDTH'd4:lut_data <= 8'h43;
  44. `LUT_WIDTH'd5:lut_data <= 8'h13;
  45. `LUT_WIDTH'd6:lut_data <= 8'h65;
  46. `LUT_WIDTH'd7:lut_data <= 8'h76;
  47. `LUT_WIDTH'd8:lut_data <= 8'h85;
  48. `LUT_WIDTH'd9:lut_data <= 8'h93;
  49. `LUT_WIDTH'd10:lut_data <= 8'h14;
  50. `LUT_WIDTH'd11:lut_data <= 8'h13;
  51. `LUT_WIDTH'd12:lut_data <= 8'h15;
  52. `LUT_WIDTH'd13:lut_data <= 8'h11;
  53. `LUT_WIDTH'd14:lut_data <= 8'h11;
  54. `LUT_WIDTH'd15:lut_data <= 8'h19;
  55. endcase
  56. end
  57.  
  58. endmodule

仿真源码3:

  1. `timescale ns / ps
  2. module tb_read();
  3. reg sys_clk;
  4. reg sys_rst_n;
  5.  
  6. initial begin
  7. sys_clk=;
  8. sys_rst_n=;
  9. # sys_rst_n=;
  10. end
  11.  
  12. always begin
  13. # sys_clk=~sys_clk;end
  14.  
  15. wire i2c_rd_ack;
  16. wire sys_rreq;
  17. wire [:] rd_reg_addr;
  18.  
  19. wire i2c_sclk;
  20. wire i2c_sdat;
  21. wire i2c_rd_idle;
  22. wire [:] sys_data_out;
  23. i2c_read_controller u0(
  24. .sys_clk( sys_clk ),
  25. .sys_rst_n( sys_rst_n ),
  26. .sys_rreq_i( sys_rreq ),
  27. .sys_rd_en( 'b1 ),
  28. .rd_reg_addr_i( rd_reg_addr ),
  29. .sys_data_o( sys_data_out ),
  30. .i2c_rd_idle_o( i2c_rd_idle ),
  31. .i2c_rd_ack_o( i2c_rd_ack ),
  32. .i2c_sclk( i2c_sclk ),
  33. .i2c_sdat( i2c_sdat )
  34. );
  35.  
  36. wire rd_back_done;
  37.  
  38. adv7181_read_back u1(
  39. .sys_clk( sys_clk ),
  40. .sys_rst_n( sys_rst_n ),
  41. .i2c_rd_ack_i( i2c_rd_ack ),
  42. .rd_back_done_o( rd_back_done ),
  43. .sys_rreq_o( sys_rreq ),
  44. .rd_reg_addr_o( rd_reg_addr )
  45. );
  46. endmodule

I2C控制器的Verilog建模之二的更多相关文章

  1. Norflash控制器的Verilog建模之二(仿真)

    前言:经过几天修改,norflash控制器基本已经完成,通过仿真.完整的norflash包含2个模块:直接操作硬件的norflash_ctrl.v与控制ctrl模块的驱动norflash_driver ...

  2. I2C控制器的Verilog建模之一

    前言:之前申请了ADI公司的一款ADV7181CBSTZ的视频解码芯片,正好原装DE2板子安的是同系列的ADV7181BBSTZ.虽然都是ADV7181的宗出,但是寄存器配置等等还是有些诧异,引脚也不 ...

  3. I2C控制器的Verilog建模之三(完结版)

    前言:终于到了测试篇,不过悲剧了一下.按照之前<二>里面的思路,在顶层用一个复用器驱动读写独立模块的I2C总线确实失败.虽然综合过去了,不过警告里已经说明:底层的2个原本是inout三态口 ...

  4. Norflash控制器的Verilog建模之一

    摘要:今天驱动一款SPANSION公司生产的norflash——S29AL032D70,没有别的参考资料,大致了解一下norflash的内部cmos电路架构以及其用途之后,直接看手册吧. 如何看手册: ...

  5. SDRAM控制器的Verilog建模之一

    前言:作为经典存储器的三剑客中的flash和sram已经建模测试过了,虽然现在都已经ddr2,ddr3,667MHZ.1333MHZ的天下了,但是接下这周来准备写一下sdram的controller. ...

  6. 异步SRAM控制器的Verilog建模

    前言:sram顾名思义静态随机存储器,分为asram异步型和ssram同步型.这里驱动DE2上一块ISSI公司的512KB的asram. 设计思路:因为实际应用中单字节读写效率不高,所以本设计中仿照s ...

  7. Norflash控制器的Verilog建模之三(測試)

    前言:回校了,辦好手續就著手寫測試篇.初步的norflash控制器已經完成,通過硬件測試.目前的norflash完成扇区块擦除.单字节写.单字节读3个功能.博文最后附上源码. 总结:和之前的博文一样, ...

  8. VGA逐行扫描控制器的Verilog建模

    前言:因为VGA是一种模拟图像传输数据接口,所要将数字信号用DAC转换成模拟量.本文用的一款ADI公司高精度的视频IC,实则一款高带宽的视频DAC.因为VGA时序较为简单,并且网上的VGA驱动基本大同 ...

  9. Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写

    "./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0内核中三星SoC的i2c控制器驱动程序, 本文试图通过对这个程序的分析, 剥离繁复的细节, 总 ...

随机推荐

  1. Hibernate 映射关系

    映射组成关系 •建立域模型和关系数据模型有着不同的出发点: –域模型: 由程序代码组成, 通过细化持久化类的的粒度可提高代码的可重用性, 简化编程 –在没有数据冗余的情况下, 应该尽可能减少表的数目, ...

  2. CentOS6.4安装Hadoop2.0.5 alpha - Single Node Cluster

    1.安装JDK7 rpm到/usr/java/jdk1.7.0_40,并建立软链接/usr/java/default到/usr/java/jdk1.7.0_40 [root@server-308 ~] ...

  3. MJRefresh的一个注意事项

    如果从视图一跳转到视图二之后,在视图二中进行MJRefresh的刷新操作,那么在推出试图二之前要用dealloc函数将MJRefreshHeaderView或者MJRefreshFooterView释 ...

  4. MyJni撒旦

    package com.baidu.jnitest; import android.os.Bundle; import android.app.Activity; import android.vie ...

  5. Android_Layout (一)

    layout (布局)  --->Android 有五大布局,分别是: LinearLayout : 线性布局,子组件按照垂直或者水平方向来布局. RelativeLayout :相对布局,按照 ...

  6. QT下调用摄像头(opencv2.4.4)

    http://www.cnblogs.com/yuliyang/p/3525107.html 项目pro文件: #------------------------------------------- ...

  7. Using python to process Big Data

    Pandas is a great lib to process BIg Data. 1) pandas.pivot_table(data,values=None,columns=None,aggfu ...

  8. kinnect相关

    1. kinnect的现状. http://tech.qq.com/a/20150909/046760.htm 2. kinnect的相关工作 http://baike.baidu.com/link? ...

  9. js创建对象的6种方式

    一.工厂模式 function createStudent(name,age){ var o=new Object(); o.name=name; o.age=age; o.myName=functi ...

  10. Map/Reduce 工作机制分析 --- 数据的流向分析

    前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议. 接下来,数据被会被送往一个个Map节点中去,这也无异议. 下面问题来了:数据在被Map节点处理完后,再何去何从呢? ...