13.DSP学习记录之SPI

SPI(串行外围设备接口)

一、简介及组成

1、简述

一种高速同步串行通信接口。

SPI是同步通信,SCI是异步通信。

同步通信时,通信双方的设备必须拥有相同的时钟脉冲,以相同的频率进行数据传输。而异步通信时,通信双方的设备可以拥有各自独立的时钟脉冲,可以独自进行数据传。

SPI接口一般使用4条线。当然,并不是所有的SPI接口都是采用四线制的,有的SPI接口带有中断信号线INT,而有的SPI接口没有主机输出/从机输入线MOSI。在F28335中SPI接口采用的是四线制。

这种模式的通信系统中通常有一个主设备和多个从设备。

其中,CS信号为片选信号,低电平表示从机的芯片选中。片选信号的存在使得允许在同一总线上连接多个SPI设备成为可能。

SPI采用的是串行通信协议,也就是说,通信时数据是一位一位进行传输的。

传输时,由SCK提供时钟脉冲,MOSI和MISO引脚则是基于此脉冲完成数据的发送或者接收。

如上图, 当M1给S1发送数据时,数据在时钟脉冲的上升沿或者下降沿时通过M1的MOSI引脚发送,在紧接着的下降沿或者上升沿时通过S1的MOSI引脚接收。当S1给M1发送数据时,原理是一样的,只不过通过MISO引脚来完成。

值得注意的是,SCK信号只由主设备控制,因此,在一个基于SPI的系统中,必须至少有一个主控设备,其向整个SPI系统提供时钟信号,系统内所有的设备都基于这个时钟脉冲进行数据的接收或者发送,所以SPI是同步串行通信接口。在点对点的通信中,SPI接口不需要寻址操作,且为全双工通信,因此显得简单高效。

工作过程:

如图,当时钟脉冲第一个上升沿来的时候,SPIDAT1将最高位1移出,并将剩余所有的数据左移1位,这时主机的MOSI引脚为高电平,而SPIDAT2将最高位0移出,并将剩余所有的数据左移1位,这时从机的MOSI引脚为低电平。然后,当时钟脉冲下降沿到来的时候,SPIDAT1将锁存主机MISO引脚上的电平,也就是从机发出的低电平,并将数值0移入其最低位,同样,SPIDAT2将锁存从机MISO引脚上的电平,也就是主机发出的高电平,并将数值1移入其最低位。经过8个时钟脉冲后,两个移位寄存器就实现了数据的交换,也就是完成了一次SPI的时序。

2、构成

(1)外部引脚有如下四个:

(2)有两种工作模式可以选择:主工作模式和从工作模式。

(3)数据传输速率:具有125种可编程的数据传输速率。而最高的数据传输速率不能超过LSPCLK/4。

(4)单次发送的数据字的长度为1~16位,可以通过寄存器设定。

(5)可选择的4种脉冲时钟配置方案

(6)接收和发送可以同步操作,也就是说,可以实现全双工通信。当然,发送功能可以通过SPICTL寄存器TALK位 禁止或者使能。

(7)和SCI相同,发送和接收都能通过查询或者中断方式来实现。

(8)具有6个控制寄存器、3个数据寄存器和3个FIFO寄存器。值得注意的是,SPI所有的控制寄存器都是8位的,当寄存器被访问时,数据位于低8位,而高8位为0,因此把数据写入SPI这6个控制寄存器的高8位是无效的。但是,3个数据寄存器SPIRXBUF、SPITXBUF和SPIDAT都是16位的。3个FIFO寄存器也是16位的。

(9)F28335的SPI也具有2个16级的FIFO:一个用于发送数据,另一个用于接收数据。发送数据的时候,数据与数据之间的延时可以通过编程进行控制。

(10)在标准的SPI模式(非FIFO模式)下,发送中断和接收中断都使用SPIINT/RXINT 。在FIFO模式中,接收中断使用SPIINT/RXINT ,而发送中断使用的是SPITXINT

二、工作原理

1.综述

如上图,SPI能够完成数据的交换主要依赖3个数据寄存器,接收数据缓冲寄存器SCIRXBUF、发送数据缓冲寄存器 SCITXBUF和数据移位寄存器SPIDAT,这3个寄存器均为16位数据寄存器。

