您当前的位置: 首页 >  fpga开发

正点原子

暂无认证

  • 2浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子FPGA连载】第四十五章FLASH读写实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

正点原子 发布时间:2021-11-23 10:57:55 ,浏览量:2

1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 在这里插入图片描述

第四十五章FLASH读写实验

FLASH存储器又称闪存,是一种长寿命的非易失性(在断电情况下仍能保持所存储的数据信息)存储器,一般用来保存一些重要的设置信息或者程序等等。通常采用SPI协议跟FLASH芯片进行数据交互。本节实验我们将带领大家一起去学习SPI通信协议,并基于SPI协议来对板载的FLASH芯片进行读写操作。 本章包括以下几个部分: 4444.1简介 44.2实验任务 44.3硬件设计 44.4程序设计 44.5下载验证

45.1简介

新起点开发板上板载的FLASH芯片型号为W25Q16BV,它是由Winbond公司生产的一款高性能FLASH芯片。这款芯片的总容量为16Mbit,整个存储阵列被分成8,192个可编程页,每页的容量为256字节。它支持Standard SPI、Dual SPI和Quad SPI三种SPI协议通信方式,最大传输数据速率可达50MB/S。下面我们来一起认识一下这款芯片。 首先我们先来看看W25Q16BV的封装图,如下所示: 在这里插入图片描述

