美文网首页
SPI初始化分析

SPI初始化分析

作者: 爱偷懒的人没江来 | 来源:发表于2020-03-27 10:47 被阅读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功能的

    相关文章

      网友评论

          本文标题:SPI初始化分析

          本文链接:https://www.haomeiwen.com/subject/sytluhtx.html