SPI模块可以通过移位寄存器实现数据的交换,即通过SPIDAT寄存器移入或者移出数据。下面简单介绍SPI工作在标准SPI模式下(FIFO未使能)时数据交换的过程。

首先,通过程序向发送缓冲寄存器SCITXBUF写入数据,如果此时SPIDAT寄存器为空,则SCITXBUF将需要发送的完整数据传输给 SPIDAT,数据在 SCITXBUF 寄存器和SCIDAT寄存器内存放都是左对齐的,也就是从高位开始存储的。

SPIDAT经过每一个时钟脉冲,完成一位数据的发送或者接收。假设在时钟脉冲的上升沿时,SPIDAT 将数据的最高位发送出去,然后将剩余的所有数据左移一位,接下来,在时钟脉冲的下降沿时,SPIDAT锁存一位数据,并保存至其最低位。当发送完指定位数的数据后,SPIDAT寄存器将其内部的数据发送给接收缓冲寄存器SPIRXBUF,等待CPU来读取。数据在SPIRXBUF中存放是右对齐的,也就是从低位开始存储的。

在标准SPI模式下,CPU可以暂时不发送\读取 SPIRXBUF 中接收到的数据,但是在新的接收操作完成之前必须读取SPIRXBUF,否则将会覆盖原来接收到的数据。

2.工作模式

SPI工作控制寄存器 SPICTL的** MASTER/SLAVE 位** 决定了SPI工作于何种模式:

MASTER/SLAVE=1时,SPI工作于主机模式;而当MASTER/SLAVE=0时,SPI工作于从机模式。

(1)举例

上图所示的是典型的SPI主/从模式的连接图,系统中有两个处理器,处理器1的SPI工作于主机模式,而处理器2的SPI工作于从机模式。时钟信号SPICLK是由主机提供给从机的,主机和从机在SPICLK的协调下同步进行数据的发送或者接收,数据在时钟脉冲信号的上升沿或者下降沿进行发送或者读取。

当然,主机和从机之间进行通信的前提是从机片选信号SPISTE为低电平,将SPI从机选中,也就是将处理器2选中。主机和从机之间可以同时实现数据的发送和接收,也就是说,可以工作于全双工模式。下

(1)主机模式

传输速率:

整个SPI的通信网络中的时钟和数据传输速率是由主机来提供的,主机通过SPICLK引脚为整个通信网络提供时钟脉冲信号。由于每经过一个时钟脉冲,SPI就完成一位数据的发送,因此时钟脉冲的频率就是通常所说的数据传输速率,其值由主机的SPIBBR寄存器来决定。通过对SPIBBR寄存器的编程,SPI能够实现125种不同的数据传输速率,最大数据传输速率为LSPCLK/4。

工作过程:

主机通过SPISIMO引脚来发送数据,通过SPISOMI引脚输入数据。当数据写到移位寄存器SPIDAT或串行发送缓冲器SPITXBUF时,会启动SPISIMO引脚开始发送数据,首先发送的是SPIDAT的最高位,接着将剩余的数据左移一位,然后将接收到的数据通过SPISOMI引脚移入SPIDAT的最低有效位。如此重复,当SPIDAT中所要发送的数据都发送出去之后,SPIDAT中接收到的数据被写到SPI的接收缓冲器

SPIRXBUF中,等待CPU来读取。

根据上面的描述不难理解,为了保证首先发送的是最高位,发送缓冲器 SPITXBUF和移位寄存器SPIDAT中的数据是左对齐的,而由于每次接收到的数据始终是写在最低位,所以接收缓冲寄存器SPIRXBUF中的数据是右对齐的。SPIRXBUF、SPITXBUF、SPIDAT这3个数据寄存器都是16位的。

移位寄存器SPIDAT完成发送时,会产生事件:

1 发送了多少位数据,同时就接收了多少位数据,因此当SPIDAT发送完规定数目中的数据时,SPIDAT中也存放了接收到的相同数目的数据,这时候,SPIDAT中接收到的数据会被写入SPIRXBUF。

2 SPI 的中断标志位SPI INT FLAG 就会被置位,这时候如果SPIINT/RXINT中断已经被使能,从三级中断的角度来看,也就是SPICTL寄存器的SPINT ENA位被置位,相应的PIE中断被使能,相应的CPU中断已开启,则会产生SPIINT/RXINT中断。由于SPI的发送和接收是一起完成的,所以这也就解释了为什么在非FIFO模式下,SPI的发送中断和接收中断使用的是同一个SPIINT/RXINT。

