MSP430 SPI 入门学习

基本简介
MSP430 User Guide 学习
23.1 增强型通用串行通信接口(eUSCI_A, eUSCI_B) 概要
23.2 eUSCI 介绍 - SPI模式
23.3 eUSCI 操作 - SPI模式
23.3.1 eUSCI 初始化和复位(Reset)
23.3.2 字符格式
23.3.3 主模式
23.3.3.1 4线制 SPI 主模式(UCSTEM = 0)
23.3.3.2 4线制 SPI 主模式(UCSTEM = 1)
23.3.4从模式
23.3.4.1 4线SPI从模式
23.3.5 SPI使能
23.3.5.1发送使能
23.3.5.2接收使能
23.3.6串行时钟控制
23.3.6.1串行时钟极性和相位
23.7.3低功耗模式的使用SPI模式
23.3.8 SPI中断
23.3.8.1 SPI 发送中断操作
23.3.8.2 SPI接收终端操作
23.3.8.3中断向量发生器 UCxIV
基本知识介绍
SPI基本知识
应用实例
基本简介
这次MSP430入门介绍是基于MSP430FR2433 Lunchpad进行学习。从小白开始进行SPI学习,理解使用SPI模块。如有错误的地方,大家多多指正。

MSP430 User Guide 学习
每个人学习MSP430的方法是不一样的,我习惯第一步先从User Guide开始。
文件:MSP430FR4xx and MSP430FR2xx Family User’s Guide.pdf
章节:Chapter 23 eUSCI - SPI Mode

23.1 增强型通用串行通信接口(eUSCI_A, eUSCI_B) 概要
eUSCI_A和eUSCI_B都支持SPI串行通信。

23.2 eUSCI 介绍 - SPI模式
在同步模式下(UCSYNC bit = 1), eUSCI模块通过3、4个管脚(UCxSIMO, UCxSOMI, UCxCLK, and UCxSTE)将430设备与外部系统进行连接。当UCSYNC = 1时,SPI模式被选择。3管脚还是4管脚设置是由UCMODEx位进行设置。
SPI模式的特点:
(1)7-8位数据长度
(2)最高位有效或者最低位有效可选的数据接收和发送
(3)3管脚或者4管脚的SPI操作
(4)主/从模式
(5)独立的接收和发送移位寄存器
(6)独立的接收和发送缓冲寄存器
(7)连续的接收和发送操作
(8)可选时钟极性和相位
(9)主模式下,时钟频率可编程
(10)独立的接收和发送中断
(11)从机可以操作在LPM4模式

图23-1显示了eUSCI配置成SPI模式的结构图。


23.3 eUSCI 操作 - SPI模式
在SPI模式,多个设备之间串行数据的发送和接收是由主机提供的时钟进行的。主机有一个额外的管脚UCxSTE来控制使能从机接收和发送数据。
3或4个信号用于SPI数据交换
(1)UCxSIMO – 从输入主输出
(2)UCxSOMI – 从输出主输入
(3)UCxCLK – eUSCI SPI clock 主机输出时钟,从机接收时钟
(4)UCxSTE – 从机使能
UCxSTE 用于4线模式,此时允许在1条总线有多个主机,它不用于3线模式。表23-1 描述了UCxSTE操作。

23.3.1 eUSCI 初始化和复位(Reset)
The eUSCI 会被 PUC 或者 UCSWRST bit进行复位. PUC后UCSWRST bit 会被自动置位使得eUSCI保持在Reset状态。当UCSWRST置位时UCRXIE,UCTXIE, UCRXIFG, UCOE, 和 UCFE bits会复位, UCTXIFG标志位会置位。清除UCSWRST会释放eUSCI使其进入运转状态。

