赞
踩
目录
SPI Flash控制器(以下简称“QSPI”)主要实现两类功能,一是与Flash设备进行数据交互,二是对Flash设备进行管理和查询。
数据交互主要通过直接访问(DAC)和间接访问(INDAC)两种方式实现,管理查询主要通过软件触发命令生成(STIG)方式实现。
DAC方式,AHB地址与Flash设备地址一一映射,可用于开机启动引导(Boot)和片内程序执行(XIP)。
INDAC方式,需设置AHB地址范围,对落入该地址范围内的访问均采用间接访问方式,并使用嵌入式SRam作为收发数据缓存,还可通过DMA外设接口与外部DMA进行握手。
STIG方式,通过APB总线配置内部的一组寄存器,产生Flash命令(不同Flash设备,对应的命令有所不同),用来访问Flash设备中的寄存器以及执行擦除(Erase)操作。
除此之外,还支持最原始的SPI访问方式,即旁路掉DAC和INDAC,直接访问底层的收发FIFO。
QSPI主要由AHB接口单元、APB接口单元、直接访问控制单元(以下简称“DAC”)、间接访问控制单元(以下简称“INDAC”)、Flash命令生成单元、SPI传输单元和SPI/Dual SPI/Qual SPI接口单元几部分组成。其中,AHB接口单元负责通信,APB接口单元负责配置,通过AHB地址区分直接/间接访问模式,分别进入DAC和INDAC。无论采用哪种模式均要经过Flash命令生成单元,转换为Flash可识别的命令格式,进入底层SPI传输单元,实现串并/并串转换,通过SPI/Dual SPI/Qual SPI接口单元与外部的Flash设备完成通信。架构框图如图1所示。
采用AMBA 3 AHB-Lite协议,数据位宽32bits,支持字节/半字/字访问。不支持传输锁定(HMASTLOCK)和保护控制(HPROT)信号。对于写操作,只支持增量式Burst(即INCR16、INCR8、INCR4、INCR和SINGLE类型);对于读操作,所有Burst类型均支持。支持Burst传输提前中止操作。
可用于双启动,需配置寄存器0x24为N,并在寄存器0x0中使能该功能,则新的地址为原地址+N。在寄存器配置完成之前建议禁用QSPI。
需在寄存器(0x14)中配置块大小,并在寄存器(0x50~0x58)中做相应配置。在寄存器配置完成之前建议禁用QSPI。
当前传输是否为连续,不依靠“htrans”信号(由于使用“htrans”信号会将每个burst的起始传输和跨1k边界后的第一次传输识别为非连续传输,从而导致传输性能受损),而是将当前地址与前一地址进行比较做出判断。如果传输方向(读/写)或读访问位宽(字节/半字/字)发生变化,则本次传输为非连续传输。如果AHB地址解码使能且发生设备间切换,则即使地址是连续的,当前传输仍为非连续传输。
不依靠“hburst”信号,而是一直持续到一个非连续传输出现才停止Burst传输。
仅用于直接读传输。控制器最多支持连接4个Flash外设,为确保大数据量连续传输的性能,通过使能AHB地址解码功能,让软件从AHB侧看过去所有地址都是连续的,不再关心设备间跨域地址边界的问题。设备间的切换全部交由控制器硬件自动执行,其中地址边界的计算基于寄存器(0x14)的配置信息。
直接访问指的是通过AHB直接对外部Flash进行读写操作,其中AHB地址与外部Flash地址直接一一映射,用于数据访问和代码执行。当AHB访问地址不在寄存器(0x1c和0x80)定义的地址范围内时,则该访问被认为是直接访问,由DAC处理。DAC不使用内嵌SRam进行缓存,而是通过插入Latency进行流控。
DAC会在AHB Burst基础上多发一次读请求(该请求在AHB接口上不可见)用于预读,以提高底层的传输效率。需要注意的是,这里AHB Burst的定义不同于AMBA协议中的定义,其定义为:
①当本次传输为非连续传输(基于地址比较而不是htrans)或此时底层传输模块处于空闲状态时,定义为一次AHB Burst的起始传输;
②当本次传输为连续传输且下一个传输为①中定义的传输时,定义为本次AHB Burst的最后一次传输;
③AHB Burst的长度定义为本次AHB Burst的起始传输到最后一次传输之间的传输次数;
④每次AHB Burst过程中,DAC向底层的读请求个数为AHB Burst的长度+1。
基本同读操作,除了没有预读,即DAC发起的写请求个数与接收到的AHB写请求个数相同。需要注意的是,AHB控制器需要确保对Flash的Burst操作不能跨越Flash的页边界(由寄存器0x14决定页大小),一旦检测到页边界需要必须打断当前的连续传输,变成非连续传输,用于强制Flash 设备进入自同步页编程周期。对于地址字对齐的写传输,一旦跨越页边界,支持分裂操作。
AHB主设备需要提前准备好一页的写数据,以确保在连续写期间不会出现太多延迟,使得Flash写周期过早的初始化,从而导致降低Flash设备寿命。如不能保证数据,则建议使用间接访问控制模式。
写Flash之前一般需要先进行擦除操作(由软件触发,STIG),当页编程周期开始后,控制器将自动轮询写周期状态,在当前写周期完成之前不允许有新的读写操作,此时直接访问控制器保持在等待状态。
XIP模式下,不需要发送OPCODE;
XIP模式下,不能使用Basic Read指令,即单线读指令。
问题:Flash设备为什么要支持XIP模式,相比与直接访问,优势在哪里?
不需要发送OPCODE是个很大优势,程序执行时大概率不会出现Bulk传输的情况,以多次读取小数据块为主,如采用直接访问,则读取每块数据都需加OPCODE,会引入额外开销,降低传输带宽。
如果Flash设备中的寄存器支持XIP使能配置,则可以通过配置寄存器的方式进入XIP模式(只有一小部分设备支持该功能)。由于当Flash设备进入到XIP模式后,会将对其寄存器的读操作按照XIP读操作处理,所以软件无法通过读Flash设备的状态寄存器来识别其上电后是否进入XIP模式。
如果已知外接Flash设备会从POR进入到XIP模式,则需要在初始化阶段配置寄存器0x28,并将寄存器0x0的bit18置1。
如果不知道外接Flash设备是否会从POR进入到XIP模式,但知道该设备支持该功能,则软件首先需要使用STIG发送退出XIP命令尝试使外接Flash设备退出XIP模式(需要注意的是,不同设备要求的mode bit不同,所以在发送该命令前需要先查询外接设备手册)。
如果希望Flash设备从POR进入XIP模式,则可以向其发送NVCR命令使能该功能。但该功能不会马上生效,需要等到下一次POR过程时才会生效。
虽然大部分Flash设备不支持从POR进入到XIP模式,但均支持XIP模式。不过如何使能XIP模式,各家厂商并没有统一标准。大部分设备采用在地址后面加特定mode bit的方式,也有一小部分设备需要在地址后面加特定mode bit的基础上增加对Flash设备内相关寄存器的配置。下面以一些具体设备为例进行说明。
1) Micron的N25Q和MT25设备(No support for Basic-XIP)
默认情况下这类设备的XIP模式禁能,所以首先需要通过使用STIG发送VCR写命令,配置Flash设备中的寄存器VCR[3]来使能XIP模式。大致操作流程为:
①禁用DAC和INDAC,确保没有新的AHB读发送到Flash设备;
②通过STIG向Flash设备发送VCR写命令;
③配置寄存器0x28(mode bit)为8’b00000000;
④配置寄存器0x0的bit17为1,使能本地控制器的XIP模式;
⑤重新使能DAC和INDAC。
2) Micron的其他设备 (Support Basic-XIP)
①禁用DAC和INDAC,确保没有新的AHB读发送到Flash设备;
②配置寄存器0x28(mode bit)为8’b10000000;
③配置寄存器0x0的bit17为1,使能本地控制器的XIP模式;
④重新使能DAC和INDAC。
3) Winbond设备
①禁用DAC和INDAC,确保没有新的AHB读发送到Flash设备;
②配置寄存器0x28(mode bit)为8’b00100000;
③配置寄存器0x0的bit17为1,使能本地控制器的XIP模式;
④重新使能DAC和INDAC。
4) Spansion设备
①禁用DAC和INDAC,确保没有新的AHB读发送到Flash设备;
②配置寄存器0x28(mode bit)为8’b10100000;
③配置寄存器0x0的bit17为1,使能本地控制器的XIP模式;
④重新使能DAC和INDAC。
退出XIP模式的流程为:
①禁用DAC和INDAC,确保没有新的AHB读发送到Flash设备;
②配置寄存器0x28(mode bit)为除对应Flash设备手册中指定的进入XIP模式的值之外的任意值;
③配置寄存器0x0的bit17为0,禁用本地控制器的XIP模式。
值得注意的是,Flash设备在退出XIP模式之前需要接收到一个读指令,即在处理下一个读指令之前,Flash设备会始终处于XIP模式。因此,在结束所有读指令之前需要确保Flash设备已退出XIP模式。
在XIP模式下,QSPI支持上电启动引导(Boot)功能。默认情况下,采用32分频(即sclk = ref_clk/32)、仅CS[0]有效、单线传输模式、使用简单读数据命令(OPCODE为0x03)。可以通过修改设计文件中定义的参数,提高启动效率。需要注意的是,需要根据实际连接的Flash设备型号,确定命令(OPCODE)是否正确。
不需要通过AHB访问来触发对Flash的读操作,而是通过APB接口对寄存器(0x60~0x6c)进行配置来实现。该单元通过底层SPI传输单元执行Flash读Burst传输,并将读回数据缓存在内嵌SRam中,等待主设备通过AHB读走。
默认情况下该控制器禁能,在使用前需要软件配置起始地址和读取的总字节数(通过寄存器0x68和0x6c)。为缩短每次读操作之间的等待周期,支持同时配置两次操作,在处理当前操作时可以触发下一次操作。
读取的总字节数不受限于SRam大小(只影响DMA请求的大小),如果SRam溢出,则底层SPI传输单元将停止当前的Flash读Burst传输,直到SRam有剩余空间后才会从停止地址处重新启动一次新的Burst传输。
如果外部主设备想要读取控制器从Flash设备中读回的数据,则需要使用特定地址发起AHB读操作,该地址必须处于间接触发地址(寄存器0x1c)~间接触发地址+(2(间接触发地址范围(寄存器0x80))-1)的范围内。对于间接读取来讲,AHB地址与Flash设备地址没有关系,其地址只要落在有效范围内即表示将从SRam中读取数据(个人理解:该SRam的行为类似一个FIFO,AHB侧发起一个有效的读操作即从SRam中顺序读取一个数据,同时读地址+1,读走数据的空间随即被释放,一直读到SRam底部后会从头循环读取直至为空,写亦如此)。
如果AHB读地址不在有效范围内,则使用DAC替代完成此次传输;
如果AHB读地址在有效范围内但SRam中的数据未准备好,则AHB侧进入等待状态直至数据准备好;
如果AHB读Burst地址跨越了有效范围边界,则在有效地址范围内的读操作由INDAC完成,而其他部分由DAC完成。注意这种情况一般被认为是软件配置错误。
在主设备发起AHB间接读传输过程中,除最后一个字外,都必须使用字传输(32bit)。对于最后一个字,允许使用字节或半字传输,如果使用字传输,则控制器会在高位自动补0。
通过配置寄存器(0x60),可随时取消本次间接操作。
主设备从控制器读取数据时的流控处理,分两种情况考虑。一是使用DMA,此时流控由硬件处理,通过寄存器(0x64)自动控制DMA请求的发送速率;二是不使用DMA,当SRam中的数据超过寄存器(0x64)设置的水位值后产生中断,通知系统读取数据。另外,当控制器从Flash设备中读出本次请求的全部数据的最后一个字节并放到SRam后,也会产生中断(无视当前SRam中数据与水位值的关系,此特性可以使软件不再关心读数据的总字节数,不用针对最后一些字节做特殊处理,从而减少软件开销)。
同时还有两个中断辅助软件了解间接操作的状态,一是操作完成时产生的中断,二是由于控制器中缓存了两个操作导致新的操作请求未被接收而产生的中断。
通过配置寄存器(0x60)来启动间接读操作,并通过该寄存器检查操作状态。
间接读传输的操作流程:
当DMA使能时,
①通过寄存器(0x00)进行整体配置;
②通过寄存器(0x64)配置SRam的水位值;
③通过寄存器(0x68)配置本次间接传输的Flash起始地址;
④通过寄存器(0x6c)配置本次间接传输的字节总数;
⑤通过寄存器(0x1c)配置本次间接传输的AHB触发地址;
⑥通过寄存器(0x80)配置本次间接传输的AHB触发地址范围;
⑦通过寄存器(0x20)配置DMA Single和Burst传输的字节数;
⑧通过寄存器(0x60)触发间接读访问启动;
⑨通过轮询寄存器(0x60),查看间接读操作的完成状态,该bit为写清除,当间接读操作完成时会生成一个中断;
⑩通过寄存器(0x60),可以查看间接读操作的完成个数。
当DMA禁能时,
①通过寄存器(0x00)进行整体配置;
②通过寄存器(0x68)配置本次间接传输的Flash起始地址;
③通过寄存器(0x6c)配置本次间接传输的字节总数;
④通过寄存器(0x1c)配置本次间接传输的AHB触发地址;
⑤通过寄存器(0x80)配置本次间接传输的AHB触发地址范围;
⑥如果使用水位值中断功能,则通过寄存器(0x64)配置SRam的水位值;
⑦通过寄存器(0x60)触发间接读访问启动;
⑧如果使用水位值中断功能则等待水位值中断,否则轮询SRam中的有效数据个数,决定何时从SRam中取数;
⑨从SRam中读取预期数量的数据,如果还有剩余数据需要读取则跳转到步骤⑧,否则跳转到步骤⑩;
⑩通过轮询寄存器(0x60)查看间接读操作的完成状态,当间接读操作完成时会生成一个中断。
间接写操作可以最高效执行从处理器或DMA到Flash 设备的批量数据传输,Flash设备将使用最少的写周期完成此传输,从而有效提高设备寿命。通过APB接口对寄存器(0x70~0x7c)进行配置来控制和触发间接写操作。该单元等待外部的AHB主设备将数据写入并缓存在本地SRam中,然后通过底层SPI传输单元执行Flash写读Burst传输。
默认情况下该控制器禁能,在使用前需要软件配置起始地址和写入的总字节数(通过寄存器0x78和0x7c)。为缩短每次写操作之间的等待周期,支持同时配置两次操作,在处理当前操作时可以触发下一次操作。
写入的总字节数不受限于SRam大小(只限制能被接收的来自外部AHB主设备的数据个数)。当外部AHB主设备为DMA时,控制器向DMA请求的数据个数绝不会超过SRam的填充值;但不使用DMA时,需要注意不要向SRam中写入超过其容量的数据个数,一旦SRam溢出,则控制器将使AHB进入等待状态。SRam的填充值可以通过寄存器(0x20)读出。
如果外部主设备想要通过间接访问方式向Flash设备中写入数据,则需要使用特定地址发起AHB写操作,该地址必须处于间接触发地址(寄存器0x1c)~间接触发地址+(2(间接触发地址范围(寄存器0x80))-1)的范围内。对于间接写来讲,AHB地址与Flash设备地址没有关系,其地址只要落在有效范围内即表示将向SRam写入数据(个人理解:该SRam的行为类似一个FIFO,AHB侧发起一个有效的写操作即向SRam中顺序写入一个数据,同时写地址+1,一直写到SRam底部后会从头循环写入直至满)。
如果AHB写地址不在有效范围内,则使用DAC替代完成此次传输;
如果AHB写地址在有效范围内但SRam已满,则AHB侧进入等待状态直至SRam中的数据被写入到Flash设备从而释放出空间;
如果AHB写Burst地址跨越了有效范围边界,则在有效地址范围内的写操作由INDAC完成,而其他部分由DAC完成。注意这种情况一般被认为是软件配置错误。
在主设备发起AHB间接写传输过程中,除最后一个字外,都必须使用字传输(32bit)。对于最后一个字,允许使用字节或半字传输,如果使用字传输,则控制器会将多余的字节丢弃。
当SRam中的数据量大于等于Flash的一个页大小,或者SRam中存储了本次传输过程的所有数据,则控制器将向Flash命令生成单元初始化一次写Burst。
通过配置寄存器(0x70),可随时取消本次间接操作。
主设备向控制器写入数据时的流控处理,分两种情况考虑。一是使用DMA,此时流控由硬件处理,通过寄存器(0x74)自动控制DMA请求的发送速率(注:由于只有当SRam中的数据量大于等于Flash的一个页大小,或者SRam中存储了本次传输过程的所有数据,控制器才会向Flash命令生成单元初始化一次写Burst,所以要求寄存器(0x74)中配置的水位值大于等于Flash的一个页大小);二是不使用DMA,当SRam中的数据低于寄存器(0x74)配置的水位值后产生中断,通知AHB主设备继续写入数据。
同时还有两个中断辅助软件了解间接操作的状态,一是操作完成时产生的中断,二是由于控制器中缓存了两个操作导致新的操作请求未被接收而产生的中断。
通过配置寄存器(0x70)来启动间接写操作,并通过该寄存器检查操作状态。
间接写传输的操作流程:
当DMA使能时,
①通过寄存器(0x78)配置本次间接传输的Flash起始地址;
②通过寄存器(0x7c)配置本次间接传输的字节总数;
③通过寄存器(0x1c)配置本次间接传输的AHB触发地址;
④通过寄存器(0x80)配置本次间接传输的AHB触发地址范围;
⑤通过寄存器(0x20)配置DMA Single和Burst传输的字节数;
⑥可选:通过寄存器(0x74)配置SRam的水位值;
⑦通过寄存器(0x70)触发间接写访问启动;
⑧控制器请求DMA传输数据;
⑨通过轮询寄存器(0x70),查看间接写操作的完成状态及间接写操作的完成个数,该bit为写清除,当间接写操作完成时会生成一个中断。
当DMA禁能时,
①通过寄存器(0x78)配置本次间接传输的Flash起始地址;
②通过寄存器(0x7c)配置本次间接传输的字节总数;
③通过寄存器(0x1c)配置本次间接传输的AHB触发地址;
④通过寄存器(0x80)配置本次间接传输的AHB触发地址范围;
⑤通过水位值中断或轮询SRam填充状态,AHB主设备决定何时写Flash一页大小的数据到SRam;
⑥如果使用水位值中断功能,则通过寄存器(0x74)配置SRam的水位值,该值应该在0~Flash一页大小之间;
⑦通过寄存器(0x70)触发间接写访问启动;
⑧如果待传输的剩余数据字节数大于等于Flash一页大小,则写Flash一页大小的数据到SRam,否则将剩余数据全部写入SRam;
⑨如果所有数据都已经写入SRam则跳转到步骤⑾,否则如果使用水位值中断功能则等待水位值中断,如果未使用该功能则轮询SRam填充状态决定何时发送数据;
⑩跳转到步骤⑧;
⑾可选:通过轮询寄存器(0x70)查看间接写操作的完成状态,当间接写操作完成时会生成一个中断。
为减少两次间接访问的间隔时间,支持最多2个的访问队列,当超过2个以上的访问试图进入队列时都将产生中断。
从软件角度看,通过在短时间内连续触发两次寄存器(0x60或0x70)的bit0来实现间接访问队列。在每次传输的bit0触发之前,寄存器(0x68、0x6c或0x78、0x7c)中的值必须是本次传输的配置值。由于这些寄存器(0x68、0x6c或0x78、0x7c)会发送变化,因此在一次传输过程中,硬件需要始终保持从这些寄存器中读出的与本次传输相关的配置值。
在INDAC中有两个独立的数据路径模块,一个是SRam的AHB侧的数据路径模块(对于间接读,是个读接口;对于间接写,是个写接口),另一个是SRam的Flash侧的数据路径模块(对于间接读,是个写接口;对于间接写,是个读接口),内部寄存器模块每次传输向数据路径模块只发送一次启动触发,每个数据路径模块单独采样这些信息。这两个数据路径模块在不同时间段处理间接传输。比如,对于间接读操作,SRam的Flash侧的数据路径模块一旦将当前传输的最后一个字节写入SRam就可以启动队列中的下一次传输,需要注意的是,在启动下一次传输之前需要重新采样寄存器(0x68、0x6c或0x78、0x7c)的值;同理,当SRam的AHB侧的数据路径模块将当前传输的全部数据都从SRam送到AHB后也将重新采样相同的寄存器。
访问队列支持读后写,也支持写后读。其中,间接写操作的优先级最高(未理解,都是顺序执行没有竞争怎么体现优先级?需要RTL仿真,先触发一个间接读操作,接着触发一个间接写操作,看看控制器的行为,是否会暂停前一个读操作,优先处理写操作?)。
内嵌SRam是一个深度可配的单口Ram,通过寄存器(0x18)分为两部分,下半部分用于间接读操作,上半部分用于间接写操作。为确保SRam读出的数据不经过组合逻辑输出到AHB总线,会在读数据路径上增加一级寄存器,相当于在原有SRam的存储总空间数上增加了一个存储空间。
举例说明,设SRam深度为8bits,即存储空间为256,再加上额外寄存用的存储空间,共256+1个存储空间。寄存器(0x18)的配置与间接读/写操作占用的存储空间关系如下:
如果配置寄存器(0x18)为0x00,则间接写操作占用256个存储空间,间接读操作占用1个存储空间;
如果配置寄存器(0x18)为0x01,则间接写操作占用255个存储空间,间接读操作占用2个存储空间;
如果配置寄存器(0x18)为0x02,则间接写操作占用254个存储空间,间接读操作占用3个存储空间;
… …
如果配置寄存器(0x18)为0xfd,则间接写操作占用3个存储空间,间接读操作占用254个存储空间;
如果配置寄存器(0x18)为0xfe,则间接写操作占用2个存储空间,间接读操作占用255个存储空间;
如果配置寄存器(0x18)为0xff,则间接写操作占用1个存储空间,间接读操作占用256个存储空间。
需要注意的是,软件要避免配置寄存器(0x18)的值为0x00和0xff,因为软件只会通过寄存器(0x2c)的低8bits读取SRam的填充状态(即最多到255),如果间接读/写填充SRam达到256时,则SRam的填充状态通过寄存器(0x2c)读取后将显示为0。
总共有4个源会访问该单口SRam,其中3个源有同时访问的可能。这4个源为固定优先级,顺序由高到低分别为间接读操作的写SRam源(SRam的Flash侧)、间接写操作的读SRam源(SRam的Flash侧)、间接写操作的写SRam源(SRam的AHB侧)和间接读操作的读SRam源(SRam的AHB侧)。由于从Flash来的数据需要立即写入SRam,因此间接读操作的写SRam源(SRam的Flash侧)的优先级最高。而AHB读/写不会同时发生,因此间接写操作的写SRam源(SRam的AHB侧)和间接读操作的读SRam源(SRam的AHB侧)的优先级相同,均为最低优先级。
使用该外设接口,用来触发外部DMA与QSPI通过AHB进行Burst数据访问,仅适用于间接访问模式。对应两个间接访问控制单元,存在两个相同的DMA外设接口。对于间接读控制单元,QSPI只有在数据已经从Flash中取出并写入到SRam后才会发送DMA请求;对于间接写控制单元,QSPI会在传输被触发后立即发送DMA请求,一直重复该动作直到本次传输完成。通过配置寄存器(0x64、0x74)控制DMA请求的发送速率。
本单元使用两条总线与外部DMA进行双向的VALID和READY握手,一条是DR请求总线(外设到DMA),另一条是DA响应总线(DMA到外设)。对于DR请求总线,当信号“drtype”和“drlast”有效时,QSPI驱动信号“drvalid”有效并保持到DMA发出信号“drready”,表示DMA已接收到该请求;对于DA响应总线,当信号“datype”有效时,DMA驱动信号“davalid”有效并保持到QSPI发出信号“daready”,表示QSPI已接收DMA发出的响应信号。
当QSPI希望DMA或其他AHB主设备通过其AHB接口传输数据时,将通过DR请求总线向DMA发送请求。该请求有“Single”和“Burst”两种类型,每种类型的字节长度均可配(默认为1)。该总线还用于响应刷新请求(Flush),请求类型的识别通过信号“drtype”实现。
DMA使用DA响应总线指示是否完成数据传输,QSPI通过发送“daready”指示是否收到响应信号。DMA也使用该总线向QSPI发送刷新请求,一旦发送刷新请求,QSPI将重新检查FIFO内的数据,并重新发送未得到响应的请求。值得注意的是,如果收到刷新请求的同时,DR总线上正在发送一个请求,则QSPI必须保持信号“drvalid”和“drtype”的值不变直到DMA响应此请求。QSPI通过在DR总线上发送一个特殊请求(信号“drtype”为2’b10)进行响应,表示刷新操作完成。drtype/datype的编码及对应的行为如下:
对一个已经发送到Flash设备中的写请求进行刷新操作是没有任何效果的。
接下来介绍一下使用DMA的操作流程。
当一次间接操作被触发,DMA控制单元可以获取本次传输的总数据量(字节数),并按照寄存器(0x20)配置的单次Burst和Single请求的字节数将本次传输拆分为多次Burst和Single请求。举例说明,如果一次间接读操作的总字节数是512B、SRam的空间是256B、单次Burst传输的字节数是256B,则当SRam中缓存了第一个256B数据后,DMA控制单元将触发一次DMA Burst请求,当剩余的256B数据缓存到SRam后才会触发第二次Burst请求。由于SRam空间只有256B,所以只有DMA将SRam中的数据全部取走后才会发送下一个请求。DMA控制单元可以看到SRam的填充状态。
间接读操作的DMA请求流程如图2所示,间接写操作的DMA请求流程如图3所示。
对于间接读操作,寄存器(0x64)的值定义了QSPI发送第一个DMA请求时SRam的最小填充值,该值设置的越高,则在启动DMA之前,SRam中可缓存的数据越多。对于间接写操作,寄存器(0x74)的值定义了QSPI发送第一个DMA请求时SRam的最大填充值。需要注意的是,当SRam为空时QSPI不能发送间接读的DMA请求,当SRam为满时QSPI不能发送间接写的DMA请求。
在同一时钟周期内,QSPI通过向DMA发送drtype[1:0]和drvalid,触发DMA请求(Single、Burst或Flush),如果同时drlast有效则表示本次请求为当前传输过程中的最后一次请求。外部DMA通过返回drready表示已接收到请求。
外部DMA通过同时发送datype[1:0]和davalid,表示前一次请求的数据传输已完成,QSPI则通过返回daready表示已接收到状态信息。只有当DMA发送取消请求时QSPI才会使用DA响应通道,除此之外的其他请求仅通过daready响应。因此,QSPI可以自由的对DR请求进行流水操作,仅受限于外部DMA对流水的要求。
DMA外设接口可以软件关闭,一旦关闭将不再发送DR请求,DA通道上来的Flush请求也将被忽略,但还是要通过置位daready来响应Flush请求。需要注意的是,当非DMA的AHB主设备执行间接数据传输操作时,DMA外设接口必须关闭。
DAC和INDAC用于数据传输,而访问易失/非易失配置寄存器、SPI状态寄存器、其他状态/保护寄存器以及执行ERASE操作时,需要使用单独的软件控制单元,即软件触发指令生成单元(以下简称“STIG”)。该单元具备通用性,可执行所有SPI Flash设备支持的指令。如果发送了当前Flash设备不支持的指令则会导致不可预期的错误。使用寄存器(0x90)的bit0触发命令执行,通过bit1查询命令的执行状态。对于读命令,支持最多8字节数据从Flash设备中读回,存放在寄存器(0xa0和0xa4)中;对于写命令,待写入Flash设备中的数据存放在寄存器(0xa8和0xac)中。
这里描述一下QSPI响应STIG请求的流程。
当STIG请求被触发后,QSPI首先查询寄存器(0x90),确定要向Flash设备发送什么数据和多少数据;
该寄存器的bit[31:24]代表要发送的指令,也是首先被发送的数据;
如果有地址需要发送,则接下来发送存在寄存器(0x94)中的地址数据(长度由寄存器0x90的bit[17:16]决定);
如果有dummy数据需要发送,则接下来发送dummy数据(长度由寄存器0x90的bit[11:7]决定);
如果有数据需要读/写,则对于读命令,支持最多8字节数据从Flash设备中读回,存放在寄存器(0xa0和0xa4)中(实际长度由寄存器0x90的bit[22:20]决定);对于写命令,待写入Flash设备中的数据存放在寄存器(0xa8和0xac)中(实际长度由寄存器0x90的bit[14:12]决定)。
如果QSPI处于自动轮询状态时,处理STIG请求会略有不同。收到STIG请求后,会立即向Flash设备发送编程悬挂命令(该命令只有OPCODE字段,没有其他字段),待Flash设备进入编程悬挂状态后再按照上述流程响应STIG请求(这部分是我的猜测,需仿真验证)。
每次状态查询之间插入延迟(延迟值由寄存器0x38的bit[31:24]决定),可最大化释放SPI的传输带宽。
由DAC、INDAC或STIG发送的请求均通过SPI Flash命令生成器转换为一串字节序列发送到底层SPI传输单元,再进行并串转换发送到外部Flash设备中。1字节的非连续读序列为:
指令OPCode→地址→Mode字节→Dummy字节→1额外字节。
对于连续访问,每读一个字节都会在序列最后插入一个额外字节写入外部Flash设备,以确保字节之间的连续性(该字节虽无实际意义,但用来保证写信号的激活状态)。
实际发送到Flash设备中的序列依赖于传输请求的类型,即连续传输或非连续传输、是否处于XIP模式以及寄存器(0x04和0x08)的状态。
在写序列被发送之前,Flash设备中的写锁存使能(write enable latch,WEL)必须为高。QSPI在使用DAC或INDAC发送写命令之前会自动发送写锁存使能命令WREN(此时不需要用户参与)。为了提高灵活性和性能,用户可以通过设置寄存器0x08的bit8关闭该功能。关闭该功能后,用户可通过STIG自行发送WREN命令,该命令的OPCODE为0x06(所有Flash设备均使用该值)。
当没有来自DAC和INDAC的新请求并且所有待处理请求都已被发送,Flash设备将自动进入页编程写周期,在该周期完成之前不会响应任何请求。QSPI通过向Flash设备发送RDSR命令来查询这个周期何时结束。WREN和RDSR是唯二的由硬件自行发送的命令,除此之外的所有指令都由用户通过STIG自行发送到Flash设备中。
为正确发送读/写的OPCODE,需要软件对寄存器(0x04、0x08)进行初始化配置,配置内容包括所需指令对应的opcode(默认是基础读和基础页编程)、指令类型、边沿模式(DDR或SDR)和传输模式(即使用单线、双线还是四线传输地址和数据)。为确保复位后控制器可用,这些寄存器的复位值采用兼容SIO设备的设置,且该设置可使用BOOT功能进行调整。
在上述这些参数中,指令类型参数仅出现在寄存器0x04中,但却同时控制读/写指令。如果软件将该参数设为一个非“0”值,则两个寄存器中的地址传输类型和数据传输类型参数均不再有效,即opcode、地址和数据均按照指令类型参数的设定进行传输。以Micron的N25Q128为例进行说明。
读指令(使用寄存器0x04中的指令类型、地址传输类型和数据传输类型参数):
OPCODE | OPCODE 传输 | 地址/Dummy /Mode传输 | 数据 传输 | 指令类型参数 | 地址传输 类型参数 | 数据传输 类型参数 |
READ | 1 | 1 | 1 | 0 | 0 | 0 |
FAST_READ | 1 | 1 | 1 | 0 | 0 | 0 |
DOFR(Dual O/p Fast Read) | 1 | 1 | 2 | 0 | 0 | 1 |
DIOFR(Dual I/O Fast Read) | 1 | 2 | 2 | 0 | 1 | 1 |
QOFR(Quad O/p Fast Read) | 1 | 1 | 4 | 0 | 0 | 2 |
QIOFR(Quad I/O Fast Read) | 1 | 4 | 4 | 0 | 2 | 2 |
DCFR(Dual Command Fast Read) | 2 | 2 | 2 | 1 | - | - |
QCFR(Quad Command Fast Read) | 4 | 4 | 4 | 2 | - | - |
写指令(使用寄存器0x04中的指令类型参数、寄存器0x08中的地址传输类型和数据传输类型参数):
OPCODE | OPCODE 传输 | 地址/Dummy /Mode传输 | 数据 传输 | 指令类型参数 | 地址传输 类型参数 | 数据传输 类型参数 |
PP | 1 | 1 | 1 | 0 | 0 | 0 |
DIFP(Dual Input Fast Program) | 1 | 1 | 2 | 0 | 0 | 1 |
DIEFP(Dual Input Extended Fast Program) | 1 | 2 | 2 | 0 | 1 | 1 |
QIFP(Quad Input Fast Program) | 1 | 1 | 4 | 0 | 0 | 2 |
QIEFP(Quad Input Extended Fast Program) | 1 | 4 | 4 | 0 | 2 | 2 |
DCPP(Dual Command Fast Program) | 2 | 2 | 2 | 1 | - | - |
QCPP(Quad Command Fast Program) | 4 | 4 | 4 | 2 | - | - |
有一些Flash设备支持DDR读(Dual Data Rate Mode,也叫做Dual Transfer Rate Mode,DTR),对于某些专用命令类型可以使用双沿发送数据。可以通过使能寄存器0x04中的bit10通知QSPI,该Flash设备的读命令中含有DDR命令类型。通过寄存器0x10可以配置延迟发送数据,默认情况下数据被延迟一个时钟周期,以保证在DDR传输过程中hold时间大于0。DDR命令的传输配置与前面描述的SDR命令是兼容的。
还有一些设备本身就具备DTR协议,可以自动处理所有命令,通过专用OPCODE来识别当前命令是否使用DTR模式,因此在这种情况下只能使用STR模式发送OPCODE。如果QSPI使能了DTR协议,则Flash设备将不再检测OPCODE,而通过查询内部寄存器的配置值来识别模式。
当配置寄存器0x0的bit8为1后,QSPI将进入传统SPI传输模式。此模式下,软件将旁路掉所有的控制单元(DAC、INDAC和STIG)而直接访问内部的RX_FIFO和TX_FIFO。软件通过AHB总线向任意地址写入任意数据来访问TX_FIFO,通过AHB总线读取任意地址来访问RX_FIFO。此方式虽然可以直接向Flash设备发送任意命令,但会导致很大的软件开销,主要开销在两方面。
一是用于满足传统SPI协议要求。该协议采用全双工传输方式,为保证片选使能有效,需要双方向始终保持数据传输状态。即使只希望从Flash设备中读取数据,也必须写入Dummy数据,以确保片选使能有效,反之亦然。举例说明,对一个3字节地址的Flash设备执行一次4字节的读操作,软件需要向TX_FIFO中写入8字节数据。其中第一个字节是指令OPCODE,接下来3字节是地址,最后4字节是Dummy数据,以确保在读数据返回时片选使能保持有效。由于软件向TX_FIFO中写入8字节数据,也希望从RX_FIFO中得到8字节的返回数据。其中开始的4字节数据为无效数据被丢弃,最后4字节数据为实际需要的读数据。
二是用于管理RX_FIFO和TX_FIFO的填充状态。由于这两个FIFO的深度有限,需要软件确保在指令执行期间TX_FIFO不会耗尽而RX_FIFO不会溢出。当FIFO的填充值超过寄存器0x30和0x34中预设的水位值后会产生中断,需要软件及时响应和处理,从而造成很大的软件开销。
根据前面的介绍,QSPI中共有三个独立的控制单元,分别为DAC、INDAC和STIG。有两个数据来源,分别为AHB侧的主设备和外部的Flash设备。组合后共有5种操作可能同时访问QSPI,分别为直接读操作、直接写操作、间接读操作、间接写操作和STIG操作。为解决这几种操作的访问冲突,采用固定优先级的仲裁方式,优先级的顺序由高到低依次为间接写操作、直接写操作、STIG、直接读操作和间接读操作,当任何一个高优先级的操作到来时都会打断当前正在处理的低优先级操作。当某个控制单元处于等待状态时,由其自身进行流控处理。
为正确采样到Flash设备送出的读数据,QSPI提供了两种采样机制,即延迟开关机制和外部DLL机制,采样数据逻辑框图如图4所示。
上电后,这两种采样机制都处于禁用状态,因为此时输出到Flash设备的时钟频率很低,因此适用于大部分应用及设备枚举。通过配置寄存器0x10决定如何进行采样。
通过配置该寄存器的bit5,决定使用ref_clk的哪个沿进行采样数据(图4中的时钟沿选择)。
通过配置该寄存器的bit[4:1],控制延迟几个ref_clk时钟周期进行采样数据(ref_clk是高频时钟,至少为Flash设备时钟的4倍以上)。由于从时钟输入到数据输出的延迟较大,再加上路径延迟和器件延迟,会导致满足时序要求的最高输入时钟频率不能达到Flash设备支持的极限频率,从而降低了访问效率。为避免出现这种情况,通过软件配置延迟周期值(图4中的开关移位配置值),可以确保在高频时钟下采样到有效数据。
通过配置该寄存器的bit0,使能外部DLL机制(图4中的使能Loopback)。如果Flash设备的时钟频率很高,导致读数据的采样窗口很小,而且在不同操作环境下该窗口还会发生变化,则延迟开关机制将无法适用,需要引入外部DLL机制。即将输入到Flash设备中的时钟输出,通过独立于QSPI的一个外部可配置的延迟线电路,产生延迟后的时钟输入到QSPI中,作为读数据的第一级采样时钟(使用下降沿采样)。需要注意的是,该机制只适用于SDR命令。
以一个8字节读传输为例,介绍如何通过QSPI与外部Flash设备之间的接口传输数据,传输过程如图5所示。
阶段0,传输开始,片选(n_ss_out)选择从设备1(从4’hf变为4’hd);
阶段1,指令周期开始,8bit指令中的第一个bit从mo0输出,本阶段不使用其他数据输出管脚;
阶段2,指令周期结束,8bit指令中的最后一个bit输出完成;
阶段3,地址周期开始,本例中使用3字节地址,通过4个数据输出管脚输出,一个时钟周期可以输出半个字节的地址,因此占用6个时钟周期完成3字节地址的输出;
阶段4,地址周期结束,最后半个字节地址输出完成;
阶段5,冗余数据周期开始,本例中需要填充3字节的Dummy数据(在读回数据准备好之前需要保持数据线的激活状态),此时输出6个半字节Dummy数据中的第一个;
阶段6,冗余数据周期结束,最后一个半字节Dummy数据输出完成,此时也是本次读传输的最后一个写周期,因此输出使能(n_mo_en)也由4’h0变为4’hf;
阶段7,读数据写入周期开始,本例中读回8字节数据,使用4个数据输入管脚传输,因此需要占用16个时钟周期,当读数据被接收时,输出管脚mo将拉低,处于非激活状态;
阶段8,读数据写入周期结束,最后一个半字节读数据输入完成,输入管脚mi变为高阻,输出管脚mo变为高,从设备1的片选使能变为无效,本次传输结束;
阶段9,输出使能变为4’h0,准备进行下次读传输。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。