1.结构

5744的SPI模块支持全双工三线同步传输,可运行在主机或从机模式,分别含有深度为5的FIFO发送和接收缓存区。其结构如下图。SPI配置允许模块发送和接收串行数据,同时也支持带FIFO缓存区的的进行扩展队列操作的数据传输。模块接收和发送的数据存放在独立的FIFO内,CPU或DMA控制器从接收FIFO读取数据,写入数据到Tx FIFO内进行发送。

spc5744内核架构 spc574s_MPC5744

2、传输过程

1)发送过程

发送数据时CPU先查询寄存器SR内TFFF的状态,若TFFF为为0则表明TX FIFO已满,继续写入无效;当TFFF为1则表明TX FIFO未满,可以继续写入。CPU通过写数据到寄存器PUSHR将要发送的数据添加到TX FIFO内,TX FIFO根据先入先出的顺序将数据移入移位寄存器进行发送,只要TX FIFO内有有效的数据,则一直进行发送。在每一次成功传输后,寄存器SR内的TCF被置位表明一次成功的传输。寄存器SR的TXCTR值阈计数TX FIFO内的有效数据数,当有数据被压入或被传送到移位寄存器时,TXCTR随之更新。当PUSHR寄存器中EOQ==1的数据被传输完成后,寄存器SR中的EOQF置位表明数据队列被全部发送完毕,可用于指示多个数据的发送完毕。

2)接收过程

当移位寄存器内的数据接收完成后,接收到的数据被添加到RX FIFO内,CPU通过读POPR寄存器将数据从RX FIFO内取出。当RX FIFO 不为空,寄存器SR中的RFDF被置位,当读取数据时,CPU先查询寄存器SR内RFDF的状态,若RFDF为0则表明RX FIFO为空,继续读取数据无效;当RFDF为1则表明RX FIFO不为空,可通过读POPR寄存器来读取RX FIFO内的数据。相应地,寄存器SR的RXCTR值阈计数RX FIFO内的有效数据数,当有数据被移入到RX FIFO 或被CPU通过POPR取出时,RXCTR随之更新。

3、传输模式

SPI传输可分为主机模式和从机模式,也有经典模式和改进模式。本文以经典主机模式为例。主机模式下SCK、PCS、SOUT为输出,SIN为输入。

1)CPHA=0

 如下图CPHA=0时,数据捕捉在SCK的奇数跳边沿,数据变化在SCK的偶数跳边沿。与之相对应地若CPOL=0,SCK高电平有效,则数据捕捉在SCK的上升沿,数据变化在SCK的下降沿;若CPOL=1,SCK低电平有效,则数据捕捉在SCK的下降沿,数据变化在SCK的上升沿。

spc5744内核架构 spc574s_spc5744内核架构_02

2)CPHA=1

如下图所示,当CPHA=1,数据捕捉在SCK的偶数跳边沿,数据变化在SCK的奇数跳边沿。相应地若CPOL=0,SCK高电平有效,则数据捕捉在SCK的下降沿,数据变化在SCK的上升沿;若CPOL=1,SCK低电平有效,则数据捕捉在SCK的上升沿,数据变化在SCK的下键沿。

spc5744内核架构 spc574s_spc5744内核架构_03

3)持续片选模式和非持续片选模式

持续片选模式是指在两个数据帧之间片选信号PCS一直保持有效为低电平;非持续片选模式是指在两个数据帧之间片选信号PCS变为无效,二者区别如下图所示。持续片选和非持续片选模式有寄存器PUSHR[CONT位决定,PUSHR[CONT]=0选择非持续片选,PUSHR[CONT]=1选择持续片选。具体选择哪种方式要根据所要驱动的外设来确定,由于该模式有PUSHR寄存器选择,故在发送数据时要求连续数据持续片选和非持续片选要保持一致,不可混合使用,否则会造成传输错误。

spc5744内核架构 spc574s_数据_04

spc5744内核架构 spc574s_数据_05

4.波特率和时序延时

SPI中协议时钟即是外设桥时钟,也就是在时钟模块所配置的时钟频率,文中缩写为fp。

1)波特率

波特率即是SCK的频率。SPI的波特率由寄存器CTARn中DBR、PBR和BR决定,计算公式如下。其中Prescaler由PBR决定,Scaler由BR决定,对应关系如下表。

spc5744内核架构 spc574s_MPC5744_06

spc5744内核架构 spc574s_数据_07

spc5744内核架构 spc574s_MPC5744_08

2)tcsc

tcsc是指从PCS有效到SCK第一个跳变沿的时间,由CTARn寄存器中PCSSCK和CSSCK决定。

3)tasc

tasc时钟从SCK最后一个跳边沿到PCS无效的时间,由CTARn寄存器中PASC和ASC决定。

4)tdt

tdt是指本次传输PCS无效到下次传输PCS有效的时间。

各个延时值如下图所示:

spc5744内核架构 spc574s_MPC5744_09

5.初始化

5744初始化步骤如下所示:

1)运行模式选择;

2)管脚复用功能配置;

1)使能SPI模块,停止传输以进行寄存器的配置;

2)配置CTARn以进行数据长度、传输模式、波特率和延时的设置,每个CTAR可有不同的配置,PUSHR写入数据到TX FIFO时可根据需要选择不同的CATR寄存器。

3)启动传输过程。

