1. 项目概述:为什么时序是DSP系统设计的“生命线”

在嵌入式系统,尤其是像TMS320C6457这样的高性能数字信号处理器(DSP)设计中,我们常常把精力集中在算法优化、内存管理和功耗控制上。然而,一个经常被新手工程师低估,却又足以让整个项目“翻车”的关键环节,就是 外设接口的时序 。你可以把它想象成一场精心编排的交响乐,处理器是指挥,各个外设是乐手,而时序参数就是乐谱上每个音符的节拍和时长。任何一个乐手抢拍或慢半拍,整首曲子就会走样。在高速数据交换的场景下,时序的微小偏差直接导致数据错乱、系统崩溃,甚至硬件损坏。

我接触过不少项目,算法跑得飞快,但一挂上外部SDRAM或者接上高速ADC,系统就变得不稳定,时好时坏。排查到最后,十有八九是时序配置的问题。TMS320C6457作为一款经典的通信基础设施DSP,其丰富的外设(如EMIFA、HPI、McBSP、I2C)为连接外部世界提供了强大能力,但同时也带来了复杂的时序设计挑战。这份来自TI官方文档SPRS582B的时序参数表,不是一堆枯燥的数字,而是确保你的硬件和软件能够“对话”的 通信协议字典 。本次分享,我就结合自己踩过的坑和实际调试经验,为你深入拆解C6457这几个核心外设接口的时序奥秘,把手册上的参数变成你电路设计和软件配置中实实在在的、可操作的准则。

2. 核心设计思路:从参数表到可靠系统的设计哲学

面对动辄数十页的时序参数表格,新手很容易感到无从下手。我的思路是,不要孤立地记忆每一个 tsu (建立时间)或 th (保持时间)的具体数值,而是要理解其背后的 设计哲学和系统级考量

2.1 理解时序参数的“上下文”

所有时序参数都不是孤立的,它们共同定义了两个设备之间信号交互的“安全窗口”。以最常见的 建立时间 保持时间 为例:

  • 建立时间 (Setup Time, tsu) :在时钟有效边沿(如上升沿)到来之前,数据或控制信号必须保持稳定的 最短时间 。这是为了让接收端的寄存器有足够的时间在时钟边沿到来前,将输入信号稳定地“锁存”住。
  • 保持时间 (Hold Time, th) :在时钟有效边沿到来之后,数据或控制信号必须继续维持稳定的 最短时间 。这是为了保证在时钟边沿之后,内部逻辑有足够的时间完成采样,防止因信号过早变化导致采样错误。

这两个时间共同定义了一个围绕时钟边沿的“数据稳定窗口”。你的电路设计(包括PCB走线长度、驱动器强度、负载电容)和软件配置(如时钟分频)必须保证信号在实际传输中满足这个窗口要求。

2.2 系统同步与时钟域考量

C6457的外设接口主要分为 同步 异步 两大类。

  • 同步接口 (如EMIFA可编程同步模式、McBSP) :所有操作都与一个共同的时钟(如 AECLKOUT , CLKX/R )边沿同步。时序参数通常以这个时钟为参考。设计重点在于 时钟质量 (抖动、占空比)和 时钟与数据之间的偏移 (Skew)。
  • 异步接口 (如EMIFA异步模式、HPI的部分握手信号) :没有统一的时钟,依靠特定的控制信号(如 HSTROBE , AARDY )的跳变来触发操作。设计重点在于 信号脉冲宽度 信号之间的相对时序

在混合时钟域的设计中(例如DSP内核时钟与外部器件时钟不同),还需要特别注意 亚稳态 问题,通常需要通过FIFO或双时钟缓冲区进行隔离。

2.3 负载与驱动能力

手册中的时序参数通常是在规定的负载条件下测试的。例如,I2C总线对 上拉电阻 总线电容 有明确要求( Cb )。如果你的PCB上挂载了多个器件,总线电容增加,会导致信号上升/下降时间变长,可能违反 tr tf 参数。此时,你需要调整上拉电阻值(减小电阻以增强驱动,但会增加功耗)或降低通信速率。