图 45.1.1 FLASH芯片封装图 从上图中我们可以看到W25Q16BV的封装是非常简单的,它一共就8个引脚,那么这8个引脚分别都有什么功能呢,我们继续往下看: 在这里插入图片描述 图 45.1.2 引脚功能表 从上表中可以看到1号引脚是片选信号,并且是低电平有效(引脚名字CS前面加了一个/一般表示低电平有效),当CS引脚拉低时FLASH芯片被选中,相当于使能,此时FLASH芯片可以进行后续指令操作;2号和5号引脚是FLASH芯片的数据输出输入引脚(Standard and Dual SPI模式下);3号引脚是写保护引脚(Quad SPI模式下被用作数据输出引脚),也是低电平有效,主要用来防止状态寄存器被写入(具体操作请参考数据手册)。4号和8号引脚是电源和GND;6号引脚是FLASH的时钟驱动引脚,在对FLASH进行各种指令操作或者读写数据时必须保证6号引脚有稳定且连续的驱动时钟。7号引脚是HOLD引脚,也是低电平有效,在Standard and Dual SPI模式下相当于FLASH暂停信号,当HOLD引脚和CS引脚同时拉低时,虽然此时FLASH芯片是被选中的,但是DO引脚会处于高阻抗状态,DI和CLK这两个引脚会忽略输入的数据和时钟,相当于DI和CLK处于无效状态。 说完了引脚最后我们再来看看W25Q16BV FLASH芯片的内部结构示意图,如下图所示: 在这里插入图片描述 图 45.1.3 内部结构示意图 在上图中我已经将FLASH芯片的内部结构图用三个框框起来了,其中一号框中的是FLASH芯片的指令控制逻辑单元,我们使用SPI协议向FLASH芯片发送不同的指令时,指令控制单元会处理不同的指令去执行对应的操作。2号框和3号框其实都是FLASH的存储单元,我们可以看到2MB(16Mb)的存储空间被划分为32个存储块,每个存储块是64KB,而单独一个64KB的存储块又被划分成16个更小的4KB存储块。这样划分最主要的目的是为了让数据的写入和擦除更加的灵活。从数据手册中我们可以知道W25Q16BV芯片的地址线是24位的,分别对应8位扇区地址、8位页地址和8位字节地址。因此我们在写入数据时就可以锁定某一扇区某一页开始写数据,如果你不想把整页都写满数据你还可以指定这一页具体从哪个字节开始写入数据(一页有256个字节)。那么擦除也有好几种方式比如我们按照存储块去擦除,上图中显示的是32个存储块,我们可以直接擦除某一个存储块中的数据,也可以选择擦除一个存储块中更小的4KB的小存储块,还可以选择整个芯片全擦除等等,这都是因为FLASH的内部将存储单元分了扇区和存储块,所以我们才能进行这样的操作。 接下来我们再来看看W25Q16BV的操作指令,如下图所示: 在这里插入图片描述 图 45.1.4 指令表 从上表中可以看到FLASH的操作指令还是不少的,但是我们本节实验并没有用到全部的指令,在这里我们只介绍用到的指令,对于其他指令感兴趣的同学可以去翻看数据手册了解。 Write Enable(06h):使能指令,Write Enable指令将状态寄存器中的Write Enable Latch (WEL)位设置为高电平,在执行页编辑、扇区擦除、块擦除、芯片擦除和写状态寄存器指令前必须先执行Write Enable指令。 Read Status Register-1(05h):读取状态寄存器1指令,这条指令的作用就是读取状态寄存器1的值。在W25Q16BV中存在两个状态寄存器可以用来指示FLASH芯片的可用性状态或者配置SPI的相关设置。在本节实验中我们主要是读取状态寄存器1的值,并且检测它的第零位也就是BUSY位是零还是一。当FLASH处于擦除或者写入数据时,状态寄存器1的BUSY位会拉高,当BUSY位重新恢复成低电平时代表FLASH擦除或者写入数据完成。 Page Program(02h):页编辑指令,可以理解成写数据指令,在上文中我们已经介绍过W25Q16BV的存储空间是分为扇区和页的,每一页又有256个字节的存储空间。当执行页编辑指令时就可以往对应的扇区对应的页中写入数据,一次性最多写入256个字节数据。这里尤其要注意一点,当整页写数据时你可以不必写满256个字节,小于256个字节也是可以正常写入的,但是千万不能超过256个字节数据,因为一旦超过256个字节,多余的数据就会返回这一页的开头重新写入,这样就会覆盖之前已经写入的数据。举个例子我们一次性写入260个数据,这样就多了4个数据出来,那么这4个数据就会回到这一页的开头把第0、1、2和3这四个数据覆盖掉。 Sector Erase-4KB(20h):区块擦除指令,在上文中我们已经提到过芯片内部的存储空间是被划分成一个一个小块的,我们可以直接对这些小块执行擦除指令。Sector Erase指令就是对4KB的小块执行擦除操作。除此之外还有Block Erase -32KB(52h)和Block Erase -64KB(D8h)指令,用于擦除更大的存储块,本节实验只使用Sector Erase区块擦除指令。 Chip Erase(c7h):全擦除指令,上一条指令我们介绍了芯片的区块擦除指令,可以擦除不同大小的区块,但是有的时候我们想直接将FLASH芯片进行格式化那怎么办呢?这个时候我们就可以执行全擦除指令了。全擦除指令会擦除整个FLASH芯片的所有存储数据。需要注意的是全擦除指令执行的比较慢,通常需要几秒钟才能完成全擦除(数据手册中给的典型值是3秒,实测大概2秒左右),在芯片处于全擦除期间我们只能对它执行访问状态寄存器指令操作,不能执行其他例如读写等操作。在擦除期间,状态寄存器1的最低位(BUSY位)始终处于高电平(不仅仅是全擦除指令,区块擦除指令、写数据指令执行时BUSY位也会拉高),当完成全擦除后BUSY位拉低,此时可以执行其他指令了。 Read Data(03h):读取数据指令,当FLASH中被写入数据后我们可以使用Read Data指令将数据读取出来。 W25Q16BV FLASH芯片就给大家介绍到这里了,更加详细的介绍大家可以去翻看数据手册,我们配套的资料盘A盘中(新起点开发板资料盘(A盘)\7_硬件资料\2_芯片资料\04_QSPI)已经放入了W25Q16BV FLASH芯片的数据手册。 接下来我们再来讲解本节实验最重要的一个点:SPI通信协议。 上文介绍FLASH芯片的时候就已经跟大家说了,我们跟FLASH芯片进行通信是基于SPI协议的,那么什么是SPI协议呢?SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。 SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制从设备 (Slave)。一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的 Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作。其工作状态图如下所示: 在这里插入图片描述 图 45.1.5 SPI主机控制从机 从上图中可以看到,三个从机的时钟信号(SCLK)、数据输入(MOSI)和数据输出(MISO)是共用的,只有片选信号(CS)是单独的,因此在进行主从机通信时,主机只需要通过CS信号选中对应的从机就可以和这个从机通信了。 宏观上我们知道主从机是如何工作的之后,我们接下来在来详细的分析基于SPI协议的主从机工作机制,其原理如下图所示: 在这里插入图片描述 图 45.1.6 SPI工作机制 上图中就是基于SPI协议的主从机通信原理图,下面先来解释一下上图中的结构: SSPBUF:Synchronous Serial Port Buffer, 泛指 SPI 设备里面的内部缓冲区, 一般在物理上是以 FIFO 的形式, 保存传输过程中的临时数据; SSPSR:Synchronous Serial Port Register, 泛指 SPI 设备里面的移位寄存器(Shift Regitser), 它的作用是根据设置好的数据位宽(bit-width) 把数据移入或者移出 SSPBUF; Controller:泛指 SPI 设备里面的控制寄存器, 可以通过配置它们来设置 SPI 总线的传输模式。 明白了SPI通信主从机的结构再去看SPI通信就很简单了,其实SPI通信就是主从机之间的数据交换,主机的SSPSR寄存器把要给从机的数据放到MOSI线上,然后从机的SSPSR寄存器把MOSI线上的数据移位寄存到自己的SSPBUF寄存器中去,同理从机的SSPSR寄存器也会把要给主机的数据放到MISO线上,然后主机的SSPSR寄存器把MISO线上的数据移位寄存到自己的SSPBUF寄存器中去。这样主从机之间就完成了一次数据交互。 这样的数据传输方式又被称为数据交换, SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个“发送者(Transmitter)” 或者 “接收者(Receiver)”。在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主设备还是从设备), 相当于该设备有一个 bit 大小的数据被交换了。一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access)。所以Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选,把想要访问的 Slave 设备选中。在数据传输的过程中,每次接收到的数据必须在下一次数据传输之前被采样。如果之前接收到的数据没有被读取,那么这些已经接收完成的数据将有可能会被丢弃,导致 SPI 物理模块最终失效。 说了这么多大家脑海里应该对SPI通信有了一个大概的认知了,下面我们再来详细的讲解一下SPI通信的时序,如下图所示: 在这里插入图片描述 图 45.1.7 SPI协议时序图(图片来源于网络) 从时序图中我们可以看到SPI通信协议分为4种模式,大家仔细观察这4种模式不难发现它其实就是根据时钟信号SCK的极性和相位划分的。 我们先来看看时钟的极性,极性全称Clock Polarity,通常简写成CPOL。它是指时钟信号在空闲状态下是高电平还是低电平,当时钟空闲时为低电平即CPOL0,反之则CPOL1。 看完极性我们再来看看相位,相位全称Clock Phase,通常简写成CKPHA。它是指时钟信号开始有效的第一个边沿和数据的关系。不管是时钟的上升沿采样还是下降沿采样,采样边沿为了满足建立时间和保持时间一般都是在数据稳定周期的正中间发生触发采样。因此当时钟信号有效的第一个边沿处于数据稳定期的正中间时我们定义CKPHA0,反之时钟信号有效的第一个边沿不处于数据稳定期的正中间我们定义CKPHA1。这样当CKPHA0模式时我们先发生数据采样然后输出数据,当CKPHA1模式时我们先发生数据输出然后进行数据采样。 下面给出一张表来辅助大家记忆SPI通信协议的四种模式,如下所示:在这里插入图片描述 图 45.1.8 SPI通信四种模式 到这里整个SPI相关的知识就讲解完了,为了让大家对SPI通信时序有个更好的理解我们以SPI模式0来给大家举个例子,我们先把模式0的时序图单独贴出来,如下所示: 在这里插入图片描述 图 45.1.9 SPI模式0 现在有一个主机想把一个8位二进制数据10101100发送给从机,而从机呢刚好也想把一个8位二进制数据11001010发送给主机(双工通信)。我们按照上图的时序来,首先主机要将从机片选信号SSEL拉低,此时代表从机被选中,在此之前SCK信号要始终处于低电平。SSEL拉低后时钟信号SCK开始启动,此时主机和从机的数据开始交互,怎么交互的呢,我用一张表格来给大家演示,如下表所示: 表 45.1.1 SPI通信过程表 在这里插入图片描述 上表中时钟信号1代表时钟上升沿,0代表下降沿。我们采用的时SPI通信模式0,所以第一个时钟上升沿到来时完成数据采样,主机将自己要发送的数据最高位放到MOSI(主机输出从机输入数据线)上,而从机也将自己要发送的数据最高位放到MISO(从机输出主机输入数据线)上,当第一个时钟的下降沿到来时主机的SSPSR把MISO上的数据存入SSPBUF,而从机的SSPSR则把MOSI上的数据存入自己的SSPBUF,这样主机从机就完成了1bit数据的交互。当第二个时钟上升沿到来时,重复第一个时钟的操作,就完成了2bit数据的交互,当8个时钟过去后,主机和从机就完成了8bit数据交互,此时主机SSPBUF中的数据由10101100变成了11001010,而从机SSPBUF中的数据也由11001010变成了10101100。 到此关于SPI通信协议就讲完了,接下来我们正式进入实战演练,开始我们的本节FLASH读写实验。