3 当SPIDAT完成数据发送时,如果SPITXBUF中还有数据,则这些数据将被写入SPIDAT,继续发送。当SPIDAT中所有的数据都发送完成后,时钟脉冲SPICLK将会停止,直到有新的数据写入SPIDAT寄存器进行发送。

数据传输过程和传输完成两种状态时,主机的SPISTE引脚化:

SPISTE引脚是从机使能信号,这是一个低电平有效的信号,也就是说,当主机需要给从机发送数据时,SPISTE引脚就被置为低电平:当主机发送完需要发送的数据后,SPISTE引脚重新被置为高电平。片选信号的存在使得系统能够同时拥有多个从机,但是在同一时刻,只能有一个从机起作用。

(2)从机模式

工作过程:

过程和主机的数据传输机制是类似的。

从机数据通过SPISOMI引脚发送,通过SPISIMO引脚接收。当从机接收到来自于主机脉冲信号的边沿时,就可以启动数据的发送和接收了。数据写入SPIDAT或者SPITXBUF后,SPIDAT就开始将数据的最高位移出,同时左移剩下的数据,然后将接收到的数据移入SPIDAT的最低位。

如果数据写到SCITXBUF时,SPIDAT内有数据正在发送,则SPITXBUF就要等待,等到SPIDAT中数据发送完成后再把 SPITXBUF中的数据写入SPIDAT,而如果数据写到SCITXBUF时,SPIDAT没有数据在发送,则这些数据会被立刻写入SPIDAT寄存器。

从机的发送禁止:

从机通常是接收功能用得比较多,可以通过设置SPICTL寄存器的TALK位低电平来禁止SPI的发送功能

3.数据格式

F28335的SPI通过对配置控制寄存器SPICCR的第3位至第0位的选择,可以实现1~16位数据的传输。

当每次传输的数据少于16位时,需要注意以下几点:

(1)当数据写入 SPITXBUF和SPIDAT寄存器时,必须左对齐;

(2)当数据从 SPIRXBUF寄存器读取时,必须右对齐;

(3)SPIRXBUF寄存器中存放的是最新接收到的数据,数据采用右对齐方式,再加上前面移位到左边后留下的位。

举例:

假设SPIDAT寄存器当前的值为737BH,发送数据的长度为1位,则SPIDATA和SPIRXBUF 在发送前后的状态如图:

4.传输速率

