作为一名长期从事DSP开发的工程师,我经常需要处理各种通信接口问题。今天我想重点分享一下TMS320F28335这款DSP芯片中的SCI(Serial Communication Interface)模块,这是我们在电机控制等嵌入式系统中经常使用的重要外设。
SCI本质上是一种全双工的异步串行通信接口,它允许DSP与其他设备进行可靠的数据交换。在电机控制系统中,我们通常用它来实现:
与SPI、I2C等同步接口不同,SCI的最大特点是异步通信——收发双方不需要共享时钟信号,这使得它在远距离通信和不同时钟域设备间的数据交换中表现出色。
F28335内部集成了3个独立的SCI模块(SCIA、SCIB、SCIC),每个模块都具备:
这些特性使得SCI成为DSP与外部世界沟通的重要桥梁。下面我将从硬件结构到软件配置,详细剖析这个模块的使用方法。
SCI模块的时钟来源于LSPCLK(低速外设时钟),这是系统时钟SYSCLKOUT经过分频得到的。时钟路径如下:
code复制SYSCLKOUT → LOSPCP分频 → LSPCLK → SCI模块
波特率计算公式非常关键:
code复制BRR = (LSPCLK / (波特率 × 8)) - 1 (当0 < BRR < 65536)
波特率 = LSPCLK / 16 (当BRR = 0)
实际配置示例:
假设SYSCLKOUT=150MHz,LOSPCP=4(四分频),则:
code复制LSPCLK = 150MHz / 4 = 37.5MHz
若需要19200bps波特率:
BRR = 37.5MHz / (19200×8) - 1 ≈ 243.15 → 取整243
对应寄存器设置:
SCIHBAUD = 0x00
SCILBAUD = 0xF3
重要提示:通信双方必须使用相同的波特率,否则会导致数据接收错误。建议在系统初始化阶段就固定波特率,避免运行时修改。
SCI支持灵活的数据帧格式配置,通过SCICCR寄存器设置:
| 配置项 | 可选参数 |
|---|---|
| 数据位长度 | 1-8位(通常选择8位) |
| 停止位 | 1位或2位 |
| 校验方式 | 无校验/奇校验/偶校验 |
| 多处理器模式 | 空闲线模式/地址位模式 |
典型的数据帧结构(8N1格式):
code复制[起始位(0)] + [8位数据] + [无校验] + [停止位(1)]
数据传输时序要点:
F28335的SCI模块配备了16级深度的FIFO缓冲区,这大大提升了通信效率。FIFO模式通过SCIFFTX寄存器使能:
c复制SciaRegs.SCIFFTX.bit.SCIFFEN = 1; // 使能FIFO模式
发送FIFO工作流程:
接收FIFO工作流程:
FIFO状态监控:
| 寄存器名称 | 主要功能 | 关键位说明 |
|---|---|---|
| SCICCR | 通信控制 | 数据格式、多处理器模式 |
| SCICTL1/2 | 控制寄存器 | 收发使能、中断使能 |
| SCIHBAUD/SCILBAUD | 波特率设置 | 波特率分频值 |
| SCIRXST | 接收状态 | 错误标志、就绪标志 |
| SCIFFTX | 发送FIFO控制 | FIFO使能、中断阈值 |
| SCIFFRX | 接收FIFO控制 | FIFO使能、中断阈值 |
| SCIFFCT | FIFO控制 | 发送延迟设置 |
c复制void SCI_Init(void)
{
// 1. 使能SCI时钟
EALLOW;
SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1; // 使能SCIA时钟
EDIS;
// 2. GPIO引脚配置
InitSciaGpio(); // 配置GPIO35/36为SCITXDA/SCIRXDA
// 3. FIFO配置
SciaRegs.SCIFFTX.all = 0xE040; // 使能FIFO、TXFIFO复位
SciaRegs.SCIFFRX.all = 0x204F; // 使能RXFIFO、清除复位
SciaRegs.SCIFFCT.all = 0x0; // 无自动波特率、无延迟
// 4. 通信参数设置
SciaRegs.SCICCR.all = 0x0007; // 1停止位、无校验、8位数据
SciaRegs.SCICTL1.all = 0x0003; // 使能发送和接收
SciaRegs.SCICTL2.all = 0x0003; // 使能接收/发送中断
// 5. 波特率设置(LSPCLK=37.5MHz, 波特率=19200)
SciaRegs.SCIHBAUD = 0x00;
SciaRegs.SCILBAUD = 0xF3;
// 6. 使能SCI模块
SciaRegs.SCICTL1.bit.SWRESET = 1;
}
发送函数:
c复制void UART_SendByte(Uint16 data)
{
while(SciaRegs.SCIFFTX.bit.TXFFST >= 16); // 等待FIFO有空位
SciaRegs.SCITXBUF = data & 0xFF; // 写入发送缓冲区
}
void UART_SendString(const char *str)
{
while(*str != '\0')
{
UART_SendByte(*str++);
}
}
接收函数:
c复制Uint16 UART_ReceiveByte(void)
{
while(SciaRegs.SCIFFRX.bit.RXFFST == 0); // 等待接收数据
return SciaRegs.SCIRXBUF.all; // 读取接收数据
}
SCI支持两种多处理器通信模式:
空闲线模式:
地址位模式:
模式选择建议:
SCI提供丰富的中断源,合理配置可以大大提高系统效率:
| 中断类型 | 触发条件 | 应用场景 |
|---|---|---|
| TXINT | 发送缓冲区空 | DMA发送、流控 |
| RXINT | 接收数据就绪 | 实时数据处理 |
| RXERRINT | 接收错误(校验、帧错误等) | 错误处理与恢复 |
中断配置示例:
c复制// 使能接收中断(FIFO模式下)
SciaRegs.SCIFFRX.bit.RXFFIENA = 1; // 使能FIFO接收中断
SciaRegs.SCIFFRX.bit.RXFFIL = 8; // 当FIFO中有8个数据时触发中断
// 在PIE控制器中配置中断
PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // 使能PIE组9的INT1(SCIA RX)
IER |= M_INT9; // 使能CPU级中断
在实际项目中,我总结了一些常见问题及解决方法:
无数据收发:
数据错误:
FIFO不工作:
中断不触发:
在电机控制系统中,SCI通常用于以下场景:
c复制void Debug_PrintMotorStatus(tMotor *motor)
{
char buffer[64];
sprintf(buffer, "Speed:%0.1f RPM, Current:%0.2f A\r\n",
motor->speed, motor->current);
UART_SendString(buffer);
}
通过SCI接收上位机指令,实时调整PID参数:
c复制void SCI_CommandHandler(char *cmd)
{
if(strncmp(cmd, "KP=", 3) == 0) {
g_PID.Kp = atof(cmd+3);
}
// 其他参数处理...
}
利用FIFO实现高效数据上传:
c复制void Log_MotorData(tMotorData *data)
{
if(SciaRegs.SCIFFTX.bit.TXFFST < 12) {
// FIFO有足够空间时一次性写入多个数据
UART_SendByte(data->speed_H);
UART_SendByte(data->speed_L);
// 其他数据...
}
}
根据我的项目经验,提供以下几点优化建议:
合理使用FIFO:
DMA配合使用:
错误处理机制:
电源管理:
通过合理配置和优化,SCI模块可以成为DSP系统中稳定可靠的通信接口。特别是在电机控制等实时性要求高的应用中,良好的串口通信设计能极大提高调试效率和系统可靠性。