DSP EMIF外扩存储器设计:SDRAM与NOR Flash实战与调试

发布时间:2026/9/2 3:53:36
DSP EMIF外扩存储器设计:SDRAM与NOR Flash实战与调试 简介面向DSP技术及应用实习的EMIF外扩存储器设计工程包以TI TMS320VC55xx系列数字信号处理器为载体针对大规模数据处理场景下的外部存储器扩展需求完整演示了通过外部存储器接口EMIF连接SDRAM等存储设备的设计过程适合电子工程专业学生、嵌入式开发初学者及参加DSP课程实习的读者。资源共95个文件压缩包大小约2.1MB按硬件设计与软件设计分模块组织硬件部分包括原理图、PCB工程、元件库及封装库软件部分提供C语言源码、头文件、链接命令文件和编译中间文件另附readme与设计文档帮助快速上手。目前已有274人学习下载。该工程覆盖了EMIF外扩存储器的核心环节包括引脚配置、读写时序参数设定、存储器初始化与内存映射并给出SDRAM、UART等外设的参考实现通过对照设计文件与代码可实际验证读写操作深入理解DSP硬件接口开发方法也能为后续存储扩展项目提供可直接参考的工程范例。 处理器的外部存储器接口EMIF外扩存储器设计是DSP开发里绕不开的一环尤其是当你的算法不再只是点个灯、跑个流水线而是真正要处理数据的时候。前阵子带DSP技术及应用实习题目就是基于TMS320C6748的EMIF外扩存储器设计从原理图到PCB再到寄存器配置完整走了一遍里面有不少坑值得记录下来。这篇博客会把方案的选型逻辑讲清楚把EMIF的地址映射、SDRAM时序换算、硬件电路设计、软件初始化和调试过程中遇到的问题挨个说透。如果你正准备接C6748或者类似的C6000平台板子想自己外挂SDRAM和Flash这篇文章应该能帮你省掉大量翻手册和试错的时间。先说一下实习的要求用EMIF接口给C6748扩展一片SDRAM和一片NOR Flash实现上电后从Flash启动程序能稳定运行同时要验证大块数据的读写。听起来不复杂但实际上涉及芯片选型、硬件连线、启动方式、时序配置、软件验证好几层东西每一层都有值得琢磨的细节。1. 项目背景与总体设计思路1.1 为什么C6748需要外扩存储器C6748这颗芯片内部存储其实不算小L1P有32KBL1D有32KBL2有256KB总共大约320KB可用。这个容量跑一些控制类程序绰绰有余但一碰到信号处理类的任务就捉襟见肘了。举个例子一段64K点的FFT输入和输出都按单精度浮点算实部加虚部总共需要64K×4字节×2等于512KBL2直接放不下。这还没说更常见的应用场景。音频设备里做回声消除AEC要缓存几百毫秒的参考信号图像采集需要帧缓冲哪怕是简单的电机编码器数据采集想连续记录一段波形做分析也得有地方放数据。DSP擅长的是计算不是存储所以外扩存储器几乎是必然的选择。换句话说EMIF外扩存储器设计从来不是为了显得专业而是实际算法需求的硬性要求。1.2 外扩方案怎么选SDRAM加NOR Flash的取舍确定要外扩之后第一步是选存储介质。常见候选有SRAM、SDRAM、NOR Flash、NAND Flash这四种各有各的脾气。SRAM的优点是不需要刷新时序控制最简单但容量做不大常见也就512KB到4MB而且单位容量价格最贵引脚数量也多。SDRAM正好相反容量从16MB到64MB很常见成本低但需要周期性刷新时序复杂度高。不过好在EMIF控制器把刷新逻辑都接管了对开发者来说反而没想象中麻烦。NOR Flash适合存程序可以支持片上执行XIP读速度快但写入慢、容量小。NAND Flash容量大、价格低但按块读写还要做坏块管理对启动加载来说不太友好。综合考虑实习方案最终定为SDRAM加NOR Flash组合SDRAM选IS42S16400J4M×16bit共8MB挂在CS0上用作程序和数据的主战场NOR Flash选SST39VF16012MB容量挂在CS2上用来固化程序。为什么不用DDR2C6748虽然自带DDR2控制器但DDR2对布线阻抗、叠层、终端匹配的要求明显更高实习周期内容易在PCB环节翻车。SDRAM的EM_CLK跑100MHz左右布线要求相对宽松作为教学和工程验证完全够用。2. EMIF接口机制与存储映射设计2.1 片选空间与地址分配C6748的EMIFA一共有6个片选空间分别是CS0、CS2、CS3、CS4、CS5CS1保留未用。每个空间的基地址和大小是固定的比如CS0映射在0x40000000空间高达512MB是专门为SDRAM准备的CS2到CS5则从0x60000000开始每个空间32MB适合接NOR Flash、SRAM、NAND这类异步器件。实际接线时SDRAM的片选信号CS连到EMIF的CS0NOR Flash的片选连到CS2。地址线和数据线直接对应连接就行C6748是16位数据总线SDRAM也是16位正好匹配。字节使能信号要特别注意C6748的BE0对应D[15:8]BE1对应D[7:0]SDRAM的UDQM和LDQM分别接到这两个信号上这样才能正确支持8位和16位混合访问。地址映射这块有个容易忽略的点C6748的EMIF地址空间是按字节寻址的但SDRAM本身是按16位字组织。设计时先定好基地址再确定地址线是怎么连接的避免后面软件访问时地址对不上。实测中很多读写异常都是地址线接反或地址偏移算错导致的画原理图时反复核对几遍不吃亏。2.2 SDRAM时序参数换算从数据手册到寄存器SDRAM能不能稳定跑起来关键在于时序参数配置。以IS42S16400J为例数据手册里能查到这些关键参数CAS Latency3时最高时钟133MHztRCD行地址到列地址延迟典型20nstRP预充电时间20nstRC行周期时间66nstRAS行激活时间45nstWR写恢复时间14ns。此外还有刷新要求8192行必须在64ms内全部刷新一遍平均刷新间隔是7.8125us。这些参数需要换算成EMIF时序寄存器里的拍数。我这次把EM_CLK配置为100MHz时钟周期10ns换算就是tRCD等于20除以10等于2拍tRP同样2拍tRC向上取整7拍tRAS向上取整5拍tWR向上取整2拍。刷新周期寄存器的值用7.8125us除以10ns得到781。这一段是整个配置里最核心的计算每一拍都要留够余量宁可多一拍也别卡着极限值。对应的初始化代码结构大致是这样的EMIFAConfig emifaCfg; emifaCfg.sdramTiming.tRcd 2; // tRCD 20ns 100MHz emifaCfg.sdramTiming.tRp 2; // tRP 20ns emifaCfg.sdramTiming.tRc 7; // tRC 66ns emifaCfg.sdramTiming.tRas 5; // tRAS 45ns emifaCfg.sdramTiming.tWr 2; // tWR 14ns emifaCfg.sdramRefreshPeriod 781; // 7.8125us / 10ns EMIFAConfigure(emifaCfg);这里用的是TI StarterWare里的EMIFA驱动接口字段含义和寄存器一一对应。配置完时序还不够SDRAM上电后需要执行初始化序列先发NOP命令然后预充电、连续刷新、设置模式寄存器这些步骤EMIF控制器在软件使能后会自动处理。你只需要在初始化时按正确顺序打开各个开关不能跳步。3. 硬件电路设计与PCB实操3.1 存储器电路、启动配置与下载电路SDRAM电路设计表面看就是连上就能用其实有不少细节。每个电源引脚旁边都要放0.1uF去耦电容而且要尽量靠近芯片引脚。CKE和CLK信号不能悬空DSP的EM_CLK输出直接给SDRAM做时钟时钟线建议串一颗22欧姆的电阻靠近DSP输出端放置能有效抑制反射。为了让回流路径最短SDRAM最好和DSP放在PCB的同一面不要隔层远距离走线。NOR Flash这边相对简单SST39VF1601是异步接口OE、WE、CE分别接到EMIF的对应信号。需要注意Flash的VCC也要做好去耦特别是烧写瞬间电流变化大电源纹波可能会导致烧写失败。启动配置是另一个重点。C6748的启动模式由一组BOOT引脚决定上电时芯片会锁存这些引脚的电平然后决定是从NOR Flash启动、NAND启动、SPI启动还是不启动No Boot。很多板子固化程序后无法脱机运行第一步就要检查BOOT引脚的上下拉电阻是否焊对是不是误配成了No Boot模式。我在调试的时候习惯先用万用表量一遍引脚电平确认无误再继续排查软件。JTAG下载电路这块C6748用标准14针JTAG接口就够了TCK、TMS、TDI、TDO四根主要信号加上EMU0、EMU1。特别提醒一下EMU0和EMU1必须接上拉电阻一般4.7k到10k都行否则仿真器可能无法识别芯片。TCK建议加一个下拉电阻防止悬空时干扰。如果遇到仿真器连接不稳定可以先查这些上下拉电阻多半是它们的问题。3.2 PCB布局布线经验SDRAM不在快在稳SDRAM虽然频率只有100MHz但对于刚接触高速布线的同学来说还是不能太随意。数据线组内等长尽量控制在50mil以内地址线和控制线相对时钟线也要控制长度差不要让时钟到了、数据还没到。数据线、地址线、控制线最好不要跨分割地平面否则回流路径被切断信号质量会明显变差。时钟线走线要特别小心尽量短且直不要打过孔两侧包地处理必要时串阻调一下信号沿。SDRAM的正下方区域尽量不要走其他高速信号保持一个完整的地平面比什么都重要。Flash的布线要求就宽松多了它是异步器件对时序不敏感只要地址数据线别太离谱就行。我当时犯过一个低级错误SDRAM的数据线在DSP端和数据端接反了结果软件读写测试时高字节和低字节对调排查了很久才用示波器发现是硬件接错。所以画完原理图之后一定逐根核对一遍总线连接这一步省不了。4. 软件配置与读写验证4.1 EMIF初始化的完整流程软件初始化的第一步是确保PLL和时钟树配置正确让EMIF模块拿到稳定的EM_CLK。很多板子为什么SDRAM初始化失败先别怀疑寄存器配错查一下EMIF时钟到底有没有起振。用CCS的寄存器窗口看EMIFA_CFG的值确认模块时钟使能位已经打开。接下来按顺序做先配置SDRAM时序参数也就是上一章讲的那组tRc、tRcd、tRp、tRas、tWr再配置刷新周期最后使能SDRAM控制器。使能之后不要立刻大规模读写先给SDRAM几十微秒的稳定时间。完整的初始化流程可以这样写void EMIF_SDRAM_Init(void) { // 1. 使能EMIF模块时钟 EMIFAModuleClkConfig(); // 2. 配置SDRAM时序与刷新 EMIFAConfig emifaCfg; emifaCfg.sdramTiming.tRcd 2; emifaCfg.sdramTiming.tRp 2; emifaCfg.sdramTiming.tRc 7; emifaCfg.sdramTiming.tRas 5; emifaCfg.sdramTiming.tWr 2; emifaCfg.sdramRefreshPeriod 781; EMIFAConfigure(emifaCfg); // 3. 使能SDRAM控制器 EMIFASDRAMEnable(); }这里多说一句在CCS里调试时也可以写一个GEL文件在连接目标板的时候自动初始化EMIF。GEL的好处是你load程序之前SDRAM就已经能访问了方便早期调试硬件。但最终交付的代码里还是要老老实实把初始化逻辑放在程序开头毕竟脱机运行的时候没有CCS帮你初始化。4.2 读写验证与FFT应用实测初始化完成后第一件事是验证基本读写。我的测试方法很简单向0x40000000起始的SDRAM区域写满0xA5A5A5A5再读回比较然后换成0x5A5A5A5A再把地址值本身写进去读出对比。这三种pattern基本能覆盖数据线短路、地址线错位、字节使能异常等常见问题。测试范围要覆盖整个SDRAM空间比如从0x40000000到0x40800000遍历8MB。这类测试通过后再跑一个有实际意义的应用。我配合定时器配置让定时器触发ADC采样采样结果通过EDMA直接搬运到SDRAM缓存区攒够一整段数据之后调用TI DSPLIB里的FFT函数做分析。外扩SDRAM带来的好处非常直接之前只能在内部RAM里做4K点FFT现在可以做64K点甚至更大频率分辨率提升了16倍测量相位也稳定得多。可以说没有足够的外部存储很多信号处理算法根本没有施展的空间。Flash烧写和脱机启动验证也不能漏。在CCS里加载程序到SDRAM运行确认功能正常后用AIS工具把out文件转成启动镜像烧写到NOR Flash的起始地址。然后断开仿真器把开发板重新上电观察程序是否能从Flash加载并正常运行。这一步是检验整个外扩存储器设计的最终标准。5. 调试实录常见问题与排查技巧5.1 固化后必须接JTAG才能启动是为什么这个问题在我带的实习里被问了不下五次程序在线调试明明一切正常固化到Flash之后一拔掉仿真器重新上电板子就没反应再连上JTAG又能跑了。看起来像是需要JTAG才能启动其实和JTAG本身没任何关系。根本原因几乎都是BOOT引脚配置不对。C6748的RBLROM Boot Loader在上电时会根据BOOT引脚的电平决定启动方式如果你把这些引脚配置成了No Boot模式芯片上电后不会去访问Flash自然是一片死寂。而连上JTAG时仿真器会通过调试接口直接把程序加载到内存里运行给人的错觉就是必须接JTAG才能启动。排查方法很简单查BOOT引脚的电平设置表确认对应的启动模式用万用表量引脚电平看是不是硬件上下拉焊得不对。另一个常见原因是烧写的镜像格式不对。RBL只认特定格式的启动镜像比如带AIS头的.bin文件如果你直接把裸的.out文件烧进去RBL找不到有效的启动头也会卡死。还有个别情况是Flash型号不被RBL支持那就要考虑二级引导加载器先用一小段启动代码初始化SDRAM再从其他介质加载主程序。我把这类问题的排查顺序整理成了表格方便对照现象可能原因排查方法掉电重启后完全无反应BOOT引脚配置成No Boot量BOOT引脚电平与手册对照程序能烧写但启动后跑飞镜像格式错误或地址不对用AIS工具重新生成启动镜像偶发能启动多数时候不行Flash型号不被RBL支持更换兼容型号或做二级引导连接JTAG才能运行在线调试掩盖了启动问题确认脱机启动模式和镜像文件5.2 数据读写偶发错误与信号质量调试另一种典型问题是SDRAM大范围读写的时候出现随机错误不是每次都有可能跑很久才蹦出一个错误。这种问题排查起来最耗时间。优先怀疑刷新周期配置这是SDRAM特有的机制刷新间隔太长数据会丢太短又占用带宽。用公式算出来的781实际工作中可以稍微放宽一点但不能离谱。然后是时序余量。SDRAM数据手册给的都是典型值或者下限值实际跑的时候要留足余量。比如tRCD是20ns在100MHz下等于2拍如果你把EM_CLK提到133MHz20ns对应2.66拍无论如何都塞不下这时候就必须把EM_CLK降回100MHz或者换更快的SDRAM。我调试时习惯先把时序参数全部放宽一档确认功能正常后再逐步收紧找极限这样能快速判断是功能性问题还是时序余量问题。电源纹波和布线信号质量也可能导致随机错误。SDRAM读写瞬间电流变化很大如果电源输入端的滤波电容不够纹波会直接影响数据采样。用示波器看SDRAM电源引脚的纹波如果超过100mV就要加大容量滤波电容或者增加磁珠隔离。信号质量方面主要看EM_CLK上升沿是否干净地址数据线有没有明显过冲这两点都能通过示波器直接观察。这次实习做完最直接的体会是EMIF外扩存储器设计这件事本身不难但细节多到需要耐心。任何一个时序参数差一拍、一根地址线接反、一个启动引脚电平不对都会让整个板子表现得像坏了一样。后来我把这套SDRAM加Flash的方案直接复用到音频采集项目里配合定时器触发采样和DSPLIB的FFT做相位测量跑起来很稳。如果你也在调类似的板子建议先别急着改PCB把启动配置和时序参数逐个确认一遍很多时候问题就出在最容易被忽略的引脚和数字上。本文还有配套的精品资源点击获取