45.2实验任务

本节实验将对板载的FLASH芯片先进行全擦除,然后写入数据,再把数据读出,读出数据正确后再把写入数据的扇区进行扇区擦除,最后再读取一遍数据看看数据是否擦除成功。读写正确则点亮led0,读写错误则led灯闪烁。

45.3硬件设计

板载的FLASH芯片硬件原理图如下所示: 在这里插入图片描述

图 45.3.1 硬件原理图 FLASH芯片的硬件原理图是比较简单的,因为芯片本身就8个引脚,每个引脚的作用在上文简介篇我已经跟大家介绍过了,这里我们可以看到写保护引脚和HOLD引脚都接到了3.3V上,因此我们的开发板只能支持普通SPI模式,没办法支持DSPI和QSPI模式。关于DSPI和QSPI这里简单提一下,其实它们是专门针对FLASH这一类器件提出的,我们知道SPI协议是全双工通信模式,而往往我们在跟FLASH进行通信时是不需要全双工的,因此我们让它处于半双工工作模式,这样两根数据线都可以同时发送或者接收数据,数据传输速率提高了一倍,这种模式就是DSPI。而QSPI则在原本的SPI 4线模式上又加了两根数据线,实现6线的操作以达到更高的数据传输速率。关于DSPI和QSPI感兴趣的同学可以去查找一些资料自己学习一下,我们的开发板不支持这两种模式,所以在这里就不再过多讲述。

