在好例子网,分享、交流、成长!
您当前所在位置:首页Others 开发实例一般编程问题 → I2C-verilog-(非常详细的i2c学习心得)

I2C-verilog-(非常详细的i2c学习心得)

一般编程问题

下载此实例
  • 开发语言:Others
  • 实例大小:1.30M
  • 下载次数:19
  • 浏览次数:145
  • 发布时间:2020-07-30
  • 实例类别:一般编程问题
  • 发 布 人:robot666
  • 文件格式:.pdf
  • 所需积分:2
 

实例介绍

【实例简介】
I2C-verilog-(非常详细的i2c学习心得),总结的非常详细。可以练手
(1)总线非忙犬态(A段):数据线SDA和时钟线SCL都保持高电平。 (2)启动数据传输(B段):当时钟线(SCL)为高电平状态时,数据线(SDA)由 高电平变为低电平的下降沿被认为是“启动”信号。只有出现“启动”信号后,其它的命令 才有效。 (3)停止数据传输(C段):当时钟线(SCL)为高电平状态时,数据线(SDA)由 低电平变为高电平的上升沿被认为是“停止”信号。随着“停在”信号出现,所有的外部操 作都结束。 (4)数据有效(D段):在出现“启动”信号以后,在时钟线(SCL)为高电平状态时 数据线是稳定的,这时数据线的状态就要传送的数据。数据线(SDA)上的数据的改变 必须在时钟线为低电平期间完成,每位数据占用一个时钟脉冲。每个数传输都是由“启动 信号开始,结束于“停止”信号。 (5)应答信号:每个正在接收数据的从机 EEPROM在接到一个字节的数据后,通 常需要发山个应答信号。而每个正在发送数据的 EEPROM在发出个字节的数据后 通常需要接收一个应答信号。 EEPROM读写控制器必须产牛一个与这个应答位相联系的 额外的时钟脉冲。在 EEPROM的读操作中, EEPROM读写控制器对 EEPROM完成的最 后一个字节产生一个高的应答位,这叫做非应答信号,随后给 EEPROM一个结束信号 第四步,理解各个模块的代码 首先介绍核心模块—— EEPROM WR模块,这个模块就下·件事,严格控制SDA与SCL 总线上的信号,使其满足12C总线时序要求。这里要用到状态机来控制SDA与SCL上的信号, 所以难点就在于对状态机的编写。因为EP2C8-2010开发板采用的 EEPROM是AT24C02, 所以该状态札控制的sCL与SDA时序就要满足AT24C02的写入和读取格式。图4、5分别 是AT24C02/4/8/16字节写入帧格式和读指定地址有储单元的数据帧格式,筍单分析一下字 节写入格式,如图4所示:第1位启动信号,接下来的第2-9位是控制字节写入,其中2-5 位是固定的机器码1010,6-8位是页地址,第10位是 EEPROM给出的应答信号0,第11-18 位是存储单元地址,19位是 EEPROM给出的应答信号0,第20-27位是写入的数据,28位 应答信号,29位停止信号。而AT24C02/4/8/16的字节读取格式也是大同小异,先写入控制 字和存储地址,然后是启动信号与控制字节信号,这时,控制字节的第8位变为了1(读取), 最后读取数据,并且在读取完毕后,主机将SDA拉高作为非应答信号。最后是停止位。 可能有人还是对这种字节写入与读取格式不明白,其实这种格式是别人定好的,我们所 需要的就是要让SDA与SCL的信号满足这种格式要求即可,下面我们来看夏老师的 EEPROM WR程序 控制字节 EEPROM存储单元地址 止 S1 00XX X 图4.AT24C02/4/8/16字节写入帧格式 启 动控制字节 EEPROM存诸单元启控制字节 指定地址(n) 数据(n) 停 山山L SI010X XX 应 应51010XXX应 非P 答 图5.AT24C02/4/8/16读指定地址存储单元的数据帧格式 首先是一堆输入输岀、寄存器的定义,我们读程序的时候大可先不看这些,等到后面有 需要的时候再回过头来看这些定义,这里需要注意的是SDA与DAIA的类型,都是 inout型, SDA我们很容易理解,因为主杪和从机都会给SDA线上发信号,比如字节写入格式时,主机 先给SDA发了1个8位数据,然后作为应答位,从机要把SDA拉低,表示我已经接受到你 的信号了,在应答位时主机是不能操作SDA线的。然而DATA设定为 inout型,我们可以看 到图2,其实在字节写入格式时,DATA是 signal模块传输给 EEPROM WR模块,作为要写入 的数据。而在字节读取格式时, EEPROM WR通过SDA从 EEPROM中读取数据,其实跟DATA 是没有关系的,这里可以只将DATA设定为 Input型,设定为 inout型是因为后续的程序会将 EEPROM_WR读取到的数据发给sigηa,与 signal当初发送的数据进行比较,检验通信是否 正确。如果将比较数据这程序操作放在 EEPROM WR模块中,就可以将DATA设为 input 提到 inout类型,还得再多补充两句, inout,顾名思义,双向口既能作为输入又能作为 输出,可以节省管脚,在具体实现上一般是用三态门来实现,图6就是用一态门实现的sda 总线的示意图。 link sda out flag EEPROM WR EEPROM SDA --------------------------------------------1 图6.sda总线示意图 link sda和 out flag分别为 EEPROM WR和 EEPROM控制三态门输出的开关,当link_sda 打开, out flag关闭时, EEPROM WR向SDA传输数据, EEPROM接收SDA的数据,此时, SDA对于 EEPROM_WR来说就是 output,对于 EEPROM来说就是 input。反之,当link_sda 关闭, out flag打开时, EEPROM_WR通过SDA从从 EEPROM中读取数据。当 link sda与 out flag都关闭吋,SDA就被置为高阻状态 下面来看程序中对于SDA和DATA三态门的描述。 assign sal (ink head) head buf 1 1"b0 assign sda2 =(ink write) shout buf[7] 1b0; assign sda3 Cink_ stop) stop buf[ 1] 1b0; assign sda4 =(sda1 sda2 sda3); assign SDa =(ink_ sda) d a4 1"b assign data =(ink read) data from_ rm 8'hzz 这是程序中应用三态门对双向口的实现,我们可以看到引入了多个开关, link head、 link write、 link stop、 link sda、 link read,其中 link sda和 link read这两个开关是最主要的, 当 link sda=1,即 link sda打开时,将sda4输出,SDA=sda4。当 link sda=0时,将SDA置 为高阻。同时sda4也是由三个开关控制的,为sda1、sda2、sda3三个信号相或的结果,这 里是将 EEPROM WR的状态分为了三个基本的状态,分别是启动状态、写入状态以及停止状 态,这是根据 EEPROM对SDA总线输出的值区分的。对照图3、图4,其实意思就是在启动 的时候给SDA一个下降沿,停止时给SDA一个上升沿,传输数据时给SDA一个有效数据。 引入这些开关是为了看得更加直观。当然,我们也可以不引入这么多廾关,只需要 link sda 和 link read,在每次 link sda打开的时候我们都给sda4赋新值即可。 下面我们来看产生串行时钟SCL的程序 always @(negedge CLK) if(RESET) SCL <=0 SCL <ENSCL 这条产生SCL的程序也是十分巧妙的,本文中的程序是用CLK的下降沿来触发SCL时钟, 用CLK的上升沿来触发SDA,这样SDA与SCL就相差了半个SCL周期,目的是为了满足1C 总线上的传输协议,具体见图7. 「」「 SDA 启动位 数据1 数据O 数据1 数据 停止位 图7.SCL与SDA基本时序关系 从图7中,我们可以看出,启动位占了一个sCL时钟周期,1时刻拉高,2时刻拉低, 保证在SCL高电平时SDA有下降沿,这样就是启动信号,同理,如果我们要传输数据时,3 时刻将传输的数据赋给SDA,比如要传输的数是1010,3时将SDA拉高,直到完成1个SCL 周期时再把下一个值0赋给SDA。这样就是一个SCL与SDA基本的时序关系,我个人的理解 是这样的:首先,要保证图3、4中字节读写格式的每一位都要占一个SCL时钟周期。其次 每个CLK上∫沿吋将数据传给SDA,比如1:SDA<=1;2:SDA<=0。这样才能保证时序的 致忆 接下来我们看到的就是主状态机程序,由图3、4列出的字节读写格式,我们可以将读 写操作分为一共11个状态,状态图如下。 读或写信 输入 应答 写开始 输出应答 操作停山 写摔制字 写数据 停止 读数据 写入地址 读操 读控制了 读开始 作 图8.读写操作状态转移 我们依次来看到各个状态 Idle egIn link read < no /空闲状态时SDA总线关闭 link write < no link head < no link stop <=NO link sda < no if(WR) /如果有写信号 begin ∥/标志位置1,主状态跳到准备状态 WF<=1 main state <=Ready else if(RD) ∥/如果有读信号 begin ∥/读标志位置1,主状态跳到准备状态 RF<=1; main state < Read en else egIn WF<=0; RF<=0; tate < ldle end end ldle:空闲状态,主要就是说当我们的读写控制器收到读/写指令时,要跳到 Ready状态, 准备往SDA上进行操作。(很多时候如果下板调试的时候读出没有信号的情况,我们可以考 虑在 signaltap中检查wR和RD是否改变了,很有可能这两个输入信号输入错误导致进入不 了状态机了) Read /准备状态时 link read link write <=NO; link stop < NO link head < YES / link head打廾,sda1=1 link sda =YeS //ink_sda打开,sda=sda4=1 head buf[1: 0 <=2"b10;// link head打开时sda1= head bu[4 stop buf[1: 0] <=2"b01;∥给stop_buf赋值,操作停止时用 head state <= head begin;/给 shift head任务中的状态 / Thead state赋值,准备启动 <=0 /标志位F置0 ACK <=0: ∥/应答信号ACK置0 main state <= Write start;//主状态跳至廾始 Ready:些初始化赋值语句,此时SDA<- head buf[1],也就是将SDA拉高,准备启动。 这里的ACK应答信号并不是我们所说的 EEPROM与 EEPROM WR传输数据中的应答信号, 如图2所示,这里的ACK是 EEPROM WR与 signal模块传输数据的应答信号。 Write start if(FF==O) ∥/此时FF=0,进入 shift head仟务 shift he 跳转到 task shift head中执行 e // shift head中将F置1,此时进入else语句 gin sh8 out buf[7:0]<={1b1,1"b0,1b1,1b0ADDR[108],1"b0} /)给sh8 out buf赋值,1010为机器码,ADDR[10:8]是页地址,0代表写操作,sh8 out buf就 ∥/是要给sda赋的值,sda取sh8 out buf的最高位。 link head <=NO; /启动信号开关断开 link write <E YES: / EEPROM写操作开关打开 )将标志位FF置0 sh8 out state<=sh8 out bite6;// hift head仟务中的状态从sh8 out bit6 /开始,而不是从sh8 out bit7开始 main state <= Ctrl write;∥'主状态跳到 输出启动信号任冬 task shift head / shift head任务,输出启动信号 /即sc为高电平时,sda由高电平变为低电平 case(head state) ∥/之前给head_ state赋过值head_ begin,所以直接从 head begin // head begin开始 if(!」CL) //当scl为低电平时 begin /sda置1,同时状态 head state跳到 head bit; link write <= no: link <= YE link head YES head state < head bit else ∥/当sc不为低电平时,继续执行 head begin head sta nd begin; if(SCL ∥/当sc为高电平时 begin FF //标志位FF置1 head_buf<-head_bufκ<1;// head buf左移一位,sda置0 head sta end else head state < head bit nead end ∥/此时FF=1,下一次ck上升沿来的时候,会跳 if(!SCL //出这个任务,执行 Write start中else的内容 begin /所以这个状态不曾进入过,可以删去 link head <= no link write <=YES nd else head state < head end endcase end endtask Write start:首先一开始FF=0,就进入任务 shift head, shift head任务就相当于图7的 时刻1与时刻2的操作,先将sda拉高,丙拉低,并且通过i(scl|)来保证在Scl高电平期 间,sa有下降沿。而在 shift head这个任务里,我们可以发现除了时刻1、2外,还有一个 状态 head end,其实我认为 head end是可以省去的,启动时我们要做的就是两件事:1时 刻sda拉高,2时刻sda拉低,进入控制字节写入环节。并且在于时刻2中FF置1,所以 从来没有进入过 head end这个状态,读者在 modelsim仿真中也可以进行验证。 这里还要多说一句的是那个ee语句,此时应该图7中的时刻3」,此时sh8 out buf7]=1, 同时 link sda打开,意味着我们已经将sda置1了,这与sh8 out state<=sh8 out bit6这条语 句要结合起来看,要传输的8个数据我们已经给发送了个了,下面就要从第二个数据开始 发,所以下一步要做的是在图7中的时刻4发送第二个数。这也就是为什么Sh8 out state不 从sh8 out bit7开始读第一个数了。在这里读者可以按照时序要求画出clk、scl、sda的时序 图,就像图7所小的那样,用时序图作参考来理解代码,这样有助于掌握。 Ctrl write 这个状态是要写入8位的控制字 if(FF==O) //sht8out实现了并行转串行的功能 shift out /将sh8 out buf的8位数据一位一位地通过sda输出 else begin//写完8位控制字后,释放sda一个周期, EEPROM给出应答信号 sh8 out state<=sh8 out bit7;∥/并转串任务的状态跳至sh8 out bit7 sh8 out buf7:0]<=ADDR[7:0];/(赋予地址值,下一个周期输出 FF =0; main state<= Addr write;//状态跳至地址写入 /1- 并行数据转换为肀行数据任务 task shift out. begin case(shout state) h out bit7 /将sh8 out buf7]给sda f(!scL)//scl为低电平吋给sda赋值,这是i2c总线时序要求的 link sda YES link write <=YES shout state <=shout bit6, end else shout state < shout bit7 sh8 out bit6:/将sh8 out buf6给sda if(!SCL) egIn link <= YES link write < YES shout state < shout bit5 shout buf < shout buf<<1. else shout state < sh out bit6 sh8 out bit5:/将sh8 out buf5给sda if(!」cL) begin shout state < shout bit4 shout buf shout buf<<1 end else shout state < shout bit5 h8 out bit4://将sh8 out bu[4]给sda if(SCL) eB shout state <e shout bit3 thout buf shout buf<<1 end else hout state shout bit 4 sh8 out bit3:/.将sh8 out buf(3]给sd if(!」cL) begin shout state shout bit2 shout buf<<1 else shout state shout bit 3 sh8out_bit2:/将sh8 out buf2]给sda if(!SCl b g shout state shout bit1 sh out buf shout buf<<1 else shOut state sh]out bit2 shout bit1: //*shout buf[1]e sda if(!SCL) begin sh&out state 'e shout bito shOut but < shOut buf<<1. else shout state ch Sout bit 1 sh8out_bt0:/将sh8 out buf[0给sda if(!SCL) b sh out state < sh&out end sh]out buf<<1 end else shout state shout bitO sh8 out end:/将sda上的数据保持一个sc周期,保持数据的完整性 f(SCL)∥到下次sc为低电平时,止好为个sc周期 begin link sda <= NO link write NO FF < nd shout state hout end endcase 【实例截图】
【核心代码】

标签:

实例下载地址

I2C-verilog-(非常详细的i2c学习心得)

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警