MPC56xx DSPI模块深度解析:从寄存器配置到主从通信实战
1. 项目概述与DSPI模块核心价值
在嵌入式系统开发中,串行外设接口(SPI)是连接微控制器与各类传感器、存储器、通信模块的“血管”。它简单、高速、全双工的特性,使其在需要快速数据交换的场景中不可或缺。然而,当你从简单的8位MCU转向像飞思卡尔(现恩智浦)MPC56xx系列这样的高性能32位汽车级微控制器时,你会发现其内置的DSPI(Deserial Serial Peripheral Interface)模块远不止一个基础的SPI控制器那么简单。它更像一个高度可编程的通信“引擎”,提供了极其精细的时序控制能力,这对于满足严苛的汽车电子或工业控制协议时序要求至关重要。
我接手过不少从其他平台移植到MPC56xx的项目,很多工程师初次接触DSPI时,都会被那一堆寄存器搞懵——CTAR、TCR、PUSHR、POPR、MCR,每个寄存器里还有一堆位域。最常见的误区就是照着旧平台的SPI配置经验生搬硬套,结果通信死活不通,或者时序对不上外设要求,最后只能抓瞎。实际上,理解DSPI的核心在于理解其“可配置的通信帧”概念。它把一次SPI通信拆解成多个可独立配置的时序阶段(PCS有效前、时钟有效期间、PCS无效后),并通过CTAR寄存器对每个阶段的时间参数进行微调。这种设计让你能精准匹配从EEPROM到高速ADC等各种外设的奇葩时序需求,而不是被固定的SPI时钟相位和极性模式所限制。
本文将以MPC56xxB系列为例,手把手带你完成一个完整的DSPI主从通信实验。我们不仅会让一块芯片的DSPI0作为主机,另一块的DSPI1作为从机进行数据交换,更会深入每个配置步骤背后的“为什么”,比如如何根据外设手册计算CTAR参数,如何理解模式转换对时钟的影响,以及那些数据手册里可能不会明说,但实际调试中一定会遇到的“坑”。目标是让你看完后,不仅能复现这个例子,更能建立起配置任意SPI外设的信心和方法论。
2. 核心思路与硬件设计解析
在开始写代码之前,理清整体思路和硬件连接是避免后续调试混乱的关键。这个实验的本质是让芯片自己和自己通信,即利用同一片MPC56xx芯片上的两个独立DSPI模块,一个配置为主模式,一个配置为从模式,然后将它们的引脚在内部或外部进行交叉连接。这样做的好处是,无需第二块硬件,仅用一块开发板就能验证SPI通信的全流程,包括配置、发送、接收和错误处理。
2.1 通信链路与信号映射
首先,我们需要明确四个基本SPI信号在主从设备间的连接关系:
- SCK (Serial Clock) :时钟信号,由主设备产生,驱动从设备。因此,主设备的SCK配置为输出,从设备的SCK配置为输入。
- MOSI/SOUT (Master Out Slave In) :主设备数据输出,从设备数据输入。在我们的例子里,主设备的SOUT连接从设备的SIN。
- MISO/SIN (Master In Slave Out) :主设备数据输入,从设备数据输出。即从设备的SOUT连接主设备的SIN。
- SS/PCS (Slave Select / Peripheral Chip Select) :从设备片选信号,低有效。主设备通过拉低某个PCS信号来选中特定的从设备。这里,我们使用主设备的PCS0信号连接到从设备的SS引脚。
对于MPC56xxB,具体的引脚分配依赖于你使用的具体型号和封装。以常见的100引脚QFP封装为例,我们可以这样规划(使用DSPI_0和DSPI_1):
- 主设备 (DSPI_0) :
PCS0_0(片选输出): 连接到从设备的SS。对应芯片引脚可能是A15。SCK_0(时钟输出): 连接到从设备的SCK。对应芯片引脚可能是A14。SOUT_0(数据输出): 连接到从设备的SIN。对应芯片引脚可能是A13。SIN_0(数据输入): 连接到从设备的SOUT。对应芯片引脚可能是A12。
- 从设备 (DSPI_1) :
SS_1(片选输入): 连接主设备的PCS0_0。对应芯片引脚可能是E5。SCK_1(时钟输入): 连接主设备的SCK_0。对应芯片引脚可能是E4。SOUT_1(数据输出): 连接主设备的SIN_0。对应芯片引脚可能是C5。SIN_1(数据输入): 连接主设备的SOUT_0。对应芯片引脚可能是C4。
注意 :在实际硬件连接时,务必查阅你所使用芯片型号的 数据手册 和 引脚复用表 ,以确认上述功能的引脚编号和复用选项。MPC56xx系列不同子型号、不同封装的引脚映射可能不同。代码中的
SIU.PCR[]配置值就是用来设置这些引脚的具体功能和电气特性的。
2.2 以MC33394为例的CTAR参数计算逻辑
DSPI最强大的特性莫过于CTAR寄存器。它不像普通SPI只有CPOL和CPHA,而是把一帧通信的时序分解为几个可配置的延时阶段。我们借用示例中提到的MC33394传感器数据手册的参数,来演示如何将这些物理时序要求,转化为CTAR寄存器中的位域值。假设系统时钟 fSYS 为64MHz,周期 tSYS 为15.625ns(计算时近似为15ns)。
- 帧大小 (FMSZ) : MC33394使用16位通信,所以
FMSZ = 0xF(因为值=帧大小-1)。 - 时钟极性 (CPOL)与相位 (CPHA) : MC33394规定SCK空闲时为低电平,在上升沿采样数据。这对应
CPOL=0(低电平空闲),CPHA=0(数据在SCK的第一个边沿捕获,对于CPOL=0就是上升沿)。 - 传输顺序 (LSBFE) : 数据手册要求LSB先发送,但示例为了逻辑分析仪观测方便设为MSB先传(
LSBFE=0)。实际项目应遵循外设要求。 - PCS到SCK延迟 (tCSC) : 即片选有效到第一个时钟沿的时间。MC33394要求最小105ns。计算公式为
tCSC = tSYS * PCSSCK_PRESCALE * CSSCK_SCALE。PCSSCK是预分频系数,可选1,3,5,7,对应位域值0,1,2,3。CSSCK是倍乘系数,为2的幂次方(2,4,8,...256),对应位域值0~7(0代表2,7代表256)。- 为了满足>105ns,我们选择
PCSSCK=0(预分频1),CSSCK=7(倍乘256)。计算得tCSC ≈ 15ns * 1 * 256 = 3.84us,远大于最小值,留有充足裕量。
- SCK后延迟 (tASC) : 即最后一个时钟沿到片选无效的时间。MC33394要求最小50ns。计算公式类似:
tASC = tSYS * PASC_PRESCALE * ASC_SCALE。- 同样选择
PASC=0,ASC=7,得到tASC ≈ 3.84us。
- 同样选择
- 传输后延迟 (tDT) : 本次传输结束到下次传输开始,片选保持高电平的时间。MC33394要求最小500ns。公式:
tDT = tSYS * PDT_PRESCALE * DT_SCALE。- 选择
PDT=2(预分频5),DT=2(倍乘8)。计算得tDT ≈ 15ns * 5 * 8 = 600ns。
- 选择
- 波特率 (BR) : MC33394最高支持5MHz,示例设定为约100kHz。公式:
SCK频率 = (fSYS / PBR_PRESCALE) * ((1+DBR)/ BR_SCALE)。DBR为双波特率特性,此处不用设为0。- 选择
PBR=2(预分频5),BR=7(分频128)。计算得SCK频率 = (64MHz / 5) * (1 / 128) = 100kHz。
将以上计算出的值组合起来,就得到了CTAR0的配置值 0x780A7727 。这个值不是魔法数字,而是上述一系列计算结果的直接体现。理解这个计算过程,你就能为任何SPI外设定制CTAR。
2.3 模式与功耗管理考虑
MPC56xx系列引入了精细的功耗模式管理(DRUN, RUN0, RUN1等),不同模式下系统时钟和外设时钟可能被门控或关闭。我们的示例需要让DSPI模块在 RUN0 模式下工作,并确保其时钟被使能。
- 模式使能 : 在模式使能寄存器
ME.ME中,使能我们计划使用的模式(如DRUN, RUN0)。 - 模式配置 : 为
RUN0模式配置系统时钟源(例如选择PLL0输出64MHz),并控制各电源域(如Flash、主调压器)的状态。 - 外设时钟配置 : 每个外设(如DSPI0, DSPI1, SIU)都有一个外设时钟控制寄存器
ME.PCTL[],需要将其配置为在RUN0模式下使用特定的外设配置集(例如PC1)。 - 外设配置集 : 在外设配置寄存器
ME.RUNPC[1]中,定义在RUN0模式下,该配置集对应的外设时钟是开启的。 - 模式转换 : 最后,通过向模式控制寄存器
ME.MCTL写入特定密钥序列,触发从当前模式(如上电后的DRUN)到目标模式(RUN0)的转换,并等待转换完成。
这一套流程是MPC56xx系列低功耗管理的基础,确保外设在正确的时钟下工作。忽略这一步,可能会导致DSPI模块根本没有时钟,所有配置都无法生效。
3. 软件实现与分步代码详解
理解了原理和设计,我们来看代码实现。我将以MPC56xxB为例,将整个过程分解为几个关键函数,并解释每一行代码的意图。
3.1 系统与时钟初始化
这是所有操作的基础,确保芯片以预期的频率运行,并进入正确的工作模式。
void initModesAndClock(void) {
/* 1. 使能需要的运行模式:DRUN, RUN0, SAFE, RESET */
ME.MER.R = 0x0000001D;
/* 2. 配置PLL0:假设使用8MHz外部晶振,倍频到64MHz */
/* 具体值需参考芯片参考手册的PLL章节计算,此处为示例 */
CGM.FMPLL_CR.R = 0x02400100;
/* 3. 配置RUN0模式的参数:选择PLL0作为系统时钟源,打开相关时钟 */
ME.RUN[0].R = 0x001F0074; /* 含义:IRC、晶振、PLL0均开启,系统时钟选择PLL0 */
/* 4. 配置外设时钟门控:设置外设配置集1仅在RUN0模式下开启时钟 */
ME.RUNPC[1].R = 0x00000010;
/* 5. 将DSPI0, DSPI1, SIU等外设分配到外设配置集1 */
ME.PCTL[4].R = 0x01; /* DSPI0 使用 PC1 */
ME.PCTL[5].R = 0x01; /* DSPI1 使用 PC1 */
ME.PCTL[68].R = 0x01; /* SIU 使用 PC1 */
/* 6. 触发模式转换:从当前模式转换到RUN0模式 */
ME.MCTL.R = 0x40005AF0; /* 写入密钥1 */
ME.MCTL.R = 0x4000A50F; /* 写入密钥2 */
while (ME.GS.B.S_MTRANS) {}; /* 等待模式转换完成 */
while(ME.GS.B.S_CURRENTMODE != 4) {}; /* 验证当前模式已是RUN0 (值4) */
}
实操心得 :模式转换的 两个密钥必须连续写入 ,且中间不能有任何其他对
ME.MCTL的访问。调试时,如果芯片“卡住”,可以检查ME.GS.B.S_MTRANS是否一直为1,这可能意味着模式转换失败,原因可能是目标模式的配置(如PLL未锁定)不满足转换条件。
3.2 外设时钟与看门狗初始化
void disableWatchdog(void) {
/* 关闭看门狗,防止在调试阶段复位 */
SWT.SR.R = 0x0000c520; /* 写入解锁密钥1 */
SWT.SR.R = 0x0000d928; /* 写入解锁密钥2 */
SWT.CR.R = 0x8000010A; /* 清除WEN位,禁用看门狗 */
}
void initPeriClkGen(void) {
/* 启用外设时钟集2,系统时钟1分频 */
/* 对于DSPI模块,需要确认其时钟来源,此配置确保时钟供给 */
CGM.SC_DC[2].R = 0x80;
}
3.3 DSPI主设备初始化
这是核心配置部分,我们以DSPI0作为主设备。
void initDSPI0_Master(void) {
/* 第一步:配置主模式控制寄存器(MCR),并使模块处于HALT状态以便安全配置 */
DSPI_0.MCR.R = 0x80010001;
/* 位域解析:
* MSTR = 1: 主模式
* CONT_SCK = 0: 非连续时钟,只在传输时产生SCK
* DCONF = 0: SPI模式
* FRZ = 0: 调试冻结时不停止传输
* MTFE = 0: 不使用修改的传输格式
* PCSSE = 0: 不使用PCS状态扩展
* ROOE = 0: 忽略接收FIFO溢出错误(调试时可先关闭)
* PCSIS[3:0] = 0x1: PCS0无效时为高电平(即低有效片选)
* MDIS = 0, DOZE = 0: 模块使能,不受低功耗模式影响
* DIS_TXF, DIS_RXF = 0: 使能TX/RX FIFO
* CLR_TXF, CLR_RXF = 0: 初始化时不清除FIFO(可先不清)
* HALT = 1: 置位HALT,模块处于停止状态,允许配置CTAR等寄存器
*/
/* 第二步:配置时钟与传输属性寄存器CTAR0 */
DSPI_0.CTAR[0].R = 0x780A7727;
/* 此值基于之前对MC33394的计算:
* FMSZ = 0xF (16位帧)
* CPOL = 0, CPHA = 0 (模式0)
* LSBFE = 0 (MSB先传)
* PCSSCK = 0, CSSCK = 7 (tCSC延迟)
* PASC = 0, ASC = 7 (tASC延迟)
* PDT = 2, DT = 2 (tDT延迟)
* DBR = 0 (不双倍波特率)
* PBR = 2, BR = 7 (波特率分频)
*/
/* 第三步:清除HALT位,启动DSPI模块,进入运行状态 */
DSPI_0.MCR.B.HALT = 0;
/* 第四步:配置SIU引脚控制寄存器(PCR),将相关引脚复用到DSPI功能 */
/* 假设使用A12~A15引脚,具体需查数据手册 */
SIU.PCR[12].R = 0x0103; /* A12: SIN_0, 输入,上拉使能 */
SIU.PCR[13].R = 0x0604; /* A13: SOUT_0, 输出,中等驱动强度 */
SIU.PCR[14].R = 0x0604; /* A14: SCK_0, 输出,中等驱动强度 */
SIU.PCR[15].R = 0x0604; /* A15: PCS0_0, 输出,中等驱动强度 */
/* PCR寄存器配置说明:
* PA[0] = 0: 引脚复用为GPIO
* PA[1] = 1: 引脚复用为主要外设功能(此处是DSPI)
* OBE = 1 (输出时): 输出缓冲使能
* IBE = 1 (输入时): 输入缓冲使能
* SRC = 0/1/2/3: 压摆率控制,值越大驱动能力越强,用于高速信号
*/
}
3.4 DSPI从设备初始化
从设备的初始化与主设备类似,但关键区别在于MCR中的模式设置和引脚方向。
void initDSPI1_Slave(void) {
/* 配置从模式控制寄存器(MCR) */
DSPI_1.MCR.R = 0x00010001; /* 与主设备主要区别:MSTR = 0 */
/* 注意:从设备的HALT位也需要在配置期间置位 */
/* 配置CTAR0:从设备的CTAR必须与主设备匹配,特别是CPOL、CPHA、帧大小 */
DSPI_1.CTAR[0].R = 0x780A7727; /* 使用与主设备相同的值 */
/* 启动从设备DSPI模块 */
DSPI_1.MCR.B.HALT = 0;
/* 配置从设备引脚:SCK和SS为输入,SOUT为输出,SIN为输入 */
/* 假设使用C4, C5, E4, E5引脚 */
SIU.PCR[36].R = 0x0103; /* C4: SIN_1, 输入 */
SIU.PCR[37].R = 0x0604; /* C5: SOUT_1, 输出 */
SIU.PCR[68].R = 0x0903; /* E4: SCK_1, 输入,注意功能选择可能需PSMI寄存器 */
SIU.PCR[69].R = 0x0903; /* E5: SS_1, 输入 */
/* 对于某些引脚,除了PCR还需要配置引脚选择模块接口(PSMI)寄存器来选择正确的输入源 */
SIU.PSMI[9].B.PADSEL = 0x2; /* 示例:将E5引脚连接到DSPI1的SS输入 */
}
3.5 主从数据交换流程
初始化完成后,就可以进行数据传输了。流程是:从设备预先在发送缓冲准备好要回复的数据,主设备发起传输并同时接收从设备的回复。
int main(void) {
uint16_t masterReceivedData = 0;
uint16_t slaveReceivedData = 0;
/* 1. 系统初始化 */
disableWatchdog();
initModesAndClock();
initPeriClkGen();
/* 2. DSPI模块初始化 */
initDSPI0_Master();
initDSPI1_Slave();
/* 3. 从设备预装载发送数据 */
/* 将数据0x1234写入从设备的PUSHR寄存器。注意从设备的PUSHR格式可能不同。
* 对于从设备,通常只需写入要发送的数据,CTAS、CONT、PCS等位可能被忽略。
* 具体需参考参考手册,这里假设写入数据即可。
*/
DSPI_1.PUSHR.R = 0x00001234;
/* 4. 主设备发起传输 */
/* 向主设备的PUSHR写入命令和数据:0x08015678
* 位域解析(参考手册PUSHR格式):
* BIT31: CONT = 0 (非连续传输,帧结束后释放PCS)
* BIT30-28: CTAS = 0 (使用CTAR0)
* BIT27: EOQ = 1 (这是传输队列的结束)
* BIT26: CTCNT = 0 (不清除SPI传输计数器)
* BIT25-16: PCS & PCSS = 0x001 (使能PCS0,其他位为0)
* BIT15-0: TXDATA = 0x5678 (要发送的数据)
*/
DSPI_0.PUSHR.R = 0x08015678;
/* 5. 从设备读取接收到的数据(来自主设备) */
while (DSPI_1.SR.B.RFDF == 0) {}; /* 等待接收FIFO非空标志 */
slaveReceivedData = DSPI_1.POPR.R; /* 从POPR读取数据 */
DSPI_1.SR.R = 0x80020000; /* 清除RDRF和TCF标志(写1清除)*/
/* 6. 主设备读取接收到的数据(来自从设备) */
while (DSPI_0.SR.B.RFDF == 0) {}; /* 等待接收FIFO非空标志 */
masterReceivedData = DSPI_0.POPR.R; /* 从POPR读取数据 */
DSPI_0.SR.R = 0x90020000; /* 清除RDRF、TCF和EOQF标志 */
/* 此时,masterReceivedData 应为 0x1234,slaveReceivedData 应为 0x5678 */
while(1) {
/* 主循环 */
}
}
4. 深度调试技巧与常见问题排查
即使按照示例一步步操作,在实际硬件上也可能遇到通信失败的情况。下面是我在多个项目中总结出的DSPI调试 checklist 和问题定位方法。
4.1 基础信号检查(使用逻辑分析仪或示波器)
这是最直接有效的方法。抓取SCK、PCS、MOSI、MISO四路信号。
- 有无SCK时钟?
- 无时钟:检查主设备DSPI的MCR[HALT]是否已清零(进入RUNNING状态)。检查主设备引脚配置(PCR)是否正确设置为输出。检查系统时钟和外设时钟是否已使能(模式转换是否成功)。
- 时钟频率不对:核对CTAR中
PBR和BR的计算,确认与预期的波特率相符。用示波器测量一个SCK周期,反推实际波特率。
- PCS片选信号是否动作?
- 一直为高(无效):检查主设备PUSHR命令字中的PCS字段是否设置正确(例如
0x001使能PCS0)。检查PCS引脚配置是否为输出。 - 一直为低:可能CONT位被错误设置为1,或者传输未正常结束。检查EOQ位是否在最后一帧被设置。
- 一直为高(无效):检查主设备PUSHR命令字中的PCS字段是否设置正确(例如
- MOSI/MISO数据线是否有数据?
- MOSI无数据:检查主设备PUSHR是否成功写入,TX FIFO是否使能(MCR[DIS_TXF]=0)。检查SOUT引脚配置。
- MISO无数据:检查从设备是否预先写入了PUSHR数据。检查从设备SIN/SOUT引脚配置是否正确(输入/输出方向)。 一个常见陷阱 :从设备的CTAR必须与主设备严格匹配(CPOL, CPHA),否则从设备会在错误的时钟边沿采样或输出数据。
- 数据值不对:检查LSBFE位设置,主从设备必须一致。检查逻辑分析仪的解析设置(MSB/LSB顺序)。
4.2 寄存器状态诊断
当没有仪器时,通过读取状态寄存器来诊断。
- 检查状态寄存器 (SR) :
TFFF(Transmit FIFO Fill Flag): 为1表示TX FIFO未满。如果主设备写PUSHR后此位不为1,可能FIFO已满或模块未运行。RDFF(Receive FIFO Drain Flag): 为1表示RX FIFO非空。这是判断数据是否收到的关键标志。如果一直为0,说明没有数据被接收。TFUF/RFOF(FIFO上溢/下溢标志): 如果置位,说明软件处理速度跟不上硬件,需要检查中断或轮询逻辑。TCF(Transfer Complete Flag): 一帧数据传输完成时置位。结合EOQF可以判断传输序列是否结束。EOQF(End Of Queue Flag): 当传输到带有EOQ标志的命令时置位。在SR中写1可清除。
- 验证配置寄存器 :
- 在初始化后,读取
MCR、CTAR等寄存器,确认写入的值是否正确生效。有时候写寄存器操作因为时钟域不同步需要等待几个时钟周期。
- 在初始化后,读取
4.3 常见问题速查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 完全无通信,无SCK | 1. DSPI模块时钟未使能 2. MCR[HALT]未清零 3. 引脚复用未配置到DSPI功能 |
1. 检查 ME.PCTL[] 和 ME.RUNPC[] 配置,确认外设时钟开启。 2. 确认 MCR 寄存器 HALT 位已写0。 3. 检查 SIU.PCR[] 的 PA[1:0] 位,确认选择了正确的复用功能。 |
| 有SCK,但无PCS信号 | 1. PUSHR中PCS字段设置错误 2. 该PCS引脚被配置为其他功能或输入 3. 使用了错误的CTAR(CTAS位) |
1. 确认 PUSHR 命令字中 PCS 位域正确(例如 0x001 )。 2. 检查PCS对应引脚的 PCR 配置(OBE=1, 输出功能)。 3. 确认 PUSHR 的 CTAS 位指向的CTAR已正确配置。 |
| 主设备能发不能收,或收数全为0 | 1. 从设备未预装发送数据 2. 从设备CTAR与主设备不匹配(CPOL/CPHA) 3. 主从设备SIN/SOUT引脚接反或配置错 4. 从设备处于HALT状态 |
1. 确保在主机发起传输前,从机已向 PUSHR 写入数据。 2. 重点检查 :对比主从 CTAR 的 CPOL 和 CPHA 位,必须完全相同。 3. 确认SOUT配置为输出,SIN配置为输入。 4. 检查从设备 MCR[HALT] 位。 |
| 数据位序错误 | 主从设备 LSBFE (LSB First Enable) 设置不一致 |
根据外设要求,统一设置主从设备 CTAR 中的 LSBFE 位。 |
| 通信几帧后停止 | 1. 未处理EOQF标志 2. TX FIFO被写满且未及时补充 3. 连续传输模式(CONT)使用不当 |
1. 在多帧传输中,需要在适当时候清除 SR[EOQF] 。 2. 检查 SR[TFFF] ,确保TX FIFO有空间再写入。 3. 若使用CONT,需了解其行为:PCS在帧间保持有效。 |
| 时序不满足外设要求 | CTAR中延时参数(CSSCK, ASC, DT)计算错误 | 根据外设数据手册的最小时间要求,重新计算 PCSSCK / CSSCK 、 PASC / ASC 、 PDT / DT 参数,确保计算值大于手册要求值。 |
4.4 高级调试:使用内部回环模式
如果你的芯片支持(查阅参考手册),DSPI模块通常提供内部回环测试模式。通过设置 MCR[LPEN] 位,可以将发送端直接连接到接收端,无需外部连线。这是验证DSPI模块本身和软件配置是否正确的最快方法。
- 配置DSPI为主模式,设置
MCR[LPEN]=1。 - 向
PUSHR写入测试数据。 - 从
POPR读取数据,如果与发送数据一致,则证明DSPI内核、FIFO和数据路径工作正常。问题很可能出在引脚配置或外部连接上。
5. 性能优化与扩展应用思考
当基本通信调通后,可以考虑如何提升效率和应对更复杂的场景。
5.1 利用FIFO与DMA提升效率
DSPI模块内置了深度可配置的TX和RX FIFO(通常4-16字深)。对于批量数据传输,应充分利用FIFO以减少CPU中断频率。
- 查询方式 :连续向
PUSHR写入多个数据帧,直到SR[TFFF]变为0(表示FIFO满)。然后等待SR[RDFF]变为1,再从POPR连续读取数据。这种方式比单帧单帧操作效率高得多。 - 中断方式 :使能
RSER[TFFF_RE](TX FIFO空中断)和RSER[RDFF_RE](RX FIFO非空中断)。在中断服务程序中批量填充或读取FIFO。 - DMA方式 :这是最高效的方式。将DSPI的TX和RX FIFO分别与DMA通道关联。设置DMA源地址为内存数组,目标地址为
DSPI_PUSHR;另一个DMA源地址为DSPI_POPR,目标地址为内存数组。配置好传输数量后,DMA会自动搬运数据,极大解放CPU。需要注意DMA传输宽度与SPI数据宽度的匹配,以及PUSHR命令字的构造(通常需要设置CONT和最终的EOQ)。
5.2 多从机与复杂通信协议
DSPI支持多个PCS信号,可以轻松连接多个从设备。
- 硬件连接 :每个从设备独占一个PCS线(如PCS0, PCS1, PCS2),SCK、MOSI、MISO共享。
- 软件控制 :在
PUSHR命令中,通过PCS位域选择本次传输激活哪个PCS线(例如0x001激活PCS0,0x002激活PCS1,0x003同时激活PCS0和PCS1等)。 关键点 :不同从设备可能要求不同的时序参数(CTAR)。DSPI模块通常提供多个CTAR寄存器(CTAR0-CTAR7)。你可以在初始化时为每个从设备配置一个专用的CTAR,然后在发送给该从设备的PUSHR命令中,通过CTAS位域指定使用哪个CTAR。这种灵活性使得单一SPI接口能以不同速率和时序与多个异构设备通信。
5.3 应对高速传输的引脚配置
当SPI波特率提高到MHz级别时,引脚的压摆率(Slew Rate)和驱动强度变得关键。MPC56xx的 SIU.PCR[SRC] 位域就是用来控制这个的。
SRC=0: 最低速度,最低功耗和EMI。SRC=3: 最高速度,驱动能力强,但噪声和功耗也大。- 建议 :对于超过10MHz的SCK或数据线,尝试将
SRC设置为2或3。如果发现信号边沿有过冲或振铃,可能需要串联一个小电阻(如22-100欧姆)进行阻抗匹配。始终以实际示波器观测到的信号完整性为准。
调试DSPI就像和一位严谨的伙伴对话,你必须把规则(配置)讲得清清楚楚,它才会正确响应。最初的寄存器配置看起来繁琐,但一旦你理解了每个位域背后的物理意义(时间、边沿、电平),它就成了你精确控制通信时序的强大工具。从简单的传感器读到复杂的FPGA配置,MPC56xx的DSPI模块都能胜任。希望这篇详尽的解析能帮你绕过我当年踩过的那些坑,顺利打通SPI通信的任督二脉。
更多推荐

所有评论(0)