初始化或者重新配置eUSCI模块
1. 置位UCSWRST
2. 通过UCSWRST = 1 初始化所有的eUSCI寄存器(包括UCxCTL1)
3. 配置端口
4. 软件清除UCSWRST
5. 设置UCRXIE or UCTXIE使能中断(可选)
23.3.2 字符格式
工作在SPI下的eUSCI模块支持7位/8位的字符长度,它由UC7BIT位进行设置。在7位数据模式下,UCxRXBUF是低有效位对齐,最高有效位总是复位。UCMSB控制着数据传送的方向,是高位在前还是低位在前。

23.3.3 主模式
图23-2显示了eUSCI作为主机模式工作在3线或者4线的配置。

当数据被移入到发送缓冲器中UCxTXBUF,eUSCI开始了数据的发送。当TX移位寄存器空的时候,UCxTXBUF的数据移位到TX移位寄存器。启动UCxSIMO的数据传输。UCMSB的设置决定了该数据是MSB在前还是LSB在前。UCxSOMI中的数据在相反的时钟沿被移入到接收移位寄存器中。
当主机接收到字符后,接收数据从接收移位寄存器移入接收缓冲器UCxRXBUF,同时接收中断标志位UCRXIFG被置位,这标志着RX和TX操作已经完成。
发送中断标志位UCTXIFG置位,表明数据已经由UCxTXBUF移位到TX移位寄存器,UCxTXBUF已经准备好接收新的数据。它不表示RX和TX操作已经完成。
主模式下为了USCI模块接收数据,数据必须写入UCxTXBUF,因为接收和发送数据是同步的。
这有两种不同的选项来配置eUSCI作为4线的主机。
(1)第四个管脚被用来输入来阻止和其他主机产生冲突(UCSTEM = 0)。
(2)第四个管脚被用来作为输出产生从机使能信号(UCSTEM = 1)。
UCSTEM位用来选择相应的选项。

23.3.3.1 4线制 SPI 主模式(UCSTEM = 0)
在4线制主模式下(UCSTEM = 0), UCxSTE 是数字输入端口来阻止和其他的主机产生冲突,如表23-1所示。
当UCxSTE处于主机-非活动状态时,UCSTEM = 0:
(1)UCxSIMO 和 UCxCLK 设置为输入状态,并且不再驱动总线。
(2)错误位UCFE置位,表明违反通信完整性,需要用户处理。
(3)内部状态机复位,移位操作终止。
如果UCxSTE保持主机在不活动状态下,将数据写入UCxTXBUF中,UCxSTE一旦转换到主机活动状态,立即发送数据。如果UCxSTE转换到主机不活动状态,而致使正在进行的数据发送停止,那么UCxSTE转换回主机活动状态下,数据必须再次写入UCxTXBUF。
UCxSTE信号不会用在3线制主机模式。

23.3.3.2 4线制 SPI 主模式(UCSTEM = 1)
如果UCSTEM = 1 在4线制主机模式,UCxSTE 是数据输出端口。这种模式下,UCxSTE会自动生成单个从机的从机使能信号。对应的行为可以看图23-4.
如果有多个从机,这个功能不能使用,软件需要使用通用I/O口来产生每个从机的单独的STE信号。

23.3.4从模式
图23-3显示了eUSCI 作为从模式的3线制和4线制的配置

UCxCLK被用作SPI时钟的输入,它必须有外部主机提供。数据传输速率由外部主机时钟决定而不是内部的时钟发生器。UCxCLK开始前,写入UCxTXBUF和移入TX移位寄存器的数据通过UCxSOMI发送。UCxSIMO中的数据在UCxCLK的反向沿移入到接收移位寄存器。当接收到设定的位数时,移入到接收缓冲器UCxBUF。
当数据从RX移位寄存器转移到接收缓冲器UCxRXBUF中时,UCRXIFG标志位置位,指示数据已经被接收到。当之前接收的数据没有从UCxRXBUF中读出而新的数据被移入到UCxRXBUF中时UCOE被置位发生overrun错误。

