基于Xilinx FPGA 的SPI Flash 控制器设计与验证
2012-12-22关珊珊周洁敏
关珊珊,周洁敏
(南京航空航天大学民航学院,南京210016)
现场可编程门阵列FPGA 常常进行大数据量的处理,数据的存储便成了问题,利用SPI Flash 大容量、读写速度快、成本低廉以及数据在断电后不丢失的特点,可以将配置数据存储于SPI Flash 中[1]。它比起传统的并行总线接口Flash 来说节省了很多的I/O 口资源,从而为系统功能的扩展提供了更多的可能。为此提出了一种基于FPGA 的SPI Flash 控制器的设计方法,并用Verilog HDL 实现,在Isim 中得出仿真和验证结果,最终应用在自行设计的VGA显示控制电路中得到成功应用,而且可以扩展到所有类似系统中[2]。
1 系统总体方案设计
FPGA 芯片采用的Spartan-6 系列的xc6slx9 芯片,封装采用tqg-144,该系列FPGA 能提供高达400 MHz 的工作时钟,高达5 720 个高效的双寄存器6 输入查找表(LUT)和一系列丰富的内置系统级模块,采用成熟的45 nm 低功耗铜制程技术制造,实现了性价比与功耗的完美平衡。该芯片有9152 个逻辑单元(Logic Element),32 个18 kbyte 的Block RAM 模块,16 个18×18 bit 嵌入式乘法器,2 个锁相环(PLL)和4个时钟管理模块(DCM)。在这款144 针tqg 封装的FPGA 中,用户可用I/O 为102 个[3],可以满足本系统的需求。
Flash 芯片采用的配置芯片是Winbond 公司的W25Q80BV 系列8 M bit 容量的SPI Flash,该芯片共由16 部分组成,每一部分有256 页,每页有256 个字节。该系列芯片具有先进的写保护机制,读取数据的最大时钟速率为50 MHz。工作的电压范围为2.7 V ~3.6 V,具有整体擦除和扇区擦除、灵活的页编程指令和写保护功能,数据保存至少20 y(year),每个扇区可承受100 000 次擦写循环。SPI Flash 具有掉电保存能力,在系统上电时,FPGA 首先从配置芯片SPI Flash 中读取编程数据,并对FPGA 进行加载。SPI Flash 的HOLD#和WP#管脚要接上拉电阻,因为FPGA 上电时管脚为高阻态,如无此上拉电阻,FLASH 的HOLD#和WP#输入为浮置状态,没有确定的电平,进而导致数据总线电平也不确定,这是不允许的。
本系统由串口、FPGA 和SPI Flash 构成,系统整体框图如图1 所示。
图1 系统框图
图1中,FPGA 为电路核心,一方面接收来自PC 串口的数据,并将数据写入Flash 中;一方面从Flash 中读出数据;另一方面产生系统所需的各种控制信号。作为现场可编程器件,FPGA 能方便地烧入程序来改变它的功能,所以在设计调试时,可将.bit 文件烧入FPGA 进行在线调试,也可将.mcs 文件程序直接下载到SPI Flash 中进行功能验证。
2 FPGA 内部模块设计
FPGA 的顶层文件包括七个模块,如图2 所示。
图2 FPGA 内部构成框图
图2 中,复位信号主要是同步外部的复位信号;DCM 模块主要是倍频和管理时钟;串口接收模块把从串口得到的数据缓存到FIFO;Flash 控制模块主要是控制对外部SPI Flash 的读写,把从串口得到的数据存入到SPI Flash,并不断把SPI Flash 中的数据送到串口发送模块;CoreRAM 是Xilinx 专用的一个IP 核,本设计中用于FPGA 内部数据的缓存;SPI 接口模块为SPI Flash 提供串行时钟,并实现数据的串并转换。当上层用户发送指令要将FPGA 的配置数据存入SPI Flash 时,配置数据从串口接收模块输出给Flash 模块,Flash 模块将数据不断提取到CoreRAM 中,CoreRAM 中的数据经过Flash 模块写入到SPI Flash 中。当系统重新上电要对FPGA 进行配置时,将SPI Flash 中的数据读入到Flash 模块中,再将Flash 模块中数据缓存在CoreRAM 中,最后将CoreRAM 中的数据提取给上层相应的模块,完成对FPGA 的配置。
从以上分析可以知道,FPGA 内部的数据流向非常的明朗,模块之间的关系也很确切,所以这个框图的划分具有一定的科学性。如果总体的框图没有划分好,调试成功的可能性也是非常小的。另外,在升级的时候如果要改变数据的获得方式,只要用新的程序替换串口接收模块即可;如果要改变数据的显示方式,只要用新的程序替换串口发送模块即可。下面分别介绍各功能模块的实现。
2.1 串口接收和发送部分
串口发送和接收部分相似,串口接收部分是将来自PC 的串口数据发送到Flash 控制器中,而串口发送部分是将从Flash 中读到的数据发送给PC 机,是串口接收的逆向过程,下面以串口发送部分为例进行分析。串口接收模块的框图如图3 所示。
图3 串口接收部分框图
图3 中包含3 个子模块,串口接收模块接收来自PC 串口的数据,为了使速度尽可能的快,设计用的波特率为115 200 bit/s;缓存接口主要是把串口接收到的数据缓存到FIFO;FIFO 是例化的一个模块,用作数据缓存。
2.1.1 串口接收
串口接收程序按照UART 的传输原理进行程序设计,本设计省略了奇偶校验部分,是按照10 bit 的串口传输方式设计的。串口程序的核心是一个接收状态机,另外还包括接收同步、采样时能生成和标志位控制模块。工作原理是来自串口的信号经两级寄存器同步后不断被采样,采样后的信号到接收状态机控制获得串口数据,如果接收完数据,把接收到数据的标志位置高告诉相关模块已经接收到新数据,标志位在标志清零输入置高后被清零,这时候标志位再次置高说明接收到下一个的数据。标志位清零的控制要注意清零位的置高周期数,最好为一个周期,不能无限制地永远置高。串口接收模块的核心状态机的状态转换图如图4 所示。
图4 串口接收状态转移图
idle:闲置状态每个时钟周期都采样接收同步信号的值,一旦该信号的值为0 则转入到下一个状态。
first:准备接收状态采样串口接收的起始位,在波特率的16 倍时钟下采样,如果6、7、8 次采样中有两次为低电平说明是起始位,转入到下一个状态(rxd),否则认为该信号是干扰信号而转入闲置状态(idle)。
rxd:接收状态把数据接收到并存入暂存寄存器,并产生标志位的原始信号,接收结束是根据暂存寄存器的最低位来判断结束的,同时在结束的时候判断结束位是否为0,如果不为0,则抛弃接收到的数据后转入到闲置状态。
2.1.2 缓存接口
缓存接收模块是一个相对简单的模块,它主要是把串口接收模块接收到的数据存入到FIFO,由于串口接收的是8 bit 的数据,FIFO 的宽度是16 bit,因此每次接收2 bit 数据再存入FIFO。缓存接口模块包含一个控制状态机,工作原理是一旦检测到串口接收模块的标志位为高时就接收1 字节的数据,并转到接收下1 字节状态,这个状态接收到第二个数据,并把整个16 bit 的数据存入到FIFO,每次接收1 字节数据后都把清零标志位置高清除串口接收模块的标志位。
FIFO 是在开发软件中例化的一个模块,为保持较高的速度,刚好用了一个M4K 块,数据的宽度为16 bit,数据的存储深度是256 个。本FIFO 读数据和写数据工作在不同的频率上,读数据的操作工作在较高的频率上,写数据的操作工作在较低的频率上。本FIFO 也把内部的其他模块和跟数据的获得模块分离,如果要把串口获得数据模块改为其他方式就可以直接修改这部分即可。
2.1.3 写缓冲FIFO
写缓冲FIFO 指的是串口数据的暂存FIFO,在FLASH 主控制模块中将用到的信号是这个FIFO 的“近空”信号(w_fifo_aempty)。在每行显示开始的时候都要检测这个信号,如果w_fifo_aempty 信号为高电平,说明写缓存FIFO 已经有足够的数据用来写,这时候把FIFO 中的数据写到FLASH 中,当w_fifo_aempty 信号为低电平说明数据即将被读空,这时候通过置w_fifo_re 使能停止向FLASH 写数据。每一次这样的一个过程至少写入了突发数据传输的数据个数。
写缓冲FIFO 的写是uart_inf 这个模块来控制的,只有在uart_rxd 接受完两个字节的数据后把这个数据合成一个16 bit 的数据存入到FIFO,准备好数据的同时把FIFO 的写使能置为低电平一个周期即可以把数据写入到FIFO 中。
2.2 Flash 控制模块
Flash 正常工作时必须严格按照Flash 的时序控制信号,Flash 主控制模块在两个有限状态机的控制下来进行,写Flash 状态机和读Flash 状态机。
由于Flash 的写操作只能将数据1 改写成为0,擦除操作才能将数据0 改写为1。所以FPGA 刚上电时,程序首先对Flash 进行擦除操作,将指定区域全写为1。当需要执行写Flash 的操作时,应该首先把数据写到FPGA 内部的BlockRAM 中,然后按照Flash Datasheet 中的页面编程时序向Flash 中写入数据。Xilinx 公司为用户提供了功能丰富的IP 核,设计中需要的BlockRAM 模块可直接在ISE 中调用IP 核,Flash 主控制模块可以控制存取BlockRAM 的地址和时间,并且按照Flash 的页编程时序,将并行数据通过SPI 接口模块转换为串行数据后送入到Flash 中。W25Q80BV 的页面编程指令的时序图如图5 所示。
图5 W25Q80BV 页面编程指令时序图
图5 中,首先拉低/CS(片选信号),第1 个时钟上升沿将页面编程指令02H 送入Flash 内,然后输入3 个字节的首地址,紧接着输入编程数据。页面编程一次最多可以输入256 个字节的数据,若超出256 个字节,则仅保留最后输入的256 个字节的数据。如果输入低8 bit 不全为零的地址,从输入的地址进行编程,一直编程到该页的最后,接着从该页的起始地址进行编程。同样,输入完数据后片选信号也必须拉高,否则页面编程指令不被执行[4]。
按照写Flash 的时序设计状态机,当写使能有效时,状态机由闲置状态(idle)进入传输写使能指令状态(tx_cmd),经过写使能指令等待状态(wait1)进入到传输擦除指令状态(tx_erase),然后经过传输擦除指令等待状态(wait2)后,擦除命令执行完毕。接着执行写Flash 的操作,首先还是进入传输写使能指令状态(tx_cmd)和写使能等待状态,然后进入传输页面编程指令状态(tx_pro),经过三个字节的传输地址状态(txadd)进入到传输数据状态(txdata),输入完256 个字节的数据后,进入到清除指令(clr_cmd)状态,最后恢复到闲置(idle)状态。写Flash 状态机如图6 所示。
图6 写Flash 状态机
当需要执行读Flash 的操作时,应该首先按照Flash 的读数据指令时序将串行数据转化为并行数据读入FPGA 的BlockRAM 中,然后从BlockRAM 中将数据读入到上层用户。W25Q80BV 的读数据指令的时序图如图7 所示。
图7 W25Q80BV 的读数据指令时序图
由图7 可以看出,W25Q80BV 的读数据指令时序比较简单,在/CS(片选信号)信号拉低以后的时钟第一个上升沿,按照高位在前低位在后的顺序将读数据指令03H 送到Flash 中,接着将所需读取内容的3 个字节的首地址送入Flash,在输入完毕后的第一个时钟下降沿,该首地址所指向的8 bit 数据便会按照从高位到低位的顺序输出。输出完毕后,地址会自动递增,然后指向下一个地址。接着输出下一个地址所指向的数据,并且当地址到达最高位后将会自动转回到首地址000000h,按照上述操作循环执行,就可读出Flash 中所有的内容,一直到拉高/CS 片选信号为止[5]。
按照读Flash 的时序设计状态机,Flash 中的数据只要按照读时序要求就可以顺利读入FPGA 中进行运算。状态机由闲置状态(idle)进入传输读数据指令状态(tx_cmd),读数据指令同样需要3 个字节的地址数据来指定读取据存储空间的起始地址,当芯片被选中时,就可以一直不断地从SPI Flash 中读取数据。接着SPI Flash 控制器经过传输地址(txadd)状态进入到读数据(rxdata)状态,如果还有未传输完的数据(即byte_count 未计数到256),SPI Flash 控制器则继续留在读数据状态,直到所需读取的数据都传输完后,再进入到清除指令(clr_cmd)状态,最后恢复到闲置(idle)状态。读Flash 状态机如图8 所示。
图8 读Flash 状态转移图
2.3 BlockRAM 模块
由于本设计选用的Flash 容量较大,一般FPGA 没有这么大的存储空间,所以FPGA 中需要调用数据缓冲存储器BlockRAM。它是由Xilinx 提供的IPCore,设计比较方便,而且灵活、高效、不容易出错。BlockRAM有两个完全独立的端口科技进入共享的存储空间,两个端口都有读/写接口。IP 允许使用者在FPGA 内部快速建立优化的存储器资源,本系统采用单端口设计,在BlockRAM 属性选择中将端口A 的宽度选为8,将深度选为256,配置选项选为Read And Write(读和写),写模式选为Write After Read。当向BlockRAM 中写数据时,将WEA 和ENA 置位,并输入地址和数据即可;当需要从BlockRAM 中读数据时,由于采用了Read And Write 模式,所以只要将地址输入给BlockRAM,就会顺利的将指定地址的数据读出[6]。
2.4 SPI 接口模块
在此模块中将设计分为三大块:并行数据串行移位,分频,串行数据并行移位。SPI Flash 的工作时钟是由外部控制器提供的,本设计中主时钟为48 MHz,取4 点进行采样,每到一个采集点,时钟翻转一次,完成分频,分频得到的时钟1 MHz 作为SPI Flash 的时钟输入。
由从Flash 控制器中得到的数据为并行数据,但SPI Flash 为串行接口,所以SPI 接口模块主要功能是将FPGA 发送的并行数据转化为串行数据输出给SPI Flash,系统由闲置状态进入并行数据串行移位状态,启动延时模块,s_do 的值要保持48×8 个系统周期才能使得mosi 在一个SPI 周期输出1 bit 数据,同时移位寄存器左移1 bit,将最高位赋给mosi 输出,如此反复直到输出8 bit 数据,为满足SPI Flash 的响应时间,系统增加传输等待状态,经过传输等待状态又回到闲置状态,完成了一个字节数据的写入。
同样,当需要读SPI Flash 中的数据时,将SPI Flash 中的串行数据转化为并行数据送入FPGA 中,系统由闲置状态进入串行数据并行移位状态,在此状态启动延时模块,SPI Flash 输出1 bit 数据需要48个系统周期,输出8 bit 数据就要48×8 个系统周期,即s_di 要保持48×8 个系统周期,首先将miso 的值赋给s_di[0],将s_di 左移一位,当延时48 个周期后,反复上述操作,直到将8 bit miso 数据都输出给s_di,经过传输等待状态回到闲置状态,完成了一个字节数据的读出。
3 系统仿真结果与分析
SPI Flash 控制器在Xilinx ISE12.2 编程环境下实现,结合自带的仿真软件Isim 进行仿真。板上调试时钟选为48 MHz,经测试数据传输准确无误。由于篇幅有限,本文仅对写Flash 和读Flash 给出仿真波形图并进行分析。
3.1 写Flash 仿真与分析
写Flash 仿真波形如图9 所示。
图9 写Flash 仿真波形
由图9 可以看出,当SPI Flash 控制器进入到传输数据(tx_data)状态,这时s_wr 变高(s_wr 在传输指令及数据地址时也保持为高电平状态),并在整个字节的写入程中保持高电平状态,在s_df 的控制下开始传输数据,经过8 个clk 周期SPI Flash 控制器通过一个移位寄存器将从s_do 获取的用户端数据逐位输出给SPI Flash。
3.2 读Flash 仿真与分析
读Flash 仿真波形如图10 所示。
图10 读Flash 仿真波形
由图10 可以看出,当SPI Flash 控制器进入到读数据(rxdata)状态时,spi_rd 变高,并在整个字节的读数据过程中保持高电平状态,经过8 个clk 周期SPI Flash 控制器通过一个移位寄存器将从SPI Flash 中读取得的1 字节数据寄存起来,最后在通过s_di 输出给用户。
4 结语
本文以实际应用为出发点,实现了一个基于FPGA 的SPI Flash 控制器,并重点分析了其工作状态转换过程。该控制器能够很好地实现对FPGA 芯片进行在线配置,具有广泛的应用价值。该方法具有较高的可移植性,以及简单方便的用户接口,并且控制器经过简单的修改就可以用于控制其它型号的SPI Flash 芯片,因此具有很高的可兼容性。
[1] 郑川.Step By Step 现场可编程门阵列设计入门与进阶[M].西安:西安电子科技大学出版社,2008:104-122.
[2] 王小峰,周吉鹏. 一种FPGA 在线配置FLASH 的方法[J]. 电子器件,2006,29(3):902-904.
[3] 张力为,钟慧敏.实现基于FPGA 的SPI Flash 控制器设计[J].微计算机信息,2010,26(6-2):124-126.
[4] 韦燕.基于FPGA 的SPI 接口时序模拟[J]. 科技信息,2010,21:79-80.
[5] Winbond,Inc.8M-BIT SERIAL FLASH MEMORY WITH DUAL AND QUAD SPI. http://www. Winbond. com/NR/rdonlyres/4D2BF674-7427-4FC8-AEF-1A534DF74F16/0/W25Q80BV.pdf.2009.
[6] Xilinx,Inc.Spartan-6 FPGA Datasheet:DC and Switching Characteristics. http://china. xilinx. com/support/documentation/data_sheets/ds162.pdf.2011.