1. MibSPI传输组:从硬件缓冲到高效数据流控的桥梁
在嵌入式开发,尤其是汽车电子和工业控制这类对实时性和可靠性要求极高的领域,SPI通信的效率直接决定了系统的响应速度和整体性能。传统的SPI模块,数据收发往往需要CPU频繁介入,进行数据搬运和状态轮询,这在处理连续、多通道数据流时,CPU负载会急剧上升,成为系统瓶颈。为了解决这个问题,像TI Hercules系列微控制器中集成的MibSPI(Multi-buffered SPI)模块,引入了一个堪称“硬件DMA”的机制——传输组(Transfer Group, TG)。它远不止是一个简单的缓冲区,而是一个集成了触发、优先级、中断和自动序列控制的硬件状态机。
你可以把每个传输组想象成一个预先编排好的“播放列表”。这个列表里包含了一连串需要发送和接收的数据帧(每个帧对应一个缓冲区)。而TGxCTRL寄存器,就是这个播放列表的“控制面板”。通过配置这个面板,你可以决定:这个列表何时开始播放(触发源和触发事件)、是播一遍就停还是循环播放(单次/连续模式)、播放时如果被打断怎么办(指针复位模式)、以及播放开始或结束时要不要通知CPU(中断使能)。这种将数据流控制逻辑从软件转移到硬件的做法,极大地解放了CPU,使其能够专注于更上层的应用逻辑,同时确保了数据传输的确定性和低延迟。
理解TGxCTRL的每一个比特,就等于掌握了指挥MibSPI硬件交响乐团的关键。接下来,我们将深入这个控制面板的每一个旋钮和开关。
2. TGxCTRL寄存器全景与核心字段深度解析
TGxCTRL寄存器是每个传输组(TG0, TG1, ..., TG15)的神经中枢,其位域定义是理解传输组行为的关键。根据技术手册,其结构布局清晰,每个字段都承担着特定的控制功能。下面,我们结合一个典型的寄存器位域图(以TG0CTRL为例,偏移地址0x98)来逐一拆解。
寄存器位域概览 (TGxCTRL - 例如 TG0CTRL @ 0x98):
| 位域 (Bits) | 字段名 (Field) | 类型 | 复位值 | 功能简述 |
|---|---|---|---|---|
| 31 | TGENA | R/W | 0 | 传输组使能。1=使能,等待触发;0=禁用。 |
| 30 | ONESHOT | R/W | 0 | 单次传输模式。1=触发后只执行一次组传输;0=连续模式。 |
| 29 | PRST | R/W | 0 | 指针复位模式。影响触发事件在传输中的处理方式。 |
| 28 | TGTD | R | 0 | (只读)传输组触发状态。1=已被触发(等待或正在服务);0=空闲。 |
| 27-24 | NU | R | 0 | 保留位。 |
| 23-20 | TRIGEVT | R/W | 0 | 触发事件类型。定义何种信号变化能触发传输。 |
| 19-16 | TRIGSRC | R/W | 0 | 触发源选择。选择触发信号来自哪个内部或外部源。 |
| 15-8 | PSTART | R/W | 0 | 传输组起始缓冲区指针。定义本组数据在缓冲区RAM中的起始地址。 |
| 7-0 | PCURRENT | R | 0 | (只读)当前缓冲区指针。指示即将传输或正在传输的缓冲区地址。 |
2.1 传输使能与触发状态:TGENA与TGTD的协同
TGENA是传输组的总开关。将其置1,并不意味着传输立即开始,而是告诉MibSPI硬件:“这个传输组已经准备就绪,请监听指定的触发条件(TRIGSRC和TRIGEVT)”。一旦触发条件满足,且满足优先级规则(即没有更高优先级的传输组正在占用总线),传输才会启动。
这里有一个至关重要的细节:TGENA在单次模式(ONESHOT=1)下的行为。当一次组传输(即从PSTART开始到组结束地址PEND的所有缓冲区传输完毕)完成后,硬件会自动将TGENA清零。这个设计非常巧妙,它确保了在单次模式下,一次触发不会意外导致传输重复执行,同时也给了软件一个明确的“传输完成”状态标志(无需单独查询中断标志位)。软件必须在下次需要传输前,重新置位TGENA。而在连续模式(ONESHOT=0)下,TGENA会一直保持为1,直到软件主动将其清零。
TGTD是一个只读的状态位,它反映了传输组在MibSPI内部调度器中的状态。当TGTD=1时,表示该传输组已经接收到了一个有效的触发事件,并且这个“任务”已经被提交到调度队列中。它可能正在等待更高优先级的传输组完成(“等待服务”),也可能正在被序列器(Sequencer)处理(“正在服务”)。要区分这两种状态,需要结合查询LTGPEND寄存器中的TGINSERVICE字段。TGTD位在传输组被触发后置位,在整个组传输完成后(对于单次模式)或当传输组被软件禁用时清零。监控TGTD位有助于软件了解硬件的调度状态,特别是在调试复杂的多传输组交互时。
实操心得:在初始化一个传输组时,标准的操作顺序应该是:先配置
PSTART、TRIGEVT、TRIGSRC、ONESHOT等所有参数,最后再置位TGENA。这样可以避免在配置过程中,因意外满足触发条件而启动非预期的传输。对于单次模式,在中断服务程序中,如果计划再次启动同一组传输,除了要重新填充缓冲区数据外,必须记得重新置位TGENA,这是一个常见的疏忽点。
2.2 传输模式控制:ONESHOT与PRST的博弈
ONESHOT和PRST这两个位共同决定了传输组的“节奏”和“韧性”,它们的组合能实现多种实用的数据传输策略。
ONESHOT(单次模式):此模式是精确控制单次数据块传输的利器。设为1时,一次有效的触发只会导致该传输组完整地执行一遍(从起始指针到结束指针)。完成后TGENA自动清零,如同一个单稳态电路。这非常适合需要精确同步、非周期性的数据交换场景,例如响应一个外部事件(如按键按下)后,发送一串特定的配置命令给传感器。
PRST(指针复位模式):这个位专门用于电平触发(TRIGEVT配置为high-active或low-active)的场景。它定义了当一个新的触发事件到来时,如果本传输组自己的传输还在进行中,硬件该如何处理。
PRST = 0(默认):传输优先。正在进行的传输组传输拥有最高优先级,在此期间到来的新触发事件被忽略。这保证了当前数据块的完整性,适用于数据包必须连续、不可被打断的场合,如通信协议帧的发送。PRST = 1:触发优先。任何新的触发事件都会立即将当前缓冲区指针PCURRENT重置回起始地址PSTART,并从头开始新一轮传输。这相当于一个“重启”信号。这在某些实时控制中非常有用,例如,用一个高电平信号使能一个模拟采样循环,而当需要立即刷新采样序列时,通过一个脉冲(新的触发事件)即可让采样序列立刻从头开始,而不必等待当前序列完成。
重要提示:技术手册明确指出,
PRST位仅对电平触发模式有意义。对于边沿触发(rising edge,falling edge,both edges),其行为是固定的:一个边沿触发一次传输,在本次传输完成前,后续边沿不会被响应。PRST位不会改变这一行为。理解这一点可以避免配置错误。
2.3 触发引擎:TRIGSRC与TRIGEVT的精密配置
触发机制是MibSPI传输组的灵魂,TRIGSRC(触发源)和TRIGEVT(触发事件)的配置赋予了传输组自动启动的灵活性。
TRIGSRC[3:0](触发源选择):这是一个4位的选择器,决定了触发信号从何而来。
0000b:禁用。这是复位后的默认值,意味着传输组只能通过软件方式触发(见下文TRIGEVT的always模式)。0001b至1110b:外部触发源 (EXT0 ~ EXT13)。这些是芯片引脚级别的硬件触发信号,具体映射到哪个物理引脚或内部外设(如HET模块的输出),需要查阅具体芯片的数据手册。这允许ADC转换完成、定时器匹配、GPIO变化等外部事件直接启动SPI传输,实现极低延迟的硬件联动。1111b:内部Tick计数器 (TICK)。这是MibSPI模块内置的一个可编程定时器(由TICKCNT寄存器控制)。选择此源,可以产生周期性的触发,实现纯硬件定时的数据传输,无需CPU或外部信号干预,是产生固定频率采样或通信心跳包的理想选择。
TRIGEVT[3:0](触发事件类型):定义了所选触发源上何种变化被视为有效触发。
0000b:never。永远不会触发。可用于临时禁用某个触发源,或用于纯软件查询模式。0001b:rising edge。上升沿触发。0010b:falling edge。下降沿触发。0011b:both edges。双边沿触发。每个边沿都会启动一次传输。0101b:high-active。高电平有效。只要触发源为高电平,传输组就会连续、循环执行(除非ONESHOT=1)。电平变低会中止当前循环。0110b:low-active。低电平有效。逻辑与high-active相反。0111b:always。软件触发模式的关键。当TRIGSRC设置为disabled (0000b),TRIGEVT设置为always (0111b)时,传输组的触发完全由TGENA位控制。置位TGENA的瞬间,就会立即触发一次传输。这为软件直接、即时地启动传输提供了途径。结合ONESHOT=1,可以实现精确的软件单次触发。
组合应用实例:假设我们需要每1毫秒通过SPI读取一次温度传感器数据。我们可以:
- 配置MibSPI的Tick计数器(
TICKCNT),使其产生1ms周期的脉冲。 - 设置
TRIGSRC = TICK (1111b),TRIGEVT = rising edge (0001b)。 - 设置
ONESHOT = 1,这样每个Tick上升沿触发一次完整的传感器数据读取序列。 如此一来,一个精准的1ms定时采样任务就完全由硬件接管了,CPU只在数据就绪中断中处理数据即可,极大地提高了系统效率。
2.4 缓冲区指针管理:PSTART与PCURRENT的职责
PSTART定义了传输组在MibSPI缓冲区RAM中的“地盘”起点。它是一个可读写的寄存器,由软件在初始化时设置。一个传输组能管理多少缓冲区,并不直接由TGxCTRL决定,而是由PSTART和下一个传输组的PSTART(或LTGPEND寄存器中的LPEND,对于最后一个传输组)隐式定义。例如,TG0的结束地址PEND0 = PSTART1 - 1。这种链表式的设计使得内存划分非常灵活。
PCURRENT是一个只读的“进度指示器”。它实时指向下一个将要被传输的缓冲区地址。当传输组被使能但未触发时,PCURRENT等于PSTART。传输开始后,每完成一个缓冲区的传输,PCURRENT自动递增。在“挂起等待”(Suspend-to-Wait)模式下,PCURRENT会停在当前被挂起的缓冲区地址,恢复后从此地址继续。通过读取PCURRENT,软件可以精确知道传输进度,这在处理可变长度数据或动态调整传输内容时非常有用。
注意事项:
PSTART和PCURRENT指向的是缓冲区编号(索引),而不是绝对内存地址。MibSPI硬件会根据缓冲区索引和预设的数据格式(字长)自动计算实际的数据RAM地址。在配置时,必须确保为每个传输组分配的缓冲区索引范围是连续且不重叠的,否则会导致数据覆盖或传输错误。
3. 从零构建一个传输组:配置流程与实战代码
理解了各个字段的含义后,我们来看如何将它们组合起来,完成一个传输组从初始化到工作的完整配置流程。这里以一个常见的场景为例:使用TG0,通过外部GPIO上升沿触发,单次发送10个字节的数据帧。
3.1 步骤一:全局规划与缓冲区划分
在动任何一个寄存器之前,必须进行全局规划。假设MibSPI有128个缓冲区,我们需要为TG0分配10个缓冲区(索引0-9),用于存放10字节的待发送数据。那么:
TG0.PSTART = 0(起始缓冲区索引)TG0的结束缓冲区索引PEND0由TG1.PSTART决定。如果我们暂时只用TG0,那么TG1.PSTART应设置为10。或者,如果TG0是最后一个使能的组,我们也可以通过LTGPEND寄存器的LPEND字段直接设置PEND0=9。这里我们采用前者,即同时初始化TG1.PSTART = 10。
3.2 步骤二:配置TGxCTRL寄存器
这是核心配置步骤。我们需要计算或组合出TG0CTRL寄存器的32位值。
确定触发源和事件:假设我们使用芯片的“EXT0”作为触发源,它映射到某个GPIO引脚。我们希望在该引脚出现上升沿时触发。查手册得知
EXT0对应TRIGSRC = 0001b,上升沿对应TRIGEVT = 0001b。确定工作模式:我们希望是单次触发模式,即一个上升沿发送完10个缓冲区数据后停止,等待下次触发。所以
ONESHOT = 1。确定指针复位模式:由于是边沿触发,
PRST位无效,我们设为默认值0。设置起始指针:
PSTART = 0(十进制0,二进制8‘b00000000)。组合寄存器值:
- Bit 31 (
TGENA): 我们先配置,先不使能,设为0。 - Bit 30 (
ONESHOT):1。 - Bit 29 (
PRST):0。 - Bits 23-20 (
TRIGEVT):0001b, 在32位寄存器中,这部分位于高字节,需要左移。0001b是4位,对应十六进制0x1。左移20位后为0x1 << 20 = 0x00100000。 - Bits 19-16 (
TRIGSRC):0001b, 十六进制0x1。左移16位后为0x1 << 16 = 0x00010000。 - Bits 15-8 (
PSTART): 0, 左移8位后还是0。 - 其他位(TGTD只读,NU保留)均为0。
因此,
TG0CTRL的配置值(十六进制)为:ONESHOT位在bit30,值为1<<30 = 0x40000000。加上触发配置:0x40000000 | 0x00100000 | 0x00010000 = 0x40110000。- Bit 31 (
3.3 步骤三:编写初始化代码(C语言示例)
以下是一个基于TI Hercules系列MCU的简化的、可直接参考的初始化函数。假设我们已定义了相关的寄存器映射指针。
#include “sys_common.h“ // 包含标准类型定义 // 假设 MibSPI1 寄存器基地址已定义 #define MIBSPI1_BASE (0xFFF7F800U) #define MIBSPI1_REG(offset) (*(volatile uint32 *)(MIBSPI1_BASE + (offset))) // TGxCTRL 寄存器偏移量 (TG0CTRL = 0x98, TG1CTRL = 0x9C, ...) #define TG0CTRL_OFFSET (0x98) #define TG1CTRL_OFFSET (0x9C) #define LTGPEND_OFFSET (0x94) // 触发源和事件宏定义 (根据具体手册) #define TRIGSRC_EXT0 (0x1U) #define TRIGEVT_RISING_EDGE (0x1U) void init_MibSPI1_TransferGroup0(void) { uint32 tg0_ctrl_value = 0; uint32 tg1_ctrl_value = 0; // 1. 首先,确保TG0和TG1被禁用 // TGENA位是bit31,清零它。我们通过写入一个除TGENA外其他位都正确的值来配置,但先不使能。 // 实际上,更安全的做法是先读取,清除TGENA位,再写回。这里为清晰起见直接赋值。 // 2. 配置TG0CTRL (单次、上升沿触发、EXT0源、PSTART=0) tg0_ctrl_value = (1U << 30); // ONESHOT = 1 tg0_ctrl_value |= (TRIGEVT_RISING_EDGE << 20); // TRIGEVT[3:0] @ bits 23-20 tg0_ctrl_value |= (TRIGSRC_EXT0 << 16); // TRIGSRC[3:0] @ bits 19-16 tg0_ctrl_value |= (0U << 8); // PSTART[7:0] = 0 @ bits 15-8 // TGENA=0, PRST=0 已默认 MIBSPI1_REG(TG0CTRL_OFFSET) = tg0_ctrl_value; // 写入配置,此时TGENA=0,传输组未使能 // 3. 配置TG1CTRL,主要目的是定义TG0的结束边界。 // 我们暂时不使用TG1,但需要设置它的PSTART来界定TG0的结束。 // 假设TG0使用缓冲区0-9,则TG1的PSTART应为10。 tg1_ctrl_value = (10U << 8); // 只设置PSTART=10,其他位保持0(禁用状态) MIBSPI1_REG(TG1CTRL_OFFSET) = tg1_ctrl_value; // 4. (可选)如果TG0是最后一个使能的组,也可以选择配置LTGPEND.LPEND // MIBSPI1_REG(LTGPEND_OFFSET) = (9U << 8); // LPEND字段在bits 15-8 // 5. 填充TG0对应的缓冲区数据 (缓冲区0到9) // 这里需要操作MibSPI的数据缓冲区RAM,地址通常有特定映射。 // 假设有一个函数或宏可以写入缓冲区:write_mibspi_tx_buffer(buffer_index, data); for (int i = 0; i < 10; i++) { // write_mibspi_tx_buffer(i, my_tx_data[i]); } // 6. 最后,使能传输组TG0,使其进入等待触发状态 // 通过置位TGENA位来使能。注意:直接写1到bit31会覆盖其他位,所以最好使用“读-改-写” uint32 temp = MIBSPI1_REG(TG0CTRL_OFFSET); temp |= (1U << 31); // 设置TGENA=1 MIBSPI1_REG(TG0CTRL_OFFSET) = temp; // 现在,TG0已配置并使能。当连接到EXT0的GPIO引脚出现上升沿时, // TG0将自动从缓冲区0开始,连续发送10个数据帧,完成后自动停止(TGENA被清零)。 }3.4 步骤四:中断配置与处理
高效的传输组使用离不开中断。MibSPI为每个传输组提供了“传输完成”和“传输挂起”两种中断。我们需要配置相应的中断使能寄存器(TGITENSR)和中断级别寄存器(TGITLVST/TGITLVCR)。
// 假设中断向量号、使能位等已定义 #define TG0_INT_ENABLE_BIT_RDY (1U << 16) // TG0完成中断使能位在TGITENSR寄存器中的位置 #define TG0_INT_LEVEL_BIT_RDY (1U << 16) // TG0完成中断级别设置位在TGITLVST中的位置 void enable_TG0_interrupt(void) { // 1. 设置中断级别:将TG0的“传输完成”中断映射到INT1线(假设INT1优先级更高) // TGITLVST: 写1将中断级别设置为INT1 MIBSPI1_REG(0x7C) |= TG0_INT_LEVEL_BIT_RDY; // SETINTLVLRDY for TG0 // 2. 使能TG0的“传输完成”中断 // TGITENSR: 写1使能中断 MIBSPI1_REG(0x74) |= TG0_INT_ENABLE_BIT_RDY; // SETINTENRDY for TG0 // 3. 在VIM(向量中断管理器)或类似模块中,使能MibSPI的INT1中断线,并注册中断服务函数。 // enable_irq(MIBSPI1_INT1_IRQn); // register_isr(MIBSPI1_INT1_IRQn, my_mibspi_isr); } // 中断服务函数示例 void my_mibspi_isr(void) { // 1. 检查中断标志,确认是TG0的“完成”中断 uint32 intflags = MIBSPI1_REG(0x84); // TGINTFLAG寄存器 if (intflags & (1U << 16)) { // 检查INTFLGRDY for TG0 // 2. 处理接收到的数据 (从缓冲区0-9读取) // for (int i = 0; i < 10; i++) { // my_rx_data[i] = read_mibspi_rx_buffer(i); // } // 3. 清除中断标志 (写1清除) MIBSPI1_REG(0x84) = (1U << 16); // 写1清除TG0的完成中断标志 // 4. 如果是单次模式(ONESHOT=1),TGENA已被硬件清零。 // 如果需要再次传输,需重新填充缓冲区并置位TGENA。 // 例如:MIBSPI1_REG(TG0CTRL_OFFSET) |= (1U << 31); } // ... 处理其他中断源 }4. 高级应用场景与配置策略
掌握了基础配置后,我们可以利用TGxCTRL寄存器的灵活性,实现更复杂的通信策略。
4.1 场景一:多传输组优先级调度与抢占
MibSPI的传输组具有固定的硬件优先级,通常TG0优先级最高,TG15最低。高优先级传输组可以抢占低优先级传输组。TGxCTRL配置如何影响这一行为?
关键在于理解“传输中”的状态。当一个低优先级传输组(如TG2)正在传输时,如果高优先级传输组(如TG0)的触发条件满足,会发生什么?这取决于TG2的TRIGEVT模式和PRST设置。
- 如果TG2是边沿触发,且
PRST=0(默认),则TG0必须等待TG2的整个组传输完成(即从PSTART到PEND的所有缓冲区),才能开始。这是非抢占式的。 - 如果TG2是电平触发(高/低有效),情况则不同。电平触发模式下,只要触发信号有效,传输就会循环进行。当高优先级TG0触发时,MibSPI硬件会立即挂起TG2的当前缓冲区传输(注意,不是整个组),转去服务TG0。TG0完成后,再恢复TG2。TG2的
PCURRENT会记住被挂起的位置。这是抢占式的。
配置策略:对于需要快速响应的紧急事件(如故障信号采集),应分配高优先级传输组(如TG0/TG1),并可能使用边沿触发+单次模式,确保其传输不被意外打断。对于后台、连续的数据流(如周期性状态上报),可以使用低优先级传输组,并采用电平触发或Tick触发,允许被高优先级任务抢占。
4.2 场景二:利用Tick计数器实现精确定时传输
内部Tick计数器是实现无CPU干预的周期性传输的完美工具。配置流程如下:
配置TICKCNT寄存器:
TICKVALUE:设置重载值。Tick时钟源频率 / 所需触发频率 = TICKVALUE。例如,SPICLK为10MHz,需要1kHz触发,则TICKVALUE = 10e6 / 1e3 = 10000。CLKCTRL:选择Tick计数器的时钟源,通常选择与SPI通信时钟同源的SPICLK。TICKENA:使能Tick计数器。RELOAD:写入1可手动重载计数器(可选)。
配置TGxCTRL:
TRIGSRC = TICK (1111b)。TRIGEVT:通常选择rising edge (0001b)或falling edge (0010b),取决于Tick计数器下溢时产生的触发脉冲极性。查看芯片手册确认。ONESHOT:根据需求选择。若需要严格的等间隔单次传输,选1;若需要连续不断的循环传输,选0。- 其他配置(
PSTART,TGENA等)同前。
这样,一个精准的硬件定时数据传输通道就建立了。其定时精度远高于软件定时器,且几乎不消耗CPU资源。
4.3 场景三:软件触发与动态缓冲区管理
TRIGEVT的always模式结合TRIGSRC=disabled,提供了纯粹的软件触发方式。这在响应非周期性的软件事件时非常有用,例如,用户命令下发或特定系统状态改变时启动SPI通信。
更高级的用法是结合PCURRENT指针进行动态管理。在中断服务程序中,除了处理数据,还可以根据PCURRENT的值和当前需求,动态修改后续缓冲区的数据,甚至通过修改PSTART或下一个TG的PSTART来改变本次或下次传输的数据块大小。这需要精细的同步,确保在硬件访问缓冲区时,软件不会修改正在传输或即将传输的数据,通常通过双缓冲区或标志位机制来实现。
5. 常见问题排查与调试技巧
在实际开发中,传输组不工作是最常见的问题。以下是一个系统性的排查清单和调试手段。
5.1 传输组无法触发
- 检查
TGENA位:这是最容易被忽略的。使用调试器读取TGxCTRL寄存器,确认bit 31是否为1。在单次模式下,一次传输完成后硬件会将其清零,需要软件重新置位。 - 确认触发源和事件:
- 对于外部触发:用示波器或逻辑分析仪检查映射的引脚是否有预期的边沿或电平变化。确认芯片引脚复用功能是否已正确配置为MibSPI触发输入。
- 对于Tick触发:检查
TICKCNT寄存器配置。TICKENA是否使能?CLKCTRL选择的时钟源是否有频率?TICKVALUE是否设置过小导致下溢过快?可以尝试读取TICKCNT的低16位(TICKVALUE镜像),看其是否在递减。 - 对于软件触发(
always模式):确认TRIGSRC=0且TRIGEVT=7。此时,置位TGENA本身就会触��。检查是否有更高优先级传输组正在占用总线导致其等待。
- 检查优先级和总线状态:读取
LTGPEND寄存器的TGINSERVICE字段,查看当前是哪个传输组正在被服务。如果一直是更高优先级的TG,那么当前TG只能等待。检查更高优先级TG的配置,看其是否是连续模式(ONESHOT=0)阻塞了总线。 - 验证缓冲区配置:确认
PSTART设置正确,且对应的缓冲区区域已预先填充了有效的发送数据。一个空的或未初始化的缓冲区可能导致传输异常。
5.2 数据传输不完整或错乱
PSTART/PEND范围错误:这是导致数据覆盖或传输长度不对的元凶。确保为每个传输组分配的缓冲区索引范围是精确的、连续的,并且没有与其他传输组重叠。使用LTGPEND寄存器显式定义最后一个传输组的结束指针是个好习惯。ONESHOT与PRST模式冲突:在电平触发模式下,如果ONESHOT=1但PRST=1,行为可能不符合直觉。新的触发事件会重置指针,但ONESHOT只允许一次完整的组传输。这可能导致传输被频繁重启,永远无法到达结束地址。仔细审查模式组合。- 中断标志未清除:如果使能了中断,必须在中断服务程序中清除相应的
TGINTFLAG位。标志位不清除,可能导致后续中断无法产生。注意清除方法是写1,而不是写0。 - 时钟与相位极性配置:虽然
TGxCTRL不直接控制SPI时钟格式,但传输组依赖于MibSPI全局的时钟配置(如SPIFMT寄存器)。确保SPI主时钟(SPICLK)已使能,且时钟极性、相位与从设备匹配。
5.3 调试工具与技巧
- 寄存器视图:调试器的寄存器实时查看窗口是最基本的工具。重点关注
TGxCTRL(状态)、TGINTFLAG(中断)、LTGPEND(当前服务组和结束指针)。 - 内存视图:查看MibSPI的TX和RX缓冲区RAM区域,确认待发送数据是否正确写入,以及接收数据是否按预期更新。
- 逻辑分析仪:这是分析硬件时序的终极工具。连接SPI的SCLK、MOSI、MISO、CS以及触发源引脚。可以直观地看到触发信号到来后,SPI传输是否启动、数据内容是否正确、时序是否符合要求。
- 软件模拟:在复杂场景下,可以在关键位置(如触发前后、中断入口)添加GPIO翻转代码,用示波器测量不同事件之间的时间间隔,分析调度和抢占的时序。
通过以上系统的配置、应用和排查方法,你应该能够驾驭MibSPI传输组这个强大的硬件引擎,为你的嵌入式系统设计出高效、可靠、实时的SPI数据通信链路。记住,所有的灵活性都源于对TGxCTRL这32个比特位的深刻理解,花时间吃透它,在项目后期调试中将会节省数倍的时间。