实操心得一:先算后画 在画原理图和PCB之前,先用时序参数进行初步估算。例如,对于EMIFA连接SDRAM,你需要根据DSP的 AECLKOUT 频率和SDRAM芯片的时序要求,计算地址/命令/数据线的有效窗口。如果窗口太紧,就要考虑降低时钟频率、选择更快的存储器、或优化PCB布局(缩短关键路径走线)。

3. EMIFA接口时序深度解析与配置实战

外部存储器接口(EMIFA)是C6457与片外存储(如SBSRAM、ZBT SRAM、异步器件)通信的大动脉。其可编程同步接口模式提供了极高的灵活性,但配置也最为复杂。

3.1 可编程同步接口时序模型拆解

文档中的图7-22、7-23、7-24是理解同步接口的钥匙。我们以 读时序(图7-22) 为例,拆解其完整流程和关键参数:

  1. 时钟启动 AECLKOUT 是主时钟,所有操作以其为基准。
  2. 地址与命令发出 :在时钟上升沿后,经过一个延迟 td(EKOH-EAV) ,地址线 AEA[19:0] 有效;同时,经过 td(EKOH-ADSV) ,地址选通信号 ASADS/ASRE 有效(表明这是一个读命令)。片选 ACEx 和字节使能 ABEx 也在此时有效。
  3. 读延迟等待 :这里引入了核心概念—— 可编程读延迟 R_LTNCY 可以配置为1、2或3个时钟周期。图中示例为 R_LTNCY=2 。这意味着从发出读命令( ASADS 有效)到DSP期望在数据总线上看到有效数据,中间隔了2个完整的 AECLKOUT 周期。
  4. 数据采样 :在延迟了 R_LTNCY 个周期后的时钟上升沿,DSP采样数据总线 AED[63:0] 。数据必须在采样沿之前满足建立时间 tsu(EDV-EKOH) ,并在之后满足保持时间 th(EKOH-EDV) 。文档给出典型值为 tsu=2ns , th=1.5ns 。这意味着在时钟上升沿到来前2ns,数据就必须稳定;在时钟上升沿过后1.5ns内,数据仍需保持稳定。
  5. 信号撤销 :读操作结束后,地址、命令等信号在时钟上升沿后经过 td(EKOH-xxIV) 时间变为无效。

写时序(图7-23, 图7-24) 逻辑类似,但数据流向相反。关键参数是 可编程写延迟 W_LTNCY 可以是0、1、2或3。 W_LTNCY=0 表示在写命令发出的同一个周期,数据就出现在总线上; W_LTNCY=1 则表示延迟一个周期。

3.2 关键时序参数计算与配置示例

假设我们要连接一个读延迟为2个时钟周期的同步SRAM,DSP的 AECLKOUT 频率为100MHz(周期T=10ns)。

  1. 确定 R_LTNCY :根据SRAM芯片手册,其从收到地址到输出数据的延迟(tAA)为15ns。我们的时钟周期是10ns,15ns介于1到2个周期之间。为了留足裕量,我们应设置 R_LTNCY=2 。这样,DSP会在发出地址2个周期(20ns)后才去采样数据,完全覆盖了SRAM的15ns延迟。
  2. 计算数据有效窗口
    • 数据必须在采样时钟沿前 tsu=2ns 稳定。
    • 数据在采样时钟沿后 th=1.5ns 内仍需稳定。
    • 因此,SRAM输出的数据必须在以采样时钟沿为中心、前后分别2ns和1.5ns的窗口内保持稳定。SRAM的数据输出保持时间(tOH)必须大于1.5ns。
  3. 配置寄存器 :我们需要设置EMIFA对应片选空间( CEnCFG )寄存器中的 R_LTNCY 字段为 2 。同时,根据接口类型(标准SRAM),设置 CE_EXT=0 R_ENABLE=0

注意事项:EMIFA的“等待”信号 除了可编程延迟,EMIFA还支持异步 AARDY (就绪)信号,如图7-21所示。当连接速度较慢的器件时,可以通过拉低 AARDY 来插入等待周期。配置时需注意 AARDY 的建立时间 tsu(AARDY-AAWEH) 和保持时间 th(AARDYH-AAWEH) ,确保DSP能正确识别。

