F28335第十一篇——串行外设接口(SPI)

摘要

本文大致介绍了F28335中SPI工作原理和大致寄存器。还有很多细节知识没有列出,需要详细了解的同学,可以参考TI官方文档(TI官网免费下载),或者可以看书籍。重点推荐符晓编写的<TMS320F28335原理、开发及应用>。重点推荐张卿杰的<手把手教你学DSP>。研旭的开发板还可以,但是书真的编辑的很烂。参考的资料比较老旧,纸张差,有错别字,细节错误很多,翻译的也不流畅。英语好的同学可以直接阅读TI官方文档,国内的书基本上就是翻译。

本文主要通过最后的例程演示SPI传输时的一些细节问题。并详细注释了一个自发自收程序。可以通过改变参数来实现添加FIFO功能。整个工程会打包传送到CSDN。有需要的同学可以下载。若是没有积分,可以留言免费索要。

概述

SPI作为高速串行接口,常用于DSP与外设或者DSP与DSP之间数据交换。F28335只有一个SPI模块。TI官方库中对应的结构体变量名称为:SpiaRegsSPI寄存器不受EALLOW保护。主要有四根信号线,F28335给出两组GPIO提供选择。具体如下表:

信号名称功能描述第一组第二组
SPISIMOSPI从输入/主输出GPIO16GPIO54
SPISOMISPI从输出/主输入GPIO17GPIO55
SPICLKSPI时钟GPIO18GPIO56
S P I S T E ‾ \overline{ \rm SPISTE} SPISTE从控制下发送使能控制位GPIO19GPIO57

在这里插入图片描述
SPI在F28335上的地址分配为:

   SPIA        : origin = 0x007040, length = 0x000010     /* SPI-A registers */

工作模式

SPI共有两种工作方式:主控制器工作方式和从控制器工作方式。

主控制器模式

  • 数据从SPISIMO引脚输出,从SPISOMI引脚锁存。
  • 主控制器提供整个通信的时钟SPICLK,设置时钟的波特率。

从控制器模式

  • 数据从SPISOMI输出,从SPISIMO输入。
  • 时钟由主控制器提供,但不能超过从控制器LSPCLK时钟频率的四分之一。
  • 选通信号允许多个设备连接在一起构成网络,但是在某个时刻只能有一个从控制器被选通。

主要特点

  • SPI是全双工,同步传输串行信号。
  • 数据的发送方向是先高位后低位。
  • 无论是主控制器还是从控制器,数据在SPICLK一个边沿发送,在另一个边沿将会被锁存。对于任意一个控制器,接收和发送数据都是同步进行的。
  • 当数据长度不为16位时,发送时保持左对齐(编程控制),接收时为右对齐(DSP自动实现)。

在这里插入图片描述

波特率

