This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR2355:为什么启用 UCRXIE (SPI)会导致 TX 数据包丢失?

Guru**** 2518690 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1119856/msp430fr2355-why-does-enabling-ucrxie-spi-cause-tx-packet-loss

器件型号:MSP430FR2355

我的代码非常简单-通过 SPI 发送包含四个十六进制{0x01、0x02、0x03、0x04}的信息包。  一切都正常、直到我在 进入 主循环之前添加一个额外的代码行、启用 UCRXIE 中断。  

在启用 UCRXIE 之前、数据线发送{0x01、0x02、0x03、0x04}。  启用 UCRXIE 后、数据线始终 发送 {0x01、0x02、0x04}-一个十六进制短整型值、出于任何原因、始终缺少0x03。   在  我能够解决这个丢包问题之前,我不能实现 RX 的中断功能-- 最后、我将使用一 个 EUSCI_A0_Vector 来处理  UCTXIE UCRXIE 中断、方法是检查哪些标志  UCTXIFG 和  UCRXIFG 已设置、我接收的 RX 数据包 取决于我在 SPI 线路上发送的 TX 数据包。

我在这里附上了屏幕截图和代码。

#include <msp430.h> 

char packet[] =
{
    0x01, 0x02, 0x03, 0x04      // packets
};

unsigned int position;

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

    UCA0CTLW0 |= UCSWRST;       // put eUSCI_A0 into SW reset

    UCA0CTLW0 |= UCSSEL__SMCLK; // choose 1MHz SMCLK as BRCLK
    UCA0BRW = 10;               // 1MHz divide by 10 = 100kHz

    UCA0CTLW0 |= UCSYNC;        // set bit to SPI mode
    UCA0CTLW0 |= UCMST;         // set bit to SPI master mode
    UCA0CTLW0 |= UCMSB_1;       // UCMSB_0=LSB; UCMSB_1=MSB
    UCA0CTLW0 |= UCMODE1;       // 4-wire STE LOW (10b)
    UCA0CTLW0 &= ~UCMODE0;      // ..
    UCA0CTLW0 |= UCSTEM;        // enable STE output pin

    P1SEL1 &= ~BIT5;            // P1.5 (UCA0SCLK)
    P1SEL0 |= BIT5;             // P1.5 ..
    P1SEL1 &= ~BIT7;            // P1.7 (UCA0SIMO)
    P1SEL0 |= BIT7;             // P1.7 ..
    P1SEL1 &= ~BIT6;            // P1.6 (UCA0SOMI)
    P1SEL0 |= BIT6;             // P1.6 ..
    P1SEL1 &= ~BIT4;            // P1.4 (STE)
    P1SEL0 |= BIT4;             // P1.4 ..

    P4DIR &= ~BIT1;             // P4.1 (SW1) clear as input
    P4REN |= BIT1;              // P4.1 (SW1) enable pull-up/down resistance
    P4OUT |= BIT1;              // P4.1 (SW1) pull-up
    P4IES |= BIT1;              // P4.1 (SW) interrupt edge select: high-to-low transition

    PM5CTL0 &= ~LOCKLPM5;       // get out of LPM
    UCA0CTLW0 &= ~UCSWRST;      // get out of SW reset

    P4IFG &= ~BIT1;             // P4.1 (SW1) clear IFG
    P4IE |= BIT1;               // P4.1 (SW1) enable IRQ

    UCA0IFG &= ~UCTXIFG;        // clear SPI Tx IFG
    UCA0IFG &= ~UCRXIFG;        // clear SPI Rx IFG
    UCA0IE |= UCTXIE;           // enable SPI TX IRQ
    UCA0IE |= UCRXIE;           // enable SPI RX IRQ

    __enable_interrupt();

    while(1)
    {
        // do nothing
    }

    return 0;
}

#pragma vector = PORT4_VECTOR
__interrupt void ISR_Port4_S1(void)
{
    position = 0;
    UCA0TXBUF = packet[position];
    P4IFG &= ~BIT1;
}

#pragma vector = EUSCI_A0_VECTOR
__interrupt void ISR_EUSCI_A0(void)
{
    position++;

    if(position < sizeof(packet))
    {
        UCA0TXBUF = packet[position];
    }
    else
    {
        UCA0IFG &= ~UCTXIFG;
    }
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您同时启用发送和接收中断、但 ISR 不会尝试弄清楚哪个中断导致其执行。 那么、考虑一下时序以及当接收中断到达时会发生什么情况。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我最初在 IRQ 例程中使用 if-else 语句开始- if ((UCA0IFG & UCTXIFG)==1){...清除 TXIFG}if  (((UCA0IFG & UCRXIFG)=1){...清除 RXIFG}、此时我遇到数据包丢失。 我以为这是条件语句、所以我将它们分条、但数据包仍然错过了一个十六进制。 条件语句是否正确?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我无法从您的代码片段中得知您是否正确使用了它们。 使用 IV 寄存器。 它只是为此目的提供的。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在中断矢量中、对标志执行操作的最佳方法是将编译器内在函数__even_in_range 与创建跳转表的实际 IV 寄存器上的 switch 语句结合使用。 这适用于任何外设的中断矢量例程。

    在 ISR 中:

    switch(__even_in_range(UCA0IV, 0x4))
    {
        case UCIV__UCTXIFG:
        
            position++;
            
            if(position < sizeof(packet))
            {
                UCA0TXBUF = packet[position];
            }
            else
            {
                UCA0IFG &= ~UCTXIFG;
            }
        
        break;
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    1) 1)您不会在 IV 寄存器中使用符号 UCTXIFG。 为 IV 寄存器提供了不同的符号、其值为:UCIV__UCTXIFG。

    2) 2)我从未见偶数_in_range 执行任何操作。 我假设它是编译器的信号、允许编译器优化开关。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    1) 1)你是对的。 我编辑了初始注释。   不过、我从来不知道 UCIV__UCTXIFG 符号、通常我只需手动键入 IV 标志值。 感谢您的提示。

    2) 2)它是一个内在函数、应该是这样做的;它记录在编译器的用户指南中。 几乎可以告诉编译器它只是一个偶数、应该创建一个简单的跳转表、而不是标准的 switch 语句实现。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我建议您不要使用中断。 您将(最终)正确地完成这项工作、并且这一过程可能是有教育意义的、但您会发现您的系统已经减速。

    SPI 的中断会引入 ISR 开销和(在您观察时)记账要求、这些要求仅适用于速度非常慢的 SPI (BRW=10、这不是您的情况)。

    我建议在这里使用 spix()函数:

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/758000/msp430fr5729-problems-with-implementing-mcp23s08-8-bit-port-expander-on-msp430fr5729/2800722

    (正如 David S 所指出的、如果您只使用此函数、则不需要第一行中的 TXIFG 测试。)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    因此、我应该检查 UCIV 寄存器中的02h 或04h、而不是检查  UCA0IFG 寄存器中的 UCTXIFG/UCRXIFG 位是否被置位。  我认为它们是相同的、我也可以使用  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您也可以检查、但不能检查您的操作方式。

     >IF (((UCA0IFG & UCTXIFG)==1)

    由于 UCTXIFG=2、该测试始终为 false。 类似的 RXIFG 测试仅在意外情况下才起作用。  适当的形式是:

    >IF (((UCA0IFG & UCTXIFG)!= 0)

    首先检查 UCRXIFG。 这将提高您避免溢出的几率。