EEPROM读写学习笔记与I2C总线(转)
reference:https://www.cnblogs.com/uiojhi/p/7565232.html
无论任何电子产品都会涉及到数据的产生与数据的保存,这个数据可能并不是用来长久保存,只是在运行程序才会用到,有些数据体量较大对于获取时效性并不太强,各种各样的数据也就有不同的存储载体,这次在EEPROM读写中,顺道把看到的关于存储的一些东西整理一下,有些话来自于网友,所以还是那句话,看到的人要带着自己的思考去看,记住尽信书不如无书,fighting!!!
一、基本概念
最熟悉的两个词语应该是RAM与ROM,RAM(Random Access Memory)的全名为随机存取记忆体,它相当于PC机上的移动存储,用来存储和保存数据的。它在任何时候都可以读写,RAM通常是作为操作系统或其他正在运行程序的临时存储介质,它的一切都是最好的,唯一缺点断电一切东西都没有了。一般情况下,现在移动设备也多了,我们叫它内存,更通常的叫运行内存。还有一个熟悉的词DDR2或DDR3,后面还会学习到的。
ROM(Read Only Memory)的全名为唯读记忆体,它相当于PC机上的硬盘,用来存储和保存数据。ROM数据不能随意更新,但是在任何时候都可以读取。即使是断电,ROM也能够保留数据。但是资料一但写入后只能用特殊方法或根本无法更改,但这么久了ROM已经有了很大的发展,不再是最初的摸样了。rom最初不能编程,出厂什么内容就永远什么内容,不灵活。后来出现了prom,可以自己写入一次,要是写错了,只能换一片,自认倒霉。人类文明不断进步,终于出现了可多次擦除写入的EPROM,每次擦除要把芯片拿到紫外线上照一下,想一下你往单片机上下了一个程序之后发现有个地方需要加一句话,为此你要把单片机放紫外灯下照半小时,然后才能再下一次,这么折腾一天也改不了几次。历史的车轮不断前进,伟大的EEPROM出现了,拯救了一大批程序员,终于可以随意的修改rom中的内容了,这一段话就说出了ROM的发展历程。
狭义的EEPROM:这种rom的特点是可以随机访问和修改任何一个字节,可以往每个bit中写入0或者1。这是最传统的一种EEPROM,掉电后数据不丢失,可以保存100年,可以擦写100w次。具有较高的可靠性,但是电路复杂/成本也高。它的改写是由高电压或者由控制端的逻辑电平来完成的。因此目前的EEPROM都是几十千字节到几百千字节的,绝少有超过512K的。我们也就发现了EEPROM的确可以实现随意读写,EEPROM的全称是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。可介绍的这两种都不存在大容量并且也十分昂贵,那我们平时见到的几十G的存储设备是什么?flash就应运而生了。flash属于广义的EEPROM,因为它也是电擦除的rom。但是为了区别于一般的按字节为单位的擦写的EEPROM,我们都叫它flash。flash做的改进就是擦除时不再以字节为单位,而是以块为单位,一次简化了电路,数据密度更高,降低了成本。上M的rom一般都是flash。
ROM的应用
对数指数、三角函数等常规计算通过写出真值表,将自变量以地址码的形式输至ROM,用ROM表来实现。还有码制转换,例如二进制码转格雷码。脉冲序列发生器,伪彩色处理电路,也就是将一幅黑白图像变成彩色图像显示,将灰度图像对应到red , green , blue三个通道上,最后将三个通道的颜色值合成为需要显示的RGB颜色值即可。具体可参考 https://blog.csdn.net/huixingshao/article/details/42706699 。
接下来说一下flash的分类,flash分为nor flash和nand flash。nor flash数据线和地址线分开,可以实现ram一样的随机寻址功能,可以读取任何一个字节。但是擦除仍要按块来擦。nand flash同样是按块擦除,但是数据线和地址线复用,不能利用地址线随机寻址。读取只能按页来读取。NOR Flash的读取,用户可以直接运行装载在NOR FLASH里面的代码。NAND Flash没有采取内存RAM的随机读取技术,它的读取是以一次读取一块的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR Flash来运行启动代码。nandflash引脚上复用,因此读取速度比nor flash慢一点,但是擦除和写入速度比nor flash快很多。nand flash内部电路更简单,因此数据密度大,体积小,成本也低。因此大容量的flash都是nand型的。小容量的2~12M的flash多是nor型的。nor flash可以进行字节寻址,所以程序可以在nor flash中运行。嵌入式系统多用一个小容量的nor flash存储引导代码,用一个大容量的nand flash存放文件系统和内核。
二、I2C总线
这个在我转载的一篇文章里面有很详细的描述,就不在提及了。有一个问题是无论UART还是I2C都是串行按位传输数据,区别在哪?还有SPI传输,下面分别总结一下三者的特点。
UART:两线,一根发送一根接收,可以全双工通信,数据异步传输,对双方的时序要求比较严格,在多机通信上面用的最多。按照标准波特率完成双向通讯,速度慢,之前提到采集一位数据就需要16个时钟周期,适合远距离传输,比如IEEE488定义并行通行状态时,规定设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。UART需要固定的波特率,就是说两位数据的间隔要相等,
I2C:能用于替代标准的并行总线,能连接的各种集成电路和功能模块。I2C是多主控总线,所以任何一个设备都能像主控器一样工作,并控制总线。总线上每一个设备都有一个独一无二的地址,根据设备它们自己的能力,它们可以作为发射器或接收器工作。多路微控制器能在同一个I2C总线上共存,当然在任何时间点上只能有一个主控。一般用于同一板卡上芯片之间的通信,较少用于远距离通信。
SPI:SPI接口和UART相比,多了一条同步时钟线,对通信双方的时序要求不严格不同设备之间可以很容易结合,而且通信速度非常快。一般用在产品内部元件之间的高速数据通信上面,如大容量存储器flash等。高速同步串行口,3~4线接口,收发独立、可同步进行。
三、EEPROM通信举例
同样通过一个程序来学习里面内容。自加内容用红笔标出。
1)IIC_WR模块
写步骤:
a. 实现开始信号
b. 发送24LC04B设备地址,从机发送应答信号
c. 发送待存储数据的地址,接受应答信号
d. 发送待写入数据,接受应答信号
e. 实现结束信号
读步骤:
a. 实现开始信号
b. 发送24LC04B设备地址,从机发送应答信号
c. 发送待读取数据的地址,接受应答信号
d. 实现开始信号
e. 发送24LC04B设备地址,从机发送应答信号
f. 读取8位数据
g. 实现非应答信号
h. 实现结束信号
通过状态机 i 来切换 IIC 的不同状态,譬 如接收到写命令,状态机i=0 转入 Start 状态,SDA 先变低,再 SCL 变低;状态机i=1 开 始 转 入 写 设 备 地 址 0xA0; 之 后 状 态 机 转 到 7 开 始 发 送 8 位 的 数 据 , 其 中 状 态 机 i=7,8,9,10,11,12,13,14 是 IIC 发送8位的数据,然后状态机进入 i=15 等待 IIC 从设备的应答 信号。状态机 i=16 为判断是否有应答,如果有的话状态机转到 i=2 写 IIC 的地址,然后状态机 又是重复i=7,8,9,10,11,12,13,14 发送地址和 i=15 等待应答,i=16 判断应答。最后状态机 i=3 开始发送 IIC 写数据。发送完数据 i=4 发送 Stop 信号。
1 module iic_com
2 (
3 input CLK,
4 input RSTn,
5
6 input [1:0] Start_Sig, //read or write command
7 input [7:0] Addr_Sig, //eeprom words address
8 input [7:0] WrData, //eeprom write data
9 output [7:0] RdData, //eeprom read data
10 output Done_Sig, //eeprom read/write finish
11
12 output SCL,
13 inout SDA
14
15 );
16
17 parameter F250K = 9'd200; //250Khz的时钟分频系数 //200分频系数不必要用到9位,可改为8
18
19 reg [4:0]i; //用来只是状态机
20 reg [4:0]Go;
21 reg [8:0]C1;
22 reg [7:0]rData; //读信号
23 reg rSCL;
24 reg rSDA;
25 reg isAck;
26 reg isDone; //结束信号
27 reg isOut;
28
29 assign Done_Sig = isDone;
30 assign RdData = rData;
31 assign SCL = rSCL;
32 assign SDA = isOut ? rSDA : 1'bz; //SDA数据输出选择 //SDA的数据输出受到SCL的控制,SCL为高时SDA保持不变,在接收应答位期间SDA也受控制
33
34 //****************************************//
35 //* I2C读写处理程序 *//
36 //****************************************//
37 always @ ( posedge CLK or negedge RSTn )
38 if( !RSTn ) begin
39 i <= 5'd0; //状态机初始为0
40 Go <= 5'd0;
41 C1 <= 9'd0;
42 rData <= 8'd0;
43 rSCL <= 1'b1; //数据线和时钟线保持高电平初始值
44 rSDA <= 1'b1;
45 isAck <= 1'b1; //信号为低电平时规定为有效应答位,高电平为非有效应答位。
46 isDone <= 1'b0;
47 isOut <= 1'b1;
48 end
49 else if( Start_Sig[0] ) //I2C 数据写 //start_sig用来判断数据为读或写
50 case( i )
51
52 0: //发送IIC开始信号
53 begin
54 isOut <= 1; //SDA端口输出
55
56 if( C1 == 0 ) rSCL <= 1'b1;
57 else if( C1 == 200 ) rSCL <= 1'b0; //SCL由高变低 //分频系数为200,计数到200表明经过一个新的时钟周期时钟线变为低电平。
58
59 if( C1 == 0 ) rSDA <= 1'b1;
60 else if( C1 == 100 ) rSDA <= 1'b0; //SDA先由高变低 //计数到100时,rSDA变为低电平,符合信号开始发送条件。
61
62 if( C1 == 250 -1) begin C1 <= 9'd0; i <= i + 1'b1; end
63 else C1 <= C1 + 1'b1; //i=0用来表示开始信号发送,根据SDA与SCL变化可得,此处C1到达249,表示又过了四分之一个新时钟周期,i+1,运行下一步
64 end
65
66 1: // Write Device Addr
67 begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end //非阻塞赋值,Go为2
68
69 2: // Wirte Word Addr
70 begin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end //addr_sig为word address,Go为3
71
72 3: // Write Data
73 begin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end //写入数据,Go为4,WrData数值赋给rData。
74
75 4: //发送IIC停止信号
76 begin
77 isOut <= 1'b1;
78
79 if( C1 == 0 ) rSCL <= 1'b0;
80 else if( C1 == 50 ) rSCL <= 1'b1; //SCL先由低变高
81
82 if( C1 == 0 ) rSDA <= 1'b0;
83 else if( C1 == 150 ) rSDA <= 1'b1; //SDA由低变高 //SCL处于高电位时,SDA由低到高变化,处于结束位
84
85 if( C1 == 250 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
86 else C1 <= C1 + 1'b1;
87 end
88
89 5:
90 begin isDone <= 1'b1; i <= i + 1'b1; end //写I2C 结束
91
92 6:
93 begin isDone <= 1'b0; i <= 5'd0; end
94
95 7,8,9,10,11,12,13,14: //发送Device Addr/Word Addr/Write Data
96 begin
97 isOut <= 1'b1; //isout=1, SDA <= rSDA
98 rSDA <= rData[14-i]; //高位先发送
99
100 if( C1 == 0 ) rSCL <= 1'b0;
101 else if( C1 == 50 ) rSCL <= 1'b1; //SCL高电平100个时钟周期,低电平100个时钟周期
102 else if( C1 == 150 ) rSCL <= 1'b0;
103
104 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end //产生250Khz的IIC时钟 //i=14运行之后,状态机i=15
105 else C1 <= C1 + 1'b1;
106 end
107
108 15: // waiting for acknowledge
109 begin
110 isOut <= 1'b0; //SDA端口改为输入
111 if( C1 == 100 ) isAck <= SDA; //读取IIC 从设备的应答信号
112
113 if( C1 == 0 ) rSCL <= 1'b0;
114 else if( C1 == 50 ) rSCL <= 1'b1; //SCL高电平100个时钟周期,低电平100个时钟周期
115 else if( C1 == 150 ) rSCL <= 1'b0;
116
117 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end //产生250Khz的IIC时钟
118 else C1 <= C1 + 1'b1;
119 end
120
121 16:
122 if( isAck != 0 ) i <= 5'd0; //判断是否接收到应答信号
123 else i <= Go; //状态机i=1时,计算出i=2
124
125 endcase
126
127 else if( Start_Sig[1] ) //I2C 数据读
128 case( i )
129
130 0: // Start
131 begin
132 isOut <= 1; //SDA端口输出
133
134 if( C1 == 0 ) rSCL <= 1'b1;
135 else if( C1 == 200 ) rSCL <= 1'b0; //SCL由高变低
136
137 if( C1 == 0 ) rSDA <= 1'b1;
138 else if( C1 == 100 ) rSDA <= 1'b0; //SDA先由高变低
139
140 if( C1 == 250 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
141 else C1 <= C1 + 1'b1;
142 end
143
144 1: // Write Device Addr(设备地址)
145 begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end //先进行一个伪写操作
146
147 2: // Wirte Word Addr(EEPROM的写地址)
148 begin rData <= Addr_Sig; i <= 5'd9; Go <= i + 1'b1; end
149
150 3: // Start again
151 begin
152 isOut <= 1'b1; //开始进行读操作
153
154 if( C1 == 0 ) rSCL <= 1'b0;
155 else if( C1 == 50 ) rSCL <= 1'b1;
156 else if( C1 == 250 ) rSCL <= 1'b0;
157
158 if( C1 == 0 ) rSDA <= 1'b0;
159 else if( C1 == 50 ) rSDA <= 1'b1;
160 else if( C1 == 150 ) rSDA <= 1'b0;
161
162 if( C1 == 300 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
163 else C1 <= C1 + 1'b1;
164 end
165
166 4: // Write Device Addr ( Read )
167 begin rData <= {4'b1010, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end
168
169 5: // Read Data
170 begin rData <= 8'd0; i <= 5'd19; Go <= i + 1'b1; end
171
172 6: // Stop
173 begin
174 isOut <= 1'b1;
175 if( C1 == 0 ) rSCL <= 1'b0;
176 else if( C1 == 50 ) rSCL <= 1'b1;
177
178 if( C1 == 0 ) rSDA <= 1'b0;
179 else if( C1 == 150 ) rSDA <= 1'b1;
180
181 if( C1 == 250 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
182 else C1 <= C1 + 1'b1;
183 end
184
185 7: //写I2C 结束
186 begin isDone <= 1'b1; i <= i + 1'b1; end
187
188 8:
189 begin isDone <= 1'b0; i <= 5'd0; end
190
191
192 9,10,11,12,13,14,15,16: //发送Device Addr(write)/Word Addr/Device Addr(read)
193 begin
194 isOut <= 1'b1;
195 rSDA <= rData[16-i]; //高位先发送 //将rData数据赋值给数据线,伪写操作
196
197 if( C1 == 0 ) rSCL <= 1'b0;
198 else if( C1 == 50 ) rSCL <= 1'b1; //SCL高电平100个时钟周期,低电平100个时钟周期
199 else if( C1 == 150 ) rSCL <= 1'b0;
200
201 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end //产生250Khz的IIC时钟
202 else C1 <= C1 + 1'b1;
203 end
204
205 17: // waiting for acknowledge
206 begin
207 isOut <= 1'b0; //SDA端口改为输入
208
209 if( C1 == 100 ) isAck <= SDA; //读取IIC 的应答信号
210
211 if( C1 == 0 ) rSCL <= 1'b0;
212 else if( C1 == 50 ) rSCL <= 1'b1; //SCL高电平100个时钟周期,低电平100个时钟周期
213 else if( C1 == 150 ) rSCL <= 1'b0;
214
215 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end //产生250Khz的IIC时钟
216 else C1 <= C1 + 1'b1;
217 end
218
219 18:
220 if( isAck != 0 ) i <= 5'd0;
221 else i <= Go;
222
223
224 19,20,21,22,23,24,25,26: // Read data
225 begin
226 isOut <= 1'b0;
227 if( C1 == 100 ) rData[26-i] <= SDA; //高位先接收
228
229 if( C1 == 0 ) rSCL <= 1'b0;
230 else if( C1 == 50 ) rSCL <= 1'b1; //SCL高电平100个时钟周期,低电平100个时钟周期
231 else if( C1 == 150 ) rSCL <= 1'b0;
232
233 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end //产生250Khz的IIC时钟
234 else C1 <= C1 + 1'b1;
235 end
236
237 27: // no acknowledge
238 begin
239 isOut <= 1'b1;
240
241 if( C1 == 0 ) rSCL <= 1'b0;
242 else if( C1 == 50 ) rSCL <= 1'b1;
243 else if( C1 == 150 ) rSCL <= 1'b0;
244
245 if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= Go; end
246 else C1 <= C1 + 1'b1;
247 end
248
249 endcase
250
251
252
253
254 endmodule
EEPROM读写学习笔记与I2C总线(转)的更多相关文章
- EEPROM读写学习笔记与I2C总线(二)
无论任何电子产品都会涉及到数据的产生与数据的保存,这个数据可能并不是用来长久保存,只是在运行程序才会用到,有些数据体量较大对于获取时效性并不太强,各种各样的数据也就有不同的存储载体,这次在EEPROM ...
- C# IO流与文件读写学习笔记
本笔记摘抄自:https://www.cnblogs.com/liyangLife/p/4797583.html,记录一下学习过程以备后续查用. 一.文件系统 1.1文件系统类的介绍 文件操作类大都在 ...
- flash读写学习笔记与spi接口及简单测试验证(三)
FPGA中的视频图像资源,以及想要永久存储的程序都是要存储在flash中,flash是FPGA一个不可缺少的部分,flash的种类有很多,根据winbond公司的128Mbit Qual SPI接口的 ...
- STM32学习笔记(八) SPI总线(操作外部flash)
1. SPI总线简介 SPI全称串行外设接口,是一种高速,全双工,同步的外设总线:它工作在主从方式,常规需要至少4根线才能够正常工作.SPI作为基本的外设接口,在FLASH,EPPROM和一些数字通讯 ...
- 【转】 树莓派学习笔记——I2C设备载入和速率设置
原文网址:http://blog.csdn.net/xukai871105/article/details/18234075 1.载入设备 方法1——临时载入设备 sudo modprobe -r i ...
- 树莓派学习笔记——I2C设备载入和速率设置
原文:http://blog.csdn.net/xukai871105/article/details/18234075 1.载入设备 方法1——临时载入设备 sudo modprobe -r i2c ...
- 基于I2C总线的MPU6050学习笔记
MPU6050学习笔记 1. 简述 一直想自己做个四轴飞行器,却无从下手,终于狠下决心,拿出尘封已久的MPU6050模块,开始摸索着数据手册分析,一步一步地实现了MPU6050模块的功能,从MPU60 ...
- I2C总线协议学习笔记 (转载)
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能有一 ...
- v3学院带你学习EEPROM读写实验
一.实验背景在消费者电子电讯和工业电子中看上去不相关的设计里经常有很多相似的地方例如几乎每个系统都包括一些智能控制通常是一个单片的微控制器,通用电路例如LCD驱动器远程I/O,RAM,EEPROM或数 ...
随机推荐
- You Don't Know JS: this & Object Prototypes( 第3章 对象)
前2章探索了this绑定指向不同的对象需要函数引用的call-site. 但是什么是对象,为什么我们需要指向它们? 本章探索细节. Syntax the rules that describe ho ...
- vux, vue如何控制微信自带的返回按钮,让其返回其他页面?
<script> import { mapState } from 'vuex' export default{ name: 'clockFx', data () { return { } ...
- C# 有哪些集合
队列[Queue] //队列:先进先出 /* *增加元素到队列结尾处 *移除队列开始处 */ Queue queue=new Queue(); queue.Enqueue(Object); queue ...
- IntelliJ IDEA调试方法补充
基本用法&快捷键 1.首先说第一组按钮,共8个按钮,从左到右依次如下: > Show Execution Point (Alt + F10):如果你的光标在其它行或其它页面,点击这个按钮 ...
- JQ 实现监测input中值的变化并绑定到另个input
$('#input').bind('input propertychange', function () { $('#myDiv ...
- 导出函数__declspec(dllexport)
一般而言,动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal function). 导出函数可以被其它模块调用,内部函数在定义它们的DLL程序内部使用. ...
- MongoDB\BSON\UTCDateTime::toDateTime
示例# 1 MongoDB \ BSON \ UTCDatetime:toDateTime()例子 <?php $utcdatetime = new MongoDB\BSON\UTCDateTi ...
- 按钮切换显示不同的内容(js控制)
今天项目发现了一个jsp页面按钮切换,下面展示模块的不同显示问题,看到同事修改完之后的效果,js控制感觉特写好,所以想写把这个好的方法js记录下来,以便以后的参考. 一:先上图,了解大概的样子,如下图 ...
- vue-router 路由钩子(hook)
钩子(hook)—劫持机制 路由钩子(守卫钩子): 1.全局钩子2.某个路由独享的钩子3.组件内钩子 三种路由钩子中都涉及到了三个参数,官方(https://router.vuejs.org/zh-c ...
- thinkphp 3.2 加载第三方库 第三方命名空间库
tp 自动加载的介绍: http://document.thinkphp.cn/manual_3_2.html#autoload 第三方库不规范库 不适用命名空间的库 可以使用import函数导入,其 ...