首页 > 其他分享 >【代码更新】IIC时序——读写EEPROM

【代码更新】IIC时序——读写EEPROM

时间:2024-03-04 13:44:25浏览次数:31  
标签:wire 0000 14 读写 b00 sda IIC reg EEPROM

【代码更新】IIC时序——读写EEPROM

 

 

 

 整体代码:

  1 //---->50MHz --->20ns  100KHz ---->10000ns
  2 `timescale 1ns / 1ps
  3 module eeprom_i2c#(parameter SCL_CYC = 1000)//100KHz 
  4 (
  5     input      clk,
  6     input    rst_n,
  7       
  8     input  write_en,
  9     input  read_en ,
 10     input [7:0]share_addr,   
 11     input [7:0]  wri_data,
 12      
 13     //仿真接口
 14     output reg sda_en,
 15     output reg [13:0] state_c,     
 16      
 17     //EEPROM接口
 18     output reg scl, //时钟
 19     inout      sda          
 20 );
 21     //   
 22     reg busy         ;//总线忙信号
 23     reg [7:0] rd_data;//读回数据
 24     reg rd_data_vld  ;
 25     // reg [13:0] state_c;
 26     // 
 27     wire sda_in;
 28     // reg  sda_en;
 29     reg  sda_reg;
 30     //
 31     assign sda    = sda_en ? sda_reg : 1'bz;
 32     assign sda_in = sda;
 33     //  
 34     reg [11:0] div_cnt;
 35     reg high_middle;
 36     reg [3:0] bit_cnt;
 37     reg [3:0] N;
 38 
 39     reg [13:0] state_n;
 40 
 41     reg rd_flag;
 42     reg [7:0] rd_buf;
 43 
 44     
 45     wire add_bit_cnt,end_bit_cnt;
 46     wire add_div_cnt,end_div_cnt;
 47     wire idle2start,start2wri_ctrl,wri_ctrl2ack1,ack12addr,addr2ack2,ack22wri_data;
 48     wire wri_data2ack3,ack32stop,ack22re_start,re_start2rd_ctrl,rd_ctrl2ack4;
 49     wire ack42rd_data,rd_data2nack,nack2stop,stop2idle,ack2idle;
 50     reg  ack_valid,ack_invalid;
 51     wire [2:0] cs;
 52 
 53     wire [7:0] device_addr_rd,device_addr_wr;
 54     wire [7:0] word_addr;
 55      wire ack_state;
 56      
 57      //状态编码
 58      localparam IDLE     = 14'b00_0000_0000_0001,//1
 59                 START    = 14'b00_0000_0000_0010,//2
 60                 WRI_CTRL = 14'b00_0000_0000_0100,//4
 61                 ACK1     = 14'b00_0000_0000_1000,//8
 62                 ADDR     = 14'b00_0000_0001_0000,//10
 63                 ACK2     = 14'b00_0000_0010_0000,//20
 64                 WRI_DATA = 14'b00_0000_0100_0000,//40
 65                 ACK3     = 14'b00_0000_1000_0000,//80
 66                 RE_START = 14'b00_0001_0000_0000,//100
 67                 RD_CTRL  = 14'b00_0010_0000_0000,//200
 68                 ACK4     = 14'b00_0100_0000_0000,//400
 69                 RD_DATA  = 14'b00_1000_0000_0000,//800
 70                 NACK     = 14'b01_0000_0000_0000,//1000
 71                 STOP     = 14'b10_0000_0000_0000;//2000
 72      
 73      //分频计数器 在响应操作直到完成或退出到IDLE中间都计数
 74      always@(posedge clk or negedge rst_n)begin
 75          if(!rst_n)
 76              div_cnt <= 0;
 77          else if(add_div_cnt)begin
 78              if(end_div_cnt)
 79                  div_cnt <= 0;
 80              else 
 81                  div_cnt <= div_cnt + 1'b1;
 82          end
 83          else 
 84              div_cnt <= 0;
 85      end
 86      
 87      assign add_div_cnt = busy == 1;
 88      assign end_div_cnt = add_div_cnt && div_cnt == SCL_CYC - 1;
 89      
 90      //比特计数器
 91      always@(posedge clk or negedge rst_n)begin
 92          if(!rst_n)
 93              bit_cnt <= 0;
 94          else if(add_bit_cnt)begin
 95              if(end_bit_cnt)
 96                  bit_cnt <= 0;
 97              else 
 98                  bit_cnt <= bit_cnt + 1'b1;
 99          end
100      end
101      
102      assign add_bit_cnt = end_div_cnt;
103      assign end_bit_cnt = add_bit_cnt && bit_cnt == N - 1;
104      
105      always@(*)begin
106          case(state_c)
107              WRI_CTRL:N = 8;
108              ADDR:N = 8;
109              WRI_DATA:N = 8;
110              RD_CTRL:N = 8;
111              RD_DATA:N = 8;
112              default:N = 1;
113          endcase
114      end
115      
116      //---------------------iic时序四段式状态机部分-------------------------
117      
118      //时序逻辑描述状态转移
119      always@(posedge clk or negedge rst_n)begin
120          if(!rst_n)
121              state_c <= IDLE;
122          else 
123              state_c <= state_n;
124      end
125      
126      //组合逻辑描述状态转移条件
127      always@(*)begin
128          case(state_c)
129              IDLE:begin       //空闲状态
130                  if(idle2start)
131                      state_n = START;
132                  else 
133                      state_n = state_c;
134              end
135              
136              START:begin    //产生开始条件 即SCL高电平期间SDA拉低
137                  if(start2wri_ctrl)
138                      state_n = WRI_CTRL;
139                  else 
140                      state_n = state_c;
141              end
142              
143              WRI_CTRL:begin  //写器件地址和写标志位
144                  if(wri_ctrl2ack1)
145                      state_n = ACK1;
146                  else 
147                      state_n = state_c;
148              end
149              
150              ACK1:begin   //等待响应
151                  if(ack12addr)
152                      state_n = ADDR;
153                  else if(ack2idle)
154                      state_n = IDLE;
155                  else 
156                      state_n = state_c;
157              end
158              
159              ADDR:begin  //写存储单元地址
160                  if(addr2ack2)
161                      state_n = ACK2;
162                  else 
163                      state_n = state_c;
164              end
165              
166              ACK2:begin   //等待响应2
167                  if(ack22wri_data)   //写操作
168                      state_n = WRI_DATA;
169                  else if(ack22re_start)//读操作
170                      state_n = RE_START;
171                  else if(ack2idle)
172                      state_n = IDLE;
173                  else 
174                      state_n = state_c;
175              end
176              
177              WRI_DATA:begin   //写数据 8bit
178                  if(wri_data2ack3)
179                      state_n = ACK3;
180                  else 
181                      state_n = state_c;
182              end
183              
184              ACK3:begin   //等待响应3
185                  if(ack32stop)
186                      state_n = STOP;
187                  else if(ack2idle)
188                      state_n = IDLE;
189                  else 
190                      state_n = state_c;
191              end
192              
193              RE_START:begin  //若为读操作在响应2后再次构造开始条件
194                  if(re_start2rd_ctrl)
195                      state_n = RD_CTRL;
196                  else 
197                      state_n = state_c;
198              end
199              
200              RD_CTRL:begin   //写入存储单元地址和读标志位
201                  if(rd_ctrl2ack4)
202                      state_n = ACK4;
203                  else 
204                      state_n = state_c;
205              end
206              
207              ACK4:begin  //等待响应4
208                  if(ack42rd_data)
209                      state_n = RD_DATA;
210                  else if(ack2idle)
211                      state_n = IDLE;
212                  else 
213                      state_n = state_c;
214              end
215              
216              RD_DATA:begin  //读数据 8bit
217                  if(rd_data2nack)
218                      state_n = NACK;
219                  else 
220                      state_n = state_c;
221              end
222              
223              NACK:begin  //不响应 无操作即可
224                  if(nack2stop)
225                      state_n = STOP;
226                  else 
227                      state_n = state_c;
228              end
229              
230              STOP:begin  //构造停止条件
231                  if(stop2idle)
232                      state_n = IDLE;
233                  else 
234                      state_n = state_c;
235              end
236              
237              default:
238                  state_n = IDLE;
239          endcase
240      end
241      
242      //连续赋值语句定义状态转移条件
243      assign idle2start       = state_c  == IDLE     && (write_en || read_en);
244      assign start2wri_ctrl   = state_c  == START    && end_bit_cnt;  
245      assign wri_ctrl2ack1    = state_c  == WRI_CTRL && end_bit_cnt;
246      assign ack12addr        = state_c  == ACK1     && ack_valid && end_bit_cnt;
247      assign addr2ack2        = state_c  == ADDR     && end_bit_cnt;
248      assign ack22wri_data    = state_c  == ACK2     && ack_valid && !rd_flag && end_bit_cnt;
249      assign wri_data2ack3    = state_c  == WRI_DATA && end_bit_cnt;
250      assign ack32stop        = state_c  == ACK3     && ack_valid && end_bit_cnt;
251      assign ack22re_start    = state_c  == ACK2     && ack_valid && rd_flag && end_bit_cnt;
252      assign re_start2rd_ctrl = state_c  == RE_START && end_bit_cnt;
253      assign rd_ctrl2ack4     = state_c  == RD_CTRL  && end_bit_cnt;
254      assign ack42rd_data     = state_c  == ACK4     && ack_valid && end_bit_cnt;
255      assign rd_data2nack     = state_c  == RD_DATA  && end_bit_cnt;
256      assign nack2stop        = state_c  == NACK     && end_bit_cnt;
257      assign stop2idle        = state_c  == STOP     && end_bit_cnt;
258      assign ack2idle         = ack_state && ack_invalid;
259      
260  
261      
262      always@(posedge clk or negedge rst_n)begin
263          if(!rst_n)
264              ack_valid <= 0;
265          else if(ack12addr || ack22wri_data || ack32stop || ack22re_start || ack42rd_data || ack2idle)
266              ack_valid <= 0;
267          else if(ack_state && high_middle && !sda_en && !sda_in)
268              ack_valid <= 1;
269      end
270      
271      assign ack_state = state_c == ACK1 || state_c == ACK2 || state_c == ACK3 || state_c == ACK4;
272      
273      always@(posedge clk or negedge rst_n)begin
274          if(!rst_n)
275              ack_invalid <= 0;
276          else if(state_c == NACK && high_middle && !sda_en && sda_in)
277              ack_invalid <= 1;
278          else if(end_bit_cnt)
279              ack_invalid <= 0;
280      end
281      
282      //时序逻辑描述状态输出
283      
284      //scl时钟信号
285      always@(posedge clk or negedge rst_n)begin
286          if(!rst_n)
287              scl <= 0;
288          else if(add_div_cnt && div_cnt == SCL_CYC/4 - 1)
289              scl <= 1;
290          else if(add_div_cnt && div_cnt == SCL_CYC/4 + SCL_CYC/2 - 1)
291              scl <= 0;
292      end
293      
294      //找到scl高低电平中间点
295      always@(posedge clk or negedge rst_n)begin
296          if(!rst_n)
297              high_middle <= 0;
298          else if(add_div_cnt && div_cnt == SCL_CYC/2 - 1)
299              high_middle <= 1;
300          else 
301              high_middle <= 0;
302      end
303      
304      //三态门输出使能
305      always@(posedge clk or negedge rst_n)begin
306          if(!rst_n)
307              sda_en <= 1;
308          else if(idle2start || ack12addr || ack22wri_data || ack32stop || ack22re_start || nack2stop|| rd_data2nack)
309              sda_en <= 1;
310          else if(wri_ctrl2ack1 || addr2ack2 || wri_data2ack3 || rd_ctrl2ack4 || ack2idle || stop2idle)
311              sda_en <= 0;
312      end
313      
314      //数据总线输出寄存器
315      always@(posedge clk or negedge rst_n)begin
316          if(!rst_n)
317              sda_reg <= 1;
318          else if(idle2start)
319              sda_reg <= 1;
320          else if((state_c == START || state_c == RE_START) && high_middle)
321              sda_reg <= 0;
322          else if(state_c == WRI_CTRL)
323              sda_reg <= device_addr_wr[7-bit_cnt];
324          else if(state_c == ADDR)
325              sda_reg <= word_addr[7 - bit_cnt];
326          else if(state_c == WRI_DATA)
327              sda_reg <= wri_data[7 - bit_cnt];
328          else if(state_c == STOP && high_middle)
329              sda_reg <= 1;
330          else if(ack22re_start)
331              sda_reg <= 1;
332          else if(state_c == RE_START && high_middle)
333              sda_reg <= 0;
334          else if(state_c == RD_CTRL)
335              sda_reg <= device_addr_rd[7- bit_cnt];
336          else if(ack_state)
337              sda_reg <= 0;
338          else if(rd_data2nack)
339              sda_reg <= 1;
340          else if(nack2stop)
341              sda_reg <= 0;
342      end
343      
344      assign device_addr_wr = {4'b1010,cs,1'b0};
345      assign cs             = 3'b000;
346      assign word_addr      = share_addr;
347      assign device_addr_rd = {4'b1010,cs,1'b1};
348      
349      //读取数据缓存
350      always@(posedge clk or negedge rst_n)begin
351          if(!rst_n)
352              rd_buf <= 0;
353          else if(state_c == RD_DATA && high_middle)
354              rd_buf <= {rd_buf[6:0],sda_in};
355      end
356      
357      //读数据有效指示
358      always@(posedge clk or negedge rst_n)begin
359          if(!rst_n)
360              rd_data_vld <= 0;
361          else if(rd_data2nack)
362              rd_data_vld <= 1;
363          else 
364              rd_data_vld <= 0;
365      end
366      
367      //读数据输出
368      always@(posedge clk or negedge rst_n)begin
369          if(!rst_n)
370              rd_data <= 0;
371          else 
372              rd_data <= rd_buf;
373      end
374      
375      //读标志位
376      always@(posedge clk or negedge rst_n)begin
377          if(!rst_n)
378              rd_flag <= 0;
379          else if(read_en)
380              rd_flag <= 1;
381          else if(rd_flag && (stop2idle || state_c == IDLE))
382              rd_flag <= 0;
383      end
384      
385      //总线忙信号
386      always@(posedge clk or negedge rst_n)begin
387          if(!rst_n)
388              busy <= 0;
389          else if(write_en || read_en)
390              busy <= 1;
391          else if(busy == 1 &&(stop2idle || state_c == IDLE))
392              busy <= 0;
393      end
394      
395  endmodule
eeprom_i2c
 1 `timescale 1ns / 1ps
 2 module tb_eeprom_i2c;
 3 
 4     reg   clk;
 5     reg rst_n;
 6     wire scl;
 7     wire sda;
 8     wire sda_en;//高电平时待测试文件为输出
 9 