23.3.4.1 4线SPI从模式
在4线从模式,UCxSTE是数据输入端口,用来使能从机发送和接收,这个信号是由主机驱动的。当UCxSTE在从机活动状态下,从机会正常运行。当UCxSTE在从机不活动状态:
(1)UCxSIMO任何的接收活动会被停止。
(2)UCxSOMI会被设置成输入方向。
(3)移位操作会被停止,直到UCxSTE转换到从机发送活动状态。
在3线制从机模式下,不使用UCxSTE输入信号。

23.3.5 SPI使能
当清除UCSWRST位,使能eUSCI模块,它可以进行发送和接收。在主模式下,位时钟(bit clock)发生器已经就绪,但是不会产生任何时钟。在从模式,位时钟发生器被禁止,它的时钟信号由主机提供。
UCBUSY=1 说明发送和接收操作正在进行。
PUC和UCSWRST位会立即禁止到eUSCI,任何的传输都会被中断。

23.3.5.1发送使能
在主模式下,通过UCxTXBUF写操作会激活位时钟发生器(bit clock)开始发送数据。
在从模式下,当主机提供时钟,开始发送数据。4线制下,UCxSTE处于从活动状态下开始发送数据。

23.3.5.2接收使能
当发送处于活动状态下,SPI开始接收数据。接收和发送同时进行。

23.3.6串行时钟控制
UCxCLK是由SPI总线上的主机提供。UCMST=1,位时钟由eUSCI 位时钟发生器通过UCxCLK管脚提供。通过UCSSELx位可以选择生成bit clock的时钟源。当UCMST=0,eUSCI时钟是由主机UCxCLK管脚提供的。从机的位时钟发生器没有使用。不用在乎UCSSELx位。SPI接收和发送是并行的需要用到相同的时钟。
为速率控制寄存器UCxxBRW中的UCBRx的16位数值是USCI时钟源BRCLK的分频因子。当UCBRx=0,主模式能产生最大的bitclock是BRCLK。调制器没有用在SPI模式,当使用eUSCI_A时UCAxMCTL应当被清除。UCAxCLK或者UCBxCLK的频率公式如下:
fBitClock=fBRCLK/UCBRx f_{BitClock} =f_{BRCLK}/{UCBRx}

BitClock
​    
 =f 
BRCLK
​    
 /UCBRx

当UCBRx=0,BRCLK没有进行任何的分频,位时钟等于BRCLK。
偶数的UCBRx设置将会产生偶数的分频,因此产生一个50/50占空比的bit clock。
奇数的UCBRx设置将会进行奇数的分频。这种情况下,bit clock的高电平会比低电平长一个BR 时钟。

23.3.6.1串行时钟极性和相位
UCxCLK的极性和相位可通过eUSCI的UCCKPL和UCCKPH控制位独立配置。每种情况的时钟如图23-4所示。


23.7.3低功耗模式的使用SPI模式
在低功耗模式下,eUSCI模块提供自动的时钟激活。低功耗模式下当eUSCI时钟处于非活动状态。当需要时会自动激活USCI时钟,而不论时钟源控制位如何设置。在eUSCI模块回到空闲状态之前,时钟源一直保持活动状态。当eUSCI模块回到空闲状态,时钟源将恢复到控制位的设置。
在SPI的从模式,不需要内部时钟源,因为时钟由外部的主机提供。即使芯片处于LPM4模式,所有的时钟都被禁用的情况下,eUSCI也可以在SPI模式下操作。接收和发送中断可以将CPU从任何的低功耗模式下唤醒。

当从机在LPM4模式下,接受多个字节,CPU的唤醒时间必须要考虑其中。如果CPU的唤醒时间比如150us,请确保请确保CPU在第二个字节被完全接收之前服务于第一个接收字节的TXIFG。否则一个overrun 错误会产生。

23.3.8 SPI中断
eUSCI模块只有一个中断向量,发送和接收公用这个中断向量。eUSCI_Ax和eUSCI_Bx不共享同一个中断向量。