S P I 波 特 率 = { L S P C L K S P I B R R + 1 ( 4 ≤ S P I B R R ≤ 127 ) L S P C L K S P I B R R + 1 ( S P I B R R = 0 , 1 , 2 , 3 ) SPI波特率=\left\{ \begin{aligned} \frac {LSPCLK}{SPIBRR+1} & & ( {4 \leq SPIBRR \leq 127})\\ \frac {LSPCLK}{SPIBRR+1} & & ({SPIBRR=0,1,2,3}) \end{aligned} \right. SPI=SPIBRR+1LSPCLKSPIBRR+1LSPCLK(4SPIBRR127)(SPIBRR=0,1,2,3)

中断

SPI在F28335中共占用两个中断向量,分别为:SPIRXINTA(INT6.1)和SPITXINTA(INT6.2)。当为非FIFO模式时,只使用SPIRXINTA中断。这是因为在SPI中,收发是同步的,换言之,收到一个数据的同时必然发出了一个数据。所以,在非FIFO模式,只需要一个中断即可同时表现收/发完成。
当为FIFO模式时,才能够同时使用两个中断。
具体的对应关系如下表:

FIFO选项FIFO使能位SPI中断源中断标志中断使能中断向量
非FIFO模式0接收溢出RXOVRNOVRNINTENASPIRXINT
非FIFO模式0正常接收完成SPIINTSOIINTENASPIRXINT
非FIFO模式0正常发送完成SPINTSPINTENASPIRXINT
FIFO模式1FIFO接收完成RXFFILRXFFIENASPIRXINT
FIFO模式1FIFO发送完成TXFFILTXFFIENASPITXINT

还可以用下图表示该逻辑:
在这里插入图片描述

数位对齐

可以通过设置寄存器规定一次传送过程中数据的长度。当数据的长度小于16时,需要保证数位对齐。

  • 发送端写入SPIDAT或者SPITXBUF中的数据必须左对齐。这需要开发者编程保证左对齐。
  • 接收端读取SPIRXBUF,得到的数据是右对齐的。这需要开发者屏蔽无效高比特位。

在这里插入图片描述

主要寄存器

struct  SPI_REGS 
{
    union SPICCR_REG     SPICCR;      // 配置与控制寄存器
    union SPICTL_REG     SPICTL;      // 运行方式控制寄存器
    union SPISTS_REG     SPISTS;      // 状态寄存器
    Uint16               rsvd1;       // reserved
    Uint16               SPIBRR;      // 波特率寄存器
    Uint16               rsvd2;       // reserved
    Uint16               SPIRXEMU;    // 仿真缓冲寄存器
    Uint16               SPIRXBUF;    // 接收缓冲寄存器
    Uint16               SPITXBUF;    // 发送缓冲寄存器
    Uint16               SPIDAT;      // 串行数据寄存器
    union SPIFFTX_REG    SPIFFTX;     // FIFO发送寄存器
    union SPIFFRX_REG    SPIFFRX;     // FIFO接收寄存器
    union SPIFFCT_REG    SPIFFCT;     // FIFO控制寄存器
    Uint16               rsvd3[2];    // reserved
    union SPIPRI_REG     SPIPRI;      // FIFO优先权控制寄存器
};

SPI模块的原理如下图所示:
在这里插入图片描述

例程

功能

1.实现SPI自发自收。
2.验证SPI发送时序。
3.验证发送数据位不足16位,左右对齐。
4.通过标志位确认是否使用FIFO,验证两种方式的中断不同!

源代码

主程序
int main(void)
{
    //1.系统初始化
    InitSysCtrl();

    //2.初始化GPIO
    InitSpiGpio(); //使用GPIO16-GPIO19
    //3.中断
    //3.1 关闭中断
    DINT;
    IER = 0x0000;    //关闭CPU级中断
    IFR = 0x0000;    //清除中断标志
    InitPieCtrl();    //关闭PIE中断
    InitPieVectTable();    //初始化PIE中断向量
    //3.2写入使用的中断向量
    EALLOW;
    PieVectTable.SPIRXINTA = &IsrSpiRx;    //接收中断服务程序
#if isFIFO
    PieVectTable.SPITXINTA = &IsrSpiTx;    //发送中断服务程序
#endif
    EDIS;
    //3.3PIE中断使能
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;    //使能PIE中断
    PieCtrlRegs.PIEIER6.bit.INTx1 = 1;    //使能第六组第一位中断(SPI接收)
#if isFIFO
    PieCtrlRegs.PIEIER6.bit.INTx2 = 1;    //使能第六组第二位中断(SPI发送)
#endif
    IER |= M_INT6;    //CPU第六组中断
    EINT;

    //4.初始化外设
    InitSpi();

    //5.自定义代码
    SpiaRegs.SPITXBUF=00;//启动发送功能

    while (1);
}

初始化SPI
void InitSpi(void)
{
    SpiaRegs.SPICCR.bit.SPISWRESET = 0; //SPI复位

    //数据在时钟上升沿发送,在时钟下降沿所存输入的数据
    SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; //上升沿触发
    SpiaRegs.SPICTL.bit.CLK_PHASE = 0; //无延时时钟

    SpiaRegs.SPICCR.bit.SPILBK = 1; //内部回路使能,实现自发自收
    SpiaRegs.SPICCR.bit.SPICHAR = 0xF; //发送和接收的数据长度16

    SpiaRegs.SPICTL.bit.OVERRUNINTENA = 0; //关闭溢出中断
    SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; //主控制器模式
    SpiaRegs.SPICTL.bit.TALK = 1; //使能发送功能
    SpiaRegs.SPICTL.bit.SPIINTENA = 1; //禁止SPI中断

    SpiaRegs.SPIBRR = 0x63; //波特率=150M/4/100=375K

    SpiaRegs.SPIPRI.bit.FREE = 1; //仿真不影响发送数据

    SpiaRegs.SPICCR.bit.SPISWRESET = 1; //SPI功能恢复

#if isFIFO
    SpiaRegs.SPIFFTX.bit.SPIFFENA = 1; //使能FIFO功能
    SpiaRegs.SPIFFTX.bit.TXFIFO = 0;//FIFO发送功能复位
    SpiaRegs.SPIFFTX.bit.TXFFIENA = 1;//使能TXFIFO中断
    SpiaRegs.SPIFFTX.bit.TXFFIL = 0;//FIFO深度,若是发送FIFO中数据少于等于0个,则触发中断

    SpiaRegs.SPIFFRX.bit.RXFIFORESET = 0;//FIFO接收功能复位
    SpiaRegs.SPIFFRX.bit.RXFFIENA = 1;//使能FIFO接收中断
    SpiaRegs.SPIFFRX.bit.RXFFIL = 1;//FIFO深度,若是接收FIFO中数据多于等于1个,则触发中断

    SpiaRegs.SPIFFTX.bit.TXFIFO = 1;//FIFO发送功能恢复
    SpiaRegs.SPIFFRX.bit.RXFIFORESET = 1;//FIFO接收功能恢复
#endif
}

中断服务程序

//定义全局变量
Uint16 rx = 0;
Uint16 tx = 0;

#if isFIFO
//SPI发送中断服务程序
interrupt void IsrSpiTx()
{
    tx++;
    SpiaRegs.SPITXBUF = tx; //发送数据
    SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1; //清除发送中断
    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //清除第六组中断
}
#endif
//SPI接收中断服务程序
interrupt void IsrSpiRx()
{
#if isFIFO==0
    tx++;
    SpiaRegs.SPITXBUF = tx;
#endif

    rx = SpiaRegs.SPIRXBUF; //接收数据

#if isFIFO
    SpiaRegs.SPIFFRX.bit.RXFFINTCLR = 1; //清除接收中断
#endif

    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //清除第六组中断

}

结果

断点是打在rx = SpiaRegs.SPIRXBUF; //接收数据处。可以总结出,读取的SPIRXBUF数据是上一次发送的数据。示波器的一号针脚连接的是SPI时钟线,二号针脚连接的是SPISIMO,即本次发送的数据值。

第一组:传送数据为16位

在这里插入图片描述

在这里插入图片描述

第二组:传送数据为5位

在这里插入图片描述
在这里插入图片描述

  • 25
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值