该文章同步至OneChan当四线并行、内存映射与DMA交织我们如何平衡带宽、延迟与系统资源实现极致吞吐导火索一个QSPI Flash的“高速”读取性能瓶颈在一个高性能嵌入式系统中使用QSPI Flash存储程序代码和数据。系统设计时预期通过内存映射模式实现快速的XIP执行但实际测试发现在内存映射模式下CPU直接读取QSPI Flash的速度仅为理论带宽的30%启用缓存后性能有所提升但偶尔会出现数据一致性问题使用DMA从QSPI Flash拷贝数据到RAM时带宽利用率也不到50%逻辑分析仪捕获的波形显示在连续读取数据时QSPI接口在每读取256字节后会有大约2μs的停顿。进一步分析发现这是因为Flash内部页编程和读取的页边界限制以及QSPI控制器在跨页时需要重新发送命令序列。矛盾点在于QSPI硬件提供了四线并行和高达133MHz的时钟频率理论上可以提供532Mbps的带宽4线×133MHz。但实际性能受限于Flash本身的特性、QSPI控制器的配置、系统总线的竞争以及软件访问模式。要榨取极致性能必须深入理解每一层的细节。第一性原理重新审视四线SPI与内存映射设计的演进从单线SPI到四线QSPI传统SPI使用两条数据线MOSI和MISO实现全双工但实际读操作中MOSI线只用于发送命令和地址大部分时间处于未充分利用状态。QSPI通过增加数据线数量将读数据的带宽提高4倍。单线SPI读取序列 命令(8位) 地址(24位) 哑元周期 数据(多位每时钟1位) 四线QSPI读取序列标准 命令(1线, 8位) 地址(4线, 24位) 哑元周期 数据(4线, 每时钟4位) 四线QSPI读取序列快速 命令(4线, 8位) 地址(4线, 24位) 哑元周期 数据(4线, 每时钟4位)关键洞察命令阶段可以单线发送也可以四线发送。四线发送命令需要Flash支持且命令本身需要设计为四线兼容通常命令字节被重复4次。地址阶段通常使用四线发送每个时钟周期传输4位地址24位地址只需6个时钟。哑元周期由于Flash从接收到地址到准备好数据需要一定时间tACC这段时间用哑元时钟填充。哑元周期数取决于Flash的延迟和QSPI时钟频率。数据阶段四线传输每个时钟周期传输4位数据。内存映射模式的实现原理内存映射模式是QSPI最吸引人的特性之一。它将外部Flash映射到处理器的地址空间使得CPU可以直接通过加载指令如LDR读取Flash内容而无需软件干预。硬件支持QSPI控制器内部有一个地址转换器当CPU访问特定的内存区域如0x9000_0000时QSPI控制器自动将访问转换为QSPI读事务。转换过程CPU发起读访问地址0x9000_1234 ↓ QSPI控制器截获该访问 ↓ 将地址0x9000_1234转换为Flash偏移0x1234 ↓ 构造QSPI读命令序列命令 地址(0x1234) 哑元 数据 ↓ 通过QSPI接口从Flash读取数据 ↓ 将数据返回给CPU优势代码可以像在内部Flash一样在外部Flash中运行XIP无需先拷贝到RAM。挑战每次访问都有固定的开销命令、地址、哑元并且访问是随机的无法利用突发读取的优化。此外缓存对性能影响巨大。性能模型理论带宽 vs. 实际带宽理论带宽计算假设QSPI时钟为100MHz四线数据则理论带宽为100MHz × 4位/时钟 400Mbps 50MB/s实际带宽模型实际带宽受限于每次读事务的开销和数据传输时间。总时间 命令时间 地址时间 哑元时间 数据时间 命令时间命令位数 / (线数 × 时钟频率) 地址时间地址位数 / (线数 × 时钟频率) 哑元时间哑元周期数 / 时钟频率 数据时间数据位数 / (线数 × 时钟频率)示例四线模式100MHz命令8位单线地址24位四线哑元周期8读取256字节2048位数据。命令时间 8位 / (1线 × 100MHz) 80ns 地址时间 24位 / (4线 × 100MHz) 60ns 哑元时间 8周期 / 100MHz 80ns 数据时间 2048位 / (4线 × 100MHz) 5120ns 总时间 8060805120 5340ns 有效数据 256字节 实际带宽 256字节 / 5340ns ≈ 47.9MB/s 效率 47.9 / 50 95.8%但上述计算假设了连续读取且没有考虑跨页边界、缓存未命中、总线竞争等因素。实际效率会低得多。性能陷阱QSPI系统的五大瓶颈瓶颈一Flash内部的页边界限制大多数QSPI Flash内部被划分为页通常256或512字节。连续读操作不能跨越页边界否则需要额外的延迟。问题当读取操作跨越页边界时Flash内部需要重新定位到下一页可能导致额外的延迟通常几微秒。解决方案软件避免跨页访问或者将跨页访问拆分为两次。使用QSPI控制器的自动递增地址功能让硬件处理页边界。瓶颈二命令序列的配置不当QSPI控制器需要正确配置命令序列包括命令、地址宽度、数据模式、哑元周期等。配置不当会导致性能下降或通信失败。常见错误哑元周期设置过小数据尚未准备好就采样导致读取错误。哑元周期设置过大增加不必要的延迟。没有使能四线模式仍然使用单线模式传输数据。优化方法根据Flash数据手册和实际时钟频率计算最佳哑元周期。有些QSPI控制器支持自动检测Flash所需哑元周期。瓶颈三内存映射模式下的缓存效应内存映射模式下CPU通过缓存访问QSPI Flash。缓存行的大小通常为32字节。每次缓存未命中QSPI控制器会发起一次读事务。但缓存行读事务可能不是最优的。示例缓存行32字节但QSPI控制器可能只支持最大8字节的突发读取。为了读取32字节需要4次8字节的读取每次都有命令、地址、哑元的开销。优化配置QSPI控制器支持更大的突发长度如64字节。使用预取指功能提前读取后续数据。瓶颈四系统总线竞争QSPI控制器通过总线如AXI连接到内存系统与CPU、DMA等共享带宽。当多个主机同时访问时QSPI的访问可能被阻塞。影响在内存映射模式下CPU读取QSPI Flash时如果总线被其他主机占用则读取延迟增加导致CPU停顿。优化提高QSPI控制器的总线优先级。使用缓存减少对QSPI的访问次数。瓶颈五软件访问模式软件以何种方式访问QSPI Flash对性能影响巨大。随机访问和顺序访问的性能差异可达10倍以上。顺序访问可以利用Flash的连续读模式只需发送一次命令和地址然后连续读取数据。随机访问每次读取都需要完整的命令序列开销巨大。优化尽量将数据顺序存储并顺序访问。使用DMA进行大块数据搬运减少CPU干预。超越XIP高级优化技巧技巧一精确计算哑元周期哑元周期必须足够长以覆盖Flash的访问时间tACC。tACC通常与电压、温度有关且在不同的时钟频率下所需的哑元周期数不同。计算公式所需哑元周期数 ceil( tACC × 时钟频率 ) - 固定延迟其中固定延迟包括命令和地址的传输时间。示例tACC 40ns时钟频率 100MHz命令8位单线80ns地址24位四线60ns。则从命令开始到数据准备好需要40ns但命令和地址已经用了140ns所以理论上不需要哑元周期。但实际上由于内部流水线可能仍需要少量哑元周期。实践通过实验确定最小哑元周期。从最大值开始递减直到读取错误然后增加1-2个周期作为余量。技巧二配置QSPI控制器的寄存器以STM32的QSPI为例需要配置多个寄存器以实现最佳性能。// 示例STM32 QSPI初始化代码片段voidQSPI_Init(void){// 1. 配置时钟分频得到100MHz时钟QUADSPI-DCR|(0QUADSPI_DCR_CKMODE_Pos);// 模式0时钟空闲为低QUADSPI-CR|(0QUADSPI_CR_PRESCALER_Pos);// 不分频输入时钟为100MHz则输出100MHz// 2. 配置Flash大小地址位数QUADSPI-DCR|(23QUADSPI_DCR_FSIZE_Pos);// 24位地址2^2416MB// 3. 配置采样边缘QUADSPI-CR|(1QUADSPI_CR_SAMPLE_SHIFTING_Pos);// 在时钟后半周期采样提高时序余量// 4. 配置双闪存模式如果使用两个Flash并行// QUADSPI-CR | (1 QUADSPI_CR_DFM_Pos); // 使能双闪存模式数据线变为8条// 5. 配置中断和DMAQUADSPI-CR|(1QUADSPI_CR_TCIE_Pos);// 使能传输完成中断// 使能DMAQUADSPI-CR|(1QUADSPI_CR_DMAEN_Pos);}技巧三内存映射模式的配置与优化内存映射模式需要正确配置存储器映射的区域和访问属性。// 配置内存映射模式voidQSPI_EnableMemoryMappedMode(void){// 1. 配置读命令序列QUADSPI-CCR(0xEBQUADSPI_CCR_INSTRUCTION_Pos)|// 快速读四线命令0xEB(3QUADSPI_CCR_ADDRESSMODE_Pos)|// 24位地址(3QUADSPI_CCR_ADDRESSIZE_Pos)|// 四线地址(0QUADSPI_CCR_ABMODE_Pos)|// 无交替字节(3QUADSPI_CCR_ABMODE_Pos)|// 四线数据(6QUADSPI_CCR_DCYC_Pos)|// 哑元周期6(1QUADSPI_CCR_DMODE_Pos);// 四线数据// 2. 设置内存映射模式QUADSPI-CCR|(1QUADSPI_CCR_FMODE_Pos);// 内存映射模式// 3. 使能QSPIQUADSPI-CR|(1QUADSPI_CR_EN_Pos);// 4. 在MPU中配置该区域为可缓存、可预取MPU_Config(0x90000000,16*1024*1024,MPU_REGION_ENABLE|MPU_REGION_CACHEABLE|MPU_REGION_BUFFERABLE);}注意内存映射区域通常配置为可缓存Cacheable和可缓冲Bufferable以提高性能。但需要处理缓存一致性问题。当QSPI Flash的内容被DMA或另一个处理器更新时必须清洗缓存。技巧四DMA与QSPI的协同DMA可以用于在QSPI Flash和RAM之间搬运数据减轻CPU负担。但需要仔细配置DMA和QSPI的握手。// 使用DMA从QSPI Flash读取数据到RAMvoidQSPI_DMA_Read(uint32_tflash_addr,uint8_t*ram_addr,uint32_tsize){// 1. 配置DMADMA_InitTypeDef dma_init;dma_init.ChannelDMA_CHANNEL_3;dma_init.DirectionDMA_PERIPH_TO_MEMORY;dma_init.PeriphIncDMA_PINC_DISABLE;dma_init.MemIncDMA_MINC_ENABLE;dma_init.PeriphDataAlignmentDMA_PDATAALIGN_WORD;// QSPI数据寄存器为32位dma_init.MemDataAlignmentDMA_MDATAALIGN_WORD;dma_init.ModeDMA_NORMAL;dma_init.PriorityDMA_PRIORITY_HIGH;HAL_DMA_Init(dma_init);// 2. 配置QSPI为间接读模式QUADSPI-CCR(0xEBQUADSPI_CCR_INSTRUCTION_Pos)|// 快速读四线命令(3QUADSPI_CCR_ADDRESSMODE_Pos)|// 24位地址(3QUADSPI_CCR_ADDRESSIZE_Pos)|// 四线地址(3QUADSPI_CCR_DMODE_Pos)|// 四线数据(6QUADSPI_CCR_DCYC_Pos);// 哑元周期QUADSPI-DLRsize-1;// 设置数据长度字节数-1QUADSPI-ARflash_addr;// 设置地址// 3. 启动DMAHAL_DMA_Start(hdma,(uint32_t)QUADSPI-DR,(uint32_t)ram_addr,size/4);// 4. 启动QSPI传输QUADSPI-CCR|(1QUADSPI_CCR_FMODE_Pos);// 间接读模式QUADSPI-CR|(1QUADSPI_CR_EN_Pos);// 5. 等待DMA完成HAL_DMA_PollForTransfer(hdma,HAL_DMA_FULL_TRANSFER,1000);}DMA配置要点QSPI的数据寄存器通常是32位的因此DMA的传输宽度应设置为字32位。数据长度需要根据字节数换算为字数。在启动DMA后再启动QSPI传输避免数据丢失。技巧五双闪存模式Dual Flash的配置对于更大的存储需求可以使用两个QSPI Flash分别连接到QSPI控制器的两组数据线。在双闪存模式下数据线扩展到8条每个时钟周期可以传输8位数据。接线方式Flash1: IO0, IO1, IO2, IO3 Flash2: IO4, IO5, IO6, IO7配置// 使能双闪存模式QUADSPI-CR|(1QUADSPI_CR_DFM_Pos);// 配置Flash1和Flash2的片选// 通常通过地址的最高位来选择A240选择Flash1A241选择Flash2// 因此两个Flash的地址空间是连续的总容量为32MB每个16MB性能提升理论上双闪存模式可以将带宽提高一倍。但需要注意两个Flash必须具有相同的型号和特性且需要同时进行相同的操作。QSPI系统设计检查清单10条1. 时钟配置检查问题QSPI时钟频率是否在Flash支持范围内是否考虑了信号完整性验证测量SCK信号确保边沿陡峭过冲小。检查点时钟频率 ≤ Flash最大频率走线长度匹配终端电阻适当。2. 命令序列配置问题命令序列命令、地址、哑元、数据的线数和时序是否正确验证用逻辑分析仪捕获波形对比Flash数据手册。检查点命令码正确地址位数匹配哑元周期足够数据线数正确。3. 内存映射配置问题内存映射区域是否配置了正确的缓存和缓冲属性验证测试随机访问和顺序访问的性能对比缓存开启和关闭的情况。检查点MPU/MMU配置正确缓存策略合理通常Write-Back, Read-Allocate。4. 哑元周期优化问题哑元周期是否针对当前时钟频率和电压温度优化验证在不同温度和电压下测试读取稳定性。检查点哑元周期在极端条件下仍能稳定工作且不过大。5. 跨页处理问题软件或硬件是否处理了Flash的页边界验证测试跨页读取检查是否有性能下降或错误。检查点QSPI控制器支持自动递增地址或软件将跨页访问拆分。6. DMA配置问题DMA与QSPI的握手是否正确传输效率如何验证测量DMA传输大量数据的时间和CPU占用率。检查点DMA传输完成中断正常无数据丢失带宽利用率80%。7. 总线竞争管理问题QSPI控制器在总线上的优先级是否足够验证在总线高负载下测试QSPI访问延迟。检查点QSPI控制器优先级高于其他主机或使用带宽预留。8. 双闪存同步问题双闪存模式下两个Flash的特性是否匹配片选逻辑是否正确验证分别测试每个Flash然后测试同时访问。检查点两个Flash型号相同时序一致片选信号正确。9. 功耗管理问题QSPI接口的功耗是否在预算内是否在低功耗模式下正确关闭验证测量不同工作频率下的电流消耗。检查点在睡眠模式下禁用QSPI时钟动态调整时钟频率。10. 错误处理问题是否检测和处理QSPI传输错误是否有重试机制验证模拟传输错误如断开数据线检查系统响应。检查点错误标志被检测有重试机制重试次数可配置。总结在带宽、延迟与复杂度之间权衡QSPI协议通过增加数据线数量、支持内存映射和DMA为外部Flash提供了高性能的访问接口。然而真正的极致性能来自于对每一层细节的深入理解和优化硬件层面信号完整性、终端匹配、时钟频率。配置层面命令序列、哑元周期、缓存策略。架构层面内存映射、DMA使用、总线竞争。软件层面访问模式、错误处理、低功耗管理。QSPI的性能优化是一个系统工程需要硬件工程师、驱动开发者和系统架构师紧密合作。只有将Flash特性、控制器配置、系统架构和软件访问模式综合考虑才能榨取出QSPI接口的每一分性能。当您下次设计基于QSPI的系统时请记住四线并行带来的不仅是带宽的提升还有时序复杂度的增加。内存映射提供了便利但也引入了缓存一致性的挑战。DMA减轻了CPU负担但需要仔细配置握手。在追求极致性能的路上每一个环节都不可或缺。思考题在您的QSPI应用中是否遇到了性能瓶颈您是如何分析并解决的是调整了哑元周期还是优化了软件访问模式下篇预告接下来我们将探讨eSPI协议。在《LPC的继承者在引脚节约、虚拟外设与安全启动间重塑板级架构》中我们将揭示eSPI如何用更少的引脚实现更强的功能虚拟外设如何改变主板设计安全启动如何集成以及eSPI在取代传统LPC接口时面临的兼容性挑战。