1. MibSPI控制寄存器:从引脚到数据的全景掌控
在嵌入式开发,尤其是汽车电子和工业控制这类对实时性和可靠性要求极高的领域,SPI通信的稳定性直接决定了整个系统的成败。我们常说的SPI,其核心无非是时钟、数据线和片选,但当你真正深入到德州仪器(TI)这类厂商的微控制器内部,尤其是面对其增强型的Multi-Buffered SPI(MibSPI)模块时,你会发现事情远不止“配置几个GPIO,然后读写数据”那么简单。MibSPI通过引入硬件多缓冲区和一系列精细的控制寄存器,将SPI从一个简单的通信外设,变成了一个可编程、可诊断、高可靠的通信引擎。今天,我们就来彻底拆解MibSPI中两个最核心的寄存器组:SPIPC(引脚控制寄存器)和SPIDAT(数据寄存器)。理解它们,你才能真正驾驭MibSPI,写出既高效又健壮的底层驱动。
很多工程师拿到芯片手册,看到几十页的寄存器描述就头疼,往往选择直接拷贝参考代码。但一旦通信出现异常,比如数据错位、片选信号异常、或者开漏模式配置错误导致总线冲突,如果没有对寄存器位域的深刻理解,排查问题就如同大海捞针。SPIPC寄存器组负责管理所有SPI相关引脚(SOMI, SIMO, CLK, ENA, SCS)的“数字人格”——它们何时作为SPI功能引脚,何时作为通用GPIO,作为GPIO时输出什么电平,甚至是否启用开漏输出,都由此决定。而SPIDAT寄存器则不仅仅是发送数据的“邮箱”,它集成了数据格式选择、片选控制、传输延迟配置等高级功能,是发起一次完整SPI事务的“控制中心”。本文将结合我多年在汽车ECU开发中调试MibSPI的经验,不仅告诉你每个比特位是干什么的,更会解释为什么要这样设计,以及在实际编程中会遇到哪些坑,如何避开。
2. SPIPC引脚控制寄存器组:定义引脚的“角色”与“行为”
SPIPC寄存器组是MibSPI模块与外部物理引脚之间的“守门人”。它的核心作用是管理引脚的功能复用、数据方向(输入/输出)和输出驱动模式。在复杂的系统中,一个引脚可能需要在不同场景下扮演不同角色,例如在系统初始化时,SPI的片选引脚可能需要作为通用输出口来复位外设;在通信过程中,它又需要作为低有效的片选信号。SPIPC寄存器组提供了这种灵活切换的能力。
2.1 SPIPC2 (SPIDIN):读取引脚的真实电平状态
偏移地址:0x1C, 复位值:0x0000_0000
这个寄存器是只读的,它的唯一功能就是反映指定SPI功能引脚当前的物理电平状态,无论该引脚当前被配置为SPI功能还是通用GPIO。你可以把它看作一组连接到这些引脚上的“数字示波器探头”。
| 位域 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 31-24 | SOMIDIN | R | 反映SPISOMIx引脚(x=1~7)的当前逻辑电平。0=低电平,1=高电平。 |
| 23-16 | SIMODIN | R | 反映SPISIMOx引脚(x=1~7)的当前逻辑电平。 |
| 15-12 | NU | R | 保留位,读为0。 |
| 11 | SOMIDIN0 | R | 反映SPISOMI0引脚的当前逻辑电平。注意:对于SOMI0引脚,位11和位24(SOMIDIN)功能相同。若进行32位写操作,位11的优先级高于位24。 |
| 10 | SIMODIN0 | R | 反映SPISIMO0引脚的当前逻辑电平。注意:对于SIMO0引脚,位10和位16(SIMODIN)功能相同。若进行32位写操作,位10的优先级高于位16。 |
| 9 | CLKDIN | R | 反映SPICLK引脚的当前逻辑电平。 |
| 8 | ENADIN | R | 反映SPIENA引脚的当前逻辑电平。 |
| 7-0 | SCSDIN | R | 反映SPISCS[7:0]引脚的当前逻辑电平。注意:实际实现的位数取决于芯片综合时的NUM_CS_PINS参数。未实现的位读始终为0。 |
实际应用与避坑指南:这个寄存器在调试阶段极其有用。假设你的SPI通信失败了,第一步就应该读取SPIPC2,确认所有相关引脚的电平是否与预期一致。例如,主设备发送数据时,你可以读取SIMODIN位,看看MCU是否真的在引脚上输出了高低变化。这能快速区分是软件配置错误,还是硬件连接(如上拉电阻缺失、对地短路)问题。
注意:这里有一个关键细节,对于SOMI0和SIMO0引脚,手册提到了位优先级。这通常意味着在硅片设计时,为了节省逻辑资源或简化布线,这两个引脚的状态可能由两套逻辑中的一套来驱动。在进行32位读取时,硬件会选择位11和位10的数据。在编程时,为了代码清晰和避免混淆,建议统一使用位11(SOMIDIN0)和位10(SIMODIN0)来读取SOMI0和SIMO0的状态,忽略高字节的位24和位16。这样可以保证读取行为的一致性。
2.2 SPIPC3 (SPIDOUT):控制GPIO模式的输出值
偏移地址:0x20, 复位值:0x0000_0000
当SPI引脚被配置为通用GPIO输出模式时,SPIPC3寄存器用于设置输出到引脚上的逻辑电平。它是一个可读可写的寄存器,但写入操作仅在引脚被配置为GPIO输出时才有效。如果引脚被配置为SPI功能或GPIO输入,写入此寄存器无效。
| 位域 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 31-24 | SOMIDOUT | R/W | 设置SPISOMIx引脚(x=1~7)作为GPIO输出时的电平。 |
| 23-16 | SIMODOUT | R/W | 设置SPISIMOx引脚(x=1~7)作为GPIO输出时的电平。 |
| 15-12 | NU | R | 保留位。 |
| 11 | SOMIDOUT0 | R/W | 设置SPISOMI0引脚作为GPIO输出时的电平。注意:优先级规则同SPIPC2。 |
| 10 | SIMODOUT0 | R/W | 设置SPISIMO0引脚作为GPIO输出时的电平。注意:优先级规则同SPIPC2。 |
| 9 | CLKDOUT | R/W | 设置SPICLK引脚作为GPIO输出时的电平。 |
| 8 | ENADOUT | R/W | 设置SPIENA引脚作为GPIO输出时的电平。 |
| 7-0 | SCSDOUT | R/W | 设置SPISCS[7:0]引脚作为GPIO输出时的电平。受NUM_CS_PINS参数影响。 |
配置流程与心得:假设我们需要在初始化阶段,利用SPI的片选引脚SCS0作为一个普通的输出引脚,去控制一个外设的复位。操作步骤如下:
- 首先,需要通过SPI的引脚方向控制寄存器(通常是SPIPC1或类似的GPIO功能复用寄存器,具体需参考芯片数据手册的“PinMux”章节)将SCS0引脚的功能选择为“GPIO”模式,并将其方向设置为“输出”。
- 然后,通过写SPIPC3寄存器的SCSDOUT位域(例如,写
SCSDOUT[0] = 1)来设置SCS0引脚输出高电平或低电平。
踩坑记录:我曾遇到一个案例,工程师试图在SPI通信过程中,通过写SPIPC3来手动拉低片选,结果毫无反应。原因就是他忘了第一步——没有将引脚从“SPI功能”切换为“GPIO功能”。在SPI功能下,片选信号是由MibSPI硬件自动控制的,软件对SPIPC3的写操作是被忽略的。务必牢记:SPIPC3/4/5/6寄存器只在GPIO模式下生效。
2.3 SPIPC4 (SPIDSET) 与 SPIPC5 (SPIDCLR):高效的位操作端口
偏移地址:SPIPC4 = 0x24, SPIPC5 = 0x28, 复位值:0x0000_0000
这两个寄存器提供了对SPIPC3输出值的**位设置(SET)和位清除(CLR)**功能。这是一个非常实用的设计,可以避免“读-修改-写”操作,在多任务或中断环境中能保证操作的原子性,防止竞争条件。
- SPIPC4 (SPIDSET):向某个位写1,会将SPIPC3中对应的输出位置1(即引脚输出高电平)。写0无效。
- SPIPC5 (SPIDCLR):向某个位写1,会将SPIPC3中对应的输出位置0(即引脚输出低电平)。写0无效。
它们的位域定义与SPIPC3完全对应(SOMISET/CLR, SIMOSET/CLR等)。
为什么需要SET/CLR寄存器?想象一��场景:一个高优先级中断服务程序(ISR)需要快速改变某个GPIO的状态。如果使用直接写SPIPC3的方式,代码需要先读取SPIPC3的当前值,修改特定位,再写回去。如果在这个过程中(读取之后,回写之前),主程序或其他中断也修改了SPIPC3,那么主程序的修改就会被ISR的旧值覆盖,导致错误。而使用SET/CLR寄存器,ISR只需要执行一条SPIPC4->SCSSET = 0x01;(置位SCS0)或SPIPC5->SCSCLR = 0x01;(清零SCS0)指令,这个操作是原子的,不会被中断,确保了状态改变的可靠性。
重要提示:手册中特别注明,读取SPIPC4或SPIPC5寄存器,返回的是SPIPC3寄存器的内容,而不是SET/CLR寄存器本身的值。这是一个需要适应的设计。当你需要读取当前输出状态时,应该直接读SPIPC3。
2.4 SPIPC6 (SPIPDR):开漏输出配置
偏移地址:0x2C, 复位值:0x0000_0000
这个寄存器用于启用SPI引脚在GPIO输出模式下的开漏(Open-Drain)功能。开漏输出意味着当内部驱动为0时,引脚被强下拉到低电平;当内部驱动为1时,引脚处于高阻态(Tri-state),电平由上拉电阻决定。这在实现线与(Wire-AND)总线(如I2C)或与不同电压域器件通信时非常有用。
| 位域 | 名称 | 类型 | 描述 |
|---|---|---|---|
| ... | ... | ... | ... |
| 9 | CLKPDR | R/W | SPICLK开漏使能。生效条件:CLKDIR=1 (配置为GPIO输出)且CLKDOUT=1 (输出值为1)。0=引脚正常推挽输出高电平;1=引脚变为高阻态。 |
| ... | ... | ... | ... |
关键点解析:开漏功能的使能是有条件的:1) 引脚必须是GPIO输出模式;2) 引脚当前的输出数据值必须为1。这个逻辑非常精妙。当你想让一个引脚作为开漏输出且输出低电平时,你只需要将其输出值设为0(CLKDOUT=0),此时无论CLKPDR是0还是1,引脚都会强输出低。只有当你想让引脚“释放”总线(输出高阻态)时,你才需要同时设置输出值为1并启用开漏模式。这避免了配置顺序不当导致的瞬间短路风险。
配置示例:假设我们需要将SPICLK引脚配置为开漏输出,并初始化为高阻态(释放总线):
- 通过PinMux配置,将SPICLK设为GPIO输出模式(设置CLKDIR=1)。
- 写SPIPC3,设置CLKDOUT=1(输出逻辑1)。
- 写SPIPC6,设置CLKPDR=1(使能开漏)。此时,引脚呈现高阻态。
- 当需要驱动低电平时,直接写SPIPC5的CLKCLR位为1(这将自动清除CLKDOUT为0),引脚输出低电平。此时CLKPDR仍为1,但条件不满足(CLKDOUT=0),所以开漏功能不激活,就是普通的强下拉。
- 当需要再次释放总线时,写SPIPC4的CLKSET位为1(这将设置CLKDOUT=1),由于CLKPDR已为1,引脚立刻变为高阻态。
3. SPIDAT数据与控制寄存器:通信事务的指挥官
如果说SPIPC寄存器管理的是“士兵”(引脚)的状态,那么SPIDAT寄存器就是发布命令的“指挥官”。它定义了每次SPI通信传输什么数据、以什么格式、选择哪个从设备、以及通信结束后的行为。
3.1 SPIDAT0:基础数据传输寄存器
偏移地址:0x38, 复位值:0x0000_0000
这是一个相对简单的寄存器,主要用于MibSPI的兼容模式(Compatibility Mode)。在多缓冲模式(Multibuffer Mode)下,此寄存器不可访问,数据通过缓冲区描述符(Buffer Descriptor)来管理。
| 位域 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 31-16 | NU | R | 保留位。 |
| 15-0 | TXDATA | R/W | SPI发送数据。写入的数据会被拷贝到发送移位寄存器(如果为空),否则暂存于发送缓冲区(TXBUF)。SPIEN必须置1才能写入。读取时,返回的是TXBUF中最新写入的数据。 |
核心工作机制:
- 写入流程:当你向TXDATA写入数据时,硬件首先检查发送移位寄存器是否为空。如果为空,数据直接加载到移位寄存器,并立即开始发送(如果时钟等已配置好)。如果移位寄存器正忙,数据则被存入一个深度的TXBUF中排队。TXFULL标志位(在SPIBUF寄存器中)用于指示TXBUF是否已满。
- 读取流程:读取SPIDAT0,返回的不是正在移位发送的数据,而是TXBUF里下一次将要发送的数据。这可以用来检查队列状态。
- 数据对齐:无论字符长度(CHARLEN)如何,发送数据都必须右对齐写入。例如,即使你配置为8位数据长度,你也需要将数据放在TXDATA[7:0]的位置,高位补0。这是很多新手容易出错的地方。
- 格式选择:默认使用SPIFMT0寄存器定义的数据格式(时钟极性、相位、长度等)。但可以通过SPIDAT1寄存器的DFSEL字段,在写入SPIDAT0前临时选择其他格式寄存器(SPIFMT1/2/3)。
3.2 SPIDAT1:增强型控制与数据传输寄存器
偏移地址:0x3C, 复位值:0x0000_0000
这是MibSPI功能强大的体现,它集成了数据传输、片选控制、延时插入和格式选择于一身。当需要使用自动片选功能时,必须使用SPIDAT1进行写入操作。
| 位域 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 31-29 | NU2 | R | 保留位。 |
| 28 | CSHOLD | R/W | 片选保持模式(仅主模式有效)。1=在一次传输结束后,片选信号保持有效,直到新的带有数据和控>制信息的SPIDAT1被写入。0=传输结束后,经过T2CDELAY时间,片选信号失效。 |
| 27 | NU1 | R | 保留位。 |
| 26 | WDEL | R/W | 使能等待延迟计数器(仅主模式有效)。1=当前事务结束后,加载对应数据格式的WDELAY值到延迟计数器,延迟期间不进行新事务。片选引脚将至少失效(WDELAY + 2)个VCLK周期。 |
| 25-24 | DFSEL | R/W | 数据格式选择。00=格式0,01=格式1,10=格式2,11=格式3。选择本次传输使用的SPIFMTx寄存器。 |
| 23-16 | CSNR | R/W | 片选编号。定义本次传输激活哪个片选信号。CSNR[7:0]的值将驱动到SPISCS[7:0]引脚上。受NUM_CS_PINS参数影响。 |
| 15-0 | TXDATA | R/W | SPI发送数据。功能同SPIDAT0,但写入此寄存器会同时触发CSNR指定的片选引脚动作。 |
高级功能深度解析:
CSHOLD(片选保持):
- 作用:在一次SPI数据传输(例如,发送16位数据)结束后,控制片选信号是立即释放,还是继续保持有效。
- 应用场景:某些SPI从设备(如一些ADC或存储器)需要在一个连续的“命令-数据”序列中保持片选有效。设置CSHOLD=1,可以在发送命令字后不释放片选,紧接着写入SPIDAT1发送数据字,从而实现背靠背(back-to-back)传输,中间片选不会出现毛刺。这提高了通信效率和可靠性。
- 工作原理:当CSHOLD=1时,传输结束硬件不会自动拉高片选。它会一直保持有效,直到你写入一个新的SPIDAT1(即使CSNR相同)。如果你写入的新CSNR和之前不同,片选会先释放再拉低新的;如果相同,则继续保持有效。要结束保持,你需要写入一个CSHOLD=0的SPIDAT1,或者直接禁用SPI模块。
WDEL(等待延迟):
- 作用:在两个连续的SPI传输之间插入一个可编程的延迟。
- 应用场景:某些慢速从设备在两次操作之间需要一定的恢复时间(t_REC)。��用硬件WDELAY可以精确控制这个间隔,解放CPU,避免使用软件空循环等待,提高系统实时性。
- 配置联动:WDELAY的时间长度不是在SPIDAT1里配置的,而是在对应的SPIFMTx寄存器中。SPIDAT1的WDEL位只是一个“开关”,决定本次传输后是否插入该格式寄存器中预设的延迟。
DFSEL(数据格式选择)与CSNR(片选编号)的预选技巧:
- 手册的Note里提到了一个高级技巧:可以仅写入SPIDAT1的控制字段(CSHOLD, WDEL, DFSEL, CSNR)而不写入TXDATA数据字段(例如通过字节写入操作)。这在主模式下不会启动SPI传输。
- 有什么用?你可以在实际数据传输之前,提前配置好下一次传输要用的时钟极性/相位(通过DFSEL选择不同的SPIFMTx)和片选信号(CSNR)。这样,当你真正写入数据发起传输时,片选和时钟信号能立即以正确的格式生效,避免了第一次传输因配置切换可能产生的信号毛刺。这对于需要动态切换通信参数的场景非常有用。
SPIDAT1写入操作流程示例:假设我们要向片选0(CS0)连接的设备,使用数据格式1(8位数据,CPOL=0, CPHA=0),发送数据0x55,并且传输后不保持片选。
// 假设 SPIEN 已经使能,SPIFMT1 已正确配置 // 构造 SPIDAT1 写入值 // CSHOLD=0, WDEL=0, DFSEL=01 (格式1), CSNR=0x01 (激活CS0), TXDATA=0x55 uint32_t spidat1_value = (0 << 28) | // CSHOLD = 0 (0 << 26) | // WDEL = 0 (1 << 24) | // DFSEL = 01b (选择格式1) (0x01 << 16) | // CSNR = 1 (二进制0000_0001,拉低CS0) (0x0055); // TXDATA = 0x55,右对齐 // 写入寄存器,启动传输 MIBSPI_REG->SPIDAT1 = spidat1_value;4. SPIBUF:状态与数据的汇聚点
偏移地址:0x40, 复位值:0x8000_0000
SPIBUF寄存器是一个只读寄存器,它是了解MibSPI工作状态和获取接收数据的核心窗口。它分为高16位的状态字段和低16位的数据字段。
4.1 状态字段详解:通信的“健康监测仪”
状态字段的每一个位都代表了通信过程中可能发生的一种特定事件或错误。
- RXEMPTY (位31):接收缓冲区空标志。为1表示自上次读取SPIBUF后,没有新数据收到。为0表示有新数据已存入RXDATA。读取RXDATA或整个SPIBUF寄存器会自动将此位置1。
- RXOVR (位30):接收溢出标志。这是最需要警惕的错误之一。当一次传输完成,接收数据要存入RXBUF,但RXBUF已满时,此位置1。关键点:溢出发生在RXBUF,而SPIBUF本身的内容不会被覆盖。你需要连续读取两次SPIBUF才能读到溢出时丢失的那个数据。第一次读取出的是溢出前SPIBUF里的旧数据,读完后,RXBUF里的数据(即溢出时接收的数据)会移动到SPIBUF,第二次读取才能得到它。
- TXFULL (位29):发送缓冲区满标志。为1表示TXBUF已满,此时写入SPIDATx会失败(数据丢失)。为0表示可以写入新数据。
- BITERR (位28):位错误标志。主模式时,MibSPI会在发送数据半个时钟周期后,采样SIMO线上的实际电平,与预期发送值比较。如果不一致,则置位。可能原因:总线冲突、噪声干扰、波特率过高或负载电容过大。
- DESYNC (位27):从设备失步标志(仅主模式)。主设备监控ENA线,如果从设备在最后一个接收点之前或最后一个比特发送后的T2EDELAY时间之后,提前释放了ENA,此位置1。表明从设备可能漏掉了主设备的时钟。
- PARITYERR (位26):奇偶校验错误标志。如果使能了奇偶校验,此位指示接收到的校验位与计算值不匹配。
- TIMEOUT (位25):超时标志(仅主模式)。主设备激活片选后,从设备未能在规定时间内通过ENA线响应,则置位。
- DLENERR (位24):数据长度错误标志。当接收到的数据位数与配置的字符长度不符时置位。
- LCSNR (位23-16):上一次传输使用的片选编号。这是从SPIDAT1的CSNR字段锁存过来的,用于诊断最后一次通信是针对哪个从设备。
4.2 数据字段与状态清除机制
- RXDATA (位15-0):接收到的数据。无论字符长度和移位方向如何,数据总是右对齐存储。这是读取接收数据的唯一入口。
- 状态清除的统一机制:除了TXFULL和LCSNR,其他所有状态标志(RXOVR, BITERR, DESYNC, PARITYERR, TIMEOUT, DLENERR)都在读取RXDATA字段(或整个SPIBUF寄存器)时被自动清除。同时,读取操作也会将RXEMPTY置1。这种设计简化了编程,一次读取操作既拿到了数据,也清除了相关中断标志(如果使能了中断)。但务必注意,对于RXOVR错误,需要两次读取操作才能完全处理。
5. 实战配置流程与常见问题排查
理解了寄存器,最终要落到代码上。下面是一个典型的主模式MibSPI初始化及单次传输流程,并附上常见问题排查表。
5.1 主模式初始化与单次传输代码框架
// 假设寄存器基地址定义为 MIBSPI1 #define MIBSPI1_BASE (0xFFF7F800UL) typedef volatile struct { ... // 其他寄存器 uint32_t SPIPC2; // 0x1C uint32_t SPIPC3; // 0x20 uint32_t SPIPC4; // 0x24 uint32_t SPIPC5; // 0x28 uint32_t SPIPC6; // 0x2C uint32_t SPIDAT0; // 0x38 uint32_t SPIDAT1; // 0x3C uint32_t SPIBUF; // 0x40 ... // 其他寄存器 } MibSpi_Reg; #define MIBSPI1 ((MibSpi_Reg *)MIBSPI1_BASE) void MibSPI1_Master_Init(void) { // 1. 引脚复用配置 (通过芯片特定的PINMUX寄存器,非SPIPC) // 将 SIMO, SOMI, CLK, SCS0 引脚功能设置为 SPI(主模式) // 例如:PINMUX_REG->SPI1_SIMO_SEL = SPI_FUNC; // PINMUX_REG->SPI1_SCS0_SEL = SPI_FUNC; // 2. 配置 SPI 格式寄存器 (SPIFMT0),例如:8位数据,CPOL=0, CPHA=0 MIBSPI1->SPIFMT0 = (0 << 24) | // SHIFTDIR, 0=MSB first (7 << 16) | // CHARLEN = 7,表示8位字符 (CHARLEN+1) (0 << 8) | // PRESCALE,时钟预分频 (0 << 6) | // POLARITY,时钟极性 (0 << 4); // PHASE,时钟相位 // 3. 使能 SPI 模块,配置为主模式 // 假设 SPIGCR1 寄存器控制全局使能和模式 MIBSPI1->SPIGCR1 |= (1 << 24); // 设置 SPIEN = 1,使能模块 MIBSPI1->SPIGCR1 |= (1 << 0); // 配置为主模式 (具体位参考手册) } uint16_t MibSPI1_Transfer(uint8_t cs_num, uint16_t data) { uint32_t spidat1_val; uint16_t received_data; // 4. 等待发送缓冲区不为满(非必须,但建议在首次发送前检查) while((MIBSPI1->SPIBUF & (1 << 29)) != 0); // 等待 TXFULL 为 0 // 5. 组装 SPIDAT1 控制字并写入,启动传输 // CSHOLD=0, WDEL=0, DFSEL=00(格式0), CSNR=cs_num, TXDATA=data spidat1_val = (0 << 28) | (0 << 26) | (0 << 24) | ((1 << cs_num) << 16) | data; MIBSPI1->SPIDAT1 = spidat1_val; // 6. 等待接收完成(轮询方式) while((MIBSPI1->SPIBUF & (1 << 31)) != 0); // 等待 RXEMPTY 为 0 // 7. 读取接收数据(同时清除状态标志) received_data = (uint16_t)(MIBSPI1->SPIBUF & 0xFFFF); // 8. (可选)检查错误标志 uint32_t status = MIBSPI1->SPIBUF; if(status & ((1<<30)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24))) { // 处理错误:RXOVR, BITERR, DESYNC, PARITYERR, TIMEOUT, DLENERR // 例如,重试或记录日志 } return received_data; }5.2 常见问题排查速查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 无时钟输出 | 1. SPI模块未使能(SPIEN=0)。 2. 引脚功能未配置为SPI。 3. 格式寄存器(SPIFMT)配置错误,如PRESCALE分频过大。 4. 主模式未正确设置。 | 1. 检查SPIGCR1.SPIEN位。 2. 检查芯片PINMUX寄存器,确认CLK引脚功能。 3. 读取SPIFMTx寄存器,确认配置值。 4. 检查主/从模式配置位。 |
| 片选信号异常 | 1. 未使用SPIDAT1写入(自动片选)或手动GPIO控制时序不对。 2. CSNR位设置错误(例如,想选CS0却写了CSNR=0x02)。 3. CSHOLD位理解错误,导致片选一直有效。 4. 引脚被配置为GPIO输入或其它功能。 | 1. 确认使用SPIDAT1并正确设置CSNR。 2. 记住CSNR是位掩码,激活CS0应写0x01。 3. 检查SPIDAT1的CSHOLD位,传输后是否需要手动拉高片选。 4. 读取SPIPC2的SCSDIN,观察片选引脚实际电平。 |
| 发送数据,但接收全为0或0xFF | 1. 从设备未就绪或连接错误。 2. 时钟极性(CPOL)和相位(CPHA)与从设备不匹配。 3. SOMI/SIMO线接反。 4. 从设备需要特定命令序列才回复。 | 1. 用逻辑分析仪抓取CLK, SIMO, SOMI, CS信号,对比从设备时序要求。 2. 调整SPIFMT中的POLARITY和PHASE位,共有4种模式(0,0),(0,1),(1,0),(1,1)。 3. 交换主设备的SIMO和SOMI连接(如果硬件允许)。 4. 查阅从设备数据手册,确认通信协议。 |
| 出现BITERR错误 | 1. 总线冲突(多主设备或引脚配置冲突)。 2. 通信速率过高,信号质量差。 3. 外部干扰。 | 1. 检查是否有其他驱动源在控制SPI总线。检查SPIPC6是否误配置为开漏导致冲突。 2. 降低SPIFMT中的波特率预分频(PRESCALE)。 3. 检查PCB布线,缩短走线,增加串联电阻。 |
| RXOVR接收溢出 | 1. 主设备发送过快,从设备来不及处理,或主设备未及时读取数据。 2. 中断服务程序未及时处理接收中断。 | 1. 降低发送频率,或在发送下一字节前检查TXFULL和RXEMPTY标志。 2. 确保在使能接收中断前,SPIBUF是空的。在中断服务程序中及时读取SPIBUF。如果发生溢出,必须连续读取两次SPIBUF以恢复。 |
| DESYNC失步错误 | 1. 从设备未能及时响应ENA信号。 2. T2CDELAY(ENA失效延迟)时间配置过短。 | 1. 确认从设备支持ENA流控且已正确使能。 2. 增加SPIFMT中与T2CDELAY相关的参数(如果可配)。检查从设备对ENA时序的要求。 |
掌握MibSPI的SPIPC和SPIDAT寄存器组,意味着你掌握了精准控制SPI通信每一个细节的能力。从引脚的电气特性到通信协议的时间序,都能通过配置这些寄存器来实现。调试时,养成习惯:先查配置(SPIFMT, SPIDAT1),再看状态(SPIBUF高16位),最后用SPIPC2读引脚电平验证硬件。把这张寄存器的地图印在脑子里,再复杂的SPI通信问题,也能一步步拆解定位。