3.3 配置代码片段与调试技巧

以下是一个简化的EMIFA同步模式初始化代码框架(以CE2空间为例,连接64位宽, R_LTNCY=2 W_LTNCY=1 的SRAM):

#include <c6x.h>

void EMIFA_Sync_Init(void) {
    // 1. 确保EMIFA模块时钟使能(通常在PLL配置中完成)

    // 2. 配置EMIFA全局控制寄存器(如AWCC, MTYPE等),此处省略

    // 3. 配置CE2空间为同步接口,64位宽
    // CEnCFG寄存器格式参考手册。假设基址:0x70000000
    volatile unsigned int *emifa_ce2_cfg = (unsigned int *)0x70000024; // CE2配置寄存器地址示例

    unsigned int cfg_value = 0;
    cfg_value |= (0x3 << 8);   // MTYPE: 同步接口
    cfg_value |= (0x1 << 4);   // READHOLD: 读保持周期,通常设为1
    cfg_value |= (0x2 << 2);   // R_LTNCY: 读延迟 = 2
    cfg_value |= (0x1 << 0);   // W_LTNCY: 写延迟 = 1
    // 其他位如W_SETUP, W_STROBE, W_HOLD, R_SETUP等根据存储器手册设置
    *emifa_ce2_cfg = cfg_value;

    // 4. 配置CESECn寄存器(如果需要设置段大小等)
    // volatile unsigned int *emifa_cesec2 = (unsigned int *)0x700000XX;
    // *emifa_cesec2 = ...;

    // 5. 软件触发一次访问以激活配置(有时需要)
    volatile unsigned long long *test_addr = (unsigned long long *)0x80000000; // CE2映射的起始地址
    unsigned long long dummy = *test_addr;
    (void)dummy; // 防止编译器警告
}

调试技巧

  • 逻辑分析仪是关键 :用逻辑分析仪同时抓取 AECLKOUT ACEx ASADS AEA AED 等信号。对照时序图,逐一检查地址发出、命令有效、数据出现的时间点是否与配置的延迟参数吻合。
  • 检查数据对齐 :对于64位宽接口,注意字节使能 ABE[7:0] 是否与你的数据访问宽度匹配。错误的字节使能会导致写入错误的内存位置或读取到错误数据。
  • 电源与去耦 :高速同步接口对电源完整性非常敏感。务必在EMIFA电源引脚附近放置充足且合适容值的去耦电容。

4. I2C总线时序精讲与软件模拟要点

I2C是一种简单却“娇气”的同步串行总线。C6457的I2C模块兼容标准模式和快速模式(400Kbps)。

4.1 标准模式 vs. 快速模式时序对比

文档表7-67和7-68详细列出了两种模式的参数。我们关注几个最核心的:

参数 标准模式 (100kbps) 快速模式 (400kbps) 说明
tc(SCL) 时钟周期 最小 10us 最小 2.5us 决定了最高通信速率。
tsu(SDAV-SCLH) SDA建立时间 最小 250ns 最小 100ns 关键! 数据必须在SCL上升沿前稳定好。
th(SCLL-SDAV) SDA保持时间 最小 0ns 最小 0ns 数据在SCL下降沿后需保持的时间。
tr(SDA)/tr(SCL) 上升时间 最大 1000ns 最大 300ns 受上拉电阻和总线电容 Cb 影响。
Cb 总线电容 最大 400pF 最大 400pF 所有器件引脚电容和走线电容之和。

快速模式的要求明显更苛刻 。如果你的设计需要跑400Kbps,必须:

  1. 选择支持快速模式的从设备。
  2. 使用更小的上拉电阻(例如从4.7kΩ减小到2.2kΩ)以加快上升沿,但同时要计算功耗是否可接受。
  3. 严格控制PCB走线,减少寄生电容。

4.2 上拉电阻计算与总线布局