SPI通过对寄存器SPIBRR的配置,可以实现125种不同的数据传输速率,计算公式如下:
SPIBaudRate = { LSPCLK 4 , 当 S P I B R R = 0 ∼ 2 时 , LSPCLK S P I B R R + 1 , 当 S P I B R R = 3 ∼ 127 时 . \text{SPIBaudRate} = \begin{cases} \dfrac{\text{LSPCLK}}{4}, & \text{当 } SPIBRR = 0 \sim 2 \text{ 时}, \\[2ex] \dfrac{\text{LSPCLK}}{SPIBRR + 1}, & \text{当 } SPIBRR = 3 \sim 127 \text{ 时}. \end{cases} SPIBaudRate=⎩ ⎨ ⎧4LSPCLK,SPIBRR+1LSPCLK,当 SPIBRR=0∼2 时,当 SPIBRR=3∼127 时.

式中的LSPCLK为DSP的低速外设时钟频率。

从上面的数据传输速率计算公式可以看出,SPI模块最大的数据传输速率为LSPCLK/4。

当SBPIBRR为奇数时,(SPIBRR+1)为偶数,SPICLK信号高电平与低电平在一个周期内保持对称;当SPIBRR为偶数时,(SPIBRR+1)为奇数,SPICLK信号高电平和低电平在一个周期内不对称。

当时钟极性位被清零时,SPILCK的低电平比高电平多一个系统时钟周期;当时钟极性被置位时,SPICLK的高电平比低电平多一个系统时钟周期。当SPIBBR=0,1,2,3时,SPICLK 如图16-8所示。当SPIBBR=4,且时钟极性被置位时,SPICLK 如图16-9所示。

5.时钟配置

指SPI在时钟脉冲的什么时刻去发送或者接收数据。

寄存器SPICCR的CLOCK POLARITY 位决定了时钟的极性
寄存器SPICTL的CLOCK PHASE位决定了SPI时钟的相位。

两个参数不同取值的组合可以构成4种不同的时钟方案,:

(1)当CLOCK POLARITY=0,且SPICLK 没有数据发送时,SPICLK处于低电平 ,这时候:

1 当CLOCK PHASE=0时,SPI在SPICLK信号的上升沿发送数据 ,在SPICLK信号的下降沿接收数据 ;

2 当CLOCK PHASE=1时,SPI在SPICLK信号的上升沿延时了半个周期后发送,在随后的上升沿处接收数据。

(2)当CLOLCK PLARITY=1,且SPICLK 没有数据发送时,SPLCLK处于高电平 ,这时候:

1当CLOCK PHASE=0时,SPI在SPICLK信号的下降沿发送数据 ,在SPICLK信号的上升沿接收数据 ;

2 当CLOCK PHASE=1时,SPI在SPICLK信号的下降沿延时了半个周期 后发送,在随后的下降沿处接收数据。

如图:

6.FIFO

F28335的SPI也具有16级深度的发送FIFO和接收FIFO。

当FIFO功能未被使能时,SPI工作于标准SPI模式;当FIFO功能被使能时,SPI工作于增强的FIFO模式。FIFO的功能由3个寄存器设置,分别是SPI FIFO发送寄存器SPIFFTXSPI FIFO接收寄存器SPIFFRXSPI FIFO控制寄存器 SPIFFCT

配置:

当DSP复位时,SPI工作在标准SPI模式下,FIFO功能被禁止。通过将SPIFFTX寄存器中的SPIFFEN位 置位来启动SPI的FIFO功能。将SPIFFTX的位SPIRST置1,可以在任何状态下复位FIFO模式,SPI FIFO将重新开始发送和接收数据。

SPI具有1个16×16b的发送缓冲器和1个16×16b的接收缓冲器,标准模式下的发送缓冲器SPITXBUF将作为发送FIFO和移位寄存器SPIDAT之间的一个发送缓冲器。

当最后一位数据从移位寄存器SPIDAT 移出后,SPITXBUF将重新从FIFO装载数据。

传输速度:

数据从FIFO转移到移位寄存器的速度是可编程的。SPIFFCT寄存器的第7位到第0位,即FFTXDLY定义了两个数据发送间的延时。这个延时是以SPI串行时钟周期SPICLK 为基准的。这个8位寄存器可以定义最小0个时钟周期的延时和最大256个时钟周期的延时。当延时为0个时钟周期时,SPI模块能够连续发送数据;当延时为256个时钟周期时,SPI模块发送数据将产生最大延时。这种可编程的特点,使得SPI接口可以更方便地与许多传输速率较慢的外设(如EEPROM、ADC、DAC等)进行通信。

有用数据个数:

发送和接收FIFO都有状态位TXFFST和RXFFST。TXFFST位于寄存器SPIFFTX[12:8],共5位;RXFFST位于寄存器SPIFFRX[12:8],共5位。

这两个状态位的作用是在任何时间都可以标识FIFO队列中有用数据的个数。当TXFFST被清零时,发送

FIFO队列的复位位TXFIFO RESET也被清零,发送FIFO的指针复位为0,可以通过将TXFIFO RESET 置位来重新启动FIFO队列的发送操作。同样,当RXFFST被清零时,接收FIFO队列的复位位RXFIFO RESET也被清零,接收FIFO的指针复位为0,可以通过将RXFIFO RESET置位来重新启动FIFO队列的接收操作。

7.中断

当SPI工作于标准SPI模式下时,能够产生接收溢出中断RX_OVRN INT和发送或接收操作的中断

SPIINT,这两个中断共用中断线 SPIRXINT。当SPI工作于FIFO模式下时,能够产生接收中断SPIRXINT 和发送中断SPITXINT。

(1)在标准SPI 模式下

当SPIFFTX寄存器的SPIFFENA位为0时,也就是FIFO功能未被使能时,SPI工作于标准 SPI模式。

当一个完整的字符移入或者移出SPIDAT时,SPIRXINT的中断标志位SPIINT FLAG被置位,时,SPIDAT中接收到的数据就会被写入SPIRXBUF缓冲寄存器,等待CPU读取。如果SPI工作控制寄存器的位SPI INT ENA被置位,也就是SPIRXINT中断被使能,则SPI将向PIE控制寄存器提出中断请求。

SPIRXINT也是一种复用的中断,当SPI接收数据产生溢出时,也会产生SPIRXINT的中断请求信号。如果在新的接收数据写入SPIRXBUF寄存器之前,旧的数据CPU还尚未读取,那么新的数据写入之后就丢失了旧的数据,这时候接收溢出标志位RX_OVRNFLAG被置位,如果SPICTL寄存器的OVERRUN INT ENA位被置位,也就是接收溢出中断被使能,则SPI也将向PIE控制寄存器提出中断请求。

无论是接收溢出,还是接收完成或者发送完成,所产生的中断都使用SPIRXINT中断线。当CPU读取SPIRXBUF寄存器中的数据后,中断标志位SPI INT FLAG会自动被清除。

(2)在FIFO 模式下

当SPIFFTX寄存器的SPIFFENA位为1时,也就是FIFO功能被使能时,SPI工作于增强的FIFO模式。

对于接收操作,接收FIFO队列有状态位RXFFST,表示接收FIFO中有多少个接收到的数据。同时,SPI FIFO接收寄存器SPIFFRX还有一个可编程的中断触发级位RXFFIL。当RXFFST的值与预设好的
RXFFIL 相等时,接收FIFO就会产生接收中断SPIRXINT信号
,如果SPIFFRX寄存器的位RXFFIENA为1,也就是FIFO接收中断已经使能,那么SPI将向PIE控制器提出中断请求。比如,假设通过编程,将RXFFIL位设置为8,那么当FIFO队列中接收到8个数据时,RXFFST的值也为8,正好和RXFFIL的值相等,这时候接收FIFO就产生了接收中断匹配事件。

对于发送操作,发送FIFO队列有状态位TXFFST,表示发送FIFO中有多少个数据需要发送。同时SPI FIFO发送寄存器SPIFFTX也有一个可编程的中断触发级位TXFFIL。当TXFFST的值与预设好的TXFFIL相等时,发送FIFO就会产生发送中断SPITXINT信号,如果SPIFFTX寄存器的位TXFFIENA为1,也就是FIFO发送中断已经使能,那么SPI将向PIE控制器提出中断请求。比如,假设通过编程,将TXFFIL位设置为8,那么当FIFO队列中还剩8个数据需要发送时,TXFFST的值也为8,正好和TXFFIL的值相等,

这时候发送FIFO就产生了发送中断匹配事件。复位后,发送FIFO的中断触发级位TXFFIL默认的值为0x0000,即0,也就是说,FIFO队列中数据全部发送完毕后产生发送中断请求。

中断表如下:

三、SPI的寄存器

SPI寄存器汇总:

(1)SPI 配置控制寄存器(SPICCR)




(2)SPI 操作控制寄存器(SPICTL)



(3)SPI 状态寄存器(SPISTS)


(4)SPI 波特率设置寄存器(SPIBRR)

具体配置过程在第二节

(5)SPI 仿真缓冲寄存器(SPIRXEMU)

SPIRXEMU 包含接收到的数据。读取 SPIRXEMU 寄存器不会清除 SPI INT FLAG位。这不是一个真正的寄存器而是来自 SPIRXBUF 寄存器的内容且在没有清除 SPIINT FLAG 位的情况下能被仿真器读的位地址

(6)SPI 串行接收缓冲寄存器(SPIRXBUF)
注意: SPIRXBUF 寄存器包含接收到的数据, 读取 SPIRXBUF 会清除 SPI INT FLAG位

(7)SPI 串行发送缓冲寄存器(SPITXBUF)

SPITXBUF 寄存器存储下一个数据是为了发送,向该寄存器写入数据会设置TXBUF FULL FLAG 位

当目前的数据发送结束时,寄存器的内容会自动的装入SPIDAT 中且 TXBUF FULL FLAG 位被清除。如果当前没有发送,写到该位的数据将会传送到 SPIDAT 寄存器中且 TXBUF FULL 标志位不

在主动模式下,如果当前发送没有被激活,则向该位写入数据将启动发送,同时数据被写入到 SPIDAT 寄存器中

(8)SPI 串行数据寄存器(SPIDAT)

SPIDAT 是发送/接收移位寄存器。写入 SPIDAT 寄存器的数据在后续的 SPICLK周期中(最高有效位)一次被移出

(9)SPI FIFO 发送寄存器SPIFFTX


(10)SPI FIFO 接收寄存器 SPIFFRX


(11)SPI FIFO 控制寄存器 SPIFFCT

(12)SPI 优先级控制寄存器 SPIPR

四、配置及实验

1.配置步骤

(1)使能 SPI 外设时钟及初始化对应

c 复制代码
EALLOW;
SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1; // SPI-A
EDIS;

外设的配置可以直接调用TI的库函数:DSP2833x_Spi.c

c 复制代码
InitSpiGpio();

其内部实现为:( 注意 :这里给出的的是GPIO54~57的配置,28335的SPI还可以复用在GPIO16 ~19)

c 复制代码
// TI File $Revision: /main/1 $
// Checkin $Date: August 18, 2006   13:46:44 $
//###########################################################################
//
// FILE:   DSP2833x_Spi.c
//
// TITLE:  DSP2833x SPI Initialization & Support Functions.
//
//###########################################################################
// $TI Release: DSP2833x Header Files V1.01 $
// $Release Date: September 26, 2007 $
//###########################################################################

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File

//---------------------------------------------------------------------------
// InitSPI: 
//---------------------------------------------------------------------------
// This function initializes the SPI(s) to a known state.
//
void InitSpi(void)
{
   // Initialize SPI-A/B/C/D

   //tbd...
 
}

//---------------------------------------------------------------------------
// Example: InitSpiGpio: 
//---------------------------------------------------------------------------
// This function initializes GPIO pins to function as SPI pins
//
// Each GPIO pin can be configured as a GPIO pin or up to 3 different
// peripheral functional pins. By default all pins come up as GPIO
// inputs after reset.  
// 
// Caution: 
// For each SPI peripheral
// Only one GPIO pin should be enabled for SPISOMO operation.
// Only one GPIO pin should be enabled for SPISOMI operation. 
// Only one GPIO pin should be enabled for SPICLKA operation. 
// Only one GPIO pin should be enabled for SPISTEA operation. 
// Comment out other unwanted lines.

void InitSpiGpio()
{

   InitSpiaGpio();
}

void InitSpiaGpio()
{

   EALLOW;
/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.  
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;   // Enable pull-up on GPIO54 (SPISIMOA)
    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;   // Enable pull-up on GPIO55 (SPISOMIA)
    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;   // Enable pull-up on GPIO56 (SPICLKA)
    GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;   // Enable pull-up on GPIO57 (SPISTEA)


//    GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;   // Enable pull-up on GPIO54 (SPISIMOA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;   // Enable pull-up on GPIO55 (SPISOMIA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;   // Enable pull-up on GPIO56 (SPICLKA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;   // Enable pull-up on GPIO57 (SPISTEA)

/* Set qualification for selected pins to asynch only */
// This will select asynch (no qualification) for the selected pins.
// Comment out other unwanted lines.

//    GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA)

    GpioCtrlRegs.GPBQSEL2.bit.GPIO54 = 3; // Asynch input GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; // Asynch input GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO56 = 3; // Asynch input GPIO18 (SPICLKA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO57 = 3; // Asynch input GPIO19 (SPISTEA)

    
/* Configure SPI-A pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be SPI functional pins.
// Comment out other unwanted lines.

//    GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA

    GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1; // Configure GPIO54 as SPISIMOA
    GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1; // Configure GPIO55 as SPISOMIA
    GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1; // Configure GPIO56 as SPICLKA
    GpioCtrlRegs.GPBMUX2.bit.GPIO57 = 1; // Configure GPIO57 as SPISTEA

    EDIS;
}

//===========================================================================
// End of file.
//===========================================================================

(2)SPI 工作方式及参数设置,包括数据格式、相位极性、FIFO 功能等。

c 复制代码
// Initialize SPI FIFO registers
SpiaRegs.SPIFFTX.all=0xE040;//使能 FIFO,清除发送中断
SpiaRegs.SPIFFRX.all=0x204f;//使能 FIFO 接收 16 级深度
SpiaRegs.SPIFFCT.all=0x0;//清除 FIFO 计数器
SpiaRegs.SPICCR.all =0x000F;//复位 SPI,上升沿发送,下降沿接收,16
位数据
SpiaRegs.SPICTL.all =0x0006;// 无相位延时,主模式
SpiaRegs.SPIBRR =0x007F;//确定 SPICLK
SpiaRegs.SPICCR.all =0x009F;//自测模式并从复位状态释放
SpiaRegs.SPIPRI.bit.FREE = 1;//自由运行

(3)SPI 发送和接收函数

SPI 发送数据,即将数据存储到== SPITXBUF 寄存器中。接收数据时,先判断FIFO ==内是否有数据,如果有数据则可从 SPIRXBUF 寄存器读取

c 复制代码
Uint16 SPIA_SendReciveData(Uint16 dat)
{
	// Transmit data
	SpiaRegs.SPITXBUF=dat;
	// Wait until data is received
	while(SpiaRegs.SPIFFRX.bit.RXFFST !=1)
	return SpiaRegs.SPIRXBUF;
}

注意:该函数会将需要发送的数据dat通过SPI发送给从机,同时会返回从机发送回来的数据

2.实验

实现效果:

配置SPI的GPIO54~GPIO57,实现使用 SPI 实现:

用上位机通过串口发送数据,DSP接收到后将数据通过SPI发送给从设备,从设备将接收到的主设备的数据原封不动的发送回来,串口再将SPI发送回来的数据加一后发送给上位机打印出来实现SPI的回环数据检测,串口只起到发送/显示数据作用

代码:

SPI配置:

c 复制代码
#include "SPI.h"

void SPI_Init(void)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1; // SPI-A
	EDIS;

	// Initialize SPI FIFO registers

	//配置控制:(初始化)
	SpiaRegs.SPICCR.all =0x000F;//复位 SPI,上升沿发送,下降沿接收,16位数据
	//操作控制
	SpiaRegs.SPICTL.all =0x0006;//禁止中断,无相位延时,SPI主模式,使能发送

	//发送和接收寄存器配置
	SpiaRegs.SPIFFTX.all=0xE040;//使能 FIFO,16位,清除发送中断,清楚TXFFINT------7,全发送完中断
	SpiaRegs.SPIFFRX.all=0x204f;//接收FIFO控,使能 FIFO,清除7位,接收 16 级中断

	//FIFO控制寄存器
	SpiaRegs.SPIFFCT.all=0x0;//无延迟,清除 FIFO 计数器
	//波特率
	SpiaRegs.SPIBRR =0x007F;//确定 SPICLK
	SpiaRegs.SPICCR.all =0x009F;//自测模式并从复位状态释放
	SpiaRegs.SPIPRI.bit.FREE = 1;//自由运行

}

Uint16 SPIA_SendReciveData(Uint16 dat)
{
	// Transmit data
	SpiaRegs.SPITXBUF=dat;
	// Wait until data is received
	while(SpiaRegs.SPIFFRX.bit.RXFFST !=1);
	return SpiaRegs.SPIRXBUF;
}

主函数:

c 复制代码
#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File
#include "LED.h"
#include "SCI.h"
#include "SPI.h"
#include "LED.h"




void main()
{
	Uint16 ReceivedChar;

	InitSysCtrl();

	SCI_Init();
	SPI_Init();

	InitPieCtrl();
	IER=0x0000;
	IFR=0x0000;
	InitPieVectTable();


	while(1)
	{
		while(SciaRegs.SCIFFRX.bit.RXFFST !=1);// wait for XRDY =1
		ReceivedChar = SciaRegs.SCIRXBUF.all;
		UARTa_SendByte(SPIA_SendReciveData(ReceivedChar)+1);

	}
}

SPI的官方初始化配置函数:

c 复制代码
// TI File $Revision: /main/1 $
// Checkin $Date: August 18, 2006   13:46:44 $
//###########################################################################
//
// FILE:   DSP2833x_Spi.c
//
// TITLE:  DSP2833x SPI Initialization & Support Functions.
//
//###########################################################################
// $TI Release: DSP2833x Header Files V1.01 $
// $Release Date: September 26, 2007 $
//###########################################################################

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File

//---------------------------------------------------------------------------
// InitSPI: 
//---------------------------------------------------------------------------
// This function initializes the SPI(s) to a known state.
//
void InitSpi(void)
{
   // Initialize SPI-A/B/C/D

   //tbd...
 
}

//---------------------------------------------------------------------------
// Example: InitSpiGpio: 
//---------------------------------------------------------------------------
// This function initializes GPIO pins to function as SPI pins
//
// Each GPIO pin can be configured as a GPIO pin or up to 3 different
// peripheral functional pins. By default all pins come up as GPIO
// inputs after reset.  
// 
// Caution: 
// For each SPI peripheral
// Only one GPIO pin should be enabled for SPISOMO operation.
// Only one GPIO pin should be enabled for SPISOMI operation. 
// Only one GPIO pin should be enabled for SPICLKA operation. 
// Only one GPIO pin should be enabled for SPISTEA operation. 
// Comment out other unwanted lines.

void InitSpiGpio()
{

   InitSpiaGpio();
}

void InitSpiaGpio()
{

   EALLOW;
/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.  
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;   // Enable pull-up on GPIO54 (SPISIMOA)
    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;   // Enable pull-up on GPIO55 (SPISOMIA)
    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;   // Enable pull-up on GPIO56 (SPICLKA)
    GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;   // Enable pull-up on GPIO57 (SPISTEA)


//    GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;   // Enable pull-up on GPIO54 (SPISIMOA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;   // Enable pull-up on GPIO55 (SPISOMIA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;   // Enable pull-up on GPIO56 (SPICLKA)
//    GpioCtrlRegs.GPBPUD.bit.GPIO57 = 0;   // Enable pull-up on GPIO57 (SPISTEA)

/* Set qualification for selected pins to asynch only */
// This will select asynch (no qualification) for the selected pins.
// Comment out other unwanted lines.

//    GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA)
//    GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA)

    GpioCtrlRegs.GPBQSEL2.bit.GPIO54 = 3; // Asynch input GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; // Asynch input GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO56 = 3; // Asynch input GPIO18 (SPICLKA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO57 = 3; // Asynch input GPIO19 (SPISTEA)

    
/* Configure SPI-A pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be SPI functional pins.
// Comment out other unwanted lines.

//    GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
//    GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA

    GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1; // Configure GPIO54 as SPISIMOA
    GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1; // Configure GPIO55 as SPISOMIA
    GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1; // Configure GPIO56 as SPICLKA
    GpioCtrlRegs.GPBMUX2.bit.GPIO57 = 1; // Configure GPIO57 as SPISTEA

    EDIS;
}

//===========================================================================
// End of file.
//===========================================================================
相关推荐
爱喝纯牛奶的柠檬26 分钟前
【已验证】STM32+MPU6050 姿态解算 + 运动状态识别 + 四阶段摔倒检测
stm32·单片机·嵌入式硬件
戏舟的嵌入式开源笔记31 分钟前
STM32 RS485读取SHT20
stm32·单片机·嵌入式硬件
LCG元2 小时前
噪声检测系统:STM32F4驱动MEMS麦克风,FFT频谱分析实战
stm32·单片机·嵌入式硬件
charlie1145141912 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(2) —— HAL 库获取、启动文件坑位与目录搭建
linux·开发语言·c++·stm32·单片机·学习·嵌入式
v先v关v住v获v取2 小时前
多功能割草装置的结构设计8张cad+三维图+设计说明书
科技·单片机·51单片机
leiming62 小时前
信号量为什么“不占CPU“
单片机·嵌入式硬件
爱喝纯牛奶的柠檬3 小时前
【已验证】基于STM32F103的土壤湿度传感器驱动
stm32·单片机·嵌入式硬件
Zevalin爱灰灰4 小时前
零基础入门学用物联网(ESP8266) 第二部分 MQTT基础篇(三)
单片机·物联网·mqtt·嵌入式·esp8266
llilian_164 小时前
ptp从时钟 ptp授时模块 如何挑选PTP从时钟授时协议模块 ptp从时钟模块
数据库·功能测试·单片机·嵌入式硬件·测试工具
Truffle7电子4 小时前
STM32理论 —— FreeRTOS:中断管理、列表
stm32·单片机·嵌入式硬件·rtos