10     reg sda_tb_out;
11     wire [13:0] state_c;
12     
13     reg  read,write;    
14 
15     
16     eeprom_i2c #(.SCL_CYC(100)) 
17     eeprom_i2c_inst(
18     .clk(clk),
19     .rst_n(rst_n),
20 
21     //用户侧接口
22     .write_en(write),  //写指令
23     .read_en(read),    //读指令
24     .share_addr(8'h15),//读写复用地址
25     .wri_data(8'h32),  //待写入数据
26 
27     //仿真接口
28     .sda_en(sda_en),
29     .state_c(state_c),
30     //eeprom侧接口
31     .scl(scl),
32     .sda(sda)
33     );
34 
35 
36 
37     assign sda = (!sda_en) ? sda_tb_out : 1'bz;
38 
39     parameter CYC = 5,
40               RST_TIME = 2;
41 
42     localparam IDLE     = 14'b00_0000_0000_0001,
43                START    = 14'b00_0000_0000_0010,
44                WRI_CTRL = 14'b00_0000_0000_0100,
45                ACK1     = 14'b00_0000_0000_1000,
46                ADDR     = 14'b00_0000_0001_0000,
47                ACK2     = 14'b00_0000_0010_0000,
48                WRI_DATA = 14'b00_0000_0100_0000,
49                ACK3     = 14'b00_0000_1000_0000,
50                RE_START = 14'b00_0001_0000_0000,
51                RD_CTRL  = 14'b00_0010_0000_0000,
52                ACK4     = 14'b00_0100_0000_0000,
53                RD_DATA  = 14'b00_1000_0000_0000,
54                NACK     = 14'b01_0000_0000_0000,
55                STOP     = 14'b10_0000_0000_0000;
56 
57     initial begin
58         clk = 0;
59         forever #(CYC/2) clk = ~clk;
60     end
61 
62     initial begin
63         rst_n = 1;
64         #1;
65         rst_n = 0;
66         #(CYC*RST_TIME);
67         rst_n = 1;
68     end
69 
70     initial begin
71         write = 1'b0;    
72         #1;
73         write = 1'b1;
74         read  = 1'b0;
75         
76         // #(CYC*RST_TIME);
77         // #(CYC*10);
78         #11664;
79         write = 1'b0;
80         read  = 1'b1;
81         #10000;
82         write = 1'b0;
83         read  = 1'b0;        
84         $stop;
85     end
86 
87     //构造响应条件
88     always@(*)begin
89         if(state_c == ACK1 || state_c == ACK2 || state_c == ACK3 || state_c == ACK4)
90             sda_tb_out <= 0;
91         else
92             sda_tb_out <= 1;
93     end
94 
95 endmodule
tb_eeprom_i2c

参考文献链接:

1.https://www.cnblogs.com/moluoqishi/p/7434902.html

2.https://www.cnblogs.com/liujinggang/p/9656358.html

标签:wire,0000,14,读写,b00,sda,IIC,reg,EEPROM
From: https://www.cnblogs.com/taylorrrrrrrrrrr/p/18051633

相关文章

  • 多线程系列(十一) -浅析并发读写锁StampedLock
    一、摘要在上一篇文章中,我们讲到了使用ReadWriteLock可以解决多线程同时读,但只有一个线程能写的问题。如果继续深入的分析ReadWriteLock,从锁的角度分析,会发现它有一个潜在的问题:如果有线程正在读数据,写线程准备修改数据的时候,需要等待读线程释放锁后才能获取写锁,简单的说就是,读......
  • txt文件的读写
    1.引用usingSystem.IO;2.创建并写publicvoidWriteTxt(stringfilepth,stringstr){FileStreamfs1=newFileStream(filepth,FileMode.Create,FileAccess.ReadWrite);StreamWritersw=newStreamWriter(fs1);sw.WriteLine(str);sw.Close();......
  • STM32硬件IIC使用
    STM32硬件IIC使用.md概述虽然STM32的硬件IIC据说有设计缺陷,但是经过我的实践,至少STM32F103的硬件IIC是没问题的。这里给出STM32的硬件IIC的使用以及编程思路。1.STM32硬件IIC引脚在这里给出STM32F103的硬件IIC引脚,方便查阅使用2.STM32硬件IIC使用流程STM32的硬件IIC我认......
  • 通过SDIO接口+FATFS对SD卡进行读写操作
    摘要:cubemax工程建立(主要描述SDIO和FATFS配置部分,实际上还添加了串口用作调试打印)代码示例主函数、fatfs、sdio接口之间的层次关系 cubemax工程建立:首先,找到SDIO,进行配置。SDIO的模式有1bit、4bits总线模式,根据板子的原理图进行选择。SDIO其他参数保持默认,只修改SDIO时......
  • RFID射频信号的耦合与传输工作频率,增加读写成功,规避读写失败
    RFID射频信号的耦合与传输工作频率:RFID读写器通过天线RFID标签的工作频率通常分为低频、高频和超高频三种。如下:1、低频标签的工作频率为125kHz,识别距离一般在10cm以内。2、高频标签的工作频率为13.56MHz,识别距离一般在1米以内。3、超高频标签的工作频率为860MHz—960MHz,......
  • AT7456E一颗集成EEPROM的单通道单色随屏显示器芯片
    AT7456E是一款集成了EEPROM的单通道、单色随屏显示发生器,集成了视频驱动器、同步分离器、视频分离开关以及EEPROM,提高了系统的集成度,有效降低了系统成本。优势1.采用符合NTSC和PAL制式的512个用户可编程字符,适合于全球市场。2.能够方便地以任意字符、尺寸显示各种信息,......
  • 读写文本文件
    <%ConstfileName="counter.txt"ConstForReading=1ConstForWriting=2ConstForAppending=8DimoFSO,oFile,sFileContentfilePath=Server.MapPath(fileName)SetoFSO=Server.CreateObject("Scripting.FileSystemObject")IfNo......
  • 文件读写
    1.文件读写操作(重点)1.回顾C语言的文件读写1.按照字符读写文件fgetc、fputcintfputc(intch,FILE*stream);//写intfgetc(FILE*stream);//读2.按照行读写文件fgets、fputs//可bit读写intfputs(constchar*str,FILE*stream);//写char*fgets(char*str,int......
  • 分布式下的数据拆分,读写分离,分库分离相关问题
    一、为什么要用分库分表当不使用分库分表的情况下,系统的性能瓶颈主要体现在:当面临高并发场景的时候,为了避免Mysql崩溃(MySql性能一般的服务器建议2000/s读写并发以下),只能使用消息队列来削峰。受制于单机限制。数据库磁盘容量吃紧。数据库单表数据量太大,sql越跑越慢而分库分......
  • mysql 一主一从 读写分离
    schema.xml配置  主从balance策略 读写分离首先需要配置主从复制 ,主从复制请查看  主库备库需要创建 itcast数据库 目前读写分离是使用的mycat 需要配置 /usr/local/mycat/conf/schema.xml (注意格式缩进)<?xmlversion="1.0"?><!DOCTYPEmycat:sch......