上拉电阻 Rp 的选择是I2C稳定性的基石。它需要在 上升时间 低电平电压 之间折衷。

  • 上升时间要求 tr <= 0.8473 * Rp * Cb (对于快速模式,要求 tr <= 300ns )。
  • 低电平电压要求 Rp > (Vdd - Vol_max) / Iol ,其中 Iol 是主设备SDA/SCL引脚的最大低电平输出电流(查DSP手册), Vol_max 是逻辑0的最大允许电压(通常0.4V)。

计算示例 :假设 Vdd=3.3V , Vol_max=0.4V , Iol=6mA ,则 Rp > (3.3-0.4)/0.006 ≈ 483Ω 。再假设总线电容 Cb=200pF ,要求 tr<=300ns ,则 Rp <= 300ns / (0.8473 * 200pF) ≈ 1.77kΩ 。因此, Rp 可以选择在1kΩ左右。

实操心得二:I2C的“线与”与总线锁死 I2C是开漏输出,依靠上拉电阻拉到高电平。任何设备拉低总线,总线就是低电平。这是“线与”逻辑。但如果某个从设备异常(比如MCU死机后I2C引脚输出固定低电平),会导致整个总线被拉低,无法通信,即“总线锁死”。 硬件上 ,一个有效的预防措施是为每个I2C设备串联一个几百欧姆的电阻(如330Ω),这样即使一个设备短路到地,也不会把总线电压拉得太低,同时主设备强大的拉低能力仍能产生有效的低电平。 软件上 ,超时机制和复位序列(发送9个时钟脉冲)是必须的。

4.3 C6457 I2C模块配置流程

  1. 引脚复用与上拉 :首先通过PINMUX寄存器将对应引脚配置为I2C功能。 务必在SDA和SCL线上连接外部上拉电阻 (根据上述计算选择阻值)。
  2. 时钟配置 :设置 ICPSC 预分频器和 ICCLKL / ICCLKH 时钟高低电平分频器,以产生符合标准的SCL时钟频率。公式参考手册,目标是让产生的SCL周期满足 tc(SCL) 要求。
  3. 自身地址 :在 ICOAR 寄存器中设置DSP作为从设备时的地址。
  4. 模式与中断 :配置 ICMDR 寄存器,选择主/从模式、7/10位地址、是否产生中断等。
  5. 数据传输 :将要发送的从机地址写入 ICSAR ,数据写入 ICDXR ,然后启动传输。通过查询 ICSTR 状态寄存器或等待中断来判断传输完成。

5. HPI主机接口时序分析与设计陷阱规避

主机端口接口(HPI)允许外部主机(如ARM、FPGA)直接访问DSP的内存空间,是主从式系统的关键桥梁。C6457支持16位(HPI16)和32位(HPI32)模式,通过 HPIWIDTH 引脚选择。

5.1 HPI接口信号与握手逻辑

HPI接口信号较多,理解其功能是分析时序的前提:

  • HCS :片选,低有效。
  • HDS1/2 :数据选通,与 HCS 一起构成 HSTROBE 信号( HSTROBE = NOT(HDS1 XOR HDS2) OR HCS )。 HSTROBE 的下降沿锁存控制信号,上升沿锁存数据。
  • HCNTL[1:0] :控制信号,用于选择访问HPI控制寄存器(HPIC)、地址寄存器(HPIA)还是数据寄存器(HPID)。
  • HR/W :读写控制。
  • HHWIL :仅在HPI16模式下有效,表示半字(高/低16位)选择。
  • HAS :地址锁存使能,可选。如果使用,主机可以在 HAS 下降沿将地址/控制信号锁存到HPI内部,从而让地址/控制信号提前于 HSTROBE 变化,简化主机时序。
  • HRDY :就绪信号, 输出 。这是HPI给主机的反馈信号,低电平表示HPI准备好进行下一次传输。 这是最易出错的信号!

5.2 关键时序路径与“HRDY”的坑

