SPI初始化分析

2020-03-27  本文已影响0人  爱偷懒的人没江来

KV56中SPI的初始化通过SPI_MasterInit(void)函数,在SPI.c文件下。
具体代码
代码清单1

void SPI_MasterInit(void)
{
   /* Configure the SPI corresponding Pins */
  PORTC_PCR4 = PORT_PCR_MUC(2);    //SPI0_PCS0
  PORTC_PCR5 = PORT_PCR_MUC(2);    //SPI0_SCK
  PORTC_PCR6 = PORT_PCR_MUC(2);    //SPI0_SOUT
  PORTC_PCR7 = PORT_PCR_MUC(2);    //SPI0_SIN

  /* SPI MCR Configure */
  SPI0_MCR &= ~SPI_MCR__MDIS_MASK;      //使能模式,注意此句必须是‘=’号,MDIS默认为1,此时无法设置DIS_TSF和DIS_RSF
  SPI0_MCR |= SPI_MCR__HALT_MASK;        //SPI Stop Transfer
  SPI0_MCR |= SPI_MCR__MSTR_MASK        //主机模式
                     |   SPI_MCR_PCSIS(0x01)          //PCSx 信号的空闲状态为高 Pcs Active Low(idles high)
                     |   SPI_MCR_CLR_TXF_MASK
                     |   SPI_MCR_CLR_RXF_MASK
                     |   SPI_MCR_DIS_TXF(FALSE) | SPI_MCR_DIS_RXF(FALSE);                          //TX RX FIFO is enableed.
  /* SPI CTAR0 Configure */
  SPI0_CTAR0 = SPI_CTAR_FMSZ(7);            //注意这句话必须是 = 号,因为fmsz默认为1111,SPI发送数据帧大小设定,实际数据位为该值+1,8bit

  /* SCK baud rate f(SCK) = [f(Busclk)/PBR]*[(1+DBR)/BR],f(SCK)最大值为f(Busclk)/2,f(Busclk) = 120MHz */
  SPI0_CTAR0  |= SPI_CTAR_BR(0);                          // BR = 0,2分频
              | SPI_CTAR_BR(2);                           // BR = 2,5分频
              | SPI_CTAR_PCSSCK(0);                       // PCS to SCK Prescaler value is 1
              | SPI_CTAR_CSSCK(2);                        //CSSCK为PCSx有效到SCK有效时间间隔value is 8
              | SPI_CTAR_PASC(1);                         //PASC为SCK无效到PCSx无效的时间间隔value is 3
              | SPI_CTAR_DBR(0);                          //DBR is 50/50 dury cycle

  /* SPI RSER Configure */
  SPI_RSER = 0;                                            //Disabled all interrupt requests 
  
  SPI0_SR |= SPI_SR_EOQF_MASK          //Clear End of Queue flag
          | SPI_SR_TFFF_MASK           //Clear Transmit FIFO Fill flag
          | SPI_SR_TCF_MASK            //Clear Transmit Complete flag

  SPI0_PUSHR |= SPI_PUSHR_PCS(1)       //Select PCS0 signals are to be asserted for the transfer
             | SPI_PUSHR_CONT_MASK;

  return;

}

分析代码清单2

代码清单2

   /* Configure the SPI corresponding Pins */
  PORTC_PCR4 = PORT_PCR_MUC(2);    //SPI0_PCS0
  PORTC_PCR5 = PORT_PCR_MUC(2);    //SPI0_SCK
  PORTC_PCR6 = PORT_PCR_MUC(2);    //SPI0_SOUT
  PORTC_PCR7 = PORT_PCR_MUC(2);    //SPI0_SIN

注释:
Configure the SPI corresponding Pins:配置SPI对应的管脚。
配置的是哪几个引脚?PTC4、PTC5、PTC6、PTC7。
分别对应:
SPI的PCS0、SCK、SOUT、SIN。
PCS0、SCK、SOUT、SIN是啥?因为以前没看过SPI这块,有点菜。
因为MKV56和k60都是飞思卡尔系列,所以先到K60上查一下。


k60-SPI信号线

再看KV56


KV56-SPI信号线1.png
KV56-SPI信号线2.png

原来把PTC4、PTC5、PTC6、PTC7配置了信号线。如何配置的呢?
代码清单2用的是PORT_PCR_MUC(2)。
看一下PORT_PCR_MUC(2)是如何实现的:
代码清单3-配置SPI信号线引脚

#define PORT_PCR_MUX(x)         (((uint32_t)(((uint32_t)(x)) << PORT_PCR_MUX_SHIFT)) & PORT_PCR_MUX_MASK)
其中
#define  PORT_PCR_MUX_SHIFT  8U
#define  PORT_PCR_MUX_MASK 0xF00U。

所以PORT_PCR_MUC(2)的结果是0x10’0000‘0000。
0x10’0000‘0000代表什么意思?
真没想出来。
后来想到,既然通过PORT_PCR_MUC(2)配置了引脚,那肯定和PORT有关。
去查PTC4


