SPI接口原理与CC27xx实战:从基础到高效配置与调试

📅 2026/7/26 15:03:06
SPI接口原理与CC27xx实战:从基础到高效配置与调试
1. SPI接口核心原理与工作模式深度解析SPI全称Serial Peripheral Interface中文常译为串行外设接口。它本质上是一种同步、全双工、基于主从架构的串行通信总线。说人话就是它像一条双向、有节奏的数据流水线一个“老板”主设备指挥着“员工”从设备在统一的节拍下同时进行收发数据。这种设计让它比I2C、UART等异步协议在速度上有着先天优势特别适合对实时性要求高、数据吞吐量大的场景比如读写高速Flash、驱动高分辨率显示屏或者与高速ADC/DAC进行数据交换。它的物理连接通常只需要四根线这也是它“简单”美誉的由来SCLK (Serial Clock)时钟信号由主设备产生是所有数据传输的节拍器。每个时钟脉冲对应一位数据的移入或移出。CS/SS (Chip Select / Slave Select)片选信号由主设备控制。通常低电平有效主设备通过拉低对应从设备的CS线来“点名”它告诉它“接下来我要和你通话了”。这是SPI支持一主多从的关键。PICO/MOSI (Peripheral In Controller Out / Master Out Slave In)主设备输出、从设备输入的数据线。数据从主设备流向从设备。POCI/MISO (Peripheral Out Controller In / Master In Slave Out)从设备输出、主设备输入的数据线。数据从从设备流回主设备。这里要特别提一下信号命名。在TI的CC27xx文档中使用了PICO/POCI而非更常见的MOSI/MISO。这其实更精确地描述了信号在“控制器”Controller即主设备和“外设”Peripheral即从设备视角下的角色避免了“主/从”可能带来的混淆。PICO就是“外设入控制器出”无论谁是主谁是从这根线永远是数据进入外设、离开控制器的方向。SPI协议的精髓或者说最容易让人困惑的地方在于时钟极性CPOL, Clock Polarity和时钟相位CPHA, Clock Phase的配置。这两个参数决定了时钟信号在空闲时的状态以及数据在时钟的哪个边沿被采样捕获。时钟极性 (CPOL/SPO)定义SCLK在空闲时的电平。CPOL 0空闲时SCLK为低电平。CPOL 1空闲时SCLK为高电平。时钟相位 (CPHA/SPH)定义数据在时钟的哪个边沿被采样。CPHA 0数据在时钟的第一个边沿对于CPOL0是上升沿对于CPOL1是下降沿被采样。CPHA 1数据在时钟的第二个边沿被采样。这两者的四种组合模式0-3必须与从设备如传感器、存储器的时序要求严格匹配否则通信必然失败。模式0CPOL0 CPHA0和模式3CPOL1 CPHA1是最常用的两种。注意很多初学者会在这里栽跟头。务必查阅你所用外设的数据手册确认其要求的SPI模式。一个常见的快速判断方法是观察数据手册的时序图看数据线MOSI/MISO的变化是发生在时钟边沿之前还是之后。如果数据在时钟边沿之前就稳定了即建立时间满足那么采样边沿就是该时钟边沿。除了标准的Motorola SPI格式CC27xx的SPI模块还支持TI同步串行格式和MICROWIRE格式。TI格式的特点是CS信号会在每个数据帧传输前产生一个高脉冲而MICROWIRE则是一种半双工协议传输以主设备发送的一个8位控制字开始随后从设备才返回数据常用于一些老式的串行EEPROM。2. CC27xx SPI模块架构与核心功能拆解CC27xx的SPI模块不是一个简单的移位寄存器而是一个高度集成、功能丰富的通信控制器。理解其内部架构是进行高效、可靠配置的基础。模块的核心可以看作由几个关键部分组成时钟生成单元、双缓冲FIFO、数据传输逻辑、中断与事件系统以及可选的CRC校验单元和µDMA接口。它们协同工作将CPU从繁重的字节搬运工作中解放出来。2.1 可编程时钟系统与速率计算SPI的通信速率直接由SCLK的频率决定。CC27xx的SPI时钟源是CLKSVT典型频率为48MHz。模块通过两级分频来产生最终的SCLK预分频器 (PRESC)位于SPI.CLKCFG0寄存器分频系数为1到8。串行时钟速率分频器 (SCR)位于SPI.CLKCFG1寄存器分频值为1 SCR其中SCR可配置范围为0到1023。因此SCLK的频率计算公式非常明确SCLK频率 CLKSVT频率 / [PRESC × (1 SCR)]例如要产生一个1MHz的SPI时钟使用48MHz的CLKSVT。我们可以先设PRESC4这样得到12MHz。然后需要再分频12倍得到1MHz即1SCR12所以SCR11。配置PRESC4SCR11即可。实操心得在满足从设备最高时钟速率的前提下尽量选择较高的PRESC值。因为PRESC分频发生在SCR之前更高的PRESC意味着对CLKSVT的初次分频更大有时能获得更精确的最终时钟减少抖动。同时务必遵守文档中的硬性规定CLKSVT的频率必须至少是SCLK频率的两倍。2.2 FIFO机制与数据流管理FIFO先进先出缓冲区是提升SPI通信效率的关键。CC27xx的SPI模块包含独立的TX FIFO和RX FIFO。动态宽度这是一个非常巧妙的设计。当数据帧大小DSS配置为4到8位时每个FIFO是16个位置深、8位宽。当数据帧大小配置为9到16位时硬件会自动将FIFO重组为8个位置深、16位宽。这最大限度地利用了存储资源无论传输8位还是16位数据都能有效缓冲多个数据帧。TX FIFO操作CPU或µDMA将待发送的数据写入SPI.TXDATA寄存器数据即进入TX FIFO。发送逻辑会按顺序从FIFO中取出数据串行化后从PICO引脚发出。模块提供了“重复发送”功能通过SPI.CTL1.REPTX配置允许将FIFO中的最后一个数据帧自动重复发送多次这对于需要连续发送相同命令如清屏指令或从某些设备读取大量数据时特别有用。RX FIFO操作从POCI引脚接收到的串行数据经移位寄存器转换为并行数据后被存入RX FIFO。CPU或µDMA通过读取SPI.RXDATA寄存器来从FIFO中取出数据。FIFO刷新通过设置SPI.CTL0.FIFORST位可以原子性地将TX和RX FIFO的读写指针重置为0实现快速清空。这里有一个至关重要的坑点FIFO刷新操作必须在没有任何SPI事务正在进行时触发。如果在一个传输过程中执行刷新你需要在此次传输完全结束后再次执行一次刷新操作才能确保FIFO指针正确归零否则后续传输可能出错。2.3 中断与µDMA高效协作为了不让CPU频繁轮询FIFO状态SPI模块提供了丰富的中断源和强大的µDMA支持。中断源包括TX FIFO服务中断当TX FIFO中的数据量低于设定的阈值时触发提示CPU可以填充更多数据。RX FIFO服务中断当RX FIFO中的数据量达到设定的阈值时触发提示CPU可以读取数据。RX FIFO超时中断在从设备模式下如果SCLK时钟在设定时间内没有活动而RX FIFO中仍有数据则触发。RX FIFO溢出中断RX FIFO已满但仍有新数据收到时触发意味着数据丢失。TX FIFO空中断TX FIFO完全空时触发。传输完成中断DMA完成/空闲中断。所有这些中断在逻辑“或”之后产生一个总的SPI中断信号提交给系统事件 fabric。你可以通过SPI.IMASK寄存器来屏蔽不需要的中断源。µDMA集成是实现高效数据搬运的利器。SPI模块为TX和RX路径提供了独立的DMA通道请求。TX DMA当TX FIFO有空间时会发出DMA请求。可以配置为“单次请求”每有一个空位就请求一次或“突发请求”当空位达到一定数量时请求一次后者能减少DMA触发次数提升总线效率。RX DMA当RX FIFO中有数据时会发出DMA请求。同样支持单次或突发模式。通过合理配置µDMA描述符你可以实现“乒乓缓冲”、“循环传输”等高级数据流让SPI在后台持续传输数KB甚至数MB的数据而CPU仅在开始和结束时介入极大节省了CPU资源降低了系统功耗。注意事项文档中明确建议对于TX/RX FIFO的服务应优先使用µDMA而非CPU中断。如果不得不用CPU处理中断务必同时使能TXEMPTY发送完和RXOVF接收溢出中断作为“安全网”。因为在某些极端情况下如中断被长时间关闭CPU可能错过FIFO阈值中断此时TXEMPTY和RXOVF可以作为一个故障安全机制防止数据丢失或发送停滞。2.4 CRC校验保障数据完整性在要求高可靠性的通信中如无线固件升级、关键传感器数据读取SPI模块内置的硬件CRC引擎是个宝藏功能。它支持CRC8-CCITT和CRC16-CCITT两种校验算法。其工作流程是发送端CRC计算单元逻辑上位于SPI.TXDATA寄存器和TX FIFO之间。每次CPU写入发送数据到TXDATA时数据既存入FIFO也实时更新内部的SPI.TXCRC状态寄存器。当一帧或一个数据块发送完毕后软件读取TXCRC的值得到该数据块的CRC校验和然后将这个校验和作为普通数据写入TXDATA发送给对方。接收端CRC计算单元逻辑上位于RX FIFO和SPI.RXDATA寄存器之间。每次CPU从RXDATA读取接收数据时数据既从FIFO读出也实时更新内部的SPI.RXCRC状态寄存器。接收完数据块和发送方传来的CRC校验和后软件可以读取RXCRC。如果传输无误在将对方发来的CRC校验和也纳入计算后最终的RXCRC值应为0。重要限制硬件CRC功能设计用于8位或16位数据帧。虽然硬件不会强制检查但软件上应遵循当数据帧配置为8位时可选择CRC8或CRC16当数据帧配置为16位时必须选择CRC16。使用不匹配的CRC位数会导致校验失败。3. CC27xx SPI模块配置与编程实战理解了原理和架构现在我们来手把手进行配置。以下是一个典型的SPI主设备控制器初始化流程假设我们要以模式0CPOL0 CPHA0、2MHz速率与一个SPI Flash通信。3.1 初始化步骤详解引脚复用配置这是第一步也是最容易忽略的一步。CC27xx的引脚功能是通过I/O控制器IOC模块动态映射的。你需要找到SCLK、CS、PICO、POCI对应的物理GPIO引脚编号例如DIO_12DIO_13等然后通过配置相应的IOCFGn寄存器将这些引脚的功能设置为SPI。具体寄存器字段请参考CC27xx的IOC章节。// 伪代码示例将DIO_12,13,14,15配置为SPI引脚 HWREG(IOC_BASE IOCFG_12) PIN_FUNC_SPI_SCLK; HWREG(IOC_BASE IOCFG_13) PIN_FUNC_SPI_CS; HWREG(IOC_BASE IOCFG_14) PIN_FUNC_SPI_PICO; HWREG(IOC_BASE IOCFG_15) PIN_FUNC_SPI_POCI;关闭SPI模块在修改关键配置如工作模式、帧格式前先确保SPI模块处于禁用状态SPI.CTL1.EN 0。配置基本参数主/从模式设置SPI.CTL1.MS 1选择控制器主模式。数据帧大小根据外设要求设置SPI.CTL0.DSS。例如对于8位数据设置为0x7因为DSS值帧位数-1。帧格式设置SPI.CTL0.FRF。对于标准Motorola SPI 4线模式设为0x0。时钟极性与相位设置SPI.CTL0.SPO和SPI.CTL0.SPH。对于模式0两者都设为0。字节序设置SPI.CTL1.MSB通常设为1MSB先发送。配置时钟根据前面计算的公式设置SPI.CLKCFG0.PRESC和SPI.CLKCFG1.SCR。例如对于48MHz源时钟生成2MHz SCLK可以设PRESC4分频至12MHzSCR5再分频6倍至2MHz因为1SCR6。配置FIFO中断阈值通过SPI.IFLS.TXSEL和RXSEL设置触发中断的FIFO水平。例如设置TXSEL为1/2FIFO深度RXSEL为1/4FIFO深度可以在数据量适中时及时通知CPU或DMA。可选配置µDMA如果使用DMA需要配置SPI的DMA控制寄存器SPI.DMACR使能TX和/或RX DMA请求并设置请求类型单次/突发。同时在µDMA控制器侧配置相应的通道描述符指定源地址发送时为内存数组接收时为SPI.RXDATA、目标地址发送时为SPI.TXDATA接收时为内存数组、数据量等。可选配置CRC如果需要设置SPI.CTL1中与CRC相关的位如PEN使能奇偶校验但注意硬件CRC是常开的并确保数据帧大小与CRC多项式选择匹配。使能SPI模块最后将SPI.CTL1.EN位设为1模块开始工作。3.2 数据收发编程模型配置完成后数据的收发主要有三种模式1. 轮询模式 最简单但效率最低。CPU不断查询状态寄存器SPI.STA中的BUSY位或TXFETX FIFO空、RXFFRX FIFO满等位。// 轮询发送一个字节 void SPI_SendBytePolling(uint8_t data) { // 等待TX FIFO有空间 while (!(HWREG(SPI_BASE SPI_STA) STA_TXFE_MASK)) { // 空循环等待 } // 写入数据 HWREG(SPI_BASE SPI_TXDATA) data; // 如果需要可以等待发送完成BUSY位变低 // while (HWREG(SPI_BASE SPI_STA) STA_BUSY_MASK); }2. 中断模式 效率较高。配置好FIFO阈值中断后在中断服务程序ISR中填充TX FIFO或读取RX FIFO。// SPI中断服务例程简化版 void SPI_IRQHandler(void) { uint32_t mis HWREG(SPI_BASE SPI_MIS); // 读取屏蔽后的中断状态 if (mis MIS_RX_MASK) { // RX FIFO达到阈值读取数据 while (!(HWREG(SPI_BASE SPI_STA) STA_RXFE_MASK)) { // 直到RX FIFO空 g_rx_buffer[rx_index] HWREG(SPI_BASE SPI_RXDATA); } } if (mis MIS_TX_MASK) { // TX FIFO低于阈值填充数据 while (!(HWREG(SPI_BASE SPI_STA) STA_TXFF_MASK) (tx_index tx_length)) { // 直到TX FIFO满或数据发完 HWREG(SPI_BASE SPI_TXDATA) g_tx_buffer[tx_index]; } } // ... 清除中断标志 }3. µDMA模式 效率最高CPU干预最少。只需初始化DMA描述符启动SPI和DMA传输然后在DMA传输完成中断中处理即可。// 配置µDMA描述符用于SPI发送概念性代码 void ConfigureSPITxDMA(uint32_t *src_buffer, uint32_t size) { // 设置DMA控制结构源地址src_buffer目的地址SPI.TXDATA // 传输大小size源地址递增目的地址固定使用基本传输模式 // 使能SPI的TX DMA请求 HWREG(SPI_BASE SPI_DMACR) | DMACR_TXDMAE_MASK; // 启动DMA传输 }3.3 片选CS与高级控制CS信号的管理对于可靠通信至关重要。CC27xx提供了硬件CS控制功能SPI.CTL0.HWCSN。当使能后在Motorola 4线模式下硬件会自动控制CS信号在TX FIFO中所有数据以及可选的CRC传输完毕之前保持CS为低电平。这简化了软件操作并确保了传输的原子性。另一个高级功能是命令/数据控制Command/Data Control常用于驱动LCD屏等设备。通过设置SPI.CTL1.CDEN和CDMODE可以利用CS线的高低电平来区分传输的是命令还是数据。例如设置CDMODE1则下一次通过TXDATA写入的数据字节会在CS为低命令模式下发送之后CS自动恢复为高数据模式。这省去了软件手动控制CS引脚电平的步骤。4. 常见问题排查与调试技巧实录在实际开发中SPI通信不出数据是最常见的问题。下面是一个系统性的排查清单和我的实战心得。问题1完全无通信用逻辑分析仪看不到SCLK或数据信号。排查步骤电源与引脚确认从设备已上电且电压电平与CC27xx的GPIO电平通常3.3V兼容。引脚配置百分之九十的问题出在这里再次用万用表或示波器确认你配置的DIO引脚是否正确输出了SPI功能。一个快速验证方法是将引脚先配置为GPIO输出模式手动拉高拉低看电平是否变化排除硬件连接问题。SPI使能确认SPI.CTL1.EN位已设置为1。时钟配置检查PRESC和SCR的计算与配置是否正确。SCLK频率是否在从设备支持的范围内用示波器测量SCLK引脚实际输出频率。主从模式确认SPI.CTL1.MS位设置正确主设备设为1。问题2有SCLK时钟但数据线PICO/POCI上没有波形。排查步骤TX FIFO状态在发送数据前检查SPI.STA.TXFE位是否为1TX FIFO空可以写入。写入数据后检查SPI.STA.BUSY位是否变为1。CS信号在4线模式下CS信号是否被正确拉低检查硬件连接如果使用软件GPIO控制CS确保时序正确通常在传输前拉低传输后拉高。数据写入确认你是向SPI.TXDATA寄存器写入数据而不是其他寄存器。写入的数据格式如8位/16位是否与DSS配置匹配从设备是否响应如果是在读数据POCI上没有波形可能是从设备没有正确响应。检查从设备的CS、电源以及它是否支持当前的SPI模式CPOL CPHA。问题3能收到数据但数据是错的全0、全1、或错位。排查步骤时钟模式CPOL/CPHA这是最可能的原因务必确保主从设备的CPOL和CPHA设置完全一致。用逻辑分析仪捕获时序图对照数据手册检查数据采样边沿。字节序MSB/LSB检查SPI.CTL1.MSB位设置确保数据位的发送顺序与从设备期望的一致。数据帧大小确认SPI.CTL0.DSS设置的数据位数与从设备每次传输的位数一致。例如很多16位ADC要求一次传输16位数据如果配置成8位就会错位。时钟速度过快过高的SCLK速率可能导致从设备建立/保持时间不满足产生误码。尝试降低SCLK频率。信号完整性长导线、未端接的线路可能引起信号振铃或边沿退化。在高速率下尽量缩短走线并在必要时考虑串联端接电阻。问题4使用DMA时传输不完整或卡住。排查步骤DMA使能确认SPI.DMACR中的TXDMAE和/或RXDMAE位已使能。DMA描述符配置仔细检查DMA源/目标地址、传输数量、地址增量模式是否正确。一个常见错误是目标地址没有设置为外设寄存器地址如SPI.TXDATA或者传输数量单位错误是字节数还是字数。FIFO阈值与DMA请求检查SPI.IFLS的阈值设置是否与DMA的“突发请求”配置匹配。如果FIFO阈值设得太浅而DMA期望的突发量很大可能导致DMA请求不触发。中断冲突确保SPI中断和DMA传输完成中断的优先级和清除逻辑正确避免相互阻塞。调试技巧实录逻辑分析仪是你的最佳伙伴一个支持SPI协议解码的逻辑分析仪如Saleae能直观地显示SCLK、CS、MOSI、MISO上的波形和解析出的数据值一眼就能看出时序、数据是否正确是排查SPI问题的终极利器。寄存器打印调试法在初始化关键步骤后和通信前后通过调试器或串口打印关键寄存器的值如CTL0CTL1CLKCFG0/1STA与预期值对比。简化测试遇到复杂问题先回归最简单配置。用轮询模式、最低速率、发送固定的已知数据模式如0xAA 0x55排除中断、DMA、高速率等因素的干扰。利用Loopback模式CC27xx SPI支持内部环回测试模式通过SPI.CTL1相关位配置。在此模式下发送的数据会被内部直接环回到接收端。这是验证SPI模块自身配置、驱动程序底层是否正确的最快方法无需连接外部设备。最后关于CC27xx SPI模块一个特别需要注意的点是**延迟采样Delayed Sampling**功能。当你的PCB走线较长或负载较重导致POCI引脚上的数据相对SCLK有较大延迟时主设备可能在正确的时刻采样到的是上一个比特的数据。这时可以通过配置SPI.CLKCFG1.DSAMPLE字段将采样点延迟若干个CLKSVT时钟周期。通常在最高SPI速率下尝试设置为1或2就能有效补偿延迟。这个功能只在控制器模式下可用是解决高速SPI通信中数据眼图闭合问题的有效硬件手段。