文档中的时序图(图7-28至7-35)和参数表(表7-71, 7-72)是设计的金科玉律。我们重点关注几个最关键的路径,特别是与 HRDY 相关的:

  1. 建立/保持时间(输入给DSP) :如 tsu(SELV-HSTBL) (控制信号在 HSTROBE 低前的建立时间,最小5ns)、 tsu(HDV-HSTBH) (主机写数据在 HSTROBE 高前的建立时间,最小5ns)。主机控制器必须满足这些要求。
  2. DSP输出延迟时间 :如 td(HSTBL-HDV) HSTROBE 低到DSP读数据有效,最大15ns或更长)。这决定了主机在发起读操作后,需要等待多久才能安全地采样数据总线 HD[31:0]
  3. HRDY 行为(核心难点) HRDY 的响应时间与 操作类型 FIFO状态 密切相关。表7-72揭示了多种情况:
    • Case 1 (HPIC/HPIA读) :延迟很短( td(HSTBL-HRDYL) ), HRDY 很快变低表示完成。
    • Case 2/3 (HPID读,无自动递增或FIFO空) :延迟很长!公式为 10 × M + 20 ns M SYSCLK5 周期。若DSP运行在1GHz, M=6ns ,则延迟高达 10*6+20=80ns !这意味着主机在发起这类读操作后,必须等待至少80ns(通过查询 HRDY 或固定延迟)才能进行下一次操作,否则会导致错误。
    • Case 4 (HPID读,有自动递增且数据已预取) :延迟短,同Case 1。
    • 写操作 也有类似的复杂情况( td(HSTBH-HRDYL) )。

避坑指南:HPI设计黄金法则

  1. 永远查询HRDY :不要使用固定延时等待。主机程序必须设计为在每次 HSTROBE 操作后,检测 HRDY 信号变为有效(低电平)后,才进行下一次操作。这是保证可靠性的唯一方法。
  2. 理解FIFO :HPI内部有读写FIFO。连续访问连续地址(使用自动递增)可以利用FIFO提升性能。单次随机访问性能最差。
  3. HAS信号的使用 :如果主机时序紧张,建议使用 HAS 信号。它允许地址/控制信号提前建立,将 tsu(SELV-HSTBL) 的要求转移到 tsu(SELV-HASL) 上,可以放宽主机对 HSTROBE 边沿附近时序的要求。
  4. HPI32 vs HPI16 :HPI32模式数据吞吐量翻倍,且省去了 HHWIL 信号,时序控制更简单。如果主机支持32位总线,优先选用HPI32模式。

5.3 主机端(以FPGA为例)状态机设计示例

以下是一个简化的FPGA Verilog代码片段,展示如何实现一个安全的HPI16读操作状态机(不使用HAS):

module hpi_controller (
    input wire clk,
    input wire rst_n,
    input wire hrdy,      // 来自DSP的HRDY信号
    output reg hcs_n,
    output reg hds1_n,
    output reg hds2_n,
    output reg hrw,
    output reg [1:0] hcntl,
    output reg hhwil,
    inout wire [15:0] hd
);
    // 状态定义
    localparam S_IDLE = 0;
    localparam S_ASSERT = 1;
    localparam S_WAIT_RDY = 2;
    localparam S_DEASSERT = 3;
    localparam S_READ_DATA = 4;

    reg [2:0] state, next_state;
    reg [15:0] hd_out;
    reg hd_oe; // 输出使能

    assign hd = hd_oe ? hd_out : 16'hzzzz;

    // 状态转移
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) state <= S_IDLE;
        else state <= next_state;
    end

    always @(*) begin
        next_state = state;
        case (state)
            S_IDLE: if (start_read) next_state = S_ASSERT;
            S_ASSERT: next_state = S_WAIT_RDY; // 短暂断言后进入等待
            S_WAIT_RDY: if (!hrdy) next_state = S_DEASSERT; // 等待HRDY变低
            S_DEASSERT: next_state = S_READ_DATA;
            S_READ_DATA: begin
                data_reg <= hd; // 采样数据
                next_state = S_IDLE;
            end
        endcase
    end

    // 输出逻辑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            {hcs_n, hds1_n, hds2_n} <= 3'b111;
            hrw <= 1'b1; // 默认读
            hcntl <= 2'b00;
            hhwil <= 1'b0;
            hd_oe <= 1'b0;
        end else begin
            case (next_state)
                S_ASSERT: begin
                    hcs_n <= 1'b0;
                    hds1_n <= 1'b0; // 与hds2_n一起产生HSTROBE下降沿
                    hds2_n <= 1'b1;
                    hrw <= 1'b1; // 读操作
                    hcntl <= 2'b11; // 假设访问HPID
                    hhwil <= 1'b0; // 低半字
                    hd_oe <= 1'b0; // 主机释放数据总线
                end
                S_WAIT_RDY: begin
                    // 保持控制信号稳定,等待HRDY
                    hds1_n <= 1'b1; // HSTROBE变高,锁存控制信号
                    hds2_n <= 1'b0;
                end
                S_DEASSERT: begin
                    hcs_n <= 1'b1; // 结束访问
                    hds1_n <= 1'b1;
                    hds2_n <= 1'b1;
                end
                S_READ_DATA: begin
                    // 状态机回到IDLE,完成一次操作
                end
                default: begin
                    {hcs_n, hds1_n, hds2_n} <= 3'b111;
                    hd_oe <= 1'b0;
                end
            endcase
        end
    end
