前言:终于到了测试篇,不过悲剧了一下。按照之前《二》里面的思路,在顶层用一个复用器驱动读写独立模块的I2C总线确实失败。虽然综合过去了,不过警告里已经说明:底层的2个原本是inout三态口的数据线在顶层复用时候被综合成wire,这样在默认情况下顶层的inout总是输出有效,失去了三态口的作用。囧,看来为了测试I2C的写还是得把读模块并进去可避免这一尴尬……

测试:DE2+Questasim10.0c+Q2_9.1;

日期:2013七夕夜

结果:以下2张图为仿真波形图与逻辑分析仪采样的时序波形图。之前还踩不到ACK信号,因为宏定义里读写器件的地址弄饭了。(若这里程序与之前的《一》《二》有出路须以此篇修改之后为准)。对比可知基本上二者相同,也踩到从器件的相应。不过有个问题,在响应的一个完整时钟周期里的后四分之一变成高电平,也就是说一个ACK仅仅保持了四分之三的低电平,这个是不是应该算正常?如果从数据有效来看,时钟高电平保持了ACK一直为低电平,似乎是对的。

解决:出现这样目前只好等读模块嵌入,如果能读出正确写入的数据,那么说明是正常的。

last update:因为其他时间耽搁了,断断续续终于今天整理完毕。仿真和硬件均测试通过。最后附出仿真文件、建模源码以及tcl脚本。

总结:IIC中从机响应脉冲宽度并未填满一整个周期,这也是之前图里的疑问。如何分辨正确:仅记ack和nack在时钟上升沿改变在时钟下降沿即可改变;不同器件数据变化时间时刻不一样,如果移植到不同器件测试得到不用stp2也无需惊讶,抓住根本的就行;

