当前位置:   article > 正文

基于FPGA的IIC读写EEPROM_eeprom fpga

eeprom fpga

本次所用开发板FPGA芯片型号为:EP4CE6F17C8 EEPROM

                                                                      芯片型号为:24LC04B UART串口设置为:

                                                                       波特率11520,无校验位。

        本次仅实现了EEPROM的单字节读写。若要实现连续读写可以在下文的EEPROM控制模块设置计数器控制读写字数。

一、I2C协议

1.1 I2C协议简介

         ①IIC:(Inter-Integrated Circuit)即集成电路总线,是一种两线 式串行总线,由 PHILIPS 公司开发,用于连接微控制器及其外围设备。 多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。

         ②IIC 总线由数据线 SDA 和时钟线 SCL 构成通信线路,既可用于 发送数据,也可接收数据,是一种半双工通信协议。
        ③需要注意的是:总线上的主设备与从设备之间以字节(8bit) 为单位进行双向的数据传输的
         下面将通过两个方面:1.物理层 2.协议层 讲解 IIC 通信协议
1.2 物理层

物理层的特点:

(1) 它是一个支持多设备的总线(支持多主机多从机)。

(2) IIC 总线只使用两条总线线路,一条双向串行数据线(SDA) 一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

(3) 每个连接到 IIC 总线的设备都有一个独立的地址,主机可以利用设备独立地址访问不同设备。

(4) IIC 总线通过上拉电阻接到电源。当 IIC 设备空闲时,设备会输出高阻态,当所有设备都空闲,都输出高阻态时,由上拉电阻把 IIC总线拉成高电平。

(5) IIC 总线具有仲裁机制。当多个主机同时发起传输时,触发仲裁机制,最终只给一个主机授权。

(6)具有三种传输模式:

1.3 IIC 协议层:

IIC 协议空闲状态

IIC 协议的起始信号

IIC 协议的数据传输(数据读写)状态(应答信号(ACK))

IIC 协议的停止信号

图中标注的①②③④表示 IIC 协议的 4 个状态,

分别为“总线空闲状态”、“起始信号”、“数据读/写状态”和“停止信号”。

空闲状态:图中标注①表示“总线空闲状态”,在此状态下串口时钟信号SCL和串行数据信号 SDA均保持高电平(都为 1),此时无IIC设备工作。

起始位:

        图中标注②表示“起始信号”,在 IIC 总线处于“空闲状态”时, 时钟信号线 SCL 为高电平时,数据信号线 SDA 被拉低(由高电平变为低电平),出现下降沿,表示产生了一个起始信号。起始信号是由主机(本实验中为 FPGA)主动建立的,在建立该信号之前IIC总线必须处于空闲状态。

数据传输:

        同时,协议规定在SCL高电平时期SDA数据线必须保持稳定,在SCL低电平时,SDA才允许发生改变。主机进行数据读写时,I2C协议规定,数据传输时先发送寻址字节,即7位从机地址+0/1。其中0表示主机写,1表示主机读。寻址字节发送完成后才是数据字节。

应答位:

        I2C协议规定,主机每次向从机传输1字节数据后,需要接收一次从机的应答信号。0为接收成功;1为接受失败,没有响应。

停止位:

        当SCL为高电平时,数据线SDA拉高,则认为检测到停止位,一次数据传输结束。

注意:SCL高电平数据必须保持,SCL低电平数据才能改变。

二、EEPROM

2.1 基本信息

        EEPROM的全称是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。本次项目中使用的EEPROM型号为24LC04B。

        24LC04B 的存储容量为 4Kbit,其内部有两个 Block,每个Block中有256个字节(一个字节为 8bit)。其读写操作都是以字节(8bit)为基本单位。24LC04B EEPROM存储芯片的器件地址包括厂商设置的高4 1010和用户需自主设置的低3A0A1A2 

        在IIC主从设备通讯时,主机在发送了起始信号后,接着会向从机发送控制命令。控制命令长度为1个字节,它的高7位为上文讲解的IIC设备的器件地址,最低位为读写控制位。EEPROM储存芯片控制命令格式示意图,具体见下图:

读写控制位为 0 时,表示主机( FPGA )要对从机( EEPROM )进行数据写入操作;读写控制位为 1 时,表示主机( FPGA )要对从机( EEPROM )进行数据读出操作。

三、IIC协议读写EEPROM 

        EEPROM的写操作有:

①单字节写(Byte WRITE) ②页写(Page WRITE)

        EEPROM的读操作有:

①当前地址读(Current Address READ)

②随机地址读(RANDOM READ)

③顺序地址读(SEQUENTIAL READ)

3.1 EEPROM单字节写(Byte WRITE)操作时序

        单字节写操作:在数据信号线SDA上,发起始 -> 控制字节,从机接收到发应答信号 -> 写数据地址,从机接收到发应答信号,如果数据地址是2位的话,就继续写数据地址,从机接收到发应答信号 -> 写数据,从机接收到发应答信号 -> 最后发停止位。

3.2 EEPROM页写操作时序

页写(PAGE WRITE)操作:一次写入16个字节(每字节为8bit)数据。

        在数据信号线SDA上,发起始位 -> 写控制字节,从机接收到应答信号 -> 写数据地址,从机接收到应答信号,如果数据地址是2位的话,就继续写数据地址,从机接收到应答信号 -> 写数据,从机接收到应答信号 -> 继续写数据,直到写完全部的数据 -> 最后发停止位。

3.3 EEPROM当前地址读(Current Address READ)操作时序
        

        当前地址读(Curren Address READ)操作:在数据线SDA上,发起始位 -> 写控制字节,从机接收到应答信号,然后读数据,无应答信号(发No ACK) ->  发停止位。

3.4 EEPROM 随机地址读 (RANDOM READ) 操作时序

        随机地制读(RANDOM READ)操作:在数据信号线SDA上,发起始位 -> 写控制字节,从机接收到应答信号 -> 再发起始位 -> 读控制字节,从机接收到应答信号 -> 接收读数据 -> 发无应答(No ACK)-> 最后发停止位。