23.3.8.1 SPI 发送中断操作
UCTXIFG由发送器置位,表示UCxTXBUF已经准备好接收下一个字符。如果UCTXIE和GIE置位将会产生中断请求。当一个字符写入UCxTXBUF中,UCTXIFG会自动复位。PUC或者UCSWRST=1时UCTXIFG会置位,UCTXIE会复位。

注意:SPI数据下写数据到UCxTXBUF
当UCTXIFG=0时写数据到UCxTXBUF中将会导致错误的数据发送
23.3.8.2 SPI接收终端操作
每次当接收一个字符并把字符装载到UCxRXBUF时,UCRXIFG中断标志置位。如果UCRXIE和GIE置位时,将产生一个中断请求。PUC或者UCSWRST=1时,UCRXIFG和UCRXIE复位。当读取UC下RXBUF时,UCRXIFG会自动复位。

23.3.8.3中断向量发生器 UCxIV
eUSCI中断标志位具有不同的优先级,他们组合共用一个中断向量。中断向量寄存器UCxIV用来决定哪一个标志位请求中断。优先级最高的中断将会在UCxIV寄存器中产生一个数字偏移量。这个偏移量累加到程序计数器PC上。程序自动跳转到相应的软件程序处。禁止中断不会影响UCxIV值。
对UCxIV寄存器的任何读和写的访问,会复位挂起优先级最高的中断标志。如果另外一个中断标志置位,在响应完之前的中断后,将立即产生另一个中断。

基本知识介绍
User Guide往往特别冗长,并且都是英文写的,所以自己在刚开始学习MSP430时,最烦的一件事情就是读User Guide。但是它又非常重要,最终还是强迫自己好好读下来,第一章是对UG的中文翻译,方便大家理解,但是有条件的话还是推荐大家读英文版的UG。读完UG后我们往往是一知半解,要想更好的理解SPI模块,我们依然还要查询SPI的基本知识。

SPI基本知识
链接:https://wenku.baidu.com/view/c96f97ca79563c1ec4da7191.html

SPI
数据极性:表示时钟信号在空闲时是高电平还是低电平。
时钟相位:决定数据是在CLK的起始沿采样还是结束沿采样。

应用实例
本次实验使用的MSP430FR2433 Lunchpad(2块板子进行通信)。SPI主机与从机通过三线连接,主机发送数据给从机,同时又接收从机发来的数据,发送数据从0x01开始递增,从机接收数据,然后立刻发出数据。主机进入接收中断,如果发送和接收的数据相同,则点亮LED灯,否则熄灭。
参考文献: MSP430FR2433示例代码

主机代码

ACLK = ~32.768kHz, MCLK = SMCLK = DCO ~ 1MHz.  BRCLK = SMCLK/2.
//
//
//                   MSP430FR2433
//                 -----------------
//             /|\|                 |
//              | |                 |
//              --|RST              |
//                |                 |
//                |             P1.4|-> Data In (UCA0SIMO)
//                |                 |
//                |             P1.5|<- Data OUT (UCA0SOMI)
//                |                 |
//                |             P1.6|-> Serial Clock Out (UCA0CLK)
//******************************************************************************

#include <msp430.h>