endmodule

这个状态机确保了在 HRDY 有效前不会结束访问,符合时序要求。实际应用中还需考虑 HHWIL 切换(16位模式)、连续读写等复杂情况。

6. McBSP多通道缓冲串行口时序与应用配置

McBSP是一个高度可配置的同步串行接口,支持多种协议(如SPI, I2S, TDM),常用于连接音频编解码器、数据转换器等。

6.1 通用模式时序分析

图7-36展示了McBSP在通用模式下的时序。关键信号:

  • CLKR/X :接收/发送时钟,可由内部产生或外部输入。
  • FSR/X :接收/发送帧同步信号。
  • DR :接收数据。
  • DX :发送数据。

关键参数解读

  • tsu(DRV-CKRL) :接收数据 DR 在接收时钟 CLKR 下降沿前的建立时间。如果 CLKR 由外部提供( CLKR ext ),要求仅为0.9ns;如果由内部产生( CLKR int ),则要求为8ns。 这是因为内部时钟路径有延迟,给数据留的窗口更小。
  • td(CKXH-DXV) :发送时钟 CLKX 上升沿到发送数据 DX 有效的延迟。外部时钟模式最大9ns,内部时钟模式最大4ns。这意味着如果你用McBSP作为主设备驱动从设备,必须确保从设备的数据建立时间要求大于这个延迟加上PCB走线延迟。

6.2 SPI模式特殊配置与时序

McBSP可以配置为SPI主或从设备。图7-38至7-41和表7-78至7-84详细描述了不同 CLKSTP CLKXP 配置下的时序。

配置要点

  • CLKSTP CLKXP 共同决定时钟极性和相位,对应SPI的4种模式(CPOL, CPHA)。
  • 作为SPI主设备时, FSX 通常被配置为输出,作为从设备片选(低有效)。
  • 时序参数中出现了 P (系统参考时钟周期)和 CLKGDV (时钟分频)等变量,说明 McBSP的内部时序与配置的时钟分频比直接相关 。例如, td(CKXH-DXV) 在从模式下的最大值公式为 24P+17 ns 。如果 P=1ns (1GHz系统),则最大延迟为41ns。你的SPI从设备必须有大于41ns的数据建立时间要求。

SPI主模式初始化示例(模式0,即CLKSTP=10b, CLKXP=0)