示例代码如下:

/******************************************************
 * 函数名        SPI_SPI0_Init
 * 功能          对SPI0模块进行初始化
 * 输入参数      无
 * 返回值        无
 * 示例          SPI_SPI0_Init();//初始化SPI0
 ******************************************************
 */
void SPI_SPI0_Init()
{
	//运行模式选择
	MC_ME.PCTL99.B.RUN_CFG=0;       //选择运行模式0

	//管脚多路复用配置
	SIUL2.MSCR[36].B.SSS=1;         //PC4,选择作为SPI0_PCS0
	SIUL2.MSCR[36].B.OBE=1;
	SIUL2.MSCR[36].B.SRC=3;

	SIUL2.MSCR[37].B.SSS=1;         //PC5,选择作为SPI0_SCK
	SIUL2.MSCR[37].B.OBE=1;
	SIUL2.MSCR[37].B.SRC=3;

	SIUL2.MSCR[38].B.SSS=1;         //PC6,选择作为SPI0_SOUT
	SIUL2.MSCR[38].B.OBE=1;
	SIUL2.MSCR[38].B.SRC=3;

	SIUL2.IMCR[41].B.SSS=1;         //PC7,选择作为SPI0_SIN
	SIUL2.MSCR[39].B.IBE=1;

	//SPI配置
	SPI_0.MCR.B.MDIS=0;             //使能SPI模块
	SPI_0.MCR.B.HALT=1;             //停止传输
	SPI_0.MCR.B.MSTR=1;             //选择主机模式
	SPI_0.MCR.B.PCSIS=1;            //PCS0无效状态为高

	//CTAR[0]寄存器
	SPI_0.MODE.CTAR[0].B.FMSZ=7;    //配置数值长度为8=FMSZ+1

        //以下两位要根据对应外设选择,否则SPI通信会失败!!!

	SPI_0.MODE.CTAR[0].B.CPHA=1;    //数据捕捉在偶数跳变沿
	SPI_0.MODE.CTAR[0].B.CPOL=1;    //SCK低电平有效

	SPI_0.MODE.CTAR[0].B.PCSSCK=2;  //tcsc=5*8/45mhz=0.875us
	SPI_0.MODE.CTAR[0].B.CSSCK=2;

	SPI_0.MODE.CTAR[0].B.PASC=2;    //tacs=5*8/45mhz=0.875us
	SPI_0.MODE.CTAR[0].B.ASC=2;
        
        //波特率=(fP/PBR)x[(1+DBR)/BR]=45mhz/5*(1+0)/4=2.25MHz
	SPI_0.MODE.CTAR[0].B.PBR=2;     
	SPI_0.MODE.CTAR[0].B.BR=1;

	SPI_0.MODE.CTAR[0].B.PDT=2;
	SPI_0.MODE.CTAR[0].B.DT=13;    //tdt=5*32768/45mhz=3.64ms

	SPI_0.MCR.B.HALT=0;            //开始传输

}

6.数据发送

发送数据通过将数据写入PUSHR寄存器发送。其实PUSHR寄存器除数据部分外,还有命令部分,可根据需要进行选择。

spc5744内核架构 spc574s_数据_10

  • CONT选择是否为持续片选模式
  • CTAS用于选择初始化中设置的CTAR寄存器用以选择用于传输的数据长度、传输模式、波特率和延时等。
  • EOQ用于标识是否为数据队列的最后一帧数据
  • PCS用于选择片选引脚。

发送步骤为:

1)将数据写入PUSHR寄存器;

2)清空SR寄存器EOQF位开始发送;

3)等待发送完成;

4)清除发送完成标志位;

代码如下:

/******************************************************
 * 函数名       SPI_SPI0_Write
 * 功能         通过SPI0发送指定数据
 * 输入参数
 *              data
 *              要发送的数据
 * 返回值       无
 * 示例         SPI_SPI0_Write(tempData);//通过SPI发送数据tempData
 ******************************************************
 */
void SPI_SPI0_Write(uint32_t data)
{

	uint32_t temp_data;
	temp_data=0x08010000|data;      //置位EOF标志为最后一帧数据,选择PCS0为片选引脚
	SPI_0.PUSHR.PUSHR.R=temp_data;
	SPI_0.SR.B.EOQF=1;              //开始传送
	while(!SPI_0.SR.B.TCF);         //等待传送完成
	SPI_0.SR.B.TCF=1;               //清除发送标志位
}

7.数据接收

数据接收时需要等待RX FIFO不为空,也即是SR寄存器RFDF为1。若RFDF为1,则通过读取POPR寄存取来读取数据,然后清空对应标志位。示例代码如下:

/******************************************************
 * 函数名      SPI_SPI0_Read
 * 功能        通过SPI0读取数据
 * 输入参数    无
 * 返回值      通过SPI0所读取到的数据
 * 示例        uint32_t tempData=SPI_SPI0_Read();//通过SPI0读取数据到tempData
 ******************************************************
 */
uint32_t SPI_SPI0_Read()
{
	uint32_t recv_data=0;
	while (SPI_0.SR.B.RFDF != 1);         //等待Rx FIFO不为空
	recv_data= SPI_0.POPR.R;              //读取接收到的数据
	SPI_0.SR.R = 0xFCFE0000;              //清空相应标志位
	return recv_data;
}