IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核

博客简介 本博客是本人大二上学期数字系统实验硬件描述3的内容,在此记录以防丢失。目录如下:

  • IIC串行总线时序分析
  • VHDL编程设计专门状态机与2片异步FIFO来实现乒乓操作
  • 设计HM62256测试电路并对其仿真验证
  • 定制开发一个1-port RAM的IP核
IIC串行总线时序分析 ① 理解IIC总线读取任意地址数据的时序
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

首先scl保持高电平,sda下拉,开始start。主机发送器件的7位地址码+写方向“0”(“伪写”),发送完释放SDA线并在SCL线上产生第9个时钟信号。被选中的器件确认是自己的地址后,在SDA线上产生应答信号。然后,主机再发一个字节的要读出器件的存储区的首地址,收到应答后,主机重复一次起始信号发出器件地址和读方向(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,主机都要回复应答信号。当最后一个字节数据读完后,主机返回以“非应答”(高电平)发出终止信号以结束读出操作
② 将所提供hex文件装入单片机中,启动仿真,掌握读写操作。
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

读写操作:
控制右下角的3个按钮来执行读/写操作,第3个按钮控制24C02C存储区的地址,第2个按钮控制将要写入的数据,第1个按钮按下代表执行写操作。数码管高两位代表24C02C存储区的地址,第4和5位代表输入的数据,低2位代表24C02C指定地址上读出的数据。因此,只需要控制按键3指定地址,按键2指定输入数据,最后按动按键1即可在相应地址上存入数据;只需要控制按键3指定地址,即可在数码管的低2位看到数据输出。
③参考IIC debugger中的数据如图C所示,抓取此时示波器中对应波形,逐条记录说明执行操作的过程。
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

  1. C图是一任意读过程,SDA由高变低,start;首先单片机发送7位地址码1010000+伪写0组成8个字节A0,表示AT24C02C地址。
  2. AT24C02C确认是自己的地址之后应答;接着单片机收到应答,发送存储区地址01H
  3. AT24C02C应答,单片机重复一次起始信号并发出器件地址和读方向位(“1”)得到A1
  4. AT24C02C应答,并且从01H取出数据03H,发送。
  5. 单片机发出终止信号结束读出操作stop。
④ VHDL设计一个基于IIC总线的读取非易失存储器24C02C任意地址数据的接口电路,完成仿真。
设计思路:(具体实现在打包的工程文件中)
首先给随机读的时序划分状态有idle,sart,发送存储器地址状态,接收地址状态,read_data读状态ack_for_read_data,响应读状态,stop停止状态等等;对于每一个状态都与时序意义对应,并且每一个状态的进入都要满足时序要求。然后输入端口有clk时钟,reset,EN,以及存储器地址信号dAddress[2:0];字地址信号dAddress[7:0];对于地址这些并行数据可以通过一个计数变量count来进行计数,每次计数时可以向sda输送一个数据位。
  • 实现如下(代码仍有改进之必要):
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity iicInterface is port( reset,clk,EN:in std_logic; dAddress:in std_logic_vector(2 downto 0); wAddress:in std_logic_vector(7 downto 0); sda,scl:inout std_logic; data:out std_logic_vector(7 downto 0)); end iicInterface; architecture Behavioral of iicInterface is signal sdaTemp:std_logic:='1'; signal sclTemp:std_logic:='1'; signal dataTemp:std_logic_vector(7 downto 0):="00000000"; type state is ( idle,--闲置状态 start,--开始 first_device_addr,--存储器地址接收状态 ack_for_first_device_addr,--响应存储器地址状态 word_addr,--字地址状态 ack_for_word_addr,--响应字地址状态 second_device_addr,--再次接收存储器地址状态 ack_for_second_device_addr,--响应再次接收存储器地址状态 read_data,--读状态 ack_for_read_data,--响应读状态 stop); --停止状态 signal current_state:state; --当前状态beginsda<=sdaTemp; scl<=sclTemp; process(clk,reset) variable count:integer range 0 to 40; begin if reset='0'then--闲置状态 sdaTemp<='1'; sclTemp<='1'; current_state<=idle; count:=0; elsif clk'event and clk='1' then--时钟上升沿 case current_state is--开始状态 when idle=> if(EN='1')then current_state<=start; else current_state<=idle; end if; when start=>--开始状态sdaTemp拉到低电平 sdaTemp<='0'; count:=0; current_state<=first_device_addr; when first_device_addr=>--存储器地址接收状态 count:=count+1; case count is when 1=>--AT24C系列EEPROM芯片的固定部分为1010 sdaTemp<='1'; sclTemp<=not sclTemp; when 2=> sdaTemp<='0'; sclTemp<=not sclTemp; when 3=> sdaTemp<='1'; sclTemp<=not sclTemp; when 4=> sdaTemp<='0'; sclTemp<=not sclTemp; when 5=> sdaTemp<=dAddress(2); sclTemp<=not sclTemp; when 6=> sdaTemp<=dAddress(1); sclTemp<=not sclTemp; when 7=> sdaTemp<=dAddress(0); sclTemp<=not sclTemp; when 8=> sdaTemp<='0'; sclTemp<=not sclTemp; --读写方向为0,伪写 current_state<=ack_for_first_device_addr; count:=0; when others=>--等待响应 sdaTemp<='Z'; sclTemp<='Z'; current_state<=ack_for_first_device_addr; count:=0; end case; when ack_for_first_device_addr=>--响应存储器地址状态 sdaTemp<='Z'; sclTemp<='Z'; if sda='0' then sclTemp<=not sclTemp; current_state<=word_addr; end if; when word_addr=>--字地址状态 count:=count+1; case count is when 1=> sdaTemp<=wAddress(7); sclTemp<=not sclTemp; when 2=> sdaTemp<=wAddress(6); sclTemp<=not sclTemp; when 3=> sdaTemp<=wAddress(5); sclTemp<=not sclTemp; when 4=> sdaTemp<=wAddress(4); sclTemp<=not sclTemp; when 5=> sdaTemp<=wAddress(3); sclTemp<=not sclTemp; when 6=> sdaTemp<=wAddress(2); sclTemp<=not sclTemp; when 7=> sdaTemp<=wAddress(1); sclTemp<=not sclTemp; when 8=> sdaTemp<=wAddress(0); sclTemp<=not sclTemp; current_state<=ack_for_word_addr; count:=0; when others=> sdaTemp<='Z'; sclTemp<='Z'; current_state<=ack_for_word_addr; count:=0; end case; when ack_for_word_addr=>--响应字地址 sdaTemp<='Z'; sclTemp<='Z'; if sda='0' then current_state<=second_device_addr; if sclTemp/='Z' then sclTemp<=not sclTemp; end if; end if; when second_device_addr=>--再次接收存储器地址状态 count:=count+1; case count is when 1=>--AT24C系列EEPROM芯片的固定部分为1010 sdaTemp<='1'; sclTemp<=not sclTemp; when 2=> sdaTemp<='0'; sclTemp<=not sclTemp; when 3=> sdaTemp<='1'; sclTemp<=not sclTemp; when 4=> sdaTemp<='0'; sclTemp<=not sclTemp; when 5=> sdaTemp<=dAddress(2); sclTemp<=not sclTemp; when 6=> sdaTemp<=dAddress(1); sclTemp<=not sclTemp; when 7=> sdaTemp<=dAddress(0); sclTemp<=not sclTemp; when 8=> sdaTemp<='1'; --读写方向为1 sclTemp<=not sclTemp; current_state<=ack_for_second_device_addr; count:=0; when others=> sdaTemp<='Z'; sclTemp<='Z'; current_state<=ack_for_second_device_addr; count:=0; end case; when ack_for_second_device_addr=>--响应再次接收存储器地址状态 sdaTemp<='Z'; sclTemp<='Z'; if sda='0' then current_state<=read_data; if sclTemp/='Z' then sclTemp<=not sclTemp; end if; end if; when read_data=> count:=count+1; case count is when 1=> dataTemp(7)<=sda; sclTemp<=not sclTemp; when 2=> dataTemp(6)<=sda; sclTemp<=not sclTemp; when 3=> dataTemp(5)<=sda; sclTemp<=not sclTemp; when 4=> dataTemp(4)<=sda; sclTemp<=not sclTemp; when 5=> dataTemp(3)<=sda; sclTemp<=not sclTemp; when 6=> dataTemp(2)<=sda; sclTemp<=not sclTemp; when 7=> dataTemp(1)<=sda; sclTemp<=not sclTemp; when 8=> dataTemp(0)<=sda; sclTemp<=not sclTemp; data(7 downto 0)<=dataTemp(7 downto 0); current_state<=ack_for_read_data; count:=0; when others=> sdaTemp<='Z'; sclTemp<='Z'; current_state<=ack_for_read_data; count:=0; end case; when ack_for_read_data=>--响应再次接收存储器地址状态 if sda='1' then current_state<=stop; --高电平表示终止 else current_state<=read_data; sclTemp<=not sclTemp; end if; when stop=> current_state<=idle; when others=>--最小冒险 current_state<=idle; end case; end if; end process; end Behavioral;

  • 顶层图:
    IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
    文章图片
  • 仿真验证:
    IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
    文章图片
  • 波形分析:
    首先设置清零,然后EN有效开始随机读时序,sart时sda拉低,接下来发送存储器件地址10100000,选中000号24C02C,最后一位0表示伪写;接下来24C02C确认是自己的地址发送响应,sda拉低;紧接着主机接收到响应后发送字地址00000000;24C02C接收到字地址之后发送响应;接到响应之后主机再次发送存储器件地址10100001,最后一位1表示读取;从机接收到后响应;并且发送字地址00000000的数据11110000;主机成功读取到这个数据F0。最后主机反馈sda为高电平表示不再读取,此时从机也不在发送数据,回到闲置状态,sda和scl拉高。
    结论:通过验证,接口电路读取到24C02C地址00H的数据F0,并在data端显示,设计电路时序满足随机读取要求。
VHDL编程设计专门状态机与2片异步FIFO来实现乒乓操作: ①用状态机设计控制模块,包括A和B两状态,分别表示A号FIFO执行写入和B号FIFO执行写入,状态机输入为两块FIFO的写满信号Awrfull,Bwrfull,当Awrfull有效时表示A号FIFO写满因此从A转换到B状态,Bwrfull有效时表示B号FIFO写满因此从B转换到A状态。
②状态机的输出:输出包括Awrreq和Ardreq分别作为A号FIFO的写使能和读使能。当处于A状态时Awrreq=1,Ardreq=0表示写A;当处于B状态时Awrreq=0,Ardreq=1;表示读A;另外对于B号FIFO的使能信号可以对Awrreq和Ardreq取反得到。
③ 状态图以及顶层实现如图:
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

③ 仿真:设置写时钟频率40MHz,读时钟频率10MHz,为了能看清时钟大小关系我将FIFO的容量改为了64,因此只读64bit
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

  • 仿真分析:
    在01.6us,Awrreq有效,写A读B,将FF00写入A号FIFO,由于B为空所以读取数据显示0000;1.6us3.2us,Bwrreq有效,写B读A,将FF11写入B号FIFO,读取A中数据FF00FF00FF00;3.2us~4.8us,Awrreq有效,写A读B,将FF22写入A号FIFO,读取B中数据FF11FF11FF11FF11……依次类推,周而复始,完成验证。
设计HM62256测试电路并对其仿真验证
  1. 设计HM62256测试电路并对其仿真验证。
    (1)HM62256A是32-kword×8静态RAM,引脚有地址A0~14,片选CS低电平有效,WE写低电平有效,OE输出低电平有效
    (2)新建Proteus工程,添加器件,并设计好HM62256的功能验证电路:
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

(3)仿真验证实现HM62256的读写功能,记录操作步骤和实验结果。
【IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核】①写入:首先将地址开关设置为A0A3=0000,开关全闭合,数据输入开关设置为A7A0=10101010,开关相间闭合;然后将WE设置为低电平,输出信号OE设置为高电平,控制三态门的开关闭合,写入地址为0x0,数据输入为10101010;可以看到LED灯组显示为暗亮暗亮暗亮暗亮,表示写入数据10101010。
②读取0x0地址:紧接着,依次将WE设置为低电平,三态门控制信号开关打开,LED灯熄灭。最后将输出信号OE设置为低电平,开关闭合的一瞬间可以看到LED显示为暗亮暗亮暗亮暗亮,表示读取成功。
③实验结论:读写操作成功。
定制开发一个1-port RAM的IP核 (1)定制步骤:Tools→ Mega wizard Plug-In Manager→Create a new custom megafunction variation→Installed Plug-Ins→ Memory Compiler→RAM1-port→设置输出q为8位,总容量为32,本应该端口RAM按地址4数据8来定制,但是最小容量是32,所以只能定制地址5数据8,后续只需要使用4位地址→新建mif文件,设置16字节容量。如左下图:
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

(2)分析并说明生成目录下的html波形报告
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

① 图一是读取操作的波形,读取发生在使能为0,时钟周期的上升沿。在13时钟上升沿读取地址00的值F0输出,45时钟上升沿读取地址01的值F1输出,同理后续时钟上升沿分别读取F2,F3输出。
② 图二是写操作的波形,wren为高使能并且处于时钟的上升沿时候将输入加载到输出端,在这一周期的下降沿才真正写入RAM。在第二个时钟周期的上升沿将数据输入加载到输出,下降沿的时候才写入Memoriy0,同样分别在第5个和第6个时钟周期的下降沿将输入02和03写入Memoriy2.
(3)仿真验证其读写功能,记录波形图并说明。
IIC总线随机读VHDL实现&FIFO实现乒乓操作&HM62256测试&定制IP核
文章图片

分析:0~600ns设置wren为高电平,执行写入操作。第1个时钟上升沿将F0写到IP的01H地址,第2个时钟上升沿将F1写到IP的02H地址,第5个时钟上升沿将F2写入IP的02H地址;600ns后设置wren信号为低电平,执行读取操作,在650ns,850ns,1050ns上升沿执行读取操作,分别读取地址01H,02H,03H的值F0,F1,F2。
结论:地址01H,02H,03H写入的数据和读取的数据一致,IP读写功能验证正确。

    推荐阅读