一、基本介绍
1.功能
MPC5744内部提供四路SPI通信模块,四路SPI支持以下功能:
- 主/从模式设置
- FIFO
- 最大16bit的帧
- CPLO/CPHA全部四种模式
- 改进的SPI通信模式
- 中断
- DMA
2.时钟源
SPI模块的时钟源为PBRIDGEx_CLK。
3.外设控制寄存器
外设控制器分别为:
- SPI0:MC_ME_PCTL99
- SPI1:MC_ME_PCTL98
- SPI2:MC_ME_PCTL209
- SPI3:MC_ME_PCTL208
4.中断向量
各路SPI中断向量如下:
5.基地址
MPC5744内部的SPI模块寄存器的基地址为:
- SPI0:0xFFE70000
- SPI1:0xFFE74000
- SPI2:0xFBE70000
- SPI3:0xFBE74000
二、寄存器介绍
每个SPI模块内部寄存器相同,各寄存器名称、偏移地址、复位值如下图:
1.模块控制寄存器SPI_MCR
- MSTR主/从模式选择位
置1:选择主模式。
置0:选择从模式 - CONT_SCKE时钟连续输出使能位
置1:时钟在发送两帧数据之间连续输出。
置0:时钟在发送两帧数据之间停止输出。
具体介绍查看连续时钟设置。 - DCONF模块配置位
读00:模块工作在SPI模式。 - FRZ调试模式停止传输位
置1:在调试模式时,使传输在下一帧边界停。
置0:在调试模式时继续传输数据。 - MTFE修改传输格式启用位
置1:修改传输格式。
置0:经典SPI格式。 - PCSSE片选选通使能位
置1:PCS5/ PCSS工作在低电平片选信号选通模式。
置0:PCS5/ PCSS工作在片选信号5模式。
该位在SPI_MCR.CONT_SCKE=1连续时钟模式时无效,PCS5/ PCSS只能工作在片选信号5模式。
具体介绍查看PCS5/ PCSS工作模式。 - ROOE接收FIFO溢出覆盖使能位
置1:当接收FIFO满后继续接收到数据则将接收到的数据移写入移位寄存器。
置0:将接收FIFO满后继续接收到数据的数据丢弃。 - PCSIS片选信号禁用状态设置位
置1:高电平为对应片选信号的禁止状态,及对应芯片的片选信号为低电平有效。
置0:低电平为对应片选信号的禁止状态,及对应芯片片选信号为高电平有效。 - MDIS模块禁止位
置1:传输完毕当前帧后模块时钟将关闭。
置0:使能模块时钟。
在SPI_MCR.MSTR=0从模式下该位应该保持为0。 - DIS_TXF禁用发送FIFO位
置1:发送FIFO被禁用。
置0:启用发送FIFO。 - DIS_RXF禁用接收FIFO位
置1:接收FIFO被禁用。
置0:启用接收FIFO。 - CLR_TXF发送FIFO清空位
置1:清除发送FIFO,SPI_SR.TXCTR,SPI_SR.TXNXTPTR,SPI_PUSHR,SPI_PUSHR_SLAVE。 - CLR_RXF接收FIFO清空位
置1:清除接收FIFO,SPI_SR.RXCTR,SPI_SR.RXNXTPTR,SPI_POPR。 - SMPL_PT采样点设置位
00:修改传输格式模式下,在SCK边沿进行采样。
01:修改传输格式模式下,在SCK边沿后一个系统时钟周期的位置进行采样。
10:修改传输格式模式下,在SCK边沿后两个系统时钟周期的位置进行采样。
该位的设置仅在SPI_CTARn.CPHA=0且系统时钟频率是SCK频率的4倍及以上的情况下起作用。具体介绍查看传输模式。 - HALT开启停止数据传输位
置1:模块停止传输数据。
置0:模块可以传输数据。
2.传输计数寄存器SPI_TCR
- SPI_TCNT发送计数器
当发送完成每帧数据的最后一位,该计数器加1。
将SPI_PUSHR.CTCNT位置1,可以清零该寄存器。
可以通过写该寄存器,将计数器设置为需要的值。
该计数器最大技术到65535,继续计数则回到0。
3.时钟和传输属性寄存器(主模式)SPI_CTARn(n=0,1,2,3)
- DBR具体介绍查看SPI时钟延时设置。
- FMSZ帧大小设置位
该位设置发送接收时每一帧数据的位数。
每一帧数据的位数为该位的值加1。
每一帧的数据位数必须大于4。 - CPOL时钟级性选择位
置1:时钟在空闲时为高电平。
置0:时钟在空闲时为低电平。 - CPHA时钟相位选择位
置1:数据在第一个时钟沿改变,在第二个时钟沿被采样。
置0:数据在第一个时钟沿被采样,在第二个时钟沿改变。 - LSBFE低位优先选择位
置1:数据传输从低位开始。
置0:数据传输从高位开始。
只在SPI_MCR.MSTR=1主模式下支持该功能,在SPI_MCR.MSTR=0从模式下,数据传输从高位开始,不支持从低位开始。 - PCSSCK具体介绍查看SPI时钟延时设置。
- PASC具体介绍查看SPI时钟延时设置。
- PDT具体介绍查看SPI时钟延时设置。
- PBR具体介绍查看SPI时钟延时设置。
- CSSCK具体介绍查看SPI时钟延时设置。
- ASC具体介绍查看SPI时钟延时设置。
- DT具体介绍查看SPI时钟延时设置。
- BR具体介绍查看SPI时钟延时设置。
4.时钟和传输属性寄存器(从模式)SPI_CTAR0_SLAVE
- FMSZ帧大小设置位
该位设置发送接收时每一帧数据的位数。
每一帧数据的位数为该位的值加1。
每一帧的数据位数必须大于4。 - CPOL时钟级性选择位
置1:时钟在空闲时为高电平。
置0:时钟在空闲时为低电平。 - CPHA时钟相位选择位
置1:数据在第一个时钟沿改变,在第二个时钟沿被采样。
置0:数据在第一个时钟沿被采样,在第二个时钟沿改变。
5.状态寄存器SPI_SR
- TCF传输完成标志位
读1:一帧数据传输完成。
读0:传输未完成。
置1:清零该位。 - TXRXS接收发送状态位
读1:接收发送功能使能,SPI模块在运行状态。
读0:接收发送功能禁用,SPI模块在停止状态。 - EOQF队列传输完成标志位
读1:主模式时SPI_PUSHR.EOQ位置1且该帧传输完成。
读0:队列传输未结束。
置1:清零该位。
该位自动置1时会清零SPI_SR.TXRXS位。 - TFUF传输下溢标志位
读1:从模式时,如果发送FIFO已空但外接的主模块继续发起传输时,该位自动置1.
读0:传输未发生下溢。
置1:清零该位。 - TFFF发送FIFO满标志位
读1:发送FIFO未满。
读0:发送FIFO已满。
置1:清零该位。 - RFOF接收FIFO溢出标志位
读1:当接收FIFO与移位寄存器满的情况下继续接收数据则此位自动置1。
读0:接收FIFO未溢出。
置1:清零该位。 - RFDF接收FIFO空标志位
读1:接收FIFO不空。
读0:接收FIFO已空。
置1:清零该位。 - TXCTR发送FIFO计数器
记录发送FIFO中有效帧的个数,当PUSH发送FIFO时该计数器加1,当帧进入移位寄存器时该位减1。 - TXNXTPTR发送指针
指示FIFO中下一个要发送的帧。每次有帧进入移位寄存器后都会更新该位。
当SPI_MCR.DIS_TXF=1发送FIFO禁用时,该位无效。 - RXCTR接收FIFO计数器
记录接收FIFO中帧的个数,POP接收FIFO时该位减1,当帧从移位寄存器进入到接收FIFO时该位加1。 - POPNXTPTR接收指针
指向FIFO中读取POPR寄存器时被读的帧,每次有帧被POP后都会更新该位。
当SPI_MCR.DIS_RXF=1接收FIFO禁用时,该位无效。
6.DMA/中断选择使能寄存器SPI_RSER
- TCF_RE发送完成中断使能位
置1:当SPI_SR.TCF位置1时触发中断。
置0:当SPI_SR.TCF位置1时禁止触发中断。 - EOQF_RE队列传输完成中断使能位
置1:当SPI_SR.EOQF位置1时触发中断。
置0:当SPI_SR.EOQF位置1时禁止触发中断。 - TFUF_RE发送FIFO下溢中断使能位
置1:当SPI_SR.TFUF位置1时触发中断。
置0:当SPI_SR.TFUF位置1时禁止触发中断。 - TFFF_RE发送FIFO满中断/DMA使能位
置1:当SPI_SR.TFFF位置1时触发中断/DMA。
置0:当SPI_SR.TFFF位置1时禁止触发中断/DMA。 - TFFF_DIRS发送FIFO满生成中断/DMA选择位
置1:当SPI_SR.TFFF位置1时生成DMA请求。
置0:当SPI_SR.TFFF位置1时生成中断请求。 - RFOF_RE接收FIFO溢出中断使能位
置1:当SPI_SR.RFOF位置1时触发中断。
置0:当SPI_SR.RFOF位置1时禁止触发中断。 - RFDF_RE接收FIFO空中断/DMA使能位
置1:当SPI_SR.RFDF位置1时触发中断/DMA。
置0:当SPI_SR.RFDF位置1时禁止触发中断/DMA。 - RFDF_DIRS接收FIFO空生成中断/DMA选择位
置1:当SPI_SR.RFDF位置1时生成DMA请求。
置0:当SPI_SR.RFDF位置1时生成中断请求。
7.PUSH发送FIFO寄存器(主模式)SPI_PUSHR
- CONT片选模式选择位
置1:在传输两个帧之间持续使能片选信号。
置0:在传输两个帧之间不使能片选信号。
具体介绍查看片选连续设置。 - CTAS时钟和传输属性选择位
000:CTAR0
001:CTAR1
010:CTAR2
011:CTAR3 - EOQ传输队列结束标志位
置1:此数据为传输队列的最后一个数据。
置0:此数据不是传输队列的最后一个数据。 - CTCNT发送计数器清零位
置1:清除SPI_TCR.SPI_TCNT位。
置0:不清除SPI_TCR.SPI_TCNT位。 - PCS片选信号选择位
置1:使用该位对应的PCSn。
置0:不使用该位对应的PCSn。 - TXDATA发送数据位
8.PUSH发送FIFO寄存器(从模式)SPI_PUSHR_SLAVE
- TXDATA发送数据位
9.POP接收FIFO寄存器SPI_POPR
- RXDATA数据读取位
该字段保存接收FIFO中SPI_SR.POPNXTPTR指向的数据。
10.发送FIFO寄存器SPI_TXFRn(n=0,1,2,3,4)
- TXCMD_TXDATA传输命令数据位
在主模式中该字段保存设置的传输属性。 - TXDATA传输数据位
该字段保存传输的数据。
当SPI_MCR.DIS_TXF=1发送FIFO禁用时,该寄存器无效。
11.接收FIFO寄存器SPI_RXFRn(n=0,1,2,3,4)
- RXDATA接收数据
当SPI_MCR.DIS_RXF=1接收FIFO禁用时,该寄存器无效。
三、功能介绍
1.SPI时钟延时设置
SPI_CTARn寄存器中的DBR、PCSSCK、PASC、PDT、PBR、CSSCK、ASC、DT、BR位设置SPI的时钟与延时。
其中DBR、PBR、BR设置SPI通信波特率。
PCSSCK、CSSCK设置从片选信号使能到第一个SCK时钟沿输出的延时Tcsc。
PASC、ASC设置最后一个SCK时钟沿到片选信号失效的延时Tasc。
PDT、DT设置两次帧传输期间片选信号失效的最短时间Tdt。
下图位以经典SPI模式MTFE=0, CPHA=0为例的时序图,从中可以看到三个延时的具体位置。
1.波特率设置
波特率设置计算公式如下:
其中DBR的值可以设置为0或1。
PBR寄存器设置值与计算值对应如下:
BR寄存器设置值与计算值对应如下:
当fsys=100MHz,DBR设置为0,PBR设置为00,BR设置为0000时,波特率为100/2*(1+0)/2=25MHz。
2.Tcsc设置
PCSSCK寄存器设置值与计算值对应如下:
CSSCK寄存器设置值与计算值对应如下:
当fsys=100MHz,PCSSCK设置为01,CSSCK设置为0100,则Tcsc=1/100MHz*3*32=0.96us。
3.Tasc设置
PASC寄存器设置值与计算值对应如下:
ASC寄存器设置值与计算值对应如下:
当fsys=100MHz,PASC设置为01,ASC设置为0100,则Tasc=1/100MHz*3*32=0.96us。
4.Tdt设置
PDT寄存器设置值与计算值对应如下:
DT寄存器设置值与计算值对应如下:
当fsys=100MHz,PDT设置为01,DT设置为0100,则Tdt=1/100MHzx*3*32=0.96us。
2.PCS5/ PCSS工作模式
当外部模块超出8个,片选信号不够使用时,使用解码器对PCSn信号解码得到片选信号,为防止解码信号时的竞争冒险现象,使用一个延迟一定时间的PCSS信号作为选通脉冲,PCSx与PCSS之间的时序如下图所示。
其中tPCSSCK与tPASC计算方式如下:
3.传输模式
SPI模块可以通过设置SPI_MCR.MTFE选择经典模式或修改模式。
经典模式要求数据的采样与发送都在时钟沿进行,但是修改传输模式则允许采样与发送与时钟沿有一定的提前或延迟。同时根据SPI_CTARn.CPOL位与SPI_CTARn.CPHA位的设置,每种传输模式下又有四种时钟数据相位模式。
1.经典模式
当SPI_CTARn.CPHA=0时,数据在时钟的奇数沿采样,在时钟的偶数沿改变。
当SPI_CTARn.CPHA=1时,数据在时钟的偶数沿采样,在时钟的奇数沿改变。
2.修改模式
修改模式下数据采样点输出点不一定与时钟沿对齐。
1.CPHA=0
当SPI_CTARn.CPHA=0,且系统时钟频率是SPI时钟频率的四倍以上时,时序图如下图所示,采样点可以根据SPI_MCR.SMPL_PT的设置进行配置,可以延迟时钟边沿一到两个系统时钟周期。
主模块的SOUT在奇数时钟沿后一个系统时钟周期后就改变。
配置为修改传输模式的从模块的SOUT of DSPI Slave在奇数时钟沿后就改变。
下图中的SOUT of Ext Slave为经典传输模式下的从模块SOUT。
当系统时钟的频率是SCK时钟频率的4倍以下时,采样点不能自由配置,自动设置为时钟沿后一个系统时钟周期进行采样,数据输出则在时钟边沿输出,不进行延迟。
下图为系统时钟频率为SCK频率2倍时的时序图。
下图为系统时钟频率为SCK频率3倍时的时序图。
2.CPHA=1
当SPI_CTARn.CPHA=1时,从SOUT的工作方式与经典模式下相同,但是其采样位置不在偶数时钟沿,而在偶数时钟沿的下一个时钟沿,这会造成在最后一位数据的采样点并没有时钟沿,这时片选信号最少要持续半个SCK时钟周期。以下三张图为系统时钟的频率为SCK频率2、3、4倍时的时序图。
4.片选连续设置
当SPI_PUSHR.CONT=0时,会在两帧传输之间插入一段Tdt,如下图所示。
当SPI_PUSHR.CONT=1时,不会会在两帧传输之间插入一段Tdt,如下图所示。
5.时钟连续设置
SPI_MCR.CONT_SCKE=1时时钟会连续输出,下面两张图分别为在时钟信号连续,片选信号不连续与连续模式下的时序图。
只有SPI_CTARn.CPHA=1时支持连续时钟。如果SPI_MCR.CONT_SCKE=1,但是SPI_CTARn.CPHA=0,则SPI_CTARn.CPHA的设置被忽略。同时,修改传输模式也支持连续时钟模式。
四、例程分析
例程要实现功能如下:
- 使用SPI1发送接收数据,SPI2接收数据。
- SPI1与SPI2的收发使用中断完成。
- SPI1先向SPI2写入四个数据,SPI2收到数据后加0xFF0后保存。
- SPI1向SPI2写完数据后,发送读请求,从SPI2读取保存的数据。
- 其中,SPI1数据帧总长16位,最高位为1时表示写命令,SPI2收到数据后按要求保存。
- 最高位为0表示读请求,低两位表示读数据的地址,SPI2收到后按照地址将保存的数据返回给SPI1。
int main(void)
{
xcptn_xmpl ();
MC_ME.RUN_PC[0].R=0x00000000;
MC_ME.RUN_PC[1].R=0x000000FE;
MC_ME.PCTL98.B.RUN_CFG = 0x1;
MC_ME.PCTL209.B.RUN_CFG = 0x1;
MC_CGM.SC_DC0.B.DIV=3;//系统时钟分频器分频系数为3,PBRIDGEn_CLK的频率为系统时钟频率的(3+1)=4分之一
MC_CGM.SC_DC0.B.DE=1;//使能系统时钟分频器
MC_CGM.AC3_SC.B.SELCTL=0;//选择IRCOSC作为 PLL0的输入
MC_CGM.AC4_SC.B.SELCTL=1;//选择XOSC作为 PLL1的输入
//PLL0输入为IRCOSC的16MHz时钟,将PHI配置为160MHz,PHI1配置为40MHz
//fPLL0_PHI=fPLL0_ref*PLL0DV[MFD]/(PLL0DV[PREDIV]*PLL0DV[RFDPHI])=16MHz*20/(1*2)=160MHz
//fPLL0_PHI1=fPLL0_ref*PLL0DV[MFD]/(PLL0DV[PREDIV]*PLL0DV[RFDPHI1])=16MHz*20/(1*8)=40MHz
PLLDIG.PLL0DV.B.RFDPHI1=8;
PLLDIG.PLL0DV.B.RFDPHI=2;
PLLDIG.PLL0DV.B.PREDIV=1;
PLLDIG.PLL0DV.B.MFD=20;
//PLL1输入为XOSC的40MHz时钟,将PHI配置为160MHz
//fPLL1_PHI=fPLL1_ref*(PLL1DV[MFD]+PLL1FD[FRCDIV]/2^12)/(2*PLL1DV[RFDPHI]))=40MHz*(16+0)/(2*2)=160MHz
PLLDIG.PLL1DV.B.RFDPHI=2;
PLLDIG.PLL1DV.B.MFD=16;
MC_ME.DRUN_MC.R=0x001300F2; //FLAON=11Flash正常工作模式,PLL1ON=1PLL1打开,PLL0ON=1PLL0打开,XOSCON=1XOSCON打开,IRCON=1IRCON打开,SYSCLK=primary PLL(PLL0_PHI)系统时钟选择PLL0_PHI
MC_ME.MCTL.R=0x30005AF0;//调整至DRUN模式,输入两次KEY
MC_ME.MCTL.R=0x3000A50F;
while(MC_ME.GS.B.S_MTRANS==1); //等待模式转换完成
//配置主机DSPI_1的引脚
SIUL2.MSCR[7].B.SSS = 1;//PA7设置为DSPI_1 SOUT
SIUL2.MSCR[7].B.OBE = 1;//输出使能
SIUL2.MSCR[7].B.SRC = 3;//全强度驱动
SIUL2.MSCR[6].B.SSS = 1;//PA6设置为DSPI_1 CLK
SIUL2.MSCR[6].B.OBE = 1;//输出使能
SIUL2.MSCR[6].B.SRC = 3;//全强度驱动
SIUL2.MSCR[8].B.IBE = 1;//输入使能
SIUL2.IMCR[44].B.SSS = 1;//PA8设置为DSPI_1 SIN
SIUL2.MSCR[5].B.SSS = 1;//PA5设置为DSPI_1 CS0
SIUL2.MSCR[5].B.OBE = 1;//输出使能
SIUL2.MSCR[5].B.SRC = 3;//全强度驱动
//配置从机DSPI_2的引脚
SIUL2.MSCR[0].B.IBE = 1;//输入使能
SIUL2.IMCR[48].B.SSS = 1;//PA0设置为DSPI_2 CLK
SIUL2.MSCR[1].B.SSS = 2;//PA1设置为DSPI_2 SOUT
SIUL2.MSCR[1].B.OBE = 1;//输出使能
SIUL2.MSCR[1].B.SRC = 3;//全强度驱动
SIUL2.MSCR[2].B.IBE = 1;//输入使能
SIUL2.IMCR[47].B.SSS = 2;//PA2设置为DSPI_2 SIN
SIUL2.MSCR[3].B.IBE = 1;//输入使能
SIUL2.IMCR[49].B.SSS = 1;//PA3设置为DSPI_2 SS
//配置主机SPI1
SPI_1.MCR.B.HALT=1;//停止SPI传输
SPI_1.MCR.B.MSTR=1;//设置为主模式
SPI_1.MCR.B.PCSIS=1;//片选信号低电平有效
SPI_1.MCR.B.MDIS=0;//使能模块时钟
SPI_1.MODE.CTAR[0].B.FMSZ=15;//帧长度为16位
SPI_1.MODE.CTAR[0].B.CPOL=0;//空闲时钟为低电平
SPI_1.MODE.CTAR[0].B.CPHA=0;//第一个时钟沿采样
SPI_1.MODE.CTAR[0].B.LSBFE=0;//数据从高位开始传输
SPI_1.MODE.CTAR[0].B.PBR=2;//设置波特率为500kHz
SPI_1.MODE.CTAR[0].B.DBR=0;
SPI_1.MODE.CTAR[0].B.BR=4;
SPI_1.MODE.CTAR[0].B.PCSSCK=0;//时钟对片选延迟时间为0.1us
SPI_1.MODE.CTAR[0].B.CSSCK=1;
SPI_1.MODE.CTAR[0].B.PASC=0;//片选对时钟延迟为0.05us
SPI_1.MODE.CTAR[0].B.ASC=0;
SPI_1.MODE.CTAR[0].B.PDT=0;//片选空闲时间为0.05us
SPI_1.MODE.CTAR[0].B.DT=0;
SPI_1.RSER.B.TCF_RE=1;//使能发送完成中断
SPI_1.RSER.B.RFDF_RE=1;//使能接收中断
SPI_1.RSER.B.RFDF_DIRS=0;//触发中断
SPI_1.MCR.B.HALT =0;//开启传输
//配置从机SPI2
SPI_2.MCR.B.HALT=1;//停止SPI传输
SPI_2.MCR.B.MSTR=0;//设置为从模式
SPI_2.MCR.B.PCSIS=1;//片选信号低电平有效
SPI_2.MCR.B.MDIS=0;//使能模块时钟
SPI_2.MODE.CTAR_SLAVE[0].B.FMSZ=15;//帧长度为16位
SPI_2.MODE.CTAR_SLAVE[0].B.CPOL=0;//空闲时钟为低电平
SPI_2.MODE.CTAR_SLAVE[0].B.CPHA=0;//第一个时钟沿采样
SPI_2.RSER.B.RFDF_RE=1;//使能接收中断
SPI_2.RSER.B.RFDF_DIRS=0;//触发中断
SPI_2.MCR.B.HALT = 0x0;//开启传输
//配置中断
INTC_0.PSR[271].B.PRC_SELN0=1;//允许SPI1发送中断
INTC_0.PSR[271].B.PRIN=9;//优先级为9
INTC_0.PSR[272].B.PRC_SELN0=1;//允许SPI1接收中断
INTC_0.PSR[272].B.PRIN=10;//优先级为10
INTC_0.PSR[281].B.PRC_SELN0=1;//允许SPI2接收中断
INTC_0.PSR[281].B.PRIN=11;//优先级为11
SPI_1.PUSHR.PUSHR.R = 0x00018000|SenDataMaster[0];//开始向从机写数据
for(;;);
}
void DSPI1_TCF_isr()//SPI1发送完成中断
{
static int i=1;
SPI_1.SR.R=1<<31;//清零发送完成标志位
if(write_cf==0)
{
SPI_1.PUSHR.PUSHR.R=0x00018000|SenDataMaster[i];//向从模块写数据
i++;
if(i>3)
{
i=0;
write_cf =1;//写完成标志
}
}
else
{
SPI_1.PUSHR.PUSHR.R=0x00010000+i;//从从机读数据
i++;
if(i>4)
{
SPI_1.RSER.B.TCF_RE=0;//读取完毕禁止发送中断
i=0;
}
}
}
void DSPI1_RFDF_isr()//SPI1接收中断
{
static int k=0;
unsigned int a=0;
a = SPI_1.POPR.R;//读取数据
SPI_1.SR.R=1<<17;//清除接收标志
if(write_cf==1)//在发送完成且主句发送两个数据后开始接收数据
{
if(k>1)
{
RecDataMaster[k-2]=a;
}
k++;
if(k>6)
{
k=0;
}
}
}
void DSPI2_RFDF_isr()//SPI2接收中断
{
static int j=0;
unsigned int a=0;
a = SPI_2.POPR.R;//读取数据
SPI_2.SR.R=1<<17;//清除接收标志
if((a&0x8000)==0x8000)//主机发送写命令
{
RecDataSlave[j]=(a&0x7fff)+0x0ff0;//将主机发送的数据加0xff0存储
j++;
if(j>3)
{
j=0;
}
}
else//主机发送读命令
{
SPI_2.PUSHR.PUSHR.R=0x00010000|RecDataSlave[a&0x3];//根据主句发送的地址发送数据
}
}
- 第3行:新建工程时自动生成代码。
- 第5~33行:单片机初始化的一些操作。
- 第35~63行:配置SPI1与SPI2的引脚。
- 第65~94行:配置SPI1。
- 第96~109行:配置SPI2;
- 第111~119行:启用对应的中断并设置其优先级。
- 第121行:首先发送一次从机写命令,触发接下来的发送完成中断。
- 第127行:清零发送完成标志。
清零标志位时不能使用位操作,置1位操作的本质是读取寄存器的值,将1左移相应位后与读取作或运算,再写入寄存器。在此过程中,当其它中断标志也处于置位状态时会错误的将其清除。 - 第131行:在写状态为结束时继续向从SPI1发送写指令。
- 第141行:当写状态结束后,向从机发送读请求。由于要读取4个数据,第一次发送的读请求要在第二次请求发出后才能得到回应,所以需要发送5次读请求。
- 第145行:当数据读取完成后,关闭发送完成中断。
- 第155~156行:读取数据。
读取数据清状态位的顺序一定是先读数再清零,否则先清零,接收FIFO中的数还在的话硬件会自动再次将标志位置1。 - 第158~168:在写状态完成,且已经接收两次后才开始接收有效的数据。由于SPI1接收中断的优先级为10,发送中断优先级为9,接收中断的优先级高,所以当SPI模块发送完成后同时发送接收中断与发送中断请求时,优先响应接收中断。下面这张图表示了SPI1接收发送中断响应顺序。上面的短竖线代表发生一次接收完成中断,除第一条与最后一条。第一条为第一次发送数据的时间,最后一条为最后一次发送数据完成的时间,因为此时发送中断已被禁止,所以不触发中断。下面的短竖线代表接收中断发生的时间。上下两条距离最近的竖线是一次发送过程完成后同时触发的接收发送中断,但是由于优先级的存在,接收的竖线在发送的竖线之前。可以看到k=2的接收中断是i=2发送数据触发的中断,他接收的数据是在i=1时写入从机的地址,从机在i=2的时钟驱动下返回的数据,所以从k=2开始到k=5接收为接收到的有效数据。
- 第180~188:若接收到写命令,则将接收到的数据加0xFF0后保存。
- 第189~192行:若接收到读命令则按照需要的地址发送数据。
- 同时需要在intc_SW_mode_isr_vectors_MPC5744P.c文件中声明中断函数并注册。
五、相关索引
- 1.SPI模块:MPC5744P-Reference Manual.pdf第1575页。
- 2.引脚复用功能列表:MPC5744P-Reference Manual.pdf第107页Table 4-7。
- 3.中断向量列表:MPC5744P-Reference Manual.pdf第193页Table 7-16。