1. 项目概述与EMIFB核心价值
在嵌入式系统开发,尤其是基于TI处理器(如Sitara系列)的项目中,外部内存接口的设计与配置往往是决定系统性能与功耗的关键一环。我们常常需要为处理器外挂SDRAM来扩展运行内存,而EMIFB(External Memory Interface B)就是负责与这片SDRAM“对话”的硬件控制器。它远不止是一个简单的信号转换器,而是一个集成了命令调度、时序管理、刷新控制和低功耗状态机的智能管家。很多工程师在初次接触时,往往只关注地址线的连接和时钟频率的匹配,却忽略了控制器内部寄存器配置的深层逻辑,导致系统出现间歇性数据错误、性能不达标或在休眠时功耗居高不下。我自己就曾在一个电池供电的工业手持设备项目上,因为对EMIFB的刷新机制和低功耗模式理解不透彻,导致设备待机电流比预期高了近一倍,排查过程苦不堪言。
EMIFB的核心价值,在于它将开发者从繁琐、严苛的SDRAM底层时序管理中解放出来。SDRAM本身是一个状态机复杂的器件,有激活(ACTV)、预充电(PRE)、读写(READ/WRT)、刷新(REFR)等多种命令,且命令之间有着严格的时序约束(如tRCD, tRP, tRFC等)。EMIFB通过一组配置寄存器(主要是SDCFG, SDCFG2, SDTIM1, SDTIM2, SDRFC),让开发者以“声明”的方式告诉控制器:我接的SDRAM是什么规格(行列地址位数、Bank数量、位宽),它的时序要求是什么(各种延迟参数),需要多久刷新一次。之后,EMIFB便会自动生成所有符合时序的底层命令序列,处理自动刷新,并支持进入自刷新(Self-Refresh)和掉电(Power-Down)等低功耗模式。特别是对于移动SDRAM(Mobile SDRAM),EMIFB还支持部分阵列自刷新(Partial Array Self Refresh, PASR),可以只刷新存有关键数据的内存区域,从而在保持数据的同时实现极致的功耗节省。理解并正确配置EMIFB,是确保嵌入式系统内存子系统稳定、高效、节能的基石。
2. EMIFB SDRAM控制器架构与核心寄存器解析
要驾驭EMIFB,首先得理解它的“控制面板”——也就是那几个核心配置寄存器。这些寄存器直接决定了控制器如何与物理SDRAM芯片交互。如果配置错误,轻则性能下降,重则系统无法启动或运行不稳定。
2.1 SDRAM配置寄存器(SDCFG)详解
SDCFG寄存器是EMIFB SDRAM控制的基石,它定义了SDRAM的基本结构和操作模式。我们可以把它看作一份给EMIFB的“硬件规格书”。
SDREN与MSDRAM_ENABLE位:这是总开关。SDREN=1启用SDRAM接口模式。如果你连接的是移动SDRAM(Mobile SDRAM),则必须同时将MSDRAM_ENABLE也置1。一个常见的坑是,在初始化序列中,必须先配置好时钟和引脚复用,最后再写SDCFG寄存器来置位这两个使能位。因为对SDCFG的写操作(特别是最低两个字节)会触发EMIFB的自动初始化序列。如果时钟还没稳定就触发初始化,序列很可能失败。
NM位(位宽配置):这个位决定了数据总线的位宽和突发长度(Burst Length)。NM=0表示32位接口,突发长度为4;NM=1表示16位接口,突发长度为8。这里的选择必须与硬件PCB上SDRAM芯片的数据线宽度(以及是否使用了两片16位芯片组成32位)严格对应。配置错误会导致读写数据错位,系统必然崩溃。
CL字段(CAS延迟):这可能是最知名的SDRAM时序参数之一,它定义了从发出读命令(READ)到数据在数据总线上有效所需的时钟周期数。SDCFG中的CL字段(通常2或3)必须设置为与SDRAM芯片标称值(如CL=3)一致。在Load Mode Register(LMR)命令中,EMIFB会根据这个CL值来设置A[6:4]地址线。
IBANK与PAGESIZE字段:这两个字段共同决定了EMIFB内部如何将系统发出的逻辑地址映射到SDRAM的物理地址(行、列、Bank)。IBANK定义了内部使用的Bank地址位数(0,1,2分别对应1,2,4个Bank),PAGESIZE定义了列地址位数(0->8位, 1->9位, 2->10位, 3->11位)。它们的组合直接决定了单次页面访问的大小(Page Size)和EMIFB可寻址的内存范围(Reach)。例如,对于一颗常见的256Mb(32Mx8)SDRAM,其内部可能是13位行地址(RA[12:0]),9位列地址(CA[8:0]),2位Bank地址(BA[1:0])。那么,PAGESIZE应设为1(对应9位列地址),IBANK应设为2(对应2位Bank地址)。务必根据芯片数据手册(Datasheet)中的实际组织结构来设置,而不是根据总容量猜测。
IBANK_POS位(内部Bank位置):这是一个影响地址映射和性能的关键位。IBANK_POS=0是默认的高性能模式,EMIFB采用Bank交错(interleaving)的地址映射。当连续访问跨页时,控制器会先遍历同一行在不同Bank的页面,保持多个Bank同时打开,从而减少预充电和激活命令的开销,提升带宽。IBANK_POS=1则用于移动SDRAM配合部分自刷新(PASR)的场景。在此模式下,地址映射变为先遍历同一Bank内的所有页,再切换到下一个Bank。这会导致同一时间只能有一个Bank处于打开状态,性能有所下降,但这是PASR功能正确工作所必需的,因为PASR是按Bank来选择刷新区域的。
2.2 SDRAM配置寄存器2(SDCFG2)与移动SDRAM
SDCFG2寄存器主要针对移动SDRAM的低功耗特性进行配置。
PASR字段(部分阵列自刷新):这是移动SDRAM的“节能神器”。在自刷新模式下,整个SDRAM阵列仍在消耗能量进行刷新。PASR允许你指定只刷新部分Bank,甚至Bank的一部分。SDCFG2中的PASR位域在初始化时会被加载到SDRAM的扩展模式寄存器(EMR)中。其可选值例如:0刷新所有4个Bank,1h刷新Bank 0和1,2h仅刷新Bank 0,5h刷新Bank 0的一半,6h刷新Bank 0的四分之一。使用PASR的核心前提是软件必须知晓:你需要将系统必须保留的数据(如唤醒后的代码、关键状态变量)提前搬运到那些会被刷新的Bank或区域中。否则,未被刷新的区域数据会丢失。这也是为什么在使用PASR时,强烈建议设置IBANK_POS=1,避免Bank交错,让软件能清晰地管理数据存放位置。
ROWSIZE字段:定义连接的移动SDRAM的行地址位数。这个值同样必须严格参照芯片数据手册。
注意:对SDCFG2寄存器的任何写操作,同样会触发EMIFB对移动SDRAM的重新初始化序列。因此,在系统运行时动态修改PASR配置需要谨慎,最好在进入低功耗模式前一次性配置好。
2.3 SDRAM时序寄存器(SDTIM1, SDTIM2)
如果说SDCFG定义了“做什么”,那么SDTIM1和SDTIM2就定义了“以多快的速度做”。它们包含了SDRAM操作的所有关键时序参数。
SDTIM1:通常包含一些最基础的延迟参数,如:
tRCD(RAS to CAS Delay):行激活到读/写命令之间的最小延迟。tRP(RAS Precharge Time):预充电命令到下一次行激活之间的最小延迟。tRAS(RAS Active Time):行激活后必须保持打开的最小时间。tWR(Write Recovery Time):写操作后到发出预充电命令前必须等待的时间。
SDTIM2:可能包含更复杂的时序,如刷新周期时间tRFC、退出自刷新时间tXSR等。
配置要点:
- 来源唯一:所有时序参数的值必须来自你所使用的具体SDRAM芯片的数据手册,而不是参考设计或其他处理器的例子。不同工艺、不同速度等级的芯片,时序要求可能不同。
- 单位转换:数据手册给出的参数单位通常是纳秒(ns)。你需要根据EMIFB的工作时钟频率
fCLK(例如133MHz,周期7.5ns)将其转换为时钟周期数。公式为:周期数 = 时序参数(ns) / 时钟周期(ns)。计算结果通常需要向上取整(ceil),以满足最坏情况下的时序要求。 - 保留裕量:在计算出的周期数基础上,适当增加1-2个周期的裕量,可以增强系统在电压、温度波动下的稳定性,尤其是在工业级或车载等严苛环境中。
2.4 SDRAM刷新控制寄存器(SDRFC)
SDRFC寄存器管理着SDRAM的生命线——刷新机制。
REFRESH_RATE字段:这是最重要的字段,它告诉EMIFB“每隔多少个时钟周期,我需要考虑执行一次刷新操作”。其计算不是随意的,必须基于SDRAM的刷新要求和EMIFB的时钟频率。计算公式在手册中给出:REFRESH_RATE ≤ fCLK / fRefresh。其中fRefresh是SDRAM要求的刷新频率。
如何确定fRefresh?SDRAM数据手册通常会写明“每64ms需要执行8192次刷新命令”。那么,fRefresh = 8192 / 64ms = 128000 Hz。如果fCLK = 133MHz,则REFRESH_RATE ≤ 133000000 / 128000 ≈ 1039。我们取整数1039(0x40F)配置进去。这个值如果设得太大,刷新不及时会导致数据丢失;设得太小,刷新过于频繁会占用大量带宽,降低系统性能。必须精确计算。
LP_MODE与SR_PD位:这两个位控制低功耗模式。
LP_MODE=1, SR_PD=0:进入自刷新模式。EMIFB会先完成所有未决访问并清空刷新积压计数器,然后向SDRAM发出自刷新命令(SLFR)。SDRAM进入自刷新后,由其内部振荡器负责刷新,EMIFB时钟甚至可以关闭,功耗极低。这是深度睡眠时常用的模式。LP_MODE=1, SR_PD=1:进入掉电模式。EMIFB发出掉电命令(POWERDOWN),SDRAM停止大部分内部操作,功耗比自刷新模式还低,但无法保持数据,需要外部供电维持存储单元电荷。通常用于短时待机,且要求快速唤醒的场景。- 任何对SDRAM的访问请求或清除
LP_MODE位,都会使EMIFB退出低功耗模式。
3. SDRAM自动初始化序列深度解析与实操
理解了寄存器之后,我们来看EMIFB如何让一片“裸”的SDRAM芯片进入工作状态。这个过程叫初始化,EMIFB为我们自动化了绝大部分步骤,但我们仍需理解其原理,以便在出现问题时能有效排查。
3.1 初始化触发条件与流程
初始化序列会在两种情况下被触发:
- 对SDRAM配置寄存器(SDCFG)的最低两个字节进行写操作。
- 对于移动SDRAM,对SDCFG2寄存器进行写操作。
这意味着,任何对SDCFG/SDCFG2关键字段的修改,都会导致SDRAM重新初始化。在系统运行时(尤其是频率切换前后)需要特别注意。
自动初始化序列的8个步骤,其设计逻辑完全遵循JEDEC标准的SDRAM上电初始化流程:
- 软件准备:软件设置
SDREN(和MSDRAM_ENABLE)位。前提是时钟(PLL)和引脚复用(PinMux)必须已经配置正确且稳定。这是一个硬性要求。 - 预充电所有Bank:如果初始化是由写SDCFG触发,且有任何Bank是打开的,EMIFB会先发一个全Bank预充电命令(
PREwithA10=1)。这是为了确保所有Bank处于关闭(idle)状态,为后续步骤提供一个干净的起点。 - 等待稳定期:EMIFB拉高时钟使能(
SDCKE),并持续发送NOP命令,等待8个刷新间隔的时间。这个步骤的目的是满足SDRAM芯片的“上电稳定时间”要求(通常为100μs或200μs)。手册中特别指出,仅靠这8个刷新间隔的等待可能不足以满足200μs的要求,尤其是在EMIFB时钟频率很高时(因为每个刷新间隔很短)。例如,如果fCLK=200MHz,REFRESH_RATE=1039,则一个刷新间隔仅为1039 / 200MHz ≈ 5.2μs,8个间隔才41.6μs,远小于200μs。因此,在系统上电后、首次配置EMIFB之前,软件必须通过延时函数确保200μs的稳定时间已经过去。这是很多初始化失败案例的根源。 - 再次预充电所有Bank:再次发出
PRE命令,确保状态。 - 执行8次自动刷新:发出8个
REFR命令。这一步是“训练”SDRAM内部的刷新计数器,是标准流程。 - 配置移动SDRAM扩展模式寄存器(仅移动SDRAM):发出
LMR命令,通过地址线A[6:0]设置扩展模式寄存器,主要用来配置PASR(值来自SDCFG2的PASR字段)。 - 配置模式寄存器:对所有SDRAM发出
LMR命令,通过地址线A[9:0]设置核心参数:突发类型(固定为顺序)、突发长度(由NM位决定)、CAS延迟(由CL字段决定)。至此,SDRAM的工作模式已被设定。 - 执行一次自动刷新周期:最后再执行一次完整的刷新周期(预充电+刷新),然后接口进入空闲状态,准备接受访问请求。
3.2 初始化配置的完整代码示例与步骤
下面以一个典型的配置流程为例,展示在C代码中如何一步步配置EMIFB来驱动一片133MHz的32位SDRAM。
// 假设寄存器基地址定义 #define EMIFB_BASE 0x4C000000 #define SDCFG (*(volatile unsigned int *)(EMIFB_BASE + 0x00)) #define SDCFG2 (*(volatile unsigned int *)(EMIFB_BASE + 0x04)) #define SDTIM1 (*(volatile unsigned int *)(EMIFB_BASE + 0x08)) #define SDTIM2 (*(volatile unsigned int *)(EMIFB_BASE + 0x0C)) #define SDRFC (*(volatile unsigned int *)(EMIFB_BASE + 0x10)) void emifb_sdram_init(void) { // 步骤0: 确保硬件稳定(最关键的一步!) // 1. 确认电源和时钟已稳定。 // 2. 等待至少200us,满足SDRAM上电稳定时间要求。 // 可以使用简单的延时循环或硬件定时器。 delay_us(200); // 步骤1: 配置系统时钟和EMIFB引脚复用(此处省略,依赖于具体SoC) // 例如,配置PLL输出133MHz给EMIFB,并将相关引脚功能设置为EMIFB。 // 步骤2: 配置SDRAM时序寄存器(SDTIM1, SDTIM2) // 参数需根据具体SDRAM芯片手册计算。以下为示例值(周期数)。 // tRCD = 20ns, tCLK=7.5ns (133MHz) -> ceil(20/7.5)=3 cycles // tRP = 20ns -> 3 cycles // tRAS = 42ns -> ceil(42/7.5)=6 cycles // tWR = 15ns -> 2 cycles (通常需要加上一个周期,这里取3) // 假设SDTIM1包含这些字段 SDTIM1 = (3 << 24) | (3 << 20) | (6 << 16) | (3 << 12); // 字段位置需查手册 // tRFC = 66ns -> 9 cycles, tXSR = 75ns -> 10 cycles // 假设SDTIM2包含这些字段 SDTIM2 = (9 << 8) | (10 << 4); // 步骤3: 配置刷新控制寄存器(SDRFC) // 计算REFRESH_RATE: fCLK=133MHz, 要求64ms内8192次刷新。 // REFRESH_RATE = 133e6 * 64e-3 / 8192 ≈ 1039 unsigned int refresh_rate = 1039; SDRFC = (refresh_rate & 0x1FFF); // REFRESH_RATE通常是13位字段 // 步骤4: 配置SDRAM结构寄存器(SDCFG),此操作将触发初始化! // 假设配置:32位宽(NM=0), CAS Latency=3(CL=3), 4个内部Bank(IBANK=2), // 页大小对应9位列地址(PAGESIZE=1), 启用SDRAM接口(SDREN=1)。 // IBANK_POS=0 使用高性能Bank交错模式。 unsigned int sdcfg_val = 0; sdcfg_val |= (0 << 31); // NM = 0 (32-bit) sdcfg_val |= (3 << 27); // CL = 3 (CAS Latency 3) sdcfg_val |= (2 << 24); // IBANK = 2 (4 banks) sdcfg_val |= (1 << 20); // PAGESIZE = 1 (9 column bits) sdcfg_val |= (0 << 19); // IBANK_POS = 0 (interleaving) sdcfg_val |= (1 << 10); // SDREN = 1 (Enable SDRAM) // 如果是移动SDRAM,还需要设置 MSDRAM_ENABLE=1 // sdcfg_val |= (1 << 9); // MSDRAM_ENABLE SDCFG = sdcfg_val; // 写入此值将立即触发自动初始化序列! // 步骤5: (仅移动SDRAM)配置SDCFG2,例如设置PASR // 假设我们只需要刷新Bank 0和1以节省功耗。 // SDCFG2 = (0x1 << 0); // PASR = 1h (Refresh banks 0 and 1) // 注意:写SDCFG2也会触发对移动SDRAM的重新初始化。 // 步骤6: 等待初始化完成(可选但建议) // EMIFB内部进行初始化需要一定时间。可以通过读取某个状态位或简单延时来确保完成。 delay_us(100); // 等待100us,通常足够 // 此时,SDRAM应已初始化完成,可以开始进行读写测试。 }实操心得:在调试初始化代码时,最有效的工具是逻辑分析仪或示波器。抓取
EMB_CLK,EMB_CS,EMB_RAS,EMB_CAS,EMB_WE和EMB_A[10]等信号,对照JEDEC标准命令真值表和上述初始化步骤,可以清晰地看到EMIFB是否发出了正确的命令序列。如果看不到完整的8次刷新或模式寄存器配置命令,说明初始化可能未正确触发或中途出错。
4. 刷新控制器机制与低功耗模式实战
SDRAM需要定期刷新,这是由其DRAM存储单元的本质决定的。EMIFB的刷新控制器设计得非常巧妙,它能在满足刷新要求的前提下,最大程度地减少对正常内存访问的干扰。
4.1 刷新紧迫度与后台调度机制
EMIFB内部有两个计数器来管理刷新:
- 刷新间隔计数器:加载
REFRESH_RATE值,每个EMIFB时钟递减1,减到0时,表示一个“刷新间隔”到期,需要安排一次刷新。 - 刷新积压计数器:记录当前“到期但未执行”的刷新次数。每当间隔计数器到期,此计数器加1;每当执行一次自动刷新,此计数器减1。
根据积压计数器的值,EMIFB定义了四个刷新紧迫度等级:
- Refresh May (1-3):不急。只在EMIFB没有待处理请求且所有SDRAM Bank都关闭时,才执行刷新。
- Refresh Release (4-7):需要释放。只要EMIFB没有待处理请求,就执行刷新,不管Bank是否打开。
- Refresh Need (8-11):需要。在当前访问完成后立即执行刷新,除非有读请求在等待(读优先)。
- Refresh Must (12-15):必须。在当前访问完成后,连续执行多次刷新,直到积压计数器降到Release级别(7)以下。
这种机制的好处是**“忙时少打扰,闲时多干活”**。当内存访问繁忙时,刷新可以适当延迟(积压计数器增加);当总线空闲时,EMIFB会抓紧时间“补课”,执行积压的刷新。这保证了在最坏情况下,刷新延迟也不会超过16 * REFRESH_RATE / fCLK的时间,确保不会丢失数据。
4.2 低功耗模式配置:自刷新与掉电
在电池供电设备中,让SDRAM在系统休眠时进入低功耗模式至关重要。
进入自刷新模式:
// 假设SDRFC的LP_MODE位在bit1, SR_PD位在bit0 SDRFC |= (1 << 1); // 设置LP_MODE=1 SDRFC &= ~(1 << 0); // 清除SR_PD=0 // 或者直接写入一个值,如 0x2执行上述操作后,EMIFB会完成所有未决访问,清空刷新积压,然后向SDRAM发出自刷新命令(SLFR)。SDRAM进入自刷新后,EMB_SDCKE信号会被保持为低。此时,EMIFB的主时钟EMB_CLK甚至可以关闭以进一步省电。SDRAM依靠其内部振荡器维持数据。
进入掉电模式:
SDRFC |= (1 << 1) | (1 << 0); // 设置LP_MODE=1, SR_PD=1EMIFB会发出掉电命令(POWERDOWN,本质上是NOP命令但伴随SDCKE变低)。此模式下SDRAM功耗最低,但不执行刷新,因此只能维持数据极短时间(取决于存储单元的电荷泄漏速度,通常远小于64ms),仅适用于极短时间的休眠。
退出低功耗模式:任何对SDRAM的访问请求,或软件清除LP_MODE位,都会使EMIFB退出低功耗模式。退出时,EMIFB会拉高SDCKE并执行一次自动刷新周期,然后恢复正常操作。
重要警告:在通过PLL动态改变
EMB_CLK频率之前,必须先将SDRAM置于自刷新模式。因为频率变化相当于时钟不稳定,如果SDRAM不在自刷新状态,其内部状态会丢失,必须重新初始化。正确的流程是:1) 置SDRAM为自刷新;2) 改变PLL和时钟MUX配置,切换频率;3) 等待时钟稳定;4) 退出自刷新;5)必要时,根据新的时钟频率重新计算并配置SDTIM1/2和SDRFC寄存器,因为时序参数的单位是时钟周期,时钟频率变了,周期数也要变。
4.3 Partial Array Self Refresh (PASR) 实战应用
PASR是移动SDRAM的专属节能功能。假设我们有一个4Bank的移动SDRAM,系统休眠时只需要保留Bank 0中的数据(比如存放了唤醒后立即执行的代码和栈)。
配置阶段:在初始化或进入休眠前,配置SDCFG2的PASR字段为
2h(仅刷新Bank 0)。SDCFG2 = (0x2 << 0); // PASR = 2h (Refresh bank 0 only)同时,必须设置
IBANK_POS=1,以确保地址映射是线性的(先遍历Bank内所有页),这样软件才能明确知道哪些数据在Bank 0,哪些在Bank 1-3。// 在SDCFG中设置IBANK_POS=1 sdcfg_val |= (1 << 19); SDCFG = sdcfg_val; // 这会触发重新初始化!数据搬运:在进入自刷新前,软件必须负责将需要保留的数据(操作系统上下文、关键变量等)从Bank 1-3搬运到Bank 0的存储区域。这是一个关键且容易出错的手动管理过程。
进入自刷新:然后按照前述方法进入自刷新模式。此时,只有Bank 0被刷新,Bank 1-3的刷新电路关闭,功耗显著降低。
唤醒后:退出自刷新后,PASR设置仍然有效。软件在访问Bank 1-3之前,需要先修改PASR设置(例如改回
0刷新全部Bank),并等待一段时间(具体见芯片手册,通常需要几个刷新周期),以确保之前未刷新的Bank中的数据状态被稳定恢复,或者直接将这些Bank的数据区域视为无效并重新初始化。
5. 读写操作、地址映射与性能优化
配置正确后,EMIFB就能高效地处理读写请求了。理解其内部调度和地址映射机制,有助于我们编写对缓存和性能更友好的代码。
5.1 读写操作时序与命令调度
读操作和写操作的流程是镜像的:
- 激活行:发出
ACTV命令,同时送上Bank地址(EMB_BA)和行地址(EMB_A)。 - 等待tRCD:满足行地址到列地址的延迟。
- 读/写命令:发出
READ或WRT命令,送上Bank地址和列地址。对于读操作,CAS延迟(CL)个周期后,数据开始出现在EMB_D总线上。对于写操作,数据在发出WRT命令的同一周期开始传输。 - 突发传输:在
READ/WRT命令后,EMIFB会自动插入NOP命令,同时数据总线持续传输突发长度的数据(4或8次)。 - 预充电:如果当前访问结束,且下一个访问不在同一行,EMIFB会发出
PRE命令关闭当前行,为激活新行做准备。也可以通过设置A10在READ/WRT命令时自动预充电。
EMIFB内部有一个复杂的命令调度器(Command Scheduler)和三个FIFO(命令、写数据、读数据)。调度器的核心算法是优先服务已打开行的请求,并尝试在读写之间进行仲裁以提升总线利用率。它会重新排序命令队列中的请求,但遵循两个基本原则以保证一致性:1) 来自同一个主设备(Master)的写命令按序完成;2) 来自同一个主设备的读命令按序完成;3) 对同一地址(或附近2048字节范围内)的读,会等待之前对该地址的写完成。这意味着对于CPU或DMA来说,内存操作是顺序一致的,但EMIFB在后台通过优化命令顺序隐藏了行激活、预充电等延迟,从而提升了整体吞吐量。
5.2 地址映射解析与性能影响
地址映射决定了线性地址如何转换成(Bank, Row, Column)。以32位SDRAM为例(表19-14),假设配置为IBANK=2(4 Banks),PAGESIZE=1(9位列地址,页大小=2^9 * 4字节 = 2KB)。
当IBANK_POS=0(默认)时,地址映射大致如下(简化):
- 逻辑地址低2位(
ADDR[1:0])对应字节选择(WE_DQM[3:0])。 - 接下来的列地址位(
ADDR[10:2])对应EMB_A的列地址部分。 - 再接下来的行地址位(
ADDR[23:11])对应EMB_A的行地址部分。 - 关键点:Bank地址(
EMB_BA)来自于行地址之上的几位(例如ADDR[25:24])。这意味着,连续访问的地址,会首先遍历同一行在不同Bank的列,然后才切换到下一行。这种Bank交错(interleaving)映射使得连续的大块内存访问可以保持多个Bank同时打开,避免了频繁的行切换,性能最优。
当IBANK_POS=1时,Bank地址位来自于列地址之上的位。这导致连续访问会先遍历完一个Bank内的所有行和列,再跳到下一个Bank。这种模式下,同一时间通常只有一个Bank处于激活状态,如果访问模式是跨Bank的,就会产生大量的行激活开销,性能下降。因此,除非为了配合PASR,否则应保持IBANK_POS=0。
5.3 常见问题排查与性能调优指南
问题1:系统随机性死机或数据错误。
- 排查点1:时序参数。这是最常见的原因。用示波器测量
EMB_CLK的波形和质量(幅度、过冲、振铃)。确保SDTIM1/2中的周期数设置满足SDRAM芯片在特定电压、温度下的最严苛(worst-case)要求。尤其检查tRFC(刷新周期时间),这个值通常很大,如果设小了,刷新不彻底会导致数据丢失。 - 排查点2:电源完整性。SDRAM对电源噪声非常敏感。检查电源纹波是否在芯片要求范围内(通常<50mV)。在电源引脚附近增加足够的去耦电容(如100nF + 10uF)。
- 排查点3:初始化时序。确认上电后等待了足够的稳定时间(200μs)再触发初始化。检查
SDREN位是否在时钟稳定后才置位。 - 排查点4:地址/数据线连接。检查PCB布线,确保地址线、数据线长度匹配,阻抗控制良好,避免信号完整性问题。
问题2:系统休眠后唤醒,数据丢失。
- 排查点1:低功耗模式配置。确认进入的是自刷新(Self-Refresh)模式而非掉电(Power-Down)模式,除非你能接受短时间休眠。
- 排查点2:PASR配置。如果使用了PASR,确认
IBANK_POS=1,并且软件已将关键数据搬运到了会被刷新的Bank中。唤醒后,在访问未刷新Bank前,是否已正确恢复全阵列刷新或重新初始化了那些Bank的数据区域。 - 排查点3:唤醒时序。从自刷新退出后,SDRAM需要一段时间(tXSR)才能接受新的命令。确保软件在退出低功耗模式后,等待了足够的时间(查芯片手册)再进行内存访问。
问题3:内存带宽达不到预期。
- 优化点1:利用突发长度。确保你的内存访问模式是顺序的,以充分利用突发传输。例如,使用DMA进行大块数据搬运时,设置源/目标地址连续。
- 优化点2:减少行切换。如果访问模式是随机的,性能下降是正常的。对于频繁访问的小块数据,尽量利用CPU缓存。可以通过调整软件算法或数据结构,提高访问的局部性(Locality),让连续访问落在同一行内。
- 优化点3:检查刷新开销。过小的
REFRESH_RATE值会导致刷新过于频繁。使用公式精确计算所需的最小值,不要盲目设置过小的值。在满足刷新要求的前提下,REFRESH_RATE值越大,刷新开销占比越小。 - 优化点4:命令调度。EMIFB的调度器已经做了很多优化。确保来自不同主设备(如CPU和多个DMA通道)的访问请求优先级设置合理,避免低优先级的长传输阻塞高优先级的实时访问。
调试技巧:在复杂问题排查时,如果条件允许,可以使用处理器的内存保护单元(MPU)或内存管理单元(MMU)将SDRAM区域设置为不可缓存(Non-cacheable)和非缓冲(Non-bufferable)。这可以强制所有访问都直接到达EMIFB,避免了缓存一致性问题带来的干扰,让你能更纯粹地测试EMIFB和SDRAM硬件本身的行为。