45.4程序设计

根据本节实验的实验任务我们设计了如下程序框图: 在这里插入图片描述 图 45.4.1 程序框图 从上图中可以看到本节实验整个工程分为5个模块,分别是顶层模块(flash_rw_test)、锁相环模块(pll_spi)读写模块(flash_rw)、LED灯模块(led_alarm)和SPI驱动模块(spi_drive)。工程的RTL视图如下所示: 在这里插入图片描述 图 45.4.2 RTL视图 接下来我们来看看每个模块的作用: 顶层模块(flash_rw_test):顶层模块的作用主要就是例化四个子模块。 锁相环模块(pll_spi):锁相环模块的作用主要是生成100Mhz的时钟给读写模块(flash_rw)和SPI驱动模块(spi_drive)使用。我们的板载FLASH芯片最高可以进行104Mhz的时钟操作,本节实验我们使用锁相环生成了100Mhz时钟再进行二分频产生50Mhz的FLASH工作时钟。之所以这样二分频操作主要是为了方便控制SPI协议的时钟极性。 读写模块(flash_rw) :读写模块的作用主要是产生要写入FLASH的数据和给SPI驱动模块(spi_drive)发送操作指令。 LED灯模块(led_alarm):LED灯模块就比较简单了,就是检测FLASH读写数据是否正确,如果正确那么SPI驱动模块(spi_drive)给出的错误标志信号为0,此时驱动LED0常亮,如果检测到读写错误标志拉高,则驱动LED0闪烁。 SPI驱动模块(spi_drive):SPI驱动模块是本节实验最重要的一个模块。它实现了基于SPI协议的FLASH通信时序,完成了对FLASH芯片擦除、写入数据、读取数据以及轮询状态寄存器等操作。并且对读出的数据进行检查给出读写正确与否的标志。 接下来我们就来详细的分析每个模块的代码,看看是如何实现这些功能的。 首先我们就来看看本节实验最重要的模块SPI驱动模块(spi_drive)的代码,在讲解这个模块代码前我先来带领大家了解一下FLASH指令的时序。在上文简介部分我已经跟大家介绍了本节实验所用到的6个操作指令,它们分别是Write Enable(06h)、Read Status Register-1(05h)、Page Program(02h)、Sector Erase-4KB(20h)、Chip Erase(c7h)以及Read Data(03h),这些指令的功能在简介篇我已经详细的介绍过了,这不再重复赘述。 下面我们直接来分析时序,先看第一个使能指令Write Enable(06h),它的操作时序如下所示: 在这里插入图片描述 图 45.4.3 使能指令Write Enable(06h)时序 学习完SPI协议再来看使能指令的时序就比较轻松了,我们可以看到它是采取SPI协议模式零的通信方式,因为时钟信号CLK的初始极性是低电平,第一个边沿处在第一个数据稳定周期的正中间,所以刚好符合SPI协议模式零。然后我们再来分析一下这个操作时序,就是当CS信号拉低时时钟信号开始有效,此时数据线DI(MOSI)上给出数据即可,DO(MISO)不用管它,因为只有读FLASH时才会用DO。时序虽然简单但是大家注意我在时序图中框出来的两个部分,其中第一个框是指CS信号拉低(下降沿)到时钟有效这一段时间,根据数据手册这一段时间必须保持至少5ns。而方框2则是当使能指令发送完成后需要拉高CS信号,但是此时使能指令还没有立即执行,需要再锁存一段时间才能重新拉低CS信号进行其他操作,这段锁存时间建议大家保持100ns。 接下来我们再来看看写指令时序和读指令时序,如下所示:

