一、SCI?
1、SCI定义
Serial Communication Interface,即串行通信接口,支持同步或异步数据传输。
注:同步:共享一个时钟信号来传输数据,如SPI,I2C,由主设备提供时钟,控制时序。异步:无共享时钟信号,依赖预定义的波特率,如UART(Universal Asynchronous Receiver/Transmitter),双方约定好数据格式。
信号电平标准:
TTL电平:高电平 ≥2.4V(典型5V系统),低电平 ≤0.8V。功耗较高,速度快,适用于短距离板级通信(如芯片间连接)。
CMOS电平:高电平 ≥0.7×Vcc(如5V时为3.5V),低电平 ≤0.3×Vcc。低静态功耗、宽电压范围(3V至15V),抗噪声能力强,适合低功耗场景。
RS-232:负逻辑(±3V至±15V),逻辑“1”为-3V至-15V,逻辑“0”为+3V至+15V。单端信号、点对点全双工,传输距离短(<15米),易受干扰,需电平转换芯片
RS-485:差分信号,逻辑“1”为B线电压高于A线 ≥+0.2V,逻辑“0”为A线电压高于B线 ≥+0.2V。抗干扰强、支持多点通信(最多32节点)、半双工/全双工(四线制),传输距离长(千米级),需终端电阻匹配。
特性 | TTL/CMOS | RS-232 | RS-485 |
---|---|---|---|
信号类型 | 单端 | 单端(负逻辑) | 差分 |
电平范围 | TTL: 0-5V;CMOS: 灵活 | ±3V至±15V | ±2V至±6V(差分电压) |
传输距离 | <1米 | <15米 | 千米级(1200米@100kbps) |
抗干扰能力 | 弱 | 一般 | 强(共模抑制) |
拓扑结构 | 点对点 | 点对点全双工 | 多点(半双工/全双工) |
设备数量 | 1对1 | 1对1 | 最多32节点(可扩展) |
速度与距离关系 | 高速(短距离) | 低速率(短距离) | 速率随距离降低 |
典型应用 | 板级通信 | 设备调试、串口通信 | 工业总线(Modbus) |
2、SCI优缺点
优点 | 详细说明 | 缺点 | 详细说明 |
---|---|---|---|
简单易用 | 硬件接口简单,通常只需少量引脚(如TX、RX),易于实现和调试。 | 传输速率较低 | 相比并行通信,串行通信速率较低,不适合大数据量传输。 |
低硬件成本 | 无需复杂的外设支持,适合资源有限的嵌入式系统。 | 抗干扰能力有限 | 单端信号(如UART)易受噪声干扰,需额外措施(如差分信号)提高可靠性。 |
低功耗 | 串行通信功耗较低,适合电池供电设备。 | 点对点通信限制 | 标准UART仅支持点对点通信,多设备通信需额外协议或硬件支持(如RS-485)。 |
长距离通信能力 | 通过电平转换(如RS-232、RS-485),可实现较长距离的可靠通信。 | 距离与速率矛盾 | 长距离通信时,传输速率需降低以保证信号完整性。 |
广泛兼容性 | 大多数微控制器和外设都支持SCI接口,易于与其他设备互联。 | 软件开销 | 需编写通信协议和错误处理机制,增加软件开发复杂度。 |
实时性较好 | 适合低数据量、实时性要求较高的场景(如传感器数据采集)。 |
二、TMS320F28335的SCI模块
SCI-CPU连接图
SCI结构图
1、SCI信号概况
SCIRXD——SCI异步串行端口——接收数据;
SCITXD——SCI异步串行端口——发送数据;
Baud clock——LSPCLK分频时钟;
TXINT——发送中断;
RXINT——接收中断;
2、多处理器和异步通信模式
SCI有两种多处理器协议(处理器之间通信),即空闲模式和地址位模式。SCI提供通用异步发送/接收(UART)模式与多个常用外设通信。
数据格式:1个bit起始位+1~8个bit数据位+1个bit奇偶校验码(可选)+1~2个停止位。(空闲模式下,如果是地址位模式,需添加1bit作为数据帧和地址帧判别)
空闲模式
地址位模式
3、SCI多处理器通信
在一条总线上,同一时刻只能有一个发送器。一般来说,发送器的第一帧数据当做地址。SCI模块中,SLEEP位置位,当读取到的地址与程序设定一致时,代码中需清零SLEEP位才能使能SCI产生接收中断。
注:SLEEP位置1时,虽然仍能接收器仍运行,但是不会置位RXRDY,RXINT和任意一个接收故障位,除非地址匹配,清零SLEEP或者接收到带有地址位的数据帧(地址位模式下)。SCI不会自动置位/清零SLEEP,由软件决定。
4、识别地址字节
处理器根据选择的模式对字节进行判断。
在空闲模式下,在发送地址字节前会留出与上一帧数据一定的时间间隔。对于处理10个字节以上的数据,该模式效率较高,常用于非多处理器通信。
注:数据块由数据帧组成,帧与帧之间由时间间隔,所以如果要区分地址还是数据,则上面所述的时间间隔的大小应大于帧与帧之间的时间间隔,同时也是用来区分上一个数据块与下一个数据块。一般间隔至少发送10个bit(高电平)所需的时间,基于波特率计算。
起始信号的产生由两种方式:
方式1:上一块的最后一帧与下一块的第一帧间隔至少10个bit(低电平)时间。
方式2:在写数据到SCITXBUF寄存器前置位寄存器SCICTL1的TXWAKE位,就会自动产生11bit的空闲时间。
注:在置位TXWAKE时,需将一个随意的数据写到SCITXBUF,但是不会发送出去,是用来产生空闲时间的。等SCISHF寄存器又空闲时,就可以写入有效数据了。
与TXWAKE相关联的wake-up temporary(WUT)位,当SCITXBUF将数据加载到TXSHF时,TXWAKE也会加载到WUT,如何TXWAKE会自动清零。
在地址位模式下,在每帧数据中会由额外的1个bit(1:表示地址帧,0:表示数据帧)来表示该帧是地址字节还是数据字节,因此帧与帧之间不用时间间隔来区分,对于传输数据量较小,如数据块包含至多11个字节时,效率较高。
添加的位其实由TXWAKE位给定。当发送时,SCITXBUF寄存器和TXWAKE分别加载到TXSHE寄存器和WUT位,然后TXWAKE自动清零,WUT位作为当前帧的地址位。换而言之,当TXWAKE置位时,发送地址帧。
5、SCI通信格式
SCI异步通信格式可以使用单路或者双路通信。数据格式由1bit起始位+1~8个数据位+1bit(奇偶校验位,可选)+1~2bit停止位。
当SCIRXD上保持4个连续SCICLK低电平时,则判定起始信号产生,接收器开始接收数据。如果出现非0,则从头开始,继续寻找4个周期低电平。
对于起始信号后bit,通过3个SCICLK来判断高电平还是低电平。分别在第4~6个周期采样,通过少数服从多数的原则,来决定是高电平还是低电平。如两次采样为1,一次采样为0,则该bit为1。因为接收器同步于自身时钟,所以外部发送和接收设备不需要使用同步时钟,两者各自产生时钟。
注:每个bit占8个SCICLK。
6、SCI接收信号时序
以地址位模式,6bit数据长度为例。当起始信号检测到时,数据开始移入寄存器,检测到停止位时,拉高RXRDY,表示接收完成,从SCIBUF寄存器读取后RXRDY自动清零。
注:当RXENA为低电平时,即禁能接收器。虽然数据仍会移入RXSHF寄存器,但是不会加载到RXBUF寄存器。
7、发送信号时序
TXENA拉高使能发送,接着写入数据到TXBUF,此时图中时刻1 TX EMPTY为低表示TXSHF寄存器空,时刻2写数据到TXBUF寄存器,TXRDY拉低,时刻3表示加载到TXSHF寄存器完成,TX EMPTY为低电平表示TXSHF寄存器为非空,TXRDY拉高,可以写入第二个字节了。接着在时刻4数据写入完成,拉低TXRDY。在时刻5第一个字节发送完成,接着第二字节移入TXSHF寄存器,TXRDY拉高表示TXBUF为空,TX EMPTY依旧为低电平,因为TXSHF一直非空。在时刻6禁能发送,但已经正在发送,所以等发送第二个字节后(时刻7),由于TXRDY一直为高,说明没有写入TXBUF,也就没有加载数据到TXSHF寄存器,所以TXSHF为空,拉高TX EMPTY。
8、SCI中断
SCI接收和发送可以通过中断来完成,两者中断独立。当不使能中断时,中断不产生,但相应的中断标志位会置起。对于发送和接收的优先级,当两者同一时刻产生时,接收的优先级高于发送,从而避免接收溢出。
以接收中断为例,当置位SCICTL2对应的接收使能位RX/BK INT ENA时,如果SCI接收到一帧数据并加载到SCIRXBUF,则会置起RXRDY标志并产生中断请求。或者检测到接收错误(在接收不到停止位后的9.625 bit 周期),就对置起BRKDT标志并产生中断请求。
当TX INT ENA置起,不论何时SCITXBUF的数据加载到TXSHF,都会产生发送中断,TXRDY被置起,表示现在可以写入新数据了。
9、波特率
SCI时钟由低速外设时钟LSPCLK和16bit波特率选择器决定。
注:最小波特率 = LSPCLK/16。
10、SCI FIFO模式
上电复位,SCI默认工作在标准模式下。FIFO模式的发送寄存器为8bit长度,接收寄存器为10bit长度。FIFO发送寄存器将数据加载到标志模式下的发送寄存器TXBUF,TXBUF再将数据加载到TXSHF寄存器。注意只有在TXSHF将最后一个bit移出后,TXBUF才加载FIFOTXBUF的数据。另外,如果使能FIFO模式,则可以配置发送延时,即延时将数据加载到TXSHF寄存器,但不同经过TXBUF。
对于延时发送,通过SCIFFCT寄存器的FFTXDLY0~FFTXDLY7配置,延时时间基于SCI波特率时钟周期计算。
FIFO中断逻辑图
中断标志位一览图
注:FIFO模式下,在延时后TXSHF直接接收数据,不经过TXBUF。
RXERR可以通过BRKDT/FE/OE/PE标志置起。在FIFO模式下,BRKDT中断只能通过RXERR标志位。
11、波特率检测
在SCIFFCT寄存器中,CDC位为1,如果ABD位被置起(硬件置起),则会产生FIFO发送中断。在中断服务结束后软件清零CDC位。如果中断服务后CDC仍位1,也不会重复产生中断。
配置步骤:置位CDC从而使能波特率检测模式,并写1到ABDCLR位清零ABD位;配置波特率为1或者不超过500Kbps。
让主机发送字符“A”或者“a”给SCI接收,则硬件波特率检测电路会测出传输的波特率大小并置位ADB位。硬件波特率检测电路会将测出的值更新到波特率寄存器,接着产生中断。
中断中清零ADB位和CDC位从而禁能波特率检索。从接收寄存器中读取“A”或“a”来清空状态寄存器位。
注:在超过100Kbps的波特率检测,测出的结果准确率会降低。
三、代码示例
标准+空闲+中断模式
目的:上位机发送数据,SCI返回接收数据给上位机。
SCI初始化
#define SCI_LSPCLK ((Uint32)(60000000)/4)
#define BAUD_RATE ((Uint32)(9600))
void InitSci(void)
{
Uint16 scibaud = 0;
EALLOW;
GpioCtrlRegs.GPBPUD.bit.GPIO36 = 0; // Enable pull-up for GPIO28 (SCIRXDA)
GpioCtrlRegs.GPBPUD.bit.GPIO35 = 0; // Enable pull-up for GPIO29 (SCITXDA)
GpioCtrlRegs.GPBDIR.bit.GPIO36 = 0; // Enable pull-up for GPIO28 (SCIRXDA)
GpioCtrlRegs.GPBDIR.bit.GPIO35 = 1; // Enable pull-up for GPIO29 (SCITXDA)
GpioCtrlRegs.GPBQSEL1.bit.GPIO36 = 3; // Asynch input GPIO28 (SCIRXDA)
GpioCtrlRegs.GPBMUX1.bit.GPIO36 = 1; // Configure GPIO28 to SCIRXDA
GpioCtrlRegs.GPBMUX1.bit.GPIO35 = 1; // Configure GPIO29 to SCITXDA
EDIS;
scibaud = SCI_LSPCLK/(BAUD_RATE*(8)) - 1;
//波特率
//SCI Asynchronous Baud = LSPCLK / ((BRR + 1) *8)
//BRR = (SCIHBAUD << 8) + (SCILBAUD)
SciaRegs.SCIHBAUD = scibaud>>8;
SciaRegs.SCILBAUD = scibaud&0x00FF;
SciaRegs.SCICCR.bit.STOPBITS = 0;//停止位数目1
SciaRegs.SCICCR.bit.PARITY = 0;//奇校验
SciaRegs.SCICCR.bit.PARITYENA = 1;//使能校验
//SciaRegs.SCICCR.bit.LOOPBKENA = ;//loop back test mode,自发自收
SciaRegs.SCICCR.bit.ADDRIDLE_MODE = 0;
SciaRegs.SCICCR.bit.SCICHAR = 7;//8位字符长度
SciaRegs.SCICTL1.bit.RXERRINTENA = 1;//使能SCI接收错误中断
SciaRegs.SCICTL1.bit.TXWAKE = 1;
SciaRegs.SCICTL1.bit.SLEEP = 0;
SciaRegs.SCICTL1.bit.TXENA = 1;
SciaRegs.SCICTL1.bit.RXENA = 1;
SciaRegs.SCICTL2.bit.RXBKINTENA = 1;//使能接收/break中断 采用FIFO需关闭
SciaRegs.SCICTL2.bit.TXINTENA = 1;//采用FIFO需关闭
SciaRegs.SCICTL1.bit.SWRESET = 1;//软件复位写0---->配置完后必须写1
}
SCI中断配置
void SCI_INTEN(void)
{
EALLOW;
PieVectTable.SCIRXINTA = &SCIARX_IRQn;
PieVectTable.SCITXINTA = &SCIATX_IRQn;
EDIS;
PieCtrlRegs.PIEIER9.bit.INTx1 = 1;//SCIA RX
PieCtrlRegs.PIEIER9.bit.INTx2 = 1;//SCIA TX
IER |= M_INT9;
}
interrupt void SCIARX_IRQn()
{
if(SciaRegs.SCIRXST.bit.RXRDY)
{
data = SciaRegs.SCIRXBUF.bit.RXDT;
}
GpioDataRegs.GPCTOGGLE.bit.GPIO66 = 1;
if(( SciaRegs.SCIRXST.bit.RXERROR)||
(SciaRegs.SCIRXST.bit.BRKDT)||
( SciaRegs.SCIRXST.bit.FE)||
(SciaRegs.SCIRXST.bit.OE)||
(SciaRegs.SCIRXST.bit.PE))
{
GpioDataRegs.GPCTOGGLE.bit.GPIO68 = 1;
}
if((SciaRegs.SCICTL2.bit.TXRDY))
{
SciaRegs.SCITXBUF = data;
}
PieCtrlRegs.PIEACK.bit.ACK9 = 1;
}
interrupt void SCIATX_IRQn()
{
GpioDataRegs.GPCTOGGLE.bit.GPIO64 = 1;
PieCtrlRegs.PIEACK.bit.ACK9 = 1;
}
main.c
void led1_Init()
{
EALLOW;
GpioCtrlRegs.GPCMUX1.bit.GPIO66 = 0;
GpioCtrlRegs.GPCDIR.bit.GPIO66 = 1;
GpioCtrlRegs.GPCPUD.bit.GPIO66 = 1;
GpioCtrlRegs.GPCMUX1.bit.GPIO68 = 0;
GpioCtrlRegs.GPCDIR.bit.GPIO68 = 1;
GpioCtrlRegs.GPCPUD.bit.GPIO68 = 1;
GpioCtrlRegs.GPCMUX1.bit.GPIO64 = 0;
GpioCtrlRegs.GPCDIR.bit.GPIO64 = 1;
GpioCtrlRegs.GPCPUD.bit.GPIO64 = 1;
EDIS;
GpioDataRegs.GPCSET.bit.GPIO66 = 1;
GpioDataRegs.GPCSET.bit.GPIO68 = 1;
GpioDataRegs.GPCSET.bit.GPIO64 = 1;
}
int main(void)
{
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
led1_Init();
InitSci();
Peripheral_INT_ENABLE();
while(1)
{
DELAY_US(1000000);
}
}