简介:一套面向DSP初学者的实习资料包,围绕TMS320VC55xx的EMIF外扩存储器设计展开,涵盖EMIF引脚配置、时序参数设定、存储器初始化及读写访问等关键环节,适合电子工程相关专业学生或嵌入式开发入门者用于课程实习和项目参考。包内共95个文件,压缩包仅2.1MB,主要包含C语言程序文件、原理图与PCB设计文件、工程配置文件等,例如.c/.h源码、.schlib与.pcblib元件库、.prjpcb工程等,可配合文档完整还原设计流程。已有274人学习。资料既包含硬件原理图设计与PCB版图,也提供软件初始化与读写示例代码,还有项目工作区与日志文件,便于读者对照学习,快速掌握DSP外部存储器扩展的完整实现方法,提升嵌入式系统设计与调试能力。 DSP技术及应用实习,我抽到的课题是“EMIF外扩存储器设计”。刚开始我以为就是照着原理图接线、开几个寄存器,等真正开始做才发现,这里面从器件选型、地址映射、时序配置到调试排错,环环相扣,哪一环没想明白都会卡壳。这篇笔记就把我从拿到题目到最终跑通读写、解决启动问题的完整过程写下来,适合正在做DSP实习、课程设计,或者第一次用TMS320C6748这类芯片外挂Flash/SRAM的同学参考。
1. 实习任务拿到手上,先想明白三个问题
EMIF全称是External Memory Interface,外部存储器接口。DSP芯片内部虽然集成了一部分RAM,但程序、数据、日志这些一放大根本不够用,所以必须通过EMIF把NOR Flash、SRAM、NAND Flash甚至SDRAM挂到DSP外面去。实习题目的核心就是:怎么把一颗外部存储器通过EMIF正确接进系统,并且保证读写可靠。
动工之前,我建议先想清楚三个问题。
第一个问题:外扩存储器到底用来装什么?这个决定了选型方向。如果只是存程序代码,选NOR Flash,掉电不丢、支持片上XIP直接执行;如果要大容量放文件系统或者做启动介质,用NAND Flash更划算;如果是为了扩展运行时的数据空间,那就得上SRAM或者更高性能的SDRAM。TMS320C6748这颗芯片里,EMIFA接口主要接NOR Flash、NAND Flash和SRAM这一类异步存储器,而DDR2 SDRAM走的是芯片上独立的DDR2/MDDR控制器,不能混为一谈。这个区别很重要,很多同学一开始就把SDRAM想当然地往EMIF上接,对着数据手册找半天也没找到对应片选。
第二个问题:DSP的EMIF接口能力边界在哪里。C6748的EMIFA支持16位数据总线,地址线有23根,也就是EA[22:0],片选信号有CS2、CS3、CS4、CS5四个空间,每个片选对应一片独立的存储区域。在做硬件连接之前,必须把数据手册里EMIFA的性能参数、电气特性、地址映射表都翻一遍,尤其是确认你选的存储器时序能不能被EMIF的时序约束满足。举个例子,有些老款NOR Flash读周期要90ns,而你把EMIFA的异步时钟配得很快会造成采样不稳定,这时候就必须降速或者调整周期参数。
第三个问题:软件侧的访问地址到底是多少。这个问题看起来简单,实际上最容易被坑。EMIF不是一个独立外设,它挂在DSP的地址总线上,所以CPU访问外部存储器就是往一段固定地址空间里读写数据。以C6748为例,CS2空间映射在0x60000000起始,后续每个片选的映射区间滚动增加。写代码前一定要把映射关系确认好,否则程序写进Flash还是读到Flash,用CCS的Memory Browser一眼就能看出来。
2. TMS320C6748的EMIF接口:引脚、片选和地址映射
对着最小系统板看C6748的引脚,EMIFA相关的引脚主要包括数据线ED[15:0]、地址线EA[22:0]、四个片选线、读写控制线、字节使能等。设计电路之前,最好把这些引脚按功能分组列个表格,方便检查。
| 信号类别 | 信号名 | 作用说明 |
|---|---|---|
| 数据总线 | ED[15:0] | 16位并行数据线,接存储器对应IO |
| 地址总线 | EA[22:0] | 用于寻址异步存储器的存储单元 |
| 片选 | CS2、CS3、CS4、CS5 | 选择当前访问哪个外部存储器 |
| 写使能 | WE | 低有效,表示当前是写操作 |
| 输出使能 | OE | 低有效,表示允许存储器输出数据 |
| 字节使能 | BA[1:0] | 16位访问时控制高/低字节 |
C6748的EMIFA映射地址在数据手册的存储器映射表里有明确说明,几个片选从低到高依次排列。这里给出我当时参考的简化映射表格,具体以你手头芯片型号的数据手册为准。
| 片选 | 地址范围 | 典型用途 |
|---|---|---|
| CS2 | 0x60000000 - 0x61FFFFFF | NOR Flash / SRAM |
| CS3 | 0x62000000 - 0x63FFFFFF | SRAM / NOR Flash |
| CS4 | 0x64000000 - 0x65FFFFFF | SRAM / 其他异步器件 |
| CS5 | 0x66000000 - 0x67FFFFFF | NAND Flash / 扩展外设 |
地址映射清楚之后,硬件设计上才不会犯低级错误。比如你打算把NOR Flash挂在CS2上,那么片选信号就必须接到DSP的CS2端,访问基地址就是0x60000000。如果顺手接到了CS3,程序里又按0x60000000去读,那不管怎么调都不会有数据。
还有一点值得注意:EMIFA的地址线是按字还是按字节编址,直接决定外部地址线的连接方式。C6748的EMIFA数据总线是16位,外部存储器端如果也是16位总线,那么DSP的EA[0]不会直接对应到存储器的A[0],具体的偏移接法必须查EMIFA接口章节里的地址映射说明。我当时就是在这里大意了,16位模式下把地址线全部一一对应接上,结果读出来的数据总像是错位了一个字节,后来翻手册才意识到问题所在。这个坑在后面的调试部分还会细说。
3. 硬件连接:NOR Flash和SRAM到底怎么接
硬件连接是EMIF设计里最容易出问题,也最容易被忽视的一环。很多实习同学拿到原理图直接照抄,连为什么这样接都不知道。我建议至少把NOR Flash和SRAM两种典型接法吃透,因为这两种存储器对应的控制逻辑在工作原理上有本质区别。
先看NOR Flash。NOR Flash的接口非常接近SRAM,有独立的地址线、数据线、片选、写使能、输出使能。典型接法是把DSP的片选接到Flash的CE端,读控制接OE,写控制接WE,地址线和数据线直接并联。由于C6748的EMIFA数据线是16位,如果选一颗16位的NOR Flash,那么总线宽度匹配,连接起来相对简单;如果选8位NOR Flash,就要把数据线的高8位空着,或者通过字节使能信号分两次访问,代码里也要按字节操作,效率会低不少。
NOR Flash的具体接线还有几个细节:地址线是否需要偏移、片选和复位引脚的时序关系、写保护引脚是否要上拉。写保护引脚常常被忽略,如果接法错误或者悬空,Flash会有概率无法写入。我的经验是,把Flash的WP引脚通过10k电阻上拉到高电平,保证正常工作状态下写保护不使能。另外,去耦电容不是随便放的,每个电源引脚旁放一个0.1uF陶瓷电容,靠近引脚放置,电源进来再加一个10uF的钽电容做储能,这些在EMIF高速读写时能明显减少噪声引起的偶发错误。
再看SRAM。SRAM的接法和NOR Flash很像,但多了一个需要注意的点:地址建立时间、读/写脉冲宽度这些参数,SRAM一般比NOR Flash更严格。由于EMIF的异步接口本身就支持可配置的建立时间、选通时间和保持时间,硬件上基本能直接连,真正要调节的是软件端的时序寄存器。SRAM的地址线、数据线、控制线接好后,用示波器看一次读操作波形,把地址有效到数据稳定的时间量出来,再回头对照寄存器配置值,这样能非常直观地验证时序是否满足要求。
如果是接NAND Flash,那就完全是另一回事了。NAND Flash把命令、地址、数据全部复用在一组IO上,通过CLE、ALE等控制信号来区分当前IO上传的是什么内容。这类存储器的接法不推荐实习阶段自己原创,最好直接参考芯片厂商的评估板原理图,C6748的EMIFA对NAND的支持一般会通过地址线的某些位来模拟CLE和ALE,每个平台的接法都有讲究,照抄官方方案是最省事的。
4. 寄存器配置和时序计算:datasheet里的ns怎么变成寄存器
硬件接完之后,真正拉开差距的是软件侧的时序配置。时序配置的本质很简单:DSP的EMIF模块用寄存器告诉你,“访问外部器件时,地址建立几个时钟周期、选通几个时钟周期、保持几个时钟周期”。外部存储器数据手册里给的都是纳秒级参数,所以关键就是把纳秒换算成时钟周期个数。
我当时用的C6748平台,EMIFA的异步接口配置主要靠异步配置寄存器,英文缩写是A1CRn,其中n对应不同的片选。寄存器里主要字段包括setup、strobe、hold和turnaround。Setup对应地址建立时间,也就是地址有效到片选/读使能拉低之间的时间;Strobe对应片选选通时间,也就是读或写脉冲的宽度;Hold是地址保持时间;Turnaround用于防止读转写、写转读时总线冲突,给出一段缓冲周期。
换算的方法可以这样理解。假设EMIFA的异步时钟是100MHz,一个时钟周期就是10ns。你选了一颗NOR Flash,数据手册上写的最大读周期时间是70ns,那么访问该Flash的单个读周期就必须大于70ns。如果配置setup=1、strobe=6、hold=1,那么总周期就是(1+6+1)×10ns=80ns,大于要求的70ns,理论上是满足的。实际工程中还要留余量,我一般会在此基础上让总周期再富余20%左右,毕竟温度、电压波动都会让存储器实际参数变化。
写配置时要注意,寄存器字段对应的数值不一定等于实际周期数,有些芯片编码需要加1,有些字段是直接数值,这个必须看寄存器描述。我当时犯过一个典型的错误:把strobe字段配成6,以为就是6个周期,实际上有的平台字段含义是“额外周期数”,实际选通周期是7个甚至8个周期。这种误差不会让系统完全不能跑,但会导致时序比预期更慢,如果之后还要优化读写速度,就会被这里的误解卡住。
异步接口还有一个容易被忽略的寄存器:A1CRn里的turnaround字段。如果你只挂一颗存储器,turnaround配成0问题不大;但如果在同一组总线上挂了Flash和SRAM,两个器件的读转写、写转读交错非常频繁,不配置turnaround就可能出现总线竞争,最典型的现象是数据总线上出现毛刺,偶尔能读到错误数据。这个参数宁可多配一点,也不要为了性能省掉。
5. 读写验证与实测踩坑:从0x55到0xAA的排查
寄存器配置完之后,就要进入调试验证阶段。第一次验证我建议写一段最笨的测试代码:往外部存储器固定地址写一个16位数据,再立刻读回来,比较是否一致。先写0x55AA,再写0xAA55,能覆盖每一位的翻转情况。如果这一步都不通过,后面都是白搭。
用CCS的Memory Browser也能直接查看地址内容,但我在调试时发现一个现象:明明写的是0x55AA,Memory Browser里显示的却是0xAA55,或者是顺序错乱的数据。这种问题九成是数据总线高低字节接反了,或者地址线偏移导致字节排列错位。还有一次,我用了一段循环测试程序,让DSP先连续写满2KB数据,再读回来校验,结果每次都在同一个偏移位置错几个字节,后来用示波器抓OE和WE波形才发现,是strobe配置太短,导致数据还没稳定就被采样了。把strobe从4个周期调到7个周期之后,连续跑100遍校验全部通过。
我建议每个做EMIF调试的同学都准备一个这样的排查清单,遇到问题先按顺序排除:
- 片选有没有拉低:用示波器看CS引脚,确认访问地址是否落在对应片选的映射区间。
- 数据线有没有接反:写0x55AA读回0xAA55,大概率是高低位反了。
- 地址线有没有偏位:读回数据看起来像“隔一个地址”的内容,多半是地址偏移接法有问题。
- 写入数据读回来是0xFFFF:NOR Flash之前没擦除,或者擦除操作没生效。
- 偶发错误:优先怀疑时序余量不够,把strobe稍微调大再观察。
NOR Flash写入还有一个很多人不知道的规则:NOR Flash的编程操作只能把位从1变成0,不能从0变成1,所以往一个已经写过数据的扇区再次写入之前,必须先执行擦除操作把扇区擦回0xFF。我第一次调试时反复写同一个地址,第二次起数据怎么都写不进去,还以为Flash坏了,后来才反应过来是没擦除。这个小坑在实习答辩时可以重点讲出来,能体现你真的做过。
慢速读写的稳定性验证通过之后,可以试着把读写速度提上来,用DMA批量搬运一定大小的数据块,校验CRC。这一步能顺便检验EMIF接口是否适合实际产品场景,因为很多DSP应用都需要独立于CPU的DMA通道来搬运外部数据。DMA搬运时DSP的CPU可以同时干别的活,这才是外扩存储器的价值真正体现出来的时刻。
6. 拔掉JTAG程序就不跑,问题多半出在初始化顺序
调试阶段通过后,我把程序固化到外扩的NOR Flash里,准备上电独立运行。结果遇到了一个很经典的问题:插着仿真器、连上CCS的时候程序一切正常,拔掉JTAG重新上电,板子就是跑不起来。很多同学遇到这个情况第一反应是启动模式不对或者Flash烧写有问题,但我在排查时发现,往往问题出在初始化顺序。
用CCS在线调试时,仿真器在连接阶段就会帮你初始化DSP、配置一部分外设寄存器,还会把代码加载到RAM里。所以调试模式下程序跑得好,不代表你的初始化代码完整。拔掉JTAG以后,DSP上电执行的是片内ROM里的引导程序,它根据启动模式引脚决定从哪个外部存储器引导。如果你想从NOR Flash启动,那么引导阶段就需要EMIF已经处于可用状态,能够正确读取NOR Flash里的程序。
我遇到的具体情况是,我的启动代码里有一步是在主函数里才初始化EMIF,而引导程序在搬移代码时需要EMIF已经从Flash读取前几KB数据,这就形成了一个矛盾:EMIF还没来得及配置,Flash数据已经取不出来了。解决办法是把EMIF的初始化放到启动阶段最开始的位置,用一组最保守的时序参数先让Flash可读,等系统跑起来后再重新配置成更快的时序。整个过程如果还涉及DDR2,还要注意DDR2控制器的初始化顺序,必须放在外部RAM被引用之前。
这个问题排查起来并不难,用CCS的JTAG连接后,在上电复位的断点处停下,单步看引导程序卡在哪一步,再检查那一步访问外部存储器的寄存器配置,基本就能定位。但这个例子很好地说明了,EMIF外扩存储器不是接完线配完寄存器就结束的,它和整个系统的启动流程、存储器管理、总线仲裁都深度耦合。实习时能把这一条想明白,比单纯调通读写测试要加分很多。
最后分享一个个人体会:做EMIF设计,最大的坑往往不在某一步,而在“想当然”。你觉得地址线应该这么接,觉得时序配一次就够了,觉得上电和在线调试没什么区别,这些想当然会在后续某个时刻集中爆发。实习生做这个题目,最重要的是把从选型到调试的整条链路走通一遍,哪怕中途多踩几个坑,都比直接抄一份能跑的工程收获大。
本文还有配套的精品资源,点击获取