TMS320F28335 SPI实战:从寄存器配置到FIFO收发,一个完整工程带你避坑
第一次接触TMS320F28335的SPI模块时,面对密密麻麻的寄存器列表和FIFO配置选项,大多数工程师都会感到无从下手。本文将带你从零开始构建一个完整的SPI通信工程,通过"自发自收"的实战案例,深入解析每个关键配置背后的原理,并分享那些手册上不会告诉你的实战经验。
1. SPI基础与寄存器全景
SPI作为工业控制领域最常用的同步串行接口,在TMS320F28335上的实现有其独特之处。与常见的8位SPI设备不同,这款DSP支持16位数据传输,且通过FIFO机制大幅提升了通信效率。我们先来梳理核心寄存器组:
| 寄存器名称 | 地址偏移 | 核心功能描述 |
|---|---|---|
| SPICCR | 0x00 | 时钟极性、数据长度、软件复位控制 |
| SPICTL | 0x01 | 主从模式、时钟相位、中断使能 |
| SPISTS | 0x02 | 接收溢出、中断标志状态 |
| SPIBRR | 0x03 | 波特率分频系数设置 |
| SPIRXEMU | 0x04 | 仿真接收缓冲(不影响中断标志) |
| SPIRXBUF | 0x05 | 实际接收数据缓冲(清除中断标志) |
| SPITXBUF | 0x06 | 发送数据缓冲 |
| SPIDAT | 0x07 | 移位寄存器(直接控制数据收发) |
| SPIFFTX | 0x08 | 发送FIFO控制与状态 |
| SPIFFRX | 0x09 | 接收FIFO控制与状态 |
| SPIFFCT | 0x0A | FIFO数据传输延时控制 |
关键提示:SPIRXEMU和SPIRXBUF虽然内容相同,但前者读取不会清除中断标志,这在调试阶段非常有用。
2. 寄存器配置的魔鬼细节
2.1 时钟与数据格式配置
SPICCR寄存器的配置需要特别注意操作顺序。以下是典型配置流程:
// 第一步:进入配置模式(必须保持复位状态) SpiaRegs.SPICCR.bit.SPISWRESET = 0; // 保持复位 // 第二步:设置基本参数 SpiaRegs.SPICCR.bit.CLKPOLARITY = 1; // 上升沿发送 SpiaRegs.SPICCR.bit.SPILBK = 0; // 禁用回环模式 SpiaRegs.SPICCR.bit.HS_MODE = 0; // 标准SPI模式 SpiaRegs.SPICCR.bit.SPICHAR = 0xF; // 16位数据长度(0xF+1) // 第三步:退出复位状态 SpiaRegs.SPICCR.bit.SPISWRESET = 1; // 释放复位常见陷阱:
- 在SPI处于工作状态时修改SPICCR会导致通信异常
- 数据长度设置值为N-1(如16位对应0xF)
- 时钟极性改变后需要至少3个SPICLK周期才能稳定
2.2 波特率计算的隐藏规则
SPIBRR的计算公式看似简单,但实际应用中有几个易错点:
// 正确计算示例(LSPCLK=37.5MHz,目标波特率=1MHz) if (desired_baud > LSPCLK/4) { // 超出最大支持波特率 } else if (desired_baud >= LSPCLK/127) { SpiaRegs.SPIBRR = (LSPCLK/desired_baud) - 1; } else { // 需要使用/4分频模式 SpiaRegs.SPIBRR = 0; // 0/1/2都对应/4分频 }实际测试发现,当SPIBRR=3时,实测波特率与理论值偏差可能达到5%,建议在高速通信时避开这个临界值。
3. FIFO配置实战技巧
3.1 发送FIFO深度优化
SPIFFTX寄存器的配置直接影响发送效率:
// 典型FIFO发送配置 SpiaRegs.SPIFFTX.bit.TXFIFO = 1; // 复位发送FIFO SpiaRegs.SPIFFTX.bit.SPIFFENA = 1; // 使能FIFO增强模式 SpiaRegs.SPIFFTX.bit.TXFFIENA = 1; // 使能发送中断 SpiaRegs.SPIFFTX.bit.TXFFIL = 8; // 中断触发深度=8调试中发现:
- FIFO深度设置为8时,中断响应与数据处理达到最佳平衡
- 发送过程中修改TXFFIL可能导致数据丢失
- TXFFINT标志需要手动清除
3.2 接收FIFO的溢出处理
SPIFFRX的配置需要特别注意溢出处理:
// 安全接收配置方案 SpiaRegs.SPIFFRX.bit.RXFIFORESET = 1; // 使能接收FIFO SpiaRegs.SPIFFRX.bit.RXFFIENA = 1; // 使能接收中断 SpiaRegs.SPIFFRX.bit.RXFFIL = 4; // 4字深度触发中断 // 中断服务程序中必须检查溢出 if (SpiaRegs.SPIFFRX.bit.RXFFOVF) { SpiaRegs.SPIFFRX.bit.RXFFOVFCLR = 1; // 清除溢出标志 // 处理溢出错误... }经验之谈:接收FIFO溢出是SPI通信中最常见的问题之一,建议在初始化后立即清除所有状态标志。
4. 完整工程实现与调试
4.1 自发自收工程框架
基于前文分析的完整实现:
void SPI_Init() { EALLOW; SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1; EDIS; // GPIO配置(略) // FIFO初始化 SpiaRegs.SPIFFTX.all = 0xE040; // 使能发送FIFO SpiaRegs.SPIFFRX.all = 0x204F; // 16级接收FIFO SpiaRegs.SPIFFCT.all = 0x0; // 无传输延迟 // SPI核心配置 SpiaRegs.SPICCR.all = 0x000F; // 16位模式,保持复位 SpiaRegs.SPICTL.all = 0x000E; // 主模式,使能自测 SpiaRegs.SPIBRR = 0x007F; // 约300Kbps@37.5MHz SpiaRegs.SPICCR.all = 0x009F; // 释放复位 } uint16_t SPI_Transfer(uint16_t data) { while (SpiaRegs.SPIFFTX.bit.TXFFST == 16); // 等待FIFO空间 SpiaRegs.SPITXBUF = data; while (!SpiaRegs.SPIFFRX.bit.RXFFST); // 等待接收数据 return SpiaRegs.SPIRXBUF; }4.2 调试中的常见问题
数据错位问题:
- 现象:接收数据位序与发送不一致
- 解决方案:检查SPICCR.CLKPOLARITY和SPICTL.CLK_PHASE的配合
FIFO卡死问题:
- 现象:发送后无法触发中断
- 解决方法:确保SPIFFTX.TXFIFO和SPIFFRX.RXFIFO同时使能
波特率异常问题:
- 现象:实际通信速率与设置不符
- 排查步骤:
- 确认LSPCLK时钟配置
- 检查SPIBRR是否在配置期间被修改
- 用示波器测量SPICLK实际频率
在完成基本通信后,可以进一步优化中断处理机制。实测发现,采用DMA配合SPI FIFO可以实现零开销数据传输,这在电机控制等实时性要求高的场景尤为有用。