KV56_PORT_PCR_MUC(2)———0x10’0000‘0000含义.png

对照上图一看,大致猜到应该是将PTC4、PTC5、PTC6、PTC7复用了SPI0。
去找GPIO->PORTx-PCRn看引脚是怎么实现复用的。
照例先看k60(中文),再看KV56(英文)。如下图,可以知道K60的PORTx-PCRn的第8-10位用来配置引脚复用。


引脚复用-k60.png

KV56的第8-11用来配置引脚复用。0x10’0000‘0000的 bit9=1,即选择ATL2


引脚复用-KV56.png

小结:

代码清单2这4句实现了2个功能
1.配置SPI信号线引脚;
2.对引脚实现功能复用(SPI)
代码清单2

   /* Configure the SPI corresponding Pins */
  PORTC_PCR4 = PORT_PCR_MUC(2);    //SPI0_PCS0
  PORTC_PCR5 = PORT_PCR_MUC(2);    //SPI0_SCK
  PORTC_PCR6 = PORT_PCR_MUC(2);    //SPI0_SOUT
  PORTC_PCR7 = PORT_PCR_MUC(2);    //SPI0_SIN

分析代码清单3

这里明显是在配置SPI的MCR寄存器。

/* SPI MCR Configure */
  SPI0_MCR &= ~SPI_MCR__MDIS_MASK;      //使能模式,注意此句必须是‘=’号,MDIS默认为1,此时无法设置DIS_TSF和DIS_RSF
  SPI0_MCR |= SPI_MCR__HALT_MASK;        //SPI Stop Transfer
  SPI0_MCR |= SPI_MCR__MSTR_MASK        //主机模式
                     |   SPI_MCR_PCSIS(0x01)          //PCSx 信号的空闲状态为高 Pcs Active Low(idles high)
                     |   SPI_MCR_CLR_TXF_MASK
                     |   SPI_MCR_CLR_RXF_MASK
                     |   SPI_MCR_DIS_TXF(FALSE) | SPI_MCR_DIS_RXF(FALSE);                          //TX RX FIFO is enableed.
  SPI0_MCR &= ~SPI_MCR__MDIS_MASK;      //使能模式,注意此句必须是‘=’号,MDIS默认为1,此时无法设置DIS_TSF和DIS_RSF
#include SPI_MCR__MDIS_MASK    0x4000U
so,  SPI0_MCR = SPI0_MCR  & 11 1111 1111 1111
而
#define   SPI0_MCR     SPI_MCR_REG(SPI0_BASE_PTR)     
#define   SPI_MCR_REG(base)   ((base)->MCR),
#define    SPI0_BASE_PTR    0x4002C000u
即 SPI0_MCR    ((0x4002C000u)->MCR)
SPI0_MCR     =  0x4002C000u & 11 1111 1111 1111 = 0;
SPI0_MCR |= SPI_MCR__HALT_MASK;    //SPI Stop Transfer
#define   SPI_MCR__HALT_MASK   0x1u,
so  SPI0_MCR = 0x1
配置MCR寄存器实现'停止传输'功能.png

继续分析代码清单3

  SPI0_MCR |= SPI_MCR__MSTR_MASK        //主机模式
           |   SPI_MCR_PCSIS(0x01)          //PCSx 信号的空闲状态为高 Pcs Active Low(idles high)
           |   SPI_MCR_CLR_TXF_MASK
           |   SPI_MCR_CLR_RXF_MASK
           |   SPI_MCR_DIS_TXF(FALSE) | SPI_MCR_DIS_RXF(FALSE);                          //TX RX FIFO is enableed.

 SPI_MCR__MSTR_MASK     0x8000'0000U    
 SPI_MCR_PCSIS(0x01)       1 0000 0000 0000 0000
 SPI_MCR_CLR_TXF_MASK      0x800U
 SPI_MCR_CLR_RXF_MASK      0x400U
 SPI_MCR_DIS_TXF(FALSE)  = 0
 SPI_MCR_DIS_RXF(FALSE) = 0
  so
  SPI0_MCR  = 1000 0000 8000 0C00
    =1 0000 0000 0000 0000 0000 0000 0000 1000 0000 0000 0000 0000 1100 0000 0000 

其中
(3.1) SPI_MCR__MSTR_MASK

 SPI_MCR__MSTR_MASK     0x8000'0000U   
0x8000'0000.png

(3.2) SPI_MCR_PCSIS(0x01)

 SPI_MCR_PCSIS(0x01)       1 0000 0000 0000 0000
SPI_MCR_PCSIS.png

(3.3)SPI_MCR_CLR_TXF_MASK

SPI_MCR_CLR_TXF_MASK      0x800U
CLR_TXF.png

(3.4)SPI_MCR_CLR_RXF_MASK

SPI_MCR_CLR_RXF_MASK      0x400U
CLR_RXF.png