void McBSP_SPI_Master_Init(void) {
    // 假设使用McBSP0
    // 1. 复位接收器和发送器
    MCBSP0->SPCR &= ~(1 << 0); // 禁止接收器
    MCBSP0->SPCR &= ~(1 << 1); // 禁止发送器

    // 2. 配置引脚功能为McBSP(通过PINMUX寄存器,此处略)

    // 3. 配置采样率生成器
    MCBSP0->SRGR = 0;
    MCBSP0->SRGR |= (0 << 8);   // CLKSM = 0, 使用外部CLKS引脚时钟(如果可用)
    // MCBSP0->SRGR |= (1 << 8); // 或 CLKSM = 1, 使用CPU时钟/6
    MCBSP0->SRGR |= (99 << 0);  // CLKGDV = 99, 产生 CLKX频率 = 输入时钟 / (1+99) = 输入时钟/100

    // 4. 配置接收控制寄存器
    MCBSP0->RCR = 0;
    MCBSP0->RCR |= (0 << 5);    // RFRLEN1 = 0, 单字帧
    MCBSP0->RCR |= (15 << 0);   // RWDLEN1 = 0b111, 32位字长

    // 5. 配置发送控制寄存器
    MCBSP0->XCR = 0;
    MCBSP0->XCR |= (0 << 5);    // XFRLEN1 = 0, 单字帧
    MCBSP0->XCR |= (15 << 0);   // XWDLEN1 = 0b111, 32位字长

    // 6. 配置引脚控制寄存器为SPI主模式
    MCBSP0->PCR = 0;
    MCBSP0->PCR |= (1 << 12);   // CLKXM = 1, CLKX由McBSP输出(主模式)
    MCBSP0->PCR |= (0 << 11);   // CLKRM = 0, CLKR为输入(对于SPI,接收时钟通常由主设备提供)
    MCBSP0->PCR |= (1 << 10);   // FSXM = 1, FSX由McBSP输出(作为片选)
    MCBSP0->PCR |= (1 << 9);    // FSXP = 1, FSX低有效
    MCBSP0->PCR |= (0 << 8);    // FSRM = 0, FSR为输入(未使用)
    MCBSP0->PCR |= (0 << 7);    // CLKXP = 0, CLKX上升沿采样(SPI模式0)
    MCBSP0->PCR |= (0 << 6);    // CLKRP = 0, CLKR上升沿采样

    // 7. 使能采样率生成器、接收器、发送器
    MCBSP0->SPCR |= (1 << 7);   // GRST = 1, 采样率生成器退出复位
    // 等待至少2个CLKG周期(软件延迟)
    MCBSP0->SPCR |= (1 << 0);   // RRST = 1, 接收器使能
    MCBSP0->SPCR |= (1 << 1);   // XRST = 1, 发送器使能
}

6.3 常见问题与调试手段

  • 问题:McBSP发送数据,从设备收不到。
    • 检查 :用示波器或逻辑分析仪看 CLKX FSX DX 三根线。确认时钟是否有输出?帧同步(片选)信号是否正确?数据是否在正确的时钟边沿变化?对照时序图,测量 td(CKXH-DXV) 是否满足从设备要求。
    • 排查 :检查 PCR 寄存器中 CLKXM FSXM CLKXP FSXP 的配置是否与从设备期望的SPI模式匹配。
  • 问题:McBSP接收数据全是0或乱码。
    • 检查 :确认 CLKR FSR 信号是否由外部主设备正确提供。测量 DR 信号在 CLKR 采样沿附近是否稳定(满足建立保持时间)。
    • 排查 :检查 RCR 寄存器中的 RWDLEN (接收字长)是否与数据流匹配。检查接收溢出标志( RFULL )。
  • 问题:数据帧错位。
    • 检查 FSX/R 的脉冲宽度和相位。在SPI模式下, FSX (作为片选)通常在数据帧开始前变低,结束后变高。检查 XDATDLY (数据延迟)配置,它决定了数据是在帧同步开始后延迟多少个时钟才开始。

实操心得三:时钟与帧同步的极性相位 McBSP的灵活性带来了配置的复杂性。务必画一个时序图,标出你希望的 CLKX/R 空闲状态(极性)、数据在哪个边沿采样(相位)、 FSX/R 的有效电平和边沿。然后去对照 PCR 寄存器的 CLKXP CLKRP FSXP FSRP 以及 SPCR 中的 CLKSTP 位。一个配置错误就会导致通信完全失败。最稳妥的方法是先用低速时钟调试,确认波形正确后再提高速率。

更多推荐