图 45.4.4 写指令时序 在这里插入图片描述 图 45.4.5 读指令时序 相比较于使能指令时序读写指令时序要稍微复杂一些,他们除了要发送8bit的指令外还要发送24bit的地址,在上文简介部分我也讲解过了这24bit地址包括8bit扇区地址、8bit页地址和8bit字节地址(一页有256个字节)。这里对于写指令尤其要注意,当我们把最后一个字节的数据传输完成后会拉高CS信号,此时数据并没有完成写入,还需要等待3秒左右的时间(数据手册给的3秒,实际要短一点)数据才能写完成。那么我们怎么知道数据写完成了呢,一种办法就是按照数据手册来,我就写完后延迟三秒再去发送其他指令,另一种方法就是轮询FLASH芯片的状态寄存器,简介部分我讲解过状态寄存器1的最低位(BUSY位)在FLASH处于写数据或者擦除数据期间是拉高的,当它拉低代表FLASH写入数据或者擦除数据完成。 下面给出读状态寄存器指令时序以及两种擦除数据指令的时序图: 在这里插入图片描述 图 45.4.6 读状态寄存器时序 在这里插入图片描述 图 45.4.7 全擦除指令时序 在这里插入图片描述 图 45.4.8 区块擦除指令时序 从上面这6个指令时序图中可以看到只有读数据指令和访问状态寄存器指令是使用到了DO(MISO)数据线,因为要读出数据,其他都是往FLASH中写入数据。时序不难,关键是怎么实现它,下面我们一起来看代码,因为代码较长所以我一段一段来给大家讲解。