3.5 EEPROM 顺序地址读(SEQUENTIAL READ)操作时序

        顺序地址读(RANDOM READ)操作:在数据信号线SDA上,发起始位 -> 写控制字节,从机接收到应答信号 ->  虚写(dummuy write),写数据地址,从机接收到应答信号  -> 再发开始位 -> 读控制字节,从机接收到应答信号 -> 然后接收读数据 -> 发No ACK -> 最后发结束位

顺序地址读实质就是在随机地制读之后

四、状态机

4.1 IIC接口模块

4.2 EEPROM控制模块

 五、程序

5.1、IIC接口模块

  1. /**************************************功能介绍***********************************
  2. Date : 202452016:16:29
  3. Author :
  4. Version : 1.0
  5. Description: I2C接口模块
  6. 接口命令列表(cmd):
  7. 0 1
  8. bit0(起始位) NO YES
  9. bit1(写数据) NO YES
  10. bit2(读数据) NO YES
  11. bit3(停止位) NO YES
  12. bit4(响应位) ACK NO ACK
  13. *********************************************************************************/
  14. //---------<模块及端口声名>------------------------------------------------------
  15. module I2C_driver(
  16. input clk ,
  17. input rst_n ,
  18. input [7:0] wr_data ,//要写进的数据
  19. input [4:0] cmd ,//命令信号
  20. input cmd_vld ,//命令信号有效信号
  21. output [7:0] rd_data ,//读出的数据
  22. output rd_data_vld,
  23. output reg rev_ack ,//记响应位为ack还是no ack
  24. output done ,//表示写/读完8bit的数据
  25. output reg scl ,
  26. inout sda
  27. );
  28. //---------<参数定义>---------------------------------------------------------
  29. //状态机参数定义
  30. localparam IDLE = 7'b0000001,//空闲状态
  31. START = 7'b0000010,//起始位
  32. WR_DATA = 7'b0000100,//写状态(包括写控制字节,写地址和写数据)
  33. RD_DATA = 7'b0001000,//读状态
  34. R_ACK = 7'b0010000,//收ACK(由EEPROM发送给FPGA)
  35. T_ACK = 7'b0100000,//发ACK(由FPGA发送给EEPROM)考虑为ACK还是NO ACK
  36. STOP = 7'b1000000;//结束位
  37. parameter T = 100_000,//速率 100k,400k,3.4M
  38. SCL_MAX = 50_000_000 / T;//速率为100k时,计1bit需要计数500
  39. parameter SCL_LOW_HALF = (SCL_MAX * 1 / 4) - 1,
  40. SCL_HIGH_HALF = (SCL_MAX * 3 / 4) - 1;
  41. `define START_BIT 5'b00001
  42. `define WRITE_BIT 5'b00010
  43. `define READ_BIT 5'b00100
  44. `define STOP_BIT 5'b01000
  45. `define ACK_BIT 5'b10000
  46. `define ACK 0
  47. `define NO_ACK 1
  48. //---------<内部信号定义>-----------------------------------------------------
  49. reg [6:0] cstate ;//现态
  50. reg [6:0] nstate ;//次态
  51. reg [4:0] cmd_r ;//cmd打一拍
  52. reg [7:0] wr_data_r ;
  53. reg [7:0] rd_data_r ;
  54. reg sda_out ;
  55. reg OE ;//三态门使能信号
  56. wire sda_in ;
  57. reg [8:0] cnt_bit ;//1bit(IIC工作时钟)
  58. wire add_cnt_bit ;
  59. wire end_cnt_bit ;
  60. reg [3:0] cnt_num ;//8bit
  61. wire add_cnt_num ;
  62. wire end_cnt_num ;
  63. reg [3:0] num ;
  64. //状态转移条件
  65. wire IDLE_START ;
  66. wire START_WR_DATA ;
  67. wire WR_DATA_R_ACK ;
  68. wire R_ACK_IDLE ;
  69. wire IDLE_WR_DATA ;
  70. wire R_ACK_STOP ;
  71. wire STOP_IDLE ;
  72. wire IDLE_RD_DATA ;
  73. wire RD_DATA_T_ACK ;
  74. wire T_ACK_IDLE ;
  75. wire T_ACK_STOP ;
  76. //寄存wr_data_r和cmd_r
  77. always @(posedge clk or negedge rst_n) begin
  78. if (!rst_n) begin
  79. wr_data_r <= 'd0;
  80. cmd_r <= 'd0;
  81. end
  82. else if (cmd_vld) begin
  83. wr_data_r <= wr_data;
  84. cmd_r <= cmd;
  85. end
  86. end
  87. /****************************************************************
  88. 计数器
  89. ****************************************************************/
  90. //1bit(IIC工作时钟)
  91. always @(posedge clk or negedge rst_n)begin
  92. if(!rst_n)begin
  93. cnt_bit <= 'd0;
  94. end
  95. else if(add_cnt_bit)begin
  96. if(end_cnt_bit)begin
  97. cnt_bit <= 'd0;
  98. end
  99. else begin
  100. cnt_bit <= cnt_bit + 1'd1;
  101. end
  102. end
  103. end
  104. assign add_cnt_bit = cstate != IDLE;
  105. assign end_cnt_bit = add_cnt_bit && cnt_bit == SCL_MAX - 1'd1;
  106. //IIC_SCL
  107. always @(posedge clk or negedge rst_n) begin
  108. if (!rst_n) begin
  109. scl <= 'd1;
  110. end
  111. else if (cnt_bit == (SCL_MAX - 1 ) >> 1 || STOP_IDLE) begin
  112. scl <= 'd1;
  113. end
  114. else if (end_cnt_bit) begin
  115. scl <= 'd0;
  116. end
  117. end
  118. //8bit计数器
  119. always @(posedge clk or negedge rst_n)begin
  120. if(!rst_n)begin
  121. cnt_num <= 'd0;
  122. end
  123. else if(add_cnt_num)begin
  124. if(end_cnt_num)begin
  125. cnt_num <= 'd0;
  126. end
  127. else begin
  128. cnt_num <= cnt_num + 1'd1;
  129. end
  130. end
  131. end
  132. assign add_cnt_num = end_cnt_bit;
  133. assign end_cnt_num = add_cnt_num && cnt_num == num - 1;
  134. //考察计bit数最大值
  135. always @(*) begin
  136. case (cstate)
  137. IDLE : num = 1;
  138. START : num = 1;
  139. WR_DATA : num = 8;
  140. RD_DATA : num = 8;
  141. R_ACK : num = 1;
  142. T_ACK : num = 1;
  143. STOP : num = 1;
  144. default : num = 1;
  145. endcase
  146. end
  147. /****************************************************************
  148. 状态机
  149. ****************************************************************/
  150. //第一段:时序逻辑描述状态转移
  151. always @(posedge clk or negedge rst_n)begin
  152. if(!rst_n)begin
  153. cstate <= IDLE;
  154. end
  155. else begin
  156. cstate <= nstate;
  157. end
  158. end
  159. //第二段:组合逻辑描述状态转移规律和状态转移条件
  160. always @(*) begin
  161. case(cstate)
  162. IDLE : begin
  163. if (IDLE_START) begin
  164. nstate = START;
  165. end
  166. else if (IDLE_WR_DATA) begin
  167. nstate = WR_DATA;
  168. end
  169. else if (IDLE_RD_DATA) begin
  170. nstate = RD_DATA;
  171. end
  172. else begin
  173. nstate = cstate;
  174. end
  175. end
  176. START : begin
  177. if (START_WR_DATA) begin
  178. nstate = WR_DATA;
  179. end
  180. else begin
  181. nstate = cstate;
  182. end
  183. end
  184. WR_DATA : begin
  185. if (WR_DATA_R_ACK) begin
  186. nstate = R_ACK;
  187. end
  188. else begin
  189. nstate = cstate;
  190. end
  191. end
  192. RD_DATA : begin
  193. if (RD_DATA_T_ACK) begin
  194. nstate = T_ACK;
  195. end
  196. else begin
  197. nstate = cstate;
  198. end
  199. end
  200. R_ACK : begin
  201. if (R_ACK_STOP) begin
  202. nstate = STOP;
  203. end
  204. else if (R_ACK_IDLE) begin
  205. nstate = IDLE;
  206. end
  207. else begin
  208. nstate = cstate;
  209. end
  210. end
  211. T_ACK : begin
  212. if (T_ACK_STOP) begin
  213. nstate = STOP;
  214. end
  215. else if (T_ACK_IDLE) begin
  216. nstate = IDLE;
  217. end
  218. else begin
  219. nstate = cstate;
  220. end
  221. end
  222. STOP : begin
  223. if (STOP_IDLE) begin
  224. nstate = IDLE;
  225. end
  226. else begin
  227. nstate = cstate;
  228. end
  229. end
  230. default : nstate = cstate;
  231. endcase
  232. end
  233. assign IDLE_START = (cstate == IDLE) && cmd_vld && (cmd & `START_BIT) ;//存在起始位
  234. assign START_WR_DATA = (cstate == START) && end_cnt_num && (cmd_r & `WRITE_BIT) ;//1bit起始位并写数据有效
  235. assign WR_DATA_R_ACK = (cstate == WR_DATA) && end_cnt_num ;//8bit数据位
  236. assign R_ACK_IDLE = (cstate == R_ACK) && end_cnt_num && !(cmd_r & `STOP_BIT) ;//1bit响应位,没有停止位
  237. assign IDLE_WR_DATA = (cstate == IDLE) && cmd_vld && (cmd & `WRITE_BIT) ;//写数据有效
  238. assign R_ACK_STOP = (cstate == R_ACK) && end_cnt_num && (cmd_r & `STOP_BIT) ;//1bit响应位,有停止位
  239. assign STOP_IDLE = (cstate == STOP) && end_cnt_num ;//1bit停止位
  240. assign IDLE_RD_DATA = (cstate == IDLE) && cmd_vld && (cmd & `READ_BIT) ;//读数据有效
  241. assign RD_DATA_T_ACK = (cstate == RD_DATA) && end_cnt_num ;//8bit数据位
  242. assign T_ACK_IDLE = (cstate == T_ACK) && end_cnt_num && !(cmd_r & `STOP_BIT) ;//1bit响应位,没有停止位
  243. assign T_ACK_STOP = (cstate == T_ACK) && end_cnt_num && (cmd_r & `STOP_BIT) ;//1bit响应位,有停止位
  244. /****************************************************************
  245. 三态门
  246. ****************************************************************/
  247. assign sda = OE ? sda_out : 1'bz;
  248. assign sda_in = sda;
  249. //考察OE
  250. always @(posedge clk or negedge rst_n) begin
  251. if (!rst_n) begin
  252. OE <= 'b0;
  253. end
  254. else if (IDLE_START || START_WR_DATA || IDLE_WR_DATA || R_ACK_STOP || RD_DATA_T_ACK) begin//FPGA发送,EEPROM接收
  255. OE <= 'b1;
  256. end
  257. else if (IDLE_RD_DATA || WR_DATA_R_ACK || STOP_IDLE) begin//FPGA接收,EEPROM发送
  258. OE <= 'b0;
  259. end
  260. end
  261. /****************************************************************
  262. 输出
  263. ****************************************************************/
  264. //考察输出
  265. always @(posedge clk or negedge rst_n) begin
  266. if (!rst_n) begin
  267. sda_out <= 1;
  268. end
  269. else begin
  270. case (cstate)
  271. IDLE :sda_out <= 1;
  272. START :begin//起始位scl一直为高电平,检测sda需要由高电平变低电平
  273. if (cnt_bit == SCL_LOW_HALF) begin
  274. sda_out <= 'b1;
  275. end
  276. else if (cnt_bit == SCL_HIGH_HALF) begin
  277. sda_out <= 'b0;
  278. end
  279. end
  280. WR_DATA :begin//高电平保持,低电平值变化采样
  281. if (cnt_bit == SCL_LOW_HALF) begin
  282. sda_out <= wr_data_r[7 - cnt_num];//高位先发
  283. end
  284. end
  285. T_ACK :begin
  286. if (cnt_bit == SCL_LOW_HALF) begin
  287. if (cmd & `ACK_BIT) begin//命令响应位为1NO ACK
  288. sda_out <= `NO_ACK;
  289. end
  290. else begin
  291. sda_out <= `ACK;//命令响应位为0:ACK
  292. end
  293. end
  294. end
  295. STOP :begin//检测sda需要由低电平变高电平
  296. if (cnt_bit == SCL_LOW_HALF) begin
  297. sda_out <= 'b0;
  298. end
  299. else if (cnt_bit == SCL_HIGH_HALF) begin
  300. sda_out <= 'b1;
  301. end
  302. end
  303. default: sda_out <= 'b1;
  304. endcase
  305. end
  306. end
  307. /****************************************************************
  308. ACK
  309. ****************************************************************/
  310. //数据接收(考察EEPROM发送数据给FPGA的情况)
  311. always @(posedge clk or negedge rst_n) begin
  312. if (!rst_n) begin
  313. rev_ack <= 0;
  314. rd_data_r <= 8'b0;
  315. end
  316. else begin
  317. case (cstate)
  318. RD_DATA:begin
  319. if (cnt_bit == SCL_HIGH_HALF) begin//高电平采样
  320. rd_data_r[7-cnt_num] <= sda_in;
  321. end
  322. end
  323. R_ACK :begin
  324. if (cnt_bit == SCL_HIGH_HALF) begin
  325. rev_ack <= sda_in;
  326. end
  327. end
  328. default:;
  329. endcase
  330. end
  331. end
  332. assign done = R_ACK_IDLE || T_ACK_IDLE || STOP_IDLE;
  333. assign rd_data = rd_data_r;
  334. assign rd_data_vld = T_ACK_IDLE || T_ACK_STOP;
  335. endmodule

