TMS320C54x DSP核心外设配置实战:BSCR、SWCR与McBSP详解
1. 项目概述:从寄存器手册到实战配置
搞DSP开发的兄弟们都清楚,手册里那些寄存器位定义表,看的时候好像都懂了,真到动手配置的时候,又是另一回事。尤其是像TMS320C54x这种经典系列,它的外设寄存器配置直接关系到系统能不能跑起来,跑得稳不稳。今天我就结合自己这些年踩过的坑,把BSCR(Bank-Switching Control Register,存储体切换控制寄存器)、SWCR(Software Wait-State Control Register,软件等待状态控制寄存器)和McBSP(Multichannel Buffered Serial Port,多通道缓冲串行端口)这三大块的核心配置逻辑和实战要点,掰开揉碎了讲清楚。这不是照着手册念,而是告诉你,在一个真实的项目里,这些寄存器该怎么设,为什么这么设,以及设错了会出什么幺蛾子。
简单来说,BSCR管的是你怎么高效、无冲突地访问外部那一大片内存;SWCR是帮你协调CPU和慢速外设之间的速度差,防止CPU“跑太快”而数据“跟不上”;McBSP则是DSP与外部音频编解码器、数据转换器或其他串行设备通信的咽喉要道。这三者配置好了,你的DSP系统基础就打牢了。无论你是做语音处理、无线通信还是电机控制,都绕不开它们。接下来,我会先带大家理清每个寄存器的设计思路,然后深入到每个关键比特位的实战含义,最后给出几个典型的配置案例和排错心法。
2. 核心思路:为什么是BSCR、SWCR与McBSP?
在深入每个寄存器的细节之前,我们必须先建立顶层视角。C54x DSP的片上资源有限,大量数据和程序需要存放在外部存储器中,同时又要与各种速度各异的外设通信。这就引出了三个核心矛盾:有限地址空间与大量外部存储的矛盾、CPU高速与外部器件低速的矛盾、批量数据流与实时串行通信的矛盾。BSCR、SWCR和McBSP正是TI工程师为解决这三个矛盾而设计的硬件解决方案在软件上的映射。
BSCR解决的是“空间扩展与访问效率”问题。你可以把外部存储器想象成一个巨大的仓库,而DSP的地址线是有限的(比如16位地址线,直接寻址只有64K字)。要想管理更大的仓库,就得用“分页”或者“分库”的思想。BSCR中的BNKCMP(Bank Compare)位就是用来定义这个“库”的大小的。它通过比较地址的高几位(MSBs)来决定是否需要进行“库切换”。切换时,如果地址从一个“库”跳转到另一个“库”,硬件会自动插入额外的周期(Bank-Switch Cycle),这会导致性能损失。因此,合理规划数据存放位置,尽量减少跨“库”访问,是优化性能的关键。BSCR的其他位,如PSDS(Program/Data Space Sequential Switch)用于控制程序空间和数据空间连续访问时的额外周期插入,EXIO(External Interface Off)则用于在不需要访问外部总线时关闭接口以省电。理解BSCR,就是理解C54x如何高效、有序地管理它的外部“内存疆域”。
SWCR解决的是“速度匹配与总线等待”问题。DSP内核速度很快,但挂接在外部总线上的存储器(如Flash、SRAM)或外设(如ADC、FPGA)可能速度较慢。CPU发出读/写命令后,需要等待外设响应。这个等待时间就是“等待状态”(Wait-State)。硬件上可以通过设置外部等待状态引脚(READY)来插入,但不够灵活。SWCR提供了软件可编程的等待状态乘法器。当SWSM(Software Wait-State Multiplier)位设为1时,你在另一个寄存器SWWSR(Software Wait-State Register)中为各个存储空间设置的等待状态数会自动翻倍。比如,你为某个慢速外设区域在SWWSR中设置了3个等待状态,当SWSM=1时,实际插入的等待状态就是6个。这相当于给了你一个粗调旋钮,当你更换了更慢速的存储器或需要更保守的时序时,无需修改多个分散的SWWSR设置,只需扳动SWSM这一个开关即可。这是系统时序裕量管理的有效手段。
McBSP解决的是“高速数据流与灵活串行协议”问题。它是C54x系列上功能极其强大的同步串行接口,绝不仅仅是一个简单的UART或SPI。McBSP可以无缝对接电信领域的T1/E1帧结构、音频领域的I2S协议,以及各种自定义的同步串行流。它的强大源于其高度可配置性:时钟极性、帧同步极性、数据延迟、字长、帧长、压缩扩展(A-law/μ-law)、多通道选择等,无一不可通过寄存器配置。SPCR1/2(串口控制寄存器)、PCR(引脚控制寄存器)、RCR/XCR(收/发控制寄存器)、SRGR(采样率发生器寄存器)以及MCR(多通道控制寄存器)共同构成了一个协议生成引擎。配置McBSP的本质,就是用软件定义出一个符合你外部设备要求的串行通信协议。因此,吃透McBSP寄存器,是让DSP与外界顺畅对话的必修课。
3. BSCR寄存器深度解析与实战配置
BSCR寄存器并非C54x全系统一,不同型号的芯片其BSCR功能有差异。我们以最常用的C5402和C5416为例进行对比分析,这能帮你避免跨型号移植时的坑。
3.1 核心字段详解:以C5402型BSCR为例
我们先看C5402的BSCR(见图A-21)。这是一个16位寄存器,每位控制一个特定功能。
BNKCMP (Bits 15-12):存储体比较域这是BSCR的灵魂。它决定了有多少个最高地址位(MSB)参与比较,从而定义了外部存储体(Bank)的大小。
- 1111 (4K words):比较A15-A12这4位。当地址的A15-A12发生变化时,就认为跨越了存储体边界。这意味着存储体大小为4K字(2^12 = 4096)。适用于将外部空间精细划分为很多小块的情况。
- 1110 (8K words):比较A15-A13这3位。存储体大小为8K字。
- 1100 (16K words):比较A15-A14这2位。存储体大小为16K字。
- 1000 (32K words):仅比较A15这1位。存储体大小为32K字。这是很常用的配置,恰好将64K字的外部数据空间分为高32K和低32K两个体。
- 0000 (64K words):不比较任何位。整个64K空间被视为一个存储体。这意味着任何外部访问都不会因存储体切换而插入额外周期,但你也失去了通过分体来扩展地址空间的能力。
实战选择:如何确定BNKCMP的值?这取决于你的硬件设计。假如你的板子上挂了两片32Kx16的SRAM,分别映射到低32K(A15=0)和高32K(A15=1)地址空间。那么你应该设置BNKCMP=1000b。这样,当程序访问从0x7FFF(低32K末尾)跳到0x8000(高32K开头)时,A15从0变1,硬件识别为跨体访问,自动插入一个额外的时钟周期(如果PSDS等设置允许),确保第二片SRAM有足够的地址建立时间。如果你用的是一片64Kx16的SRAM,那么可以设置BNKCMP=0000b,关闭体切换逻辑以获得最佳连续访问性能。
PSDS (Bit 11):程序/数据空间顺序访问控制此位控制当连续两次访问分别是“程序读”后跟“数据读”,或“数据读”后跟“程序读”时,是否自动插入一个额外的周期。
- 0 (NOEXCY):仅在跨越存储体边界(由BNKCMP定义)时插入额外周期。同一存储体内的程序-数据交叉访问不插入。
- 1 (INSCY):只要发生程序读与数据读的连续访问,无论是否跨体,都插入一个额外周期。
为什么需要这个?早期的存储器芯片,其程序区和数据区可能是物理分开的,或者共享同一总线时需要切换。插入额外周期可以避免总线冲突,给存储器更多反应时间。在现代设计中,如果使用的是统一的RAM,通常将此位设为0以提升性能。但在一些严格的系统中,设为1可以增加时序裕量,提高稳定性。
HBH (Bit 2, C5401/2/9/5416):HPI数据总线保持器使能HPI(Host Port Interface)是主机接口。当HPI未被访问时,其数据总线HD[7:0]可能处于高阻态,易受噪声干扰产生毛刺。将此位置1,内部总线保持器会在总线释放后将其电平保持在之前的逻辑状态(类似一个弱上拉/下拉),增强了总线稳定性。
- 0 (DISABLE):禁用HPI数据总线保持器。
- 1 (ENABLE):使能HPI数据总线保持器。
BH (Bit 1):总线保持器使能此位控制外部数据总线D[15:0]的总线保持器。功能同HBH,但作用于主数据总线。在总线负载较重、布线较长或干扰较大的环境中,强烈建议使能此功能(设为1),它能有效抑制总线浮空带来的不稳定问题。
EXIO (Bit 0):外部总线接口关闭使能这是一个省电和总线冲突规避功能。
- 0 (NORMAL):外部总线接口正常工作。
- 1 (INACTIF):在当前总线周期完成后,外部总线接口(地址、数据、控制信号)变为无效(高阻或固定电平)。同时,PMST寄存器中的DROM、MP/MC、OVLY位以及ST1寄存器中的HM位被锁定,不可修改。此模式一旦开启,CPU将无法再访问任何外部存储器或设备,直到将此位清零。它用于当DSP仅使用片内资源运行(如算法循环)时,彻底关闭外部总线以降低功耗和减少噪声。
3.2 型号差异与移植注意:C5410/5416型BSCR
C5410和C5416的BSCR(见图A-22)与C5402有显著不同,主要体现在高字节。
CONSEC (Bit 15):连续存储体切换模式
- 0 (32KFASTREAD):仅在32K字边界(即A15变化)时进行存储体切换。对于连续的外部存储器读操作(无起始和结束周期),可以实现快速访问。
- 1 (EXTMEM):对外部存储器读进行连续的存储体切换。每次读周期由3个周期组成:起始周期、读周期、结束周期。这会显著降低连续读外部存储器的性能,通常只在特定时序要求下使用。
DIVFCT (Bits 14-13):CLKOUT输出分频因子这个功能很实用!它允许你将CPU内核时钟(CLKOUT)进行分频后输出到CLKOUT引脚。
- 00:不分频,CLKOUT = CPU时钟。
- 01:2分频。
- 10:3分频。
- 11:4分频。应用场景:你的DSP主频可能很高(如160MHz),但外部器件(如FPGA、低速ADC)可能无法承受这么快的时钟信号。通过DIVFCT分频,你可以产生一个适合外部器件的、与CPU时钟同步的参考时钟,省去一个额外的晶振或时钟芯片。
IACK (Bit 12):IACK信号输出关闭使能IACK是中断应答信号。在某些多DSP系统中,可能不需要此引脚功能。将其置1可以关闭IACK引脚输出,可能有助于减少功耗或引脚冲突。
HBH 和 BH (Bits 2,1):功能与C5402类似,但仅在某些型号(如C5416)上存在。
3.3 实战配置流程与代码示例
假设我们为一个基于C5402的系统配置BSCR,硬件情况如下:
- 外部扩展了一片512K x 16bit的异步SRAM,通过CPLD进行地址译码,映射到连续的64K字空间(实际使用Bank切换逻辑访问全部512K)。
- 希望将外部空间划分为16个4K字的存储体(BNKCMP=1111b),以获得更精细的访问控制。
- 系统对功耗敏感,当运行纯片内算法时,希望关闭外部总线。
- 为提高总线抗干扰能力,使能数据总线保持器。
配置代码如下(假设使用C语言和TI的CSL库或直接寄存器操作):
// 方法1:直接操作内存映射寄存器地址(需查阅芯片头文件) #define BSCR (volatile unsigned int *)0x0029 // BSCR的地址通常是0x0029 void configure_BSCR(void) { unsigned int bscr_val = 0; // 1. 设置BNKCMP = 1111b (0xF), 4K字存储体 bscr_val |= (0xF << 12); // 2. 设置PSDS = 0, 仅跨体时插入额外周期 // bscr_val |= (0 << 11); // 默认就是0,可不设置 // 3. 设置HBH = 1, 使能HPI总线保持器(如果使用HPI) bscr_val |= (1 << 2); // 4. 设置BH = 1, 使能数据总线保持器 bscr_val |= (1 << 1); // 5. 初始时EXIO = 0, 外部总线开启 // bscr_val |= (0 << 0); // 默认是0 *BSCR = bscr_val; // 写入寄存器 } // 函数:进入低功耗片内运行模式 void enter_low_power_mode(void) { *BSCR |= (1 << 0); // 设置EXIO位为1,关闭外部总线接口 // 注意:此后无法再访问外部存储器! } // 函数:退出低功耗模式,恢复外部访问 void exit_low_power_mode(void) { *BSCR &= ~(1 << 0); // 清除EXIO位,重新开启外部总线接口 }关键提示:对BSCR的修改,特别是EXIO位,一定要在确保当前没有正在进行的关键外部访问时进行。通常会在关闭中断、确保代码和数据都在片内RAM中运行的前提下操作EXIO位。
4. SWCR寄存器:软件等待状态的精细调控
SWCR寄存器相对简单,但作用关键。它只有一个用户可配置位:SWSM(Software Wait-State Multiplier, Bit 0)。
4.1 SWSM位的作用机制
SWSM是一个全局乘数因子,作用于SWWSR(Software Wait-State Register)寄存器中为各个存储空间(如程序空间、数据空间、I/O空间)所设置的等待状态数值。
- SWSM = 0 (NOMULT):等待状态数按SWWSR中的设定值执行。例如,SWWSR中设定某区域等待状态为3,则访问该区域时插入3个等待状态。
- SWSM = 1 (MULTBY2):等待状态数按SWWSR中设定值的两倍执行。同上例,实际插入的等待状态变为6个。
它解决了什么问题?想象一个场景:你的产品早期使用70ns的快速SRAM,在SWWSR中为外部存储空间设置了2个等待状态(假设CPU周期15ns,2个等待状态约30ns,加上其他建立保持时间,勉强满足70ns SRAM的读周期)。后来由于成本或供货原因,换成了100ns的慢速SRAM。此时,你需要增加等待状态。如果没有SWSM,你需要重新计算并修改SWWSR中多个字段的值。有了SWSM,你只需要将其从0改为1,所有区域的等待状态自动翻倍(从2变为4,约60ns),很可能就满足了新SRAM的时序要求。这是一个快速的、全局的时序降速开关。
4.2 与硬件等待状态(READY引脚)的协同
系统总的等待状态由三部分决定:
- 固定等待状态:由芯片的硬件设计决定,通常为1个。
- 软件可编程等待状态:由SWWSR寄存器设定,并受SWSM位乘数影响。
- 硬件可编程等待状态:由外部设备的READY信号线控制。设备可通过拉低READY来通知DSP插入任意数量的额外等待状态,直到数据准备好。
它们的优先级通常是:硬件READY信号最高。即使软件等待状态已满足,如果设备READY未就绪,访问周期会一直等待。SWSM和SWWSR提供了一种基础的、可预测的等待状态管理,而READY引脚提供了动态的、由外设控制的等待能力。
4.3 实战配置与计算示例
配置前,必须计算所需等待状态数。公式如下:所需等待状态数 >= (外设访问时间 - DSP访问周期时间) / DSP时钟周期
假设:
- DSP时钟频率
CLKOUT = 100 MHz,周期T = 10 ns。 - 外部Flash存储器读访问时间
t_acc = 70 ns。 - DSP访问周期中,地址建立、数据保持等固定开销时间
t_overhead = 20 ns(此值需查芯片数据手册时序图估算)。
计算:所需有效等待时间 = t_acc - t_overhead = 70ns - 20ns = 50ns所需等待周期数 = ceil(50ns / 10ns) = 5个周期
固定等待状态假设为1个周期,则需要在SWWSR中为该Flash映射的空间设置的软件等待状态数为:5 - 1 = 4。
如果设置SWSM=0,则插入总等待状态 = 1(固定) + 4 = 5,刚好满足。 如果后期系统降频运行(如为省电),CLKOUT = 50 MHz, T=20ns,则所需等待周期数 = ceil(50ns/20ns)=3个周期。此时,1(固定)+4=5 > 3,仍然满足,且有余量。 如果后期换用更慢的Flash(t_acc=90ns),所需有效等待时间=70ns,所需周期数(100MHz下)=7。此时,可以将SWSM设为1,则实际软件等待状态=4*2=8,总等待状态=1+8=9 > 7,满足要求。这就是SWSM的便捷之处。
配置代码示例:
// 假设SWWSR地址为0x0028, SWCR地址为0x002B #define SWWSR (volatile unsigned int *)0x0028 #define SWCR (volatile unsigned int *)0x002B void configure_wait_states(void) { unsigned int swwsr_val = 0; unsigned int swcr_val = 0; // 配置SWWSR:假设将外部数据空间(0x8000-0xFFFF)的等待状态设为4 // 假设SWWSR中对应数据空间的字段在bits 8-10(具体需查手册) swwsr_val |= (4 << 8); // 设置DATA空间等待状态为4 // 其他空间(程序、IO等)同理配置... // swwsr_val |= (2 << 11); // 设置IO空间等待状态为2 *SWWSR = swwsr_val; // 配置SWCR:初始SWSM=0,不倍增 swcr_val = 0; // SWSM bit 0 = 0 *SWCR = swcr_val; } // 当需要全局增加等待状态时(例如更换慢速存储器) void increase_wait_states_globally(void) { *SWCR |= 0x0001; // 将SWSM位置1,所有SWWSR设置翻倍 }5. McBSP寄存器集群:构建灵活的串行通信引擎
McBSP的配置是C54x外设中最复杂的部分,因为它要定义一个完整的通信协议。我们必须以“协议驱动”的思路来配置它,而不是孤立地看每个寄存器。
5.1 配置逻辑与核心寄存器组梳理
配置McBSP通常遵循一个清晰的流程,对应不同的寄存器组:
- 复位与全局使能 (SPCR1/2):首先通过RRST和XRST位复位接收器和发送器,然后进行其他配置,最后再使能它们。
- 引脚功能定义 (PCR):决定McBSP的引脚(CLKX, CLKR, FSX, FSR, DX, DR, CLKS)是作为串口功能还是通用GPIO。同时设置时钟和帧同步的极性、模式(输入/输出)。
- 时钟与帧同步生成 (SRGR1/2):如果使用内部采样率发生器(CLKSM=1),在此寄存器设置时钟分频比(CLKGDV)、帧同步脉冲宽度(FWID)和帧周期(FPER)。这决定了串行比特率和帧频率。
- 数据格式定义 (RCR1/2, XCR1/2):设置接收和发送的数据格式:单相/双相帧、每帧字数(RFRLEN/XFRLEN)、每字位数(RWDLEN/XWDLEN)、数据延迟(RDATDLY/XDATDLY)、压缩扩展模式(RCOMPAND/XCOMPAND)等。
- 多通道选择 (MCR1/2, RCER/XCER):如果使用TDM多通道模式,在此寄存器中选择激活哪些通道。
5.2 关键字段实战精讲
时钟与帧同步模式 (PCR寄存器中的CLKXM, CLKRM, FSXM, FSRM)这是最容易出错的地方。
- CLKXM/CLKRM:决定时钟源是内部产生(输出)还是外部输入。
- CLKXM=1:CLKX引脚为输出,DSP是主设备,为通信提供时钟。
- CLKXM=0:CLKX引脚为输入,DSP是从设备,接收外部时钟。
- CLKRM同理,但通常在主模式下,CLKRM也设为1(输出),让接收时钟与发送时钟同源(内部生成)。
- FSXM/FSRM:决定帧同步信号源。
- FSXM=1且FSGM=1 (在SRGR2中):FSX由内部采样率发生器产生,DSP控制帧同步。
- FSXM=0:FSX由外部输入,DSP响应外部帧同步。
- FSRM配置逻辑类似。
一个典型的主模式(DSP提供时钟和帧同步)I2S配置示例:
// 假设McBSP0的寄存器基址已定义 void mcbsp0_config_i2s_master(void) { // 1. 复位收发器 SPCR1 &= ~RRST; // 复位接收器 SPCR2 &= ~XRST; // 复位发送器 // 2. 配置PCR:主模式,时钟和帧同步输出 PCR = 0; // 先清零 PCR |= CLKXM | CLKRM; // CLKX, CLKR 输出 (主模式) PCR |= FSXM | FSRM; // FSX, FSR 输出 (主模式) PCR &= ~(FSXP | FSRP); // 帧同步高有效 (I2S标准) PCR &= ~(CLKXP | CLKRP); // 数据在时钟下降沿采样 (I2S标准) // 3. 配置SRGR:生成所需的时钟和帧同步 // 假设CPU时钟100MHz, 需要生成2.048MHz的串行时钟(BCLK)和48kHz的帧同步(LRCK) // CLKGDV = (CPU_CLK / (2 * SCLK)) - 1 // 目标SCLK = 2.048MHz * 32 (位时钟) * 2 (左右通道) = 约131MHz? 显然不对。 // 实际计算:I2S的BCLK = 采样率 * 位数 * 通道数 = 48k * 32 * 2 = 3.072 MHz // 我们需要从100MHz CPU时钟分频得到~3.072MHz的CLKG。 // CLKGDV = floor(100MHz / (2 * 3.072MHz)) - 1 ≈ floor(16.28) -1 = 15 // 帧同步频率就是采样率48kHz。 SRGR1 = (0 << 8) | 15; // FWID=0 (帧同步脉冲宽度1个CLKG周期), CLKGDV=15 // FPER = (CLKG / FSR) - 1 = (3.072M / 48k) -1 = 63 SRGR2 = (1 << 12) | 63; // FSGM=1 (FSX由采样率发生器产生), FPER=63 // 4. 配置数据格式 (RCR2, XCR2): I2S格式,32位字长(包含左右通道各16位) RCR2 = 0; RCR2 |= (1 << 5); // RWDLEN2=001b? 不对,32位应为101b。仔细看手册,RWDLEN2在bit7-5。 // 正确设置:单相帧,32位字长,无压缩,忽略后续帧同步,1位数据延迟(I2S通常需要) RCR2 = (0 << 15) | // RPHASE=0, 单相帧 (0 << 8) | // RFRLEN2=0, 每帧1个字(对于I2S,一帧就是一个32位的字,包含L+R) (5 << 5) | // RWDLEN2=101b, 32位字长 (0 << 3) | // RCOMPAND=00, 无压缩,MSB先传 (1 << 2) | // RFIG=1, 忽略后续帧同步 (1 << 0); // RDATDLY=01b, 1位数据延迟(I2S标准) XCR2 = ... // 发送配置与接收对称 // 5. 使能采样率发生器和帧同步发生器 SPCR2 |= GRST; // 启动采样率发生器 (CLKG开始运行) // 等待至少2个CLKG周期稳定(软件延时) delay_cycles(10); SPCR2 |= FRST; // 启动帧同步发生器 (FSG开始运行) // 6. 最后使能收发器 SPCR1 |= RRST; SPCR2 |= XRST; }注意:上述I2S配置是一个简化示例,实际I2S协议中,一帧通常包含左右两个声道数据,可能需要配置为双相帧(RPHASE=1),并设置相应的帧长。这里旨在展示配置流程和关键位的作用。
数据延迟 (RDATDLY/XDATDLY)这个位极其重要,它定义了从帧同步信号有效开始,到第一个数据位出现在数据线上的延迟时钟周期数。常见值为1。在大多数标准协议(如SPI, I2S)中,数据是在帧同步有效后的下一个时钟边沿才有效的。如果设成0,可能会导致读到错误的数据(帧同步边沿上的数据是旧的或不稳定的)。
压缩扩展 (RCOMPAND/XCOMPAND)用于语音通信的A-law或μ-law压缩扩展。只有当字长设置为8位(RWDLEN/XWDLEN=000)时,此功能才有效。硬件会自动完成13位线性码与8位压缩码之间的转换。如果你的数据是16位线性PCM音频,就不要启用这个功能。
5.3 多通道操作 (MCR, RCER/XCER) 配置要点
McBSP支持最多128个时分复用(TDM)通道。这在电信E1/T1接口或多路音频系统中非常有用。
- RMCM/XMCM (MCR1/2):接收/发送多通道选择使能。必须置1才能启用多通道模式。
- RPABLK/RPBBLK (MCR1):将128个通道划分为A、B两个分区,每个分区包含8个块(block),每个块16个通道。这两个字段选择当前接收使能的是A分区和B分区中的哪个块。
- RCER/XCER (通道使能寄存器):这是两个寄存器组(RCERA~RCERH),每个寄存器32位,对应128个通道。每一位使能一个具体的通道(0~127)。只有被RPABLK/RPBBLK选中的块内的通道,并且其在RCER中对应的位被置1,该通道的数据才会被接收或发送。
配置多通道模式的关键是理解“块”和“分区”的概念。它允许你动态地切换所关注的通道组,而不需要重新配置整个数据格式。
6. 调试与排错实战经验录
配置这些寄存器时,问题往往不是单一的。下面是我总结的几个常见问题场景和排查思路。
6.1 问题1:访问外部存储器数据错误或程序跑飞
- 可能原因A (BSCR相关):BNKCMP设置与硬件地址译码不匹配。例如,硬件上将两片32K SRAM分别映射到低32K和高32K,但BNKCMP设成了1111(4K)。这会导致频繁的、不必要的存储体切换,甚至在某些访问模式下产生错误的地址选通。
- 排查:检查硬件原理图的地址译码逻辑,确保BNKCMP设置的存储体大小与硬件分区一致。用示波器观察地址线A15(或BNKCMP涉及的更高位)和片选信号,看切换是否符合预期。
- 可能原因B (SWCR/SWWSR相关):等待状态不足。这是最常见的原因。CPU速度太快,存储器反应不过来,读回的数据是无效的。
- 排查:首先确认SWSM是0还是1。然后核对SWWSR中对应存储区域的等待状态设置。使用示波器测量存储器读周期,看从地址有效到数据稳定的时间是否小于(CPU周期数 * 时钟周期)。一个技巧:先将等待状态设得非常大(如7或14),如果问题消失,则基本确定是等待状态问题,再逐步减小至临界值。
- 可能原因C (BSCR的EXIO位被意外置位):这会导致外部总线接口被关闭,任何对外部的访问都会失败。
- 排查:在调试器中查看BSCR寄存器的值,确认EXIO位是否为0。
6.2 问题2:McBSP无法收发数据
这是一个系统性问题,需要分层排查:
时钟和帧同步信号有没有?
- 用示波器测量CLKX/CLKR和FSX/FSR引脚。
- 如果应该是输出但没有信号,检查PCR中的CLKXM/CLKRM/FSXM/FSRM是否配置正确,SPCR2中的GRST和FRST是否已置位。
- 检查SRGR的配置,CLKGDV计算是否正确导致时钟频率为0。
数据线是否有动静?
- 在确保时钟和帧同步正常后,查看DX/DR引脚。发送时,DX应该在时钟和帧同步的控制下输出数据;接收时,确保外部设备确实在DR引脚上发送了数据。
寄存器状态位是否正常?
- 检查SPCR1中的RRDY位(接收就绪)和SPCR2中的XRDY位(发送就绪)。它们是判断McBSP内部状态的关键。
- 检查RFULL或XEMPTY位,判断是否发生溢出或欠载。
- 特别关注RINTM/XINTM:你配置的是哪种中断模式?是每个字结束(RRDY/XRDY)产生中断,还是每帧结束?这决定了你的中断服务程序(ISR)被调用的时机。
数据格式是否匹配?
- 字长不匹配:最常见。DSP配置为接收16位,但外设发送8位,会导致数据错位。
- 数据延迟不匹配:如果外设数据在帧同步有效后第2个时钟边沿有效,而DSP设置RDATDLY=0,就会采样到错误数据。绝大多数标准协议需要1位数据延迟。
- 时钟极性/相位不匹配:CLKXP/CLKRP, FSXP/FSRP必须与外设严格一致。用示波器对照时序图一点一点地核对。
6.3 问题3:McBSP只能收/发一次数据,后续就停止了
- 可能原因:DXR(发送数据寄存器)没有被及时写入新数据,或DRR(接收数据寄存器)的数据没有被及时读取。
- 排查:
- 对于发送:在XRDY变高(表示DXR空,可以写入新数据)后,必须在一个合理的时间内将下一个数据写入DXR。通常是在发送中断服务程序(ISR)中完成。如果使用查询方式,必须循环检测XRDY位。
- 对于接收:在RRDY变高(表示DRR有数据)后,必须及时读取数据。否则,当后续数据到来时,会导致RBR(接收缓冲寄存器)溢出,RFULL置位,接收器可能停止。
- 检查RFIG/XFIG位:如果设为0(NO),那么第一个帧同步脉冲之后的帧同步脉冲会重启传输。如果外设是连续发送多帧数据,这会导致后续帧被错误地当作新传输的开始,造成混乱。在连续流传输中,通常将此位置1(YES),让McBSP忽略第一个帧同步之后的同步脉冲。
6.4 实用调试技巧
- 先配置,后使能:永远遵循“复位 -> 配置所有参数 -> 使能时钟/帧同步发生器 -> 使能收发器”的顺序。不要在收发器运行中(RRST/XRST=1)修改关键配置寄存器(如RCR/XCR, SRGR)。
- 利用数字回环 (Digital Loopback, DLB):将SPCR1中的DLB位置1,可以在芯片内部将发送端连接到接收端。这是一个极好的自检手段。先配置为自发自收模式,发送一个已知数据模式,然后读取接收寄存器,看是否一致。这可以排除外部电路问题,聚焦于DSP本身的配置是否正确。
- 从最简单配置开始:先尝试配置一个最基本的、单相、单字、无压缩、内部时钟的模式,让McBSP先跑起来。成功后再逐步增加复杂度,如改为外部时钟、启用多通道、改变数据格式等。
- 善用示波器或逻辑分析仪:这是调试硬件接口的终极武器。同时抓取时钟、帧同步、数据三条线,与数据手册中的时序图和你的寄存器配置进行比对,任何不匹配都无所遁形。