1   module spi_drive(
2   
3       input             clk_100m      ,
4       input             sys_rst_n     ,
5       
6       //user interface
7       input             spi_start     ,//spi开启使能。
8       input [7:0 ]      spi_cmd       ,//FLAH操作指令
9       input [23:0]      spi_addr      ,//FLASH地址
10      input [7:0 ]      spi_data      ,//FLASH写入的数据
11      input [3:0 ]      cmd_cnt       ,
12      
13      output            idel_flag_r   ,//空闲状态标志的上升沿 
14      output reg        w_data_req    ,//FLASH写数据请求 
15      output reg [7:0]  r_data        ,//FLASH读出的数据
16      output reg        erro_flag     ,//读出的数据错误标志
17      
18      //spi interface
19      output reg        spi_cs        ,//SPI从机的片选信号,低电平有效。
20      output reg        spi_clk       ,//主从机之间的数据同步时钟。
21      output reg        spi_mosi      ,//数据引脚,主机输出,从机输入。
22      input             spi_miso       //数据引脚,主机输入,从机输出。
23  
24  );
25  
26  //状态机
27  parameter IDLE         =4'd0;//空闲状态
28  parameter WEL          =4'd1;//写使能状态
29  parameter S_ERA        =4'd2;//扇区擦除状态
30  parameter C_ERA        =4'd3;//全局擦除
31  parameter READ         =4'd4;//读状态
32  parameter WRITE        =4'd5;//写状态
33  parameter R_STA_REG    =4'd6;
34  
35  //指令集
36  parameter WEL_CMD      =8'h06;
37  parameter S_ERA_CMD    =8'h20;
38  parameter C_ERA_CMD    =8'hc7;
39  parameter READ_CMD     =8'h03;
40  parameter WRITE_CMD    =8'h02;
41  parameter R_STA_REG_CMD=8'h05;

代码第1~24行是定义了SPI驱动模块的端口,每个端口我都写了注释,这里就不重复啰嗦了,大家可以直接看端口注释,需要注意的是第11行接入了一个cmd_cnt信号,这个信号是干嘛的呢?它是指令个数计数器,FLASH读写模块向SPI驱动模块发送指令,每发送一个指令cmd_cnt就会加一,我们在检查读出的数据是否正确时就要用到这个计数器,当计数器为6时刚好FLASH处于第一次读数据状态,在此状态我们检查读取的数据是否正确。之后会执行区块擦除指令将我们写入的数据擦除掉,所以之后再次读取数据时是读不到数据的。 代码第27~41行分别是SPI驱动模块的状态机状态和FLASH指令集,在下文讲解三段式状态机时会详细讲解。

42  
43  //wire define
44  wire      idel_flag;
45  
46  //reg define
47  reg[3:0]  current_state  ;
48  reg[3:0]  next_state     ;
49  reg[7:0 ] data_buffer    ;
50  reg[7:0 ] cmd_buffer     ;
51  reg[7:0 ] sta_reg        ;
52  reg[23:0] addr_buffer    ;
53  reg[31:0] bit_cnt        ;
54  reg       clk_cnt        ;
55  reg       dely_cnt       ;
56  reg[31:0] dely_state_cnt ;
57  reg[7:0 ] rd_data_buffer ;
58  reg       spi_clk0       ;
59  reg       stdone         ;
60  reg[7:0 ] data_check     ;
61  reg       idel_flag0     ;
62  reg       idel_flag1     ;
63  
64  //*****************************************************
65  //**                    main code
66  //*****************************************************
67  
68  assign idel_flag=(current_state==IDLE)?1:0;//空闲状态标志
69  assign idel_flag_r=idel_flag0&&(~idel_flag1);//空闲状态标志的上升沿
70  
71  always @(posedge clk_100m or negedge sys_rst_n )begin
72      if(!sys_rst_n)begin
73          idel_flag0            
关注
打赏
1665308814
查看更多评论
0.0702s