5.2 IIC控制模块

  1. /**************************************功能介绍***********************************
  2. Date : 202452016:19:44
  3. Author :
  4. Version : 1.0
  5. Description: I2C控制模块
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module I2C_control #(
  9. parameter ADDR_BIT = 8 //从机寄存器地址的位宽
  10. )(
  11. input clk ,
  12. input rst_n ,
  13. input wr_req ,//写使能
  14. input rd_req ,//读使能
  15. input [6:0] device_id ,//从机设备ID
  16. input [ADDR_BIT - 1:0] reg_addr ,//读写地址
  17. input reg_addr_vld,
  18. input [7:0] wr_data ,
  19. input wr_data_vld ,
  20. output [7:0] rd_data ,
  21. output rd_data_vld ,
  22. output ready ,
  23. output scl ,
  24. inout sda
  25. );
  26. //---------<参数定义>---------------------------------------------------------
  27. //接口模块控制命令
  28. `define START_BIT 5'b00001
  29. `define WRITE_BIT 5'b00010
  30. `define READ_BIT 5'b00100
  31. `define STOP_BIT 5'b01000
  32. `define ACK_BIT 5'b10000
  33. //状态机参数定义
  34. localparam IDLE = 6'b000001,//
  35. WR_REQ = 6'b000010,//
  36. WR_WAIT = 6'b000100,//
  37. RD_REQ = 6'b001000,//
  38. RD_WAIT = 6'b010000,//
  39. DONE = 6'b100000;//
  40. localparam WR_CTRL_BYTE = 8'b1010_0000;
  41. localparam RD_CTRL_BYTE = 8'b1010_0001;
  42. //---------<内部信号定义>-----------------------------------------------------
  43. reg [5:0] cstate ;//现态
  44. reg [5:0] nstate ;//次态
  45. wire IDLE_WR_REQ ;
  46. wire IDLE_RD_REQ ;
  47. wire WR_REQ_WR_WAIT ;
  48. wire RD_REQ_RD_WAIT ;
  49. wire WR_WAIT_WR_REQ ;
  50. wire WR_WAIT_DONE ;
  51. wire RD_WAIT_RD_REQ ;
  52. wire RD_WAIT_DONE ;
  53. wire DONE_IDLE ;
  54. reg [2:0] num ;//字节计数器最大值(写3字节,读4字节)
  55. wire done ;
  56. reg [4:0] cmd ;
  57. reg cmd_vld ;
  58. reg [7:0] op_wr_data ;
  59. reg [15:0] addr_r ;
  60. reg [7:0] wr_data_r ;
  61. reg [2:0] cnt_byte ;
  62. wire add_cnt_byte ;
  63. wire end_cnt_byte ;
  64. //同步数据打拍
  65. reg wr_req_r;
  66. reg rd_req_r;
  67. always @(posedge clk or negedge rst_n) begin
  68. if (!rst_n) begin
  69. wr_req_r <=0;
  70. rd_req_r <= 0;
  71. end
  72. else begin
  73. wr_req_r <= wr_req;
  74. rd_req_r <= rd_req;
  75. end
  76. end
  77. //寄存
  78. always @(posedge clk or negedge rst_n) begin
  79. if (!rst_n) begin
  80. addr_r <= 'd0;
  81. end
  82. else if (reg_addr_vld) begin
  83. addr_r <= reg_addr;
  84. end
  85. end
  86. always @(posedge clk or negedge rst_n) begin
  87. if (!rst_n) begin
  88. wr_data_r <= 'd0;
  89. end
  90. else if (wr_req) begin
  91. wr_data_r <= wr_data;
  92. end
  93. end
  94. //字节计数器
  95. always @(posedge clk or negedge rst_n)begin
  96. if(!rst_n)begin
  97. cnt_byte <= 'd0;
  98. end
  99. else if(add_cnt_byte)begin
  100. if(end_cnt_byte)begin
  101. cnt_byte <= 'd0;
  102. end
  103. else begin
  104. cnt_byte <= cnt_byte + 1'd1;
  105. end
  106. end
  107. end
  108. assign add_cnt_byte = done;
  109. assign end_cnt_byte = add_cnt_byte && cnt_byte == num - 1;
  110. //考察字节计数器最大值(写3字节,读4字节)
  111. always @(posedge clk or negedge rst_n) begin
  112. if (!rst_n) begin
  113. num <= 1;
  114. end
  115. else if (wr_req) begin
  116. num <= 4;
  117. end
  118. else if (rd_req) begin
  119. num <= 5;
  120. end
  121. else if (end_cnt_byte) begin
  122. num <= 1;
  123. end
  124. end
  125. assign IDLE_WR_REQ = (cstate == IDLE) && wr_req_r;//写使能拉高
  126. assign IDLE_RD_REQ = (cstate == IDLE) && rd_req_r;//读使能拉高
  127. assign WR_REQ_WR_WAIT = (cstate == WR_REQ) && 1;
  128. assign RD_REQ_RD_WAIT = (cstate == RD_REQ) && 1;
  129. assign WR_WAIT_WR_REQ = (cstate == WR_WAIT) && done;//写完1byte
  130. assign WR_WAIT_DONE = (cstate == WR_WAIT) && end_cnt_byte;//写完3byte
  131. assign RD_WAIT_RD_REQ = (cstate == RD_WAIT) && done;//读完1byte
  132. assign RD_WAIT_DONE = (cstate == RD_WAIT) && end_cnt_byte;//读完4byte
  133. assign DONE_IDLE = (cstate == DONE) && 1;
  134. //第一段:时序逻辑描述状态转移
  135. always @(posedge clk or negedge rst_n)begin
  136. if(!rst_n)begin
  137. cstate <= IDLE;
  138. end
  139. else begin
  140. cstate <= nstate;
  141. end
  142. end
  143. //第二段:组合逻辑描述状态转移规律和状态转移条件
  144. always @(*) begin
  145. case(cstate)
  146. IDLE :begin
  147. if (IDLE_WR_REQ) begin
  148. nstate = WR_REQ;
  149. end
  150. else if (IDLE_RD_REQ) begin
  151. nstate = RD_REQ;
  152. end
  153. else begin
  154. nstate = cstate;
  155. end
  156. end
  157. WR_REQ :begin
  158. if (WR_REQ_WR_WAIT) begin
  159. nstate = WR_WAIT;
  160. end
  161. else begin
  162. nstate = cstate;
  163. end
  164. end
  165. WR_WAIT :begin
  166. if (WR_WAIT_DONE) begin
  167. nstate = DONE;
  168. end
  169. else if (WR_WAIT_WR_REQ) begin
  170. nstate = WR_REQ;
  171. end
  172. else begin
  173. nstate = cstate;
  174. end
  175. end
  176. RD_REQ :begin
  177. if (RD_REQ_RD_WAIT) begin
  178. nstate = RD_WAIT;
  179. end
  180. else begin
  181. nstate = cstate;
  182. end
  183. end
  184. RD_WAIT :begin
  185. if (RD_WAIT_DONE) begin
  186. nstate = DONE;
  187. end
  188. else if (RD_WAIT_RD_REQ) begin
  189. nstate = RD_REQ;
  190. end
  191. else begin
  192. nstate = cstate;
  193. end
  194. end
  195. DONE :begin
  196. if (DONE_IDLE) begin
  197. nstate = IDLE;
  198. end
  199. else begin
  200. nstate = cstate;
  201. end
  202. end
  203. default : nstate = cstate;
  204. endcase
  205. end
  206. always @(posedge clk or negedge rst_n) begin
  207. if (!rst_n) begin
  208. TX(0,4'h0,8'h00);
  209. end
  210. else begin
  211. case (cstate)
  212. RD_REQ:begin
  213. case (cnt_byte)
  214. 0 : TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);
  215. 1 : TX(1,(`WRITE_BIT ),addr_r[15:8]);
  216. 2 : TX(1,(`WRITE_BIT ),addr_r[7:0] );
  217. 3 : TX(1,(`START_BIT | `WRITE_BIT),RD_CTRL_BYTE);
  218. 4 : TX(1,(`READ_BIT | `STOP_BIT ),8'h00 );
  219. default: TX(0,cmd,op_wr_data);
  220. endcase
  221. end
  222. WR_REQ:begin
  223. case (cnt_byte)
  224. 0 : TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);
  225. 1 : TX(1,(`WRITE_BIT ),addr_r[15:8]);
  226. 2 : TX(1,(`WRITE_BIT ),addr_r[7:0] );
  227. 3 : TX(1,(`WRITE_BIT | `STOP_BIT ),wr_data_r );
  228. default: TX(0,cmd,op_wr_data);
  229. endcase
  230. end
  231. default: TX(0,cmd,op_wr_data);
  232. endcase
  233. end
  234. end
  235. I2C_driver u_I2C_driver(
  236. .clk (clk),
  237. .rst_n (rst_n),
  238. .wr_data (op_wr_data),
  239. .cmd (cmd),
  240. .cmd_vld (cmd_vld),
  241. .rd_data (rd_data),
  242. .rd_data_vld (rd_data_vld),
  243. .done (done),
  244. .scl (scl),
  245. .sda (sda)
  246. );
  247. task TX;
  248. input task_cmd_vld ;
  249. input [3:0] task_cmd ;
  250. input [7:0] task_wr_data ;
  251. begin
  252. cmd_vld = task_cmd_vld ;
  253. cmd = task_cmd ;
  254. op_wr_data = task_wr_data ;
  255. end
  256. endtask
  257. assign ready = cstate == IDLE;
  258. endmodule

5.3按键消抖模块(可以不用)

  1. /**************************************功能介绍***********************************
  2. Date : 202452016:33:32
  3. Author :
  4. Version : 1.0
  5. Description: 四位按键消抖模块
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module key_debounce #(parameter WIDTH = 1,
  9. parameter DELAY_20MS = 1000_000
  10. )(
  11. input clk ,
  12. input rst_n ,
  13. input [WIDTH-1:0] key_in ,
  14. output [WIDTH-1:0] key_out
  15. );
  16. //---------<参数定义>---------------------------------------------------------
  17. reg [WIDTH-1:0] key_out_r;
  18. //状态机参数定义
  19. localparam IDLE = 4'b0001,//空闲状态
  20. FILETER_DOWN = 4'b0010,//按键按下抖动状态
  21. HOLD_DOWN = 4'b0100,//按下稳定按下状态
  22. FILTER_UP = 4'b1000;//按键释放抖动状态
  23. //---------<内部信号定义>-----------------------------------------------------
  24. reg [3:0] cstate ;//现态
  25. reg [3:0] nstate ;//次态
  26. reg [WIDTH-1:0] key_r0 ;//同步打拍
  27. reg [WIDTH-1:0] key_r1 ;
  28. reg [WIDTH-1:0] key_r2 ;
  29. wire [WIDTH-1:0] n_edge ;//下降沿
  30. wire [WIDTH-1:0] p_edge ;//上升沿
  31. reg [19:0] cnt_20ms ;//20ms计数器
  32. wire add_cnt_20ms;
  33. wire end_cnt_20ms;
  34. //状态转移条件定义
  35. wire idle2filter_down ;
  36. wire fiter_down2hold_down ;
  37. wire hold_down2filter_up ;
  38. wire filter_up2idle ;
  39. //****************************************************************
  40. //--cstate
  41. //****************************************************************
  42. //第一段:时序逻辑描述状态转移
  43. always @(posedge clk or negedge rst_n)begin
  44. if(!rst_n)begin
  45. cstate <= IDLE;//复位的初始状态
  46. end
  47. else begin
  48. cstate <= nstate;
  49. end
  50. end
  51. //第二段:组合逻辑描述状态转移规律和状态转移条件
  52. always @(*) begin
  53. case(cstate)
  54. IDLE : begin
  55. if(idle2filter_down)begin
  56. nstate = FILETER_DOWN;
  57. end
  58. else begin
  59. nstate = cstate;
  60. // state_n = IDLE;
  61. end
  62. end
  63. FILETER_DOWN : begin
  64. if(fiter_down2hold_down)begin
  65. nstate = HOLD_DOWN;
  66. end
  67. else begin
  68. nstate = cstate;
  69. end
  70. end
  71. HOLD_DOWN : begin
  72. if(hold_down2filter_up)begin
  73. nstate = FILTER_UP;
  74. end
  75. else begin
  76. nstate = cstate;
  77. end
  78. end
  79. FILTER_UP : begin
  80. if(filter_up2idle)begin
  81. nstate = IDLE;
  82. end
  83. else begin
  84. nstate = cstate;
  85. end
  86. end
  87. default : nstate = IDLE;
  88. endcase
  89. end
  90. assign idle2filter_down = cstate == IDLE && n_edge;
  91. assign fiter_down2hold_down = cstate == FILETER_DOWN && end_cnt_20ms;
  92. assign hold_down2filter_up = cstate == HOLD_DOWN && p_edge;
  93. assign filter_up2idle = cstate == FILTER_UP && end_cnt_20ms;
  94. //****************************************************************
  95. //--n_edge、p_edge
  96. //****************************************************************
  97. always @(posedge clk or negedge rst_n)begin
  98. if(!rst_n)begin
  99. key_r0 <= {WIDTH{1'b1}};
  100. key_r1 <= {WIDTH{1'b1}};
  101. key_r2 <= {WIDTH{1'b1}};
  102. end
  103. else begin
  104. key_r0 <= key_in;
  105. key_r1 <= key_r0;
  106. key_r2 <= key_r1;
  107. end
  108. end
  109. assign n_edge = ~key_r1 & key_r2;
  110. assign p_edge = ~key_r2 & key_r1;
  111. //****************************************************************
  112. //--cnt_20ms
  113. //****************************************************************
  114. always @(posedge clk or negedge rst_n)begin
  115. if(!rst_n)begin
  116. cnt_20ms <= 'd0;
  117. end
  118. else if(add_cnt_20ms)begin
  119. if(end_cnt_20ms)begin
  120. cnt_20ms <= 'd0;
  121. end
  122. else begin
  123. cnt_20ms <= cnt_20ms + 1'b1;
  124. end
  125. end
  126. end
  127. assign add_cnt_20ms = cstate == FILETER_DOWN || cstate == FILTER_UP;
  128. assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == DELAY_20MS - 1;
  129. //****************************************************************
  130. //--key_out
  131. //****************************************************************
  132. always @(posedge clk or negedge rst_n)begin
  133. if(!rst_n)begin
  134. key_out_r <= 'd0;
  135. end
  136. else if(hold_down2filter_up)begin
  137. key_out_r <= ~key_r2;
  138. end
  139. else begin
  140. key_out_r <= 'd0;
  141. end
  142. end
  143. assign key_out = key_out_r;
  144. endmodule

 5.4串口接收模块(非必要)

  1. /**************************************功能介绍***********************************
  2. Date : 2202452016:38:29
  3. Author :
  4. Version : 1.0
  5. Description: FPGA收上位机发来的数据【1bit(波形)变8bit
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module uart_rx(
  9. input clk ,
  10. input rst_n ,
  11. input rx ,
  12. output rx_data_vld,
  13. output [7:0] rx_data
  14. );
  15. //---------<参数定义>---------------------------------------------------------
  16. parameter MAX_BPS = 115200;
  17. parameter CLOCK = 50_000_000;
  18. parameter MAX_1bit = CLOCK/MAX_BPS;//1bit要计434
  19. parameter CHECK_BIT = "None";//None无校验,Odd奇校验,Even偶校验
  20. //状态机参数定义
  21. localparam IDLE = 'b0001,//空闲状态
  22. START = 'b0010,//起始位
  23. DATA = 'b0100,//数据位
  24. CHECK = 'b1000;
  25. //---------<内部信号定义>-----------------------------------------------------
  26. reg [3:0] cstate ;//现态
  27. reg [3:0] nstate ;//次态
  28. wire IDLE_START;
  29. wire START_DATA;
  30. wire DATA_IDLE;
  31. wire DATA_CHECK;
  32. wire CHECK_IDLE;
  33. reg [8:0] cnt_baud ;//波特计数器,波特率115200
  34. wire add_cnt_baud ;
  35. wire end_cnt_baud ;
  36. reg [2:0] cnt_bit ;//bit计数器,起始位1bit,数据位8bit,结束位1bit
  37. wire add_cnt_bit ;
  38. wire end_cnt_bit ;
  39. reg [3:0] bit_max;//bit最大值,复用需要考察每个状态的bit
  40. reg [7:0] rx_temp;
  41. reg rx_check;
  42. wire check_val;
  43. reg rx_r1;
  44. reg rx_r2;
  45. wire rx_nege;
  46. //打两拍
  47. always @(posedge clk or negedge rst_n) begin
  48. if (!rst_n) begin
  49. rx_r1 <= 1;
  50. rx_r2 <= 1;
  51. end
  52. else begin
  53. rx_r1 <= rx;
  54. rx_r2 <= rx_r1;
  55. end
  56. end
  57. assign rx_nege = ~rx_r1 && rx_r2;
  58. //434
  59. always @(posedge clk or negedge rst_n)begin
  60. if(!rst_n)begin
  61. cnt_baud <= 'd0;
  62. end
  63. else if(add_cnt_baud)begin
  64. if(end_cnt_baud)begin
  65. cnt_baud <= 'd0;
  66. end
  67. else begin
  68. cnt_baud <= cnt_baud + 1'd1;
  69. end
  70. end
  71. end
  72. assign add_cnt_baud = cstate != IDLE;
  73. assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
  74. //bit计数器
  75. always @(posedge clk or negedge rst_n)begin
  76. if(!rst_n)begin
  77. cnt_bit <= 'd0;
  78. end
  79. else if(add_cnt_bit)begin
  80. if(end_cnt_bit)begin
  81. cnt_bit <= 'd0;
  82. end
  83. else begin
  84. cnt_bit <= cnt_bit + 1'd1;
  85. end
  86. end
  87. end
  88. assign add_cnt_bit = end_cnt_baud;
  89. assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
  90. //计数器复用
  91. always @(*)begin
  92. case (cstate)
  93. IDLE :bit_max = 'd0;
  94. START:bit_max = 'd1;//起始位1bit
  95. DATA :bit_max = 'd8;//数据位8bit
  96. CHECK:bit_max = 'd1;
  97. default: bit_max = 'd0;
  98. endcase
  99. end
  100. assign IDLE_START = (cstate == IDLE) && rx_nege;//识别到起始位0
  101. assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据
  102. assign DATA_IDLE = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";//计8bit数据
  103. assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;
  104. assign CHECK_IDLE = (cstate == CHECK) && end_cnt_bit;
  105. //第一段:时序逻辑描述状态转移
  106. always @(posedge clk or negedge rst_n)begin
  107. if(!rst_n)begin
  108. cstate <= IDLE;
  109. end
  110. else begin
  111. cstate <= nstate;
  112. end
  113. end
  114. //第二段:组合逻辑描述状态转移规律和状态转移条件
  115. always @(*) begin
  116. case(cstate)
  117. IDLE :begin
  118. if (IDLE_START) begin
  119. nstate = START;
  120. end
  121. else begin
  122. nstate = cstate;
  123. end
  124. end
  125. START :begin
  126. if (START_DATA) begin
  127. nstate = DATA;
  128. end
  129. else begin
  130. nstate = cstate;
  131. end
  132. end
  133. DATA :begin
  134. if (DATA_IDLE) begin
  135. nstate = IDLE;
  136. end
  137. else if (DATA_CHECK) begin
  138. nstate = CHECK;
  139. end
  140. else begin
  141. nstate = cstate;
  142. end
  143. end
  144. CHECK:begin
  145. if (CHECK_IDLE) begin
  146. nstate = IDLE;
  147. end
  148. else begin
  149. nstate = cstate;
  150. end
  151. end
  152. default : nstate = IDLE;
  153. endcase
  154. end
  155. //接受校验位
  156. always @(posedge clk or negedge rst_n) begin
  157. if (!rst_n) begin
  158. rx_check <= 0;
  159. end
  160. else if (cstate == CHECK && cnt_baud == MAX_1bit >>1) begin
  161. rx_check <= rx_r1;
  162. end
  163. end
  164. //计算校验位
  165. assign check_val = (CHECK_BIT == "Odd") ? ~^rx_temp : ^rx_temp;
  166. //第三段:描述输出,时序逻辑或组合逻辑皆可
  167. always @(posedge clk or negedge rst_n) begin
  168. if (!rst_n) begin
  169. rx_temp <= 0;
  170. end
  171. else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin//电平中间值采样,边沿采样容易出错
  172. rx_temp[cnt_bit] <= rx_r1;
  173. end
  174. else begin
  175. rx_temp <= rx_temp;
  176. end
  177. end
  178. assign rx_data = rx_temp;
  179. assign rx_data_vld = (CHECK_BIT == "None") ? DATA_IDLE
  180. :(CHECK_IDLE && (check_val == rx_check)) ? 1
  181. : 0;
  182. endmodule

5.5串口发送模块(非必要)

  1. /**************************************功能介绍***********************************
  2. Date : 202452016:40:06
  3. Author :
  4. Version : 2.0
  5. Description: FPGA向上位机发送数据【8bit1bit(波形)】
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module uart_tx(
  9. input clk ,
  10. input rst_n ,
  11. input [7:0] tx_data ,
  12. input tx_data_vld,
  13. output ready ,
  14. output reg tx
  15. );
  16. //---------<参数定义>---------------------------------------------------------
  17. parameter MAX_BPS = 115200;
  18. parameter CLOCK = 50_000_000;
  19. parameter MAX_1bit = CLOCK/MAX_BPS;//1bit要计434
  20. parameter CHECK_BIT = "None";//None无校验,Odd奇校验,Even偶校验
  21. //状态机参数定义
  22. localparam IDLE = 'b00001,//空闲状态
  23. START = 'b00010,//起始位
  24. DATA = 'b00100,//数据位
  25. CHECK = 'b01000,//校验位
  26. STOP = 'b10000;//停止位
  27. //---------<内部信号定义>-----------------------------------------------------
  28. reg [4:0] cstate ;//现态
  29. reg [4:0] nstate ;//次态
  30. wire IDLE_START;
  31. wire START_DATA;
  32. wire DATA_CHECK;
  33. wire CHECK_STOP;
  34. wire STOP_IDLE;
  35. reg [8:0] cnt_baud ;//波特计数器,波特率115200
  36. wire add_cnt_baud ;
  37. wire end_cnt_baud ;
  38. reg [2:0] cnt_bit ;//bit计数器,起始位1bit,数据位8bit,结束位1bit
  39. wire add_cnt_bit ;
  40. wire end_cnt_bit ;
  41. reg [3:0] bit_max;//bit最大值,复用需要考察每个状态的bit值
  42. reg [7:0] tx_data_r;
  43. wire check_val;
  44. //计434次
  45. always @(posedge clk or negedge rst_n)begin
  46. if(!rst_n)begin
  47. cnt_baud <= 'd0;
  48. end
  49. else if(add_cnt_baud)begin
  50. if(end_cnt_baud)begin
  51. cnt_baud <= 'd0;
  52. end
  53. else begin
  54. cnt_baud <= cnt_baud + 1'd1;
  55. end
  56. end
  57. end
  58. assign add_cnt_baud = cstate != IDLE;
  59. assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
  60. //bit计数器
  61. always @(posedge clk or negedge rst_n)begin
  62. if(!rst_n)begin
  63. cnt_bit <= 'd0;
  64. end
  65. else if(add_cnt_bit)begin
  66. if(end_cnt_bit)begin
  67. cnt_bit <= 'd0;
  68. end
  69. else begin
  70. cnt_bit <= cnt_bit + 1'd1;
  71. end
  72. end
  73. end
  74. assign add_cnt_bit = end_cnt_baud;
  75. assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
  76. //计数器复用
  77. always @(*)begin
  78. case (cstate)
  79. IDLE :bit_max = 'd0;
  80. START:bit_max = 'd1;//起始位1bit
  81. DATA :bit_max = 'd8;//数据位7bit
  82. CHECK:bit_max = 'd1;//校验位1bit
  83. STOP :bit_max = 'd1;//结束位1bit
  84. default: bit_max = 'd0;
  85. endcase
  86. end
  87. assign IDLE_START = (cstate == IDLE) && tx_data_vld;//考察到开始传输信号
  88. assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据
  89. assign DATA_STOP = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";
  90. assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;//计8bit数据
  91. assign CHECK_STOP = (cstate ==CHECK) && end_cnt_bit;//计1bit数据
  92. assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;//计1bit数据
  93. //第一段:时序逻辑描述状态转移
  94. always @(posedge clk or negedge rst_n)begin
  95. if(!rst_n)begin
  96. cstate <= IDLE;
  97. end
  98. else begin
  99. cstate <= nstate;
  100. end
  101. end
  102. //第二段:组合逻辑描述状态转移规律和状态转移条件
  103. always @(*) begin
  104. case(cstate)
  105. IDLE :begin
  106. if (IDLE_START) begin
  107. nstate = START;
  108. end
  109. else begin
  110. nstate = cstate;
  111. end
  112. end
  113. START :begin
  114. if (START_DATA) begin
  115. nstate = DATA;
  116. end
  117. else begin
  118. nstate = cstate;
  119. end
  120. end
  121. DATA :begin
  122. if (DATA_CHECK) begin
  123. nstate = CHECK;
  124. end
  125. else if (DATA_STOP) begin
  126. nstate = STOP;
  127. end
  128. else begin
  129. nstate = cstate;
  130. end
  131. end
  132. CHECK :begin
  133. if (CHECK_STOP) begin
  134. nstate = STOP;
  135. end
  136. else begin
  137. nstate = cstate;
  138. end
  139. end
  140. STOP :begin
  141. if (STOP_IDLE) begin
  142. nstate = IDLE;
  143. end
  144. else begin
  145. nstate = cstate;
  146. end
  147. end
  148. default : nstate = cstate;
  149. endcase
  150. end
  151. //寄存一拍
  152. always @(posedge clk or negedge rst_n) begin
  153. if (!rst_n) begin
  154. tx_data_r <= 'd0;
  155. end
  156. else if (tx_data_vld) begin
  157. tx_data_r <= tx_data;
  158. end
  159. else begin
  160. tx_data_r <= tx_data_r;
  161. end
  162. end
  163. assign check_val = (CHECK_BIT == "Odd") ? ~^tx_data_r : ^tx_data_r;
  164. //第三段:描述输出,时序逻辑或组合逻辑皆可
  165. always @(*)begin
  166. case (cstate)
  167. IDLE : tx = 1'b1;
  168. START: tx = 1'b0;//起始位为0
  169. DATA : tx = tx_data_r[cnt_bit];
  170. CHECK: tx = check_val;
  171. STOP : tx = 1'b1;//结束位为1
  172. default: tx = 1'b1;
  173. endcase
  174. end
  175. assign ready = cstate == IDLE;//当状态为IDLE时,表示tx端可以接收数据
  176. endmodule

5.6顶层模块: 

 

  1. /**************************************功能介绍***********************************
  2. Date : 202452016:54:32
  3. Author :
  4. Version :
  5. Description:
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module top(
  9. input clk ,
  10. input rst_n ,
  11. input key_in ,
  12. input rx ,
  13. output tx ,
  14. output scl ,
  15. inout sda
  16. );
  17. //---------<参数定义>---------------------------------------------------------
  18. wire rd_req;
  19. wire wr_req;
  20. wire [7:0] wr_data;
  21. wire [7:0] rd_data;
  22. wire rd_data_vld;
  23. //---------<内部信号定义>-----------------------------------------------------
  24. key_debounce u_key_debounce(
  25. .clk (clk),
  26. .rst_n (rst_n),
  27. .key_in (key_in),
  28. .key_out(rd_req)
  29. );
  30. uart_rx u_uart_rx(
  31. .clk (clk),
  32. .rst_n (rst_n),
  33. .rx (rx),
  34. .rx_data_vld (wr_req),
  35. .rx_data (wr_data)
  36. );
  37. uart_tx u_uart_tx(
  38. .clk (clk),
  39. .rst_n (rst_n),
  40. .tx_data (rd_data),
  41. .tx_data_vld(rd_data_vld),
  42. .ready (),
  43. .tx (tx)
  44. );
  45. I2C_control u_I2C_control(
  46. .clk (clk),
  47. .rst_n (rst_n),
  48. .wr_req (wr_req),
  49. .rd_req (rd_req),
  50. .device_id (7'b1010000),
  51. .reg_addr (8'h03),
  52. .reg_addr_vld(1'b1),
  53. .wr_data (wr_data),
  54. .wr_data_vld (wr_req),
  55. .rd_data (rd_data),
  56. .rd_data_vld (rd_data_vld),
  57. .ready (),
  58. .scl (scl),
  59. .sda (sda)
  60. );
  61. endmodule

 

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

闽ICP备14008679号