源码1:iic读写控制器

  1. `timescale ns / ps
  2. `define SIM
  3. `define SYS_CLK
  4. `define IIC_CLK
  5. `define IIC_CLK_DIV `SYS_CLK/`IIC_CLK
  6. `define ADV7181B
  7. `define SCLK_CNT_WIDTH
  8. //VERSION:V0.0
  9. module iic_ctrl(
  10. //common
  11. sys_clk,
  12. sys_rst_n,
  13. iic_sclk,
  14. iic_sdat,
  15. //read
  16. rreq_i,
  17. iic_rd_addr_i,
  18. rd_en_i,
  19. iic_rd_ack_o,
  20. sys_byte_o,
  21. //write
  22. wreq_i,
  23. wr_en_i,
  24. iic_wr_addr_i,
  25. sys_byte_i,
  26. iic_wr_ack_o
  27. );
  28. //common port
  29. input sys_clk; //global clk in
  30. input sys_rst_n; //global rst_n in
  31. output iic_sclk; //iic sclk
  32. inout iic_sdat; //iic sdat
  33. //read port
  34. input rreq_i; //read requast in
  35. input [:] iic_rd_addr_i; //read register address in
  36. input rd_en_i; //read enable in
  37. output iic_rd_ack_o; //module read ack
  38. output [:] sys_byte_o; //read byte out
  39. //write port
  40. input wreq_i; //write request in
  41. input wr_en_i; //write enable in
  42. input [:] iic_wr_addr_i; //write register address in
  43. input [:] sys_byte_i; //byte to be written
  44. output iic_wr_ack_o; //module write ack
  45. //macro
  46. `ifdef ADV7181B
  47. parameter DEVICE_READ = 'h41; //器件读操作地址
  48. parameter DEVICE_WRITE = 'h40; //器件写操作地址
  49. `endif
  50. //marcro
  51. `ifdef SIM
  52. parameter ST_WIDTH = ;
  53. parameter IDLE = "IDLE...",
  54. START1 = "START1.",
  55. WR_SLAVE = "WR_SLAV",
  56. ACK1 = "ACK1...",
  57. SET_REG = "SET_REG",
  58. ACK2 = "ACK2...",
  59. WR_DATA = "WR_DATA",
  60. ACK3 = "ACK3...",
  61. STOP = "STOP...";
  62. parameter START2 = "START2.",
  63. RD_SLAVE = "RD_SLAV",
  64. ACK4 = "ACK4...",
  65. RD_DATA = "RD_DATA",
  66. NACK = "NACK...";
  67.  
  68. `else
  69. `define FSM
  70. parameter ST_WIDTH = ;
  71. parameter IDLE = `FSM'b00_0000_0000_0001,
  72. START1 = `FSM'b00_0000_0000_0010, //写操作一共有1个start,读操作一共2个start
  73. WR_SLAVE = `FSM'b00_0000_0000_0100,
  74. ACK1 = `FSM'b00_0000_0000_1000,
  75. SET_REG = `FSM'b00_0000_0001_0000,
  76. ACK2 = `FSM'b00_0000_0010_0000,
  77. WR_DATA = `FSM'b00_0000_0100_0000,
  78. ACK3 = `FSM'b00_0000_1000_0000,
  79. STOP = `FSM'b00_0001_0000_0000;
  80. parameter START2 = `FSM'b00_0010_0000_0000,
  81. RD_SLAVE = `FSM'b00_0100_0000_0000,
  82. ACK4 = `FSM'b00_1000_0000_0000,
  83. RD_DATA = `FSM'b01_0000_0000_0001,
  84. NACK = `FSM'b10_0000_0000_0001;
  85. `endif
  86. //caputre the posedge of rreq_i;
  87. reg rreq_r0 = ;
  88. always @ (posedge sys_clk) begin
  89. if(sys_rst_n == 'b0) rreq_r0 <= 0;
  90. else rreq_r0 <= rreq_i;
  91. end
  92. wire do_rreq = rreq_i & ~rreq_r0 & rd_en_i;
  93. //generate the rd_start;
  94. reg rd_start = ;
  95. always @ (posedge sys_clk) begin
  96. if(sys_rst_n == 'b0) rd_start <= 0;
  97. else if(iic_rd_ack_o == 'b1) rd_start <= 0;
  98. else if(do_rreq) rd_start <= ;
  99. else rd_start <= rd_start;
  100. end
  101. //caputre the posedge of wreq_i;
  102. reg wreq_r0 = ;
  103. always @ (posedge sys_clk) begin
  104. if(sys_rst_n == 'b0) wreq_r0 <= 0;
  105. else wreq_r0 <= wreq_i;
  106. end
  107. wire do_wreq = wreq_i & ~wreq_r0 & wr_en_i;
  108. //generate the wr_start;
  109. reg wr_start = ;
  110. always @ (posedge sys_clk) begin
  111. if(sys_rst_n == 'b0) wr_start <= 0;
  112. else if(iic_wr_ack_o == 'b1) wr_start <= 0;
  113. else if(do_wreq) wr_start <= ;
  114. else wr_start <= wr_start;
  115. end
  116. //GENERATE SCLK
  117. reg [`SCLK_CNT_WIDTH-:] sclk_cnt = ;
  118. wire sclk_cnt_en1 = ((sclk_cnt < `IIC_CLK_DIV-)&&(wr_en_i == 'b1)&&(wr_start == 1'b1))?'b1:1'b0;
  119. wire sclk_cnt_en2 = ((sclk_cnt < `IIC_CLK_DIV-)&&(rd_en_i == 'b1)&&(rd_start == 1'b1))?'b1:1'b0;
  120. always @ (posedge sys_clk) begin
  121. if('b0 == sys_rst_n) sclk_cnt <= 0;
  122. else if(sclk_cnt_en1 | sclk_cnt_en2) sclk_cnt <= sclk_cnt + 'd1;
  123. else sclk_cnt <= ;
  124. end
  125. //时间片
  126. `define SCLK_POS (sclk_cnt == `SCLK_CNT_WIDTH'd499)
  127. `define SCLK_HIGH (sclk_cnt == `SCLK_CNT_WIDTH'd124)
  128. `define SCLK_NEG (sclk_cnt == `SCLK_CNT_WIDTH'd249)
  129. `define SCLK_LOW (sclk_cnt == `SCLK_CNT_WIDTH'd374)
  130. //内部i2c串行时钟
  131. wire iic_sclk_w = ((sclk_cnt <= `SCLK_CNT_WIDTH'd249)&&(rd_en_i | wr_en_i))?1'b1:'b0;
  132. //fsm registers
  133. reg [:] iic_byte = ;
  134. reg [:] sys_byte_o = ;
  135. reg sdat_r = ;
  136. reg link = ; //read:0
  137. reg [:] bit_cnt = ;
  138. reg [ST_WIDTH-:] c_st = IDLE;
  139. reg [ST_WIDTH-:] n_st = IDLE;
  140. //FSM-1
  141. always @ (posedge sys_clk) begin
  142. if('b0 == sys_rst_n) c_st <= IDLE;
  143. else c_st <= n_st;
  144. end
  145. //FSM-2,实际的状态转移中ack[2:0]比物理等待的ack少四分之一
  146. always @ (*) begin
  147. n_st = IDLE;
  148. case(c_st)
  149. IDLE:begin
  150. n_st = ((wr_start == 'b1)||(rd_start == 1'b1))?START1:IDLE;end
  151. START1:begin
  152. n_st = (`SCLK_LOW)?WR_SLAVE:START1;end //sclk为高电平中心时转移
  153. WR_SLAVE:begin
  154. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
  155. ACK1:begin
  156. n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
  157. SET_REG:begin
  158. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK2:SET_REG;end//数据在低电平是更新
  159. ACK2:begin
  160. if(`SCLK_NEG) begin
  161. n_st = (wr_start == 'b1)?WR_DATA:START2;end
  162. else begin
  163. n_st = ACK2;end
  164. end//为保证下一步设置寄存器,提前1/4进入下一个状态
  165. WR_DATA:begin
  166. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK3:WR_DATA;end
  167. ACK3:begin
  168. n_st = (`SCLK_NEG)?STOP:ACK3;end
  169. STOP:begin
  170. n_st = (`SCLK_NEG)?IDLE:STOP;end
  171. START2:begin
  172. n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
  173. RD_SLAVE:begin
  174. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK4:RD_SLAVE;end
  175. ACK4:begin
  176. n_st = (`SCLK_NEG)?RD_DATA:ACK4;end
  177. RD_DATA:begin
  178. n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?NACK:RD_DATA;end
  179. NACK:begin
  180. n_st = (`SCLK_NEG)?STOP:NACK;end
  181. default:begin
  182. n_st = IDLE;end
  183. endcase
  184. end
  185. //FSM-3
  186. always @ (posedge sys_clk) begin
  187. if(sys_rst_n == 'b0) begin
  188. link <= 'd0;
  189. iic_byte <= ;
  190. sys_byte_o <= sys_byte_o; //保持
  191. bit_cnt <= 'd0;
  192. sdat_r <= 'd1;
  193. end
  194. else begin
  195. case(c_st)
  196. IDLE:begin
  197. link <= 'd0;
  198. sys_byte_o <= sys_byte_o;
  199. iic_byte <= DEVICE_WRITE;
  200. bit_cnt <= 'd0;
  201. sdat_r <= 'd1;
  202. end
  203. START1:begin
  204. link <= 'd1;
  205. bit_cnt <= 'd1;
  206. sys_byte_o <= sys_byte_o;
  207. iic_byte <= (`SCLK_LOW)?iic_byte<<:iic_byte;
  208. if(`SCLK_HIGH) begin
  209. sdat_r <= 'b0;end
  210. else if(`SCLK_LOW) begin
  211. sdat_r <= iic_byte[];end //pull down,由于i2c_byte缓存一级的缘故,需要提前在START里输出第MSB位
  212. else begin
  213. sdat_r <= sdat_r;end
  214. end
  215. WR_SLAVE:begin
  216. sys_byte_o <= sys_byte_o;
  217. if(`SCLK_LOW) begin
  218. link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
  219. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  220. iic_byte <= {iic_byte[:],'d0};//左移一位
  221. sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
  222. else begin
  223. link <= link;
  224. bit_cnt <= bit_cnt;
  225. iic_byte <= iic_byte;
  226. sdat_r <= sdat_r;end
  227. end
  228. ACK1:begin
  229. link <= 'd0;
  230. sys_byte_o <= sys_byte_o;
  231. if(`SCLK_POS) begin
  232. iic_byte <= (wr_start=='b1)?iic_wr_addr_i:iic_rd_addr_i;end
  233. else begin
  234. iic_byte <= iic_byte;end //读入待写的寄存器地址
  235. bit_cnt <= 'd0;
  236. sdat_r <= 'd1;
  237. end
  238. SET_REG:begin
  239. sys_byte_o <= sys_byte_o;
  240. if(`SCLK_LOW) begin
  241. link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
  242. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  243. iic_byte <= {iic_byte[:],'d0};//左移一位
  244. sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
  245. else begin
  246. link <= link;
  247. bit_cnt <= bit_cnt;
  248. iic_byte <= iic_byte;
  249. sdat_r <= sdat_r;end
  250. end
  251. ACK2:begin
  252. link <= 'd0;
  253. bit_cnt <= 'd0;
  254. sdat_r <= 'd1;
  255. sys_byte_o <= sys_byte_o;
  256. if(`SCLK_POS) begin
  257. iic_byte <= (wr_start)?sys_byte_i:DEVICE_READ;end //读入待写的寄存器地址
  258. else begin
  259. iic_byte <= iic_byte;end
  260. end
  261. WR_DATA:begin
  262. sys_byte_o <= sys_byte_o;
  263. if(`SCLK_LOW) begin
  264. link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
  265. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  266. iic_byte <= {iic_byte[:],'d0};//左移一位
  267. sdat_r <= iic_byte[];end
  268. else begin
  269. link <= link;
  270. bit_cnt <= bit_cnt;
  271. iic_byte <= iic_byte;
  272. sdat_r <= sdat_r;end
  273. end
  274. ACK3:begin
  275. sys_byte_o <= sys_byte_o;
  276. link <= 'd0;
  277. sdat_r <= 'd0;//预先拉低
  278. bit_cnt <= bit_cnt;
  279. iic_byte <= iic_byte;end
  280. STOP:begin
  281. sys_byte_o <= sys_byte_o;
  282. link <= (`SCLK_LOW)?'b1:link;
  283. bit_cnt <= bit_cnt;
  284. iic_byte <= iic_byte;
  285. if(`SCLK_LOW) begin
  286. sdat_r <= 'b0;end
  287. else if(`SCLK_HIGH) begin
  288. sdat_r <= 'b1;end
  289. else begin
  290. sdat_r <= sdat_r;end
  291. end
  292. START2:begin
  293. link <= (`SCLK_LOW)?'b1:link;
  294. sys_byte_o <= sys_byte_o;
  295. iic_byte <= iic_byte;
  296. bit_cnt <= bit_cnt;
  297. sdat_r <= (`SCLK_HIGH)?'b0:sdat_r;
  298. end
  299. RD_SLAVE:begin
  300. sys_byte_o <= sys_byte_o;
  301. if(`SCLK_LOW) begin
  302. link <= (bit_cnt == 'd8)?1'b0:'b1;
  303. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  304. iic_byte <= {iic_byte[:],'d0};//左移一位
  305. sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
  306. else begin
  307. link <= link;
  308. bit_cnt <= bit_cnt;
  309. iic_byte <= iic_byte;
  310. sdat_r <= sdat_r;end
  311. end
  312. ACK4:begin
  313. link <= 'b0;
  314. bit_cnt <= 'd0;
  315. sys_byte_o <= sys_byte_o;
  316. iic_byte <= ;
  317. sdat_r <= 'd1;end
  318. RD_DATA:begin
  319. sys_byte_o <= sys_byte_o;
  320. if(`SCLK_POS) begin
  321. link <= (bit_cnt == 'd8)?1'b1:'b0; //为主设备产生NACK准备
  322. bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
  323. iic_byte[:] <= iic_byte[:];//左移一位
  324. iic_byte[] <= iic_sdat;end
  325. else begin
  326. link <= link;
  327. bit_cnt <= bit_cnt;
  328. iic_byte <= iic_byte;
  329. sdat_r <= sdat_r;end
  330. end
  331. NACK:begin
  332. link <= 'd1;
  333. sdat_r <= 'd1;//预先拉低
  334. bit_cnt <= bit_cnt;
  335. iic_byte <= iic_byte;
  336. sys_byte_o <= iic_byte;end
  337. default:begin
  338. link <= 'd0;
  339. iic_byte <= 'd0;
  340. bit_cnt <= 'd0;
  341. sdat_r <= 'd1;
  342. sys_byte_o <= sys_byte_o;
  343. end
  344. endcase
  345. end
  346. end
  347. //assign
  348. assign iic_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(rd_start))?'b1:1'b0;
  349. assign iic_sclk = (c_st != IDLE)?iic_sclk_w:'b1;
  350. assign iic_sdat = (link == 'b1)?sdat_r:1'bz;
  351. assign iic_wr_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(wr_start))?'b1:1'b0;
  352.  
  353. endmodule

源码2:写iic的寄存器地址和数据,移植不同器件更改这部分查找表内容

  1. `timescale ns / ps
  2. `define LUT_WIDTH
  3. module wr_config(
  4. sys_clk,
  5. sys_rst_n,
  6. iic_wr_ack_i,
  7. wreq_o,
  8. sys_byte_o,
  9. iic_wr_addr_o,
  10. wr_config_done_o
  11. );
  12. input sys_clk;
  13. input sys_rst_n;
  14. input iic_wr_ack_i;
  15. output wreq_o;
  16. output [:] sys_byte_o;
  17. output [:] iic_wr_addr_o;
  18. output wr_config_done_o;
  19.  
  20. //generate wreq_o
  21. reg wreq_o = ;
  22. reg [`LUT_WIDTH-:] lut_index = ;
  23. reg [:] lut_data = ;
  24. always @ (posedge sys_clk) begin
  25. if('b0 == sys_rst_n) begin
  26. wreq_o <= ;
  27. lut_index <= ;end
  28. else if((iic_wr_ack_i == 'b1)&&(wr_config_done_o == 1'b0)) begin
  29. wreq_o <= ;
  30. lut_index <= lut_index + 'd1;end
  31. else begin
  32. wreq_o <= ;
  33. lut_index <= lut_index;end
  34. end
  35.  
  36. //generate done
  37. reg wr_config_done_o = ;
  38. always @ (posedge sys_clk) begin
  39. if(sys_rst_n == 'b0) wr_config_done_o <= 0;
  40. else if((lut_index == 'd34) && (iic_wr_ack_i == 1'b1)) wr_config_done_o <= ;
  41. else wr_config_done_o <= wr_config_done_o;
  42. end
  43.  
  44. //assign
  45. assign sys_byte_o = lut_data[:];
  46. assign iic_wr_addr_o = lut_data[:];
  47. //lut
  48. always @ (*) begin
  49. case(lut_index)
  50. `LUT_WIDTH'd0:lut_data <= 16'h0080;
  51. `LUT_WIDTH'd1:lut_data <= 16'h0701;
  52. `LUT_WIDTH'd2:lut_data <= 16'h1500;
  53. `LUT_WIDTH'd3:lut_data <= 16'h1741;
  54. `LUT_WIDTH'd4:lut_data <= 16'h19FA;
  55. `LUT_WIDTH'd5:lut_data <= 16'h1D40;
  56. `LUT_WIDTH'd6:lut_data <= 16'h0F40;
  57. `LUT_WIDTH'd7:lut_data <= 16'h3A16;
  58. `LUT_WIDTH'd8:lut_data <= 16'h3DC3;
  59. `LUT_WIDTH'd9:lut_data <= 16'h3FE4;
  60. `LUT_WIDTH'd10:lut_data <= 16'h500A;
  61. `LUT_WIDTH'd11:lut_data <= 16'hC309;
  62. `LUT_WIDTH'd12:lut_data <= 16'hC480;
  63. `LUT_WIDTH'd13:lut_data <= 16'h0E80;
  64. `LUT_WIDTH'd14:lut_data <= 16'h5020;
  65. `LUT_WIDTH'd15:lut_data <= 16'h5218;
  66. `LUT_WIDTH'd16:lut_data <= 16'h58ED;
  67. `LUT_WIDTH'd17:lut_data <= 16'h77C5;
  68. `LUT_WIDTH'd18:lut_data <= 16'h7C93;
  69. `LUT_WIDTH'd19:lut_data <= 16'h7D00;
  70. `LUT_WIDTH'd20:lut_data <= 16'h90C9;
  71. `LUT_WIDTH'd21:lut_data <= 16'h9140;
  72. `LUT_WIDTH'd22:lut_data <= 16'h923C;
  73. `LUT_WIDTH'd23:lut_data <= 16'h93CA;
  74. `LUT_WIDTH'd24:lut_data <= 16'h94D5;
  75. `LUT_WIDTH'd25:lut_data <= 16'hCF50;
  76. `LUT_WIDTH'd26:lut_data <= 16'hD04E;
  77. `LUT_WIDTH'd27:lut_data <= 16'hD6DD;
  78. `LUT_WIDTH'd28:lut_data <= 16'hE551;
  79. `LUT_WIDTH'd29:lut_data <= 16'hD5A0;
  80. `LUT_WIDTH'd30:lut_data <= 16'hD7EA;
  81. `LUT_WIDTH'd31:lut_data <= 16'hE43E;
  82. `LUT_WIDTH'd32:lut_data <= 16'hE93E;
  83. `LUT_WIDTH'd33:lut_data <= 16'hEA0F;
  84. `LUT_WIDTH'd34:lut_data <= 16'h0E00;
  85. default:lut_data <= 'h0080;
  86. endcase
  87. end
  88. endmodule

源码3:读回写入寄存器内容

  1. `timescale ns / ps
  2. `define LUT_WIDTH
  3. module rd_check(
  4. sys_clk,
  5. sys_rst_n,
  6. key_n,
  7. rreq_o,
  8. iic_rd_addr_o
  9. );
  10. input sys_clk;
  11. input sys_rst_n;
  12. input key_n;
  13. output rreq_o;
  14. output [:] iic_rd_addr_o;
  15.  
  16. //capture the negedge of key_n;
  17. reg key_n_r0 = ;
  18. always @ (posedge sys_clk) begin
  19. if('b0 == sys_rst_n) key_n_r0 <= 1;
  20. else key_n_r0 <= key_n;
  21. end
  22. wire key_neg = ~key_n & key_n_r0;
  23. //generate the rreq_o
  24. reg rreq_o = ;
  25. always @ (posedge sys_clk) begin
  26. if('b0 == sys_rst_n) rreq_o <= 0;
  27. else if(key_neg) rreq_o <= ;
  28. else rreq_o <= ;
  29. end
  30.  
  31. //generate the iic_rd_addr_o
  32. reg [:] lut_index = ;
  33. reg [:] lut_data = ;
  34. always @ (posedge sys_clk) begin
  35. if('b0 == sys_rst_n) lut_index <= 0;
  36. else if(lut_index == `LUT_WIDTH'd35) lut_index <= 0;
  37. else if(key_neg) lut_index <= lut_index + 'd1;
  38. else lut_index <= lut_index;
  39. end
  40.  
  41. always @ (*) begin
  42. case(lut_index)
  43. `LUT_WIDTH'd0:lut_data <= 8'hFF; //offset no meaning
  44. `LUT_WIDTH'd1:lut_data <= 8'h00;
  45. `LUT_WIDTH'd2:lut_data <= 8'h07;
  46. `LUT_WIDTH'd3:lut_data <= 8'h15;
  47. `LUT_WIDTH'd4:lut_data <= 8'h17;
  48. `LUT_WIDTH'd5:lut_data <= 8'h19;
  49. `LUT_WIDTH'd6:lut_data <= 8'h1D;
  50. `LUT_WIDTH'd7:lut_data <= 8'h0F;
  51. `LUT_WIDTH'd8:lut_data <= 8'h3A;
  52. `LUT_WIDTH'd9:lut_data <= 8'h3D;
  53. `LUT_WIDTH'd10:lut_data <= 8'h3F;
  54. `LUT_WIDTH'd11:lut_data <= 8'h50;
  55. `LUT_WIDTH'd12:lut_data <= 8'hC3;
  56. `LUT_WIDTH'd13:lut_data <= 8'hC4;
  57. `LUT_WIDTH'd14:lut_data <= 8'h0E;
  58. `LUT_WIDTH'd15:lut_data <= 8'h50;
  59. `LUT_WIDTH'd16:lut_data <= 8'h52;
  60. `LUT_WIDTH'd17:lut_data <= 8'h58;
  61. `LUT_WIDTH'd18:lut_data <= 8'h77;
  62. `LUT_WIDTH'd19:lut_data <= 8'h7C;
  63. `LUT_WIDTH'd20:lut_data <= 8'h7D;
  64. `LUT_WIDTH'd21:lut_data <= 8'h90;
  65. `LUT_WIDTH'd22:lut_data <= 8'h91;
  66. `LUT_WIDTH'd23:lut_data <= 8'h92;
  67. `LUT_WIDTH'd24:lut_data <= 8'h93;
  68. `LUT_WIDTH'd25:lut_data <= 8'h94;
  69. `LUT_WIDTH'd26:lut_data <= 8'hCF;
  70. `LUT_WIDTH'd27:lut_data <= 8'hD0;
  71. `LUT_WIDTH'd28:lut_data <= 8'hD6;
  72. `LUT_WIDTH'd29:lut_data <= 8'hE5;
  73. `LUT_WIDTH'd30:lut_data <= 8'hD5;
  74. `LUT_WIDTH'd31:lut_data <= 8'hD7;
  75. `LUT_WIDTH'd32:lut_data <= 8'hE4;
  76. `LUT_WIDTH'd33:lut_data <= 8'hE9;
  77. `LUT_WIDTH'd34:lut_data <= 8'hEA;
  78. `LUT_WIDTH'd35:lut_data <= 8'h0E;
  79. default:lut_data <= 'h00;
  80. endcase
  81. end
  82. //assign
  83. assign iic_rd_addr_o = lut_data;
  84.  
  85. endmodule

源码4:顶层例化文件

  1. `timescale ns / ps
  2. module iic_driver(
  3. sys_clk,
  4. sys_rst_n,
  5. iic_sclk,
  6. iic_sdat,
  7. //for test
  8. key_n
  9. );
  10. input sys_clk;
  11. input sys_rst_n;
  12. input key_n;
  13. output iic_sclk;
  14. inout iic_sdat;
  15.  
  16. wire wreq;
  17. wire rreq;
  18.  
  19. wire iic_wr_ack;
  20. wire iic_rd_ack;
  21.  
  22. wire [:] sys_data_o;
  23. wire [:] sys_data_i;
  24.  
  25. wire [:] iic_wr_addr;
  26. wire [:] iic_rd_addr;
  27.  
  28. wire wr_config_done;
  29.  
  30. wr_config inst_wr_config(
  31. .sys_clk(sys_clk),
  32. .sys_rst_n(sys_rst_n),
  33. .iic_wr_ack_i(iic_wr_ack),
  34. .wreq_o(wreq),
  35. .sys_byte_o(sys_data_i),
  36. .iic_wr_addr_o(iic_wr_addr),
  37. .wr_config_done_o(wr_config_done)
  38. );
  39.  
  40. rd_check inst_rd_check(
  41. .sys_clk(sys_clk),
  42. .sys_rst_n(sys_rst_n),
  43. .key_n(key_n),
  44. .rreq_o(rreq),
  45. .iic_rd_addr_o(iic_rd_addr)
  46. );
  47.  
  48. iic_ctrl inst_iic_ctrl(
  49. //common
  50. .sys_clk(sys_clk),
  51. .sys_rst_n(sys_rst_n),
  52. .iic_sclk(iic_sclk),
  53. .iic_sdat(iic_sdat),
  54. //read
  55. .rreq_i(rreq),
  56. .iic_rd_addr_i(iic_rd_addr),
  57. .rd_en_i(wr_config_done),
  58. .iic_rd_ack_o(iic_rd_ack),
  59. .sys_byte_o(sys_data_o),
  60. //write
  61. .wreq_i(wreq),
  62. .wr_en_i(~wr_config_done),
  63. .iic_wr_addr_i(iic_wr_addr),
  64. .sys_byte_i(sys_data_i),
  65. .iic_wr_ack_o(iic_wr_ack)
  66. );
  67.  
  68. endmodule

源码5:仿真文件

  1. `timescale ns / ps
  2. `define T1
  3. `define T20
  4. `define T500
  5. module iic_tsb;
  6.  
  7. reg sys_clk;
  8. reg sys_rst_n;
  9. reg key_n;
  10.  
  11. initial begin
  12. sys_clk=;
  13. sys_rst_n=;
  14. key_n=;
  15. # sys_rst_n=;
  16. #`T1 key_n=;
  17. #`T20 key_n=;
  18. #`T500 key_n=;
  19. #`T20 key_n=;
  20. #`T500 key_n=;
  21. #`T20 key_n=;
  22. end
  23.  
  24. always begin
  25. # sys_clk=~sys_clk;
  26. end
  27.  
  28. wire iic_sclk;
  29. wire iic_sdat;
  30.  
  31. iic_driver inst_iic_driver(
  32. .sys_clk(sys_clk),
  33. .sys_rst_n(sys_rst_n),
  34. .iic_sclk(iic_sclk),
  35. .iic_sdat(iic_sdat),
  36. .key_n(key_n)
  37. );
  38.  
  39. endmodule

脚本文件1:windows .bat

  1. rd work /s /q
  2. del *.wlf
  3. del modelsim.ini
  4. del transcript
  5.  
  6. vsim -do iic_tsb.do

脚本文件2:仿真tcl脚本

  1. # creat lib
  2. vlib work
  3. vmap work work
  4.  
  5. # compile
  6. vlog -work work iic_ctrl.v
  7. vlog -work work rd_check.v
  8. vlog -work work wr_config.v
  9. vlog -work work iic_driver.v
  10. vlog -work work iic_tsb.v
  11.  
  12. # simulation
  13. vsim -novopt -lib work iic_tsb
  14.  
  15. # wave
  16. view wave
  17. add wave sim:/iic_tsb/inst_iic_driver/sys_clk
  18. add wave sim:/iic_tsb/inst_iic_driver/sys_rst_n
  19. add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2host
  20. add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2slave
  21. add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_wr_addr
  22. add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_rd_addr
  23. add wave sim:/iic_tsb/inst_iic_driver/wreq
  24. add wave sim:/iic_tsb/inst_iic_driver/rreq
  25. add wave sim:/iic_tsb/inst_iic_driver/iic_wr_ack
  26. add wave sim:/iic_tsb/inst_iic_driver/iic_rd_ack
  27. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk
  28. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk_w
  29. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sdat
  30. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/sdat_r
  31. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/link
  32. add wave -radix unsigned sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/bit_cnt
  33. add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_byte
  34. add wave -radix ascii sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/c_st
  35. #write config cost 10ms
  36. run 12ms

I2C控制器的Verilog建模之三(完结版)的更多相关文章

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

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

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

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

  3. I2C控制器的Verilog建模之二

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

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

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

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

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

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

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

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

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

  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. Lantern卫星接收器:为你提供免费上网服务

    包括笔者在内,许多现代人的日常生活都无法离开网络,因为在网络上我们几乎可以找到任何我们需要的信息.但你是否有想过在户外无网络信号的情况下如何接收网络数据呢?一个名为Outernet Inc.的公司为我 ...

  2. a few changes of Android 5.0

    1.Service Intent must be explicit Intent serviceIntent = new Intent(context,MyService.class);context ...

  3. ffmepg-nginx-nginx-rtmp-module配置脚本

    把上个月写的的配置脚本贴一下: #!/bin/bash #version:-- #create by itn #dis: this is used to auto install ffmpeg+ngi ...

  4. Windows Server 2012 R2在桌面上顯示我的電腦等圖示

    Windows Server 2012 R2在桌面上顯示我的電腦等圖示   從Windows2012開始,微軟取消了服務器桌面個性化選項,如何重新調出配置界面,可以使用微軟命令調出.方法如下: 同時按 ...

  5. 从零开始学习Node.js例子四 多页面实现数学运算

    app-node.js ; var http = require('http'); var htutil = require('./htutil'); var server = http.create ...

  6. 阿里 RocketMQ 安装与简介

    一.简介 官方简介: l  RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: l  能够保证严格的消息顺序 l  提供丰富的消息拉取模式 l  高效的订阅者水平扩展能力 l  实时的 ...

  7. 数据库update死锁

    比较常见的死锁场景,并发批量update时的一个场景: update cross_marketing set gmtModified = NOW(), pageview = pageview+ #ex ...

  8. Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    标签:scrollview   android   滑动   嵌套 scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview ...

  9. Android学习七:new Date使用

    1.例子 学习时间函数,并实现了简单的多个按钮监听同一个事件的方法 2.代码 代码很简单,也很清晰 package com.example.datetime; import java.text.Sim ...

  10. SpringMVC学习系列(5) 之 数据绑定-2

    在系列(4)中我们介绍了如何用@RequestParam来绑定数据,下面我们来看一下其它几个数据绑定注解的使用方法. 1.@PathVariable 用来绑定URL模板变量值,这个我们已经在系列(3) ...