(3.5) SPI_MCR_DIS_TXF(FALSE) | SPI_MCR_DIS_RXF(FALSE) = 0;开始传输


TXF -RXF.png

分析代码清单4

  SPI0_CTAR0 = SPI_CTAR_FMSZ(7);            //注意这句话必须是 = 号,因为fmsz默认为1111,SPI发送数据帧的大小设定,实际数据位为该值+1,8bit

  /* SCK baud rate f(SCK) = [f(Busclk)/PBR]*[(1+DBR)/BR],f(SCK)最大值为f(Busclk)/2,f(Busclk) = 120MHz */
  SPI0_CTAR0  |= SPI_CTAR_BR(0);                          // BR = 0,2分频
              | SPI_CTAR_BR(2);                           // BR = 2,5分频
              | SPI_CTAR_PCSSCK(0);                       // PCS to SCK Prescaler value is 1
              | SPI_CTAR_CSSCK(2);                        //CSSCK为PCSx有效到SCK有效时间间隔value is 8
              | SPI_CTAR_PASC(1);                         //PASC为SCK无效到PCSx无效的时间间隔value is 3
              | SPI_CTAR_DBR(0);                          //DBR is 50/50 dury cycle

  /* SPI RSER Configure */
  SPI_RSER = 0;                                            //Disabled all interrupt requests 

(4.1)

//注意这句话必须是 = 号,因为fmsz默认为1111,SPI发送数据帧大小设定,实际数据位为该值+1,8bit
  SPI0_CTAR0 = SPI_CTAR_FMSZ(7);   
           =111 1000 0000 0000 0000 0000 0000 0000

bit30\29\28\27为1


FMSZ.png

(4.2)

  /* SCK baud rate f(SCK) = [f(Busclk)/PBR]*[(1+DBR)/BR],f(SCK)最大值为f(Busclk)/2,f(Busclk) = 120MHz */
  SPI0_CTAR0  |= SPI_CTAR_BR(0);                          // BR = 0,2分频
              | SPI_CTAR_BR(2);                           // BR = 2,5分频
              | SPI_CTAR_PCSSCK(0);                       // PCS to SCK Prescaler value is 1
              | SPI_CTAR_CSSCK(2);                        //CSSCK为PCSx有效到SCK有效时间间隔value is 8
              | SPI_CTAR_PASC(1);                         //PASC为SCK无效到PCSx无效的时间间隔value is 3
              | SPI_CTAR_DBR(0);                          //DBR is 50/50 dury cycle

(4.2.1)

SPI_CTAR_BR(0)  ==0<<0U & FU =  0
BR.png

(4.2.2)
SPI_CTAR_PBR(2); // BR = 2,5分频

SPI_CTAR_PBR(2)  == 2<<16 & 0x3'0000 = 10 0000 0000 0000 0000

bit16 = 0,bit17=1;


PBR.png

(4.2.3)
SPI_CTAR_PCSSCK(0) // PCS to SCK Prescaler value is 1

SPI_CTAR_PCSSCK(0) = 0<<22 & 0xC0'0000
PCSSCK.png

(4.2.4)
SPI_CTAR_CSSCK(2); //CSSCK为PCSx有效到SCK有效时间间隔value is 8

SPI_CTAR_CSSCK(2) ==2<<12 & 0xF000 =10 0000 0000 0000
CSSCK.png

(4.2.5)
SPI_CTAR_PASC(1); //PASC为SCK无效到PCSx无效的时间间隔value is 3
其中SPI_CTAR_PASC(1) =1<<20 &0x30'0000 = 1 0000 0000 0000 0000 0000,bit20 ==1


PASC.png

(4.2.6)
SPI_CTAR_DBR(0); //DBR is 50/50 dury cycle
SPI_CTAR_DBR(0) =0<<31 & 0x8000'0000= 0000 0000 0000 0000 0000 0000 0000 0000,bit31等于0


DBR.png

代码清单5


  /* SPI RSER Configure */
  SPI_RSER = 0;                                            //Disabled all interrupt requests 
  
  SPI0_SR |= SPI_SR_EOQF_MASK          //Clear End of Queue flag
          | SPI_SR_TFFF_MASK           //Clear Transmit FIFO Fill flag
          | SPI_SR_TCF_MASK            //Clear Transmit Complete flag

  SPI0_PUSHR |= SPI_PUSHR_PCS(1)       //Select PCS0 signals are to be asserted for the transfer
             | SPI_PUSHR_CONT_MASK;

代码清单5这里就不在分析,和上面的分析是一样的。

总结

SPI的初始化,其实就是对各个寄存器的配置(各个寄存器位的值设置)。当然不是乱配置的,而是,基于我们要实现的SPI功能,进行相应的配置。
我这里只是,结合配置\初始化好的SPI程序,去学习操作手册。
没错,这篇文章,其实就是教你如何去看操作手册,以及,了解程序中是如何通过代码来设置寄存器实现SPI功能的

上一篇下一篇

猜你喜欢

热点阅读