unsigned char RXData = 0;
unsigned char TXData;

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;                 // Stop watchdog timer

    P1SEL0 |= BIT4 | BIT5 | BIT6;             // set 3-SPI pin as second function

    //++
    P1DIR |=BIT0;
    P1OUT &= ~BIT0;


    UCA0CTLW0 |= UCSWRST;                     // **Put state machine in reset**
    UCA0CTLW0 |= UCMST|UCSYNC|UCCKPL|UCMSB;   // 3-pin, 8-bit SPI master
                                              // Clock polarity high, MSB
    UCA0CTLW0 |= UCSSEL__SMCLK;               // SMCLK
    UCA0BR0 = 0x01;                           // /2,fBitClock = fBRCLK/(UCBRx+1).
    UCA0BR1 = 0;                              //
    UCA0MCTLW = 0;                            // No modulation
    UCA0CTLW0 &= ~UCSWRST;                    // **Initialize USCI state machine**
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
    TXData = 0x01;                            // Holds TX data

    PM5CTL0 &= ~LOCKLPM5;                     // Disable the GPIO power-on default high-impedance mode
                                              // to activate previously configured port settings
    while(1)
    {
        UCA0IE |= UCTXIE;                     // Enable TX interrupt
        __bis_SR_register(LPM0_bits | GIE);   // enable global interrupts, enter LPM0
        __no_operation();                     // For debug,Remain in LPM0
        __delay_cycles(2000);                 // Delay before next transmission
        TXData++;                             // Increment transmit data
    }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(UCA0IV,USCI_SPI_UCTXIFG))
    {
        case USCI_NONE: break;                // Vector 0 - no interrupt
        case USCI_SPI_UCRXIFG:
              while(!(UCA0IFG&UCTXIFG));

              RXData = UCA0RXBUF;
              UCA0IFG &= ~UCRXIFG;

              //+++++++
              if(RXData == TXData-1)
              {
                  P1OUT |=BIT0;
                    __delay_cycles(200);
              }
              else
              {
                  P1OUT &=~BIT0;
                    //__delay_cycles(200);
              }

              __bic_SR_register_on_exit(LPM0_bits);// Wake up to setup next TX
              break;
        case USCI_SPI_UCTXIFG:
              UCA0TXBUF = TXData;             // Transmit characters
              UCA0IE &= ~UCTXIE;
              __delay_cycles(200);
              break;
        default: break;
    }
}


从机代码:

//******************************************************************************

//                   MSP430FR2433
//                 -----------------
//             /|\|                 |
//              | |                 |
//              --|RST              |
//                |                 |
//                |             P1.4|<- Data In (UCA0SIMO)
//                |                 |
//                |             P1.5|-> Data OUT (UCA0SOMI)
//                |                 |
//                |             P1.6|<- Serial Clock In (UCA0CLK)
//
//

//******************************************************************************
#include <msp430.h>

int main(void)
{
    WDTCTL = WDTPW|WDTHOLD;                   // Stop watchdog timer

    P1SEL0 |= BIT4 | BIT5 | BIT6;             // set 3-SPI pin as second function

    UCA0CTLW0 |= UCSWRST;                     // **Put state machine in reset**
    UCA0CTLW0 |= UCSYNC|UCCKPL|UCMSB;         // 3-pin, 8-bit SPI slave
                                              // Clock polarity high, MSB
    UCA0CTLW0 |= UCSSEL__SMCLK;               // SMCLK
    UCA0BR0 = 0x01;                           // /2,fBitClock = fBRCLK/(UCBRx+1).
    UCA0BR1 = 0;                              //
    UCA0MCTLW = 0;                            // No modulation
    UCA0CTLW0 &= ~UCSWRST;                    // **Initialize USCI state machine**
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

    PM5CTL0 &= ~LOCKLPM5;                     // Disable the GPIO power-on default high-impedance mode
                                              // to activate previously configured port settings
    P1DIR |=BIT0;
    P1OUT |=BIT0;

    __bis_SR_register(LPM0_bits | GIE);       // Enter LPM0, enable interrupts
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    while (!(UCA0IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
    UCA0TXBUF = UCA0RXBUF;                    // Echo received data
}


注意:1.对于SPI通信而言,发送和接收是同步进行的,在主机代码中,主机进入发送中断服务函数,执行完后,会直接进入接收中断函数。
2. 假设数据0x05被主机发送后,它接收的是0x04。因为他们是通过移位寄存器进行数据传递的,所以在判断条件是:RXData == TXData-1。
3. UCxTXIFG = 1表示 UCxTXBUF是空的,可以接收新的数据。 UCxTXIFG = 0表示 UCxTXBUF是满的,不可以接收新的数据。

上一篇:MSP430系列单片机笔记00


下一篇:NN中BP推导及w不能初始化为0