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.

[参考译文] MSP430F67771A:UART ISR 从中断矢量寄存器中读取0值

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/996331/msp430f67771a-uart-isr-reads-value-of-0-from-interrupt-vector-register

器件型号:MSP430F67771A

下面是 UART 模式下用于 USCI_A0的 ISR 函数的精简版本(某些宏也部分扩展)。 通过 BACnet MS/MS 协议运行时、我会看到一些溢出错误、但我也会看到大量的中断、其中 IV 值为0并下降到默认情况。 我们的 BACnet 堆栈有时会在接收到的帧丢失几个字节 (生成最终的 CRC 错误)时发生故障、但我无法确认这些故障是否仅 来自溢出错误。

  • IV 寄存器值为0时、如何触发中断?
  • 是否有可能某些接收到的字节在不设置 USCI_UART_UCRXIFG 标志的情况下生成中断(导致数据丢失)?
  • 在启用/禁用 UCA0IE 寄存器中的中断和清除 UCA0IFG 寄存器中的标志时、是否应该避免可能的竞争情况?

void _uartISR(void)
{
    uint16_t err;

    switch(_even_in_range(HWREG16((0x05C0) + OFS_UCAxIV), USCI_UART_UCTXCPTIFG))
    {
        case USCI_UART_UCRXIFG:
            // Read the error status before unloading the rx buffer.
            err = HWREG16((0x05C0) + OFS_UCAxSTATW);
            *m_rx.pHead = HWREG16((0x05C0) + OFS_UCAxRXBUF);

            if(err & (UCFE | UCOE | UCPE))
            {
                if(err & UCFE)
                    g_nRxErrors.framing++;
                else if(err & UCOE)
                    g_nRxErrors.overrun++;
                else if(err & UCPE)
                    g_nRxErrors.parity++;
                else
                    g_nRxErrors.undefined++;
            }
            break;

        case USCI_UART_UCTXCPTIFG:
            if(!(HWREG16((0x05C0) + OFS_UCAxSTATW) & UCBUSY))
            {
                // Disable UART tx complete interrupt.
                do {HWREG16((0x05C0) + OFS_UCAxIE) &= ~((0x0008)); _nop();} while(0);
                do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0008)); _nop();} while(0);
                
                // Enable rx interrupt.
                do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0002)); _nop();} while(0);
                do {HWREG16((0x05C0) + OFS_UCAxIE) |= ((0x0001));} while(0);
            }
            break;

        default:
            g_nRxErrors.ivZero++;
            break;
    }
}

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

    是否启用了其他中断? 如果是、他们可能负责达到默认情况。 此外、发送完成中断在每个停止位被发送后发生。 (请参阅勘误表中的 USCI42。) 在我披露此错误时、曾讨论过一些权变措施、但 TI 决定在发布勘误表时没有可靠的权变措施。

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

    不、只启用这两个中断。 我使用 DMA 外设执行 RAM 中触发一个 Tx 中断标志 USCI_UART_UCTXIFG 的本地缓冲区的 Tx、该中断标志应在 UART 外设的硬件缓冲区 UCAxTXBUFTx 变为空时生成中断。 当 DMA 完成其操作时、它会生成它自己的中断并且 ISR 会启用 UCTXCPTIE、这样就会启用 USCI_UART_UCTXCPTIFG 标志、正如我在上面的代码中看到的那样。 我检查 UART 是否忙以确保硬件缓冲 器 UCAxTXBUF 或 Tx 移位寄存器中没有数据。

    我所能说的一切似乎都能正常工作。 我能够在 RAM 中发送本地缓冲器、并且能够检测到该 Tx 的结束。

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

    让我看看我是否理解您所说的内容(代码会有所帮助)。

    发送数据通过 DMAC 移动。 当 DMA 完成传输时、它的传输完成 ISR 将置位 UCTXCPTIE。

    这是一个问题。 当 DMAC 完成其工作时、UART 移位寄存器中将有一个字节、TXBUF 中将有一个字节。 UCTXCP过渡 联邦政府当然是由以前的转让所确定的。

    因此、当您启用 UCTXCPTIE 时、有一个中断挂起、另有两个中断从该触发器发出。 我很确定 TI 在决定没有权变措施之前考虑了检查 UCBUSY 的可能性。

    由于你不清除 UCTXCPTIE (或者至少不显示它被清除的位置)、这几乎肯定是你意外中断的源。

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

    很抱歉造成混淆。 是的、我已经考虑了这种情况。 在我最初的帖子中、第26行的代码正在检查忙标志 UCBUSY、以确保我们确实完成了每个字节的 Txing。

    此处是 DMA ISR、供其他参考。

    __interrupt void _txDMAISR(void)
    {
        switch(_even_in_range(GET_DMA_IV(), DMAIV_DMA2IFG))
        {
            case DMAIV_DMA1IFG:
                // Clear and enable UART tx complete interrupt.
                do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0008)); _nop();} while(0);
                do {HWREG16((0x05C0) + OFS_UCAxIE) |= ((0x0008));} while(0);
                break;
    
            default:
                break;
        }
    }

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

    检查 UCBUSY 不能保证正常工作、否则它将被显示为勘误表中的权变措施。

    如果遇到默认情况、您不知道 IV 寄存器中有0。 还有其他可能、您至少应该为这些情况放置残桩。

    哦、在您的中断代码中、您在启用 RXIE 之前清除 TXIFG。 这看起来很奇怪。

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

    为了简洁起见、我减少了部分代码(并扩展了宏)、因此 下面的代码会更准确地显示我们正在计数空 IV 寄存器。

    在查看勘误表中的 USCI42后、我看到您的观点是没有指定任何权变措施。 话虽如此、至少在第26行中"似乎"正常工作、其中 if 语句要求 UCBUSY 标志为0。 在第29行、我们将切换 GPIO 引脚以 将 RS-485收发器置于 Rx 模式、通过探测 UART 信号和此 GPIO 引脚的示波器、可以看出时序准确到最后一个字节的最后一个停止位。 从应用的角度来看、我们通过该 UART 运行的 BACnet 协议在我们的应力测试下似乎运行良好。

    如果勘误表表明这个问题 在某种程度上导致从 IV 寄存器中读取0值、那么我们将假定我们的应用工作正常、并且这些寄生中断可以被忽略。

    void _uartISR(void)
    {
        uint16_t err;
    
        switch(_even_in_range(HWREG16((0x05C0) + OFS_UCAxIV), USCI_UART_UCTXCPTIFG))
        {
            case USCI_UART_UCRXIFG:
                // Read the error status before unloading the rx buffer.
                err = HWREG16((0x05C0) + OFS_UCAxSTATW);
                *m_rx.pHead = HWREG16((0x05C0) + OFS_UCAxRXBUF);
    
                if(err & (UCFE | UCOE | UCPE))
                {
                    if(err & UCFE)
                        g_nRxErrors.framing++;
                    else if(err & UCOE)
                        g_nRxErrors.overrun++;
                    else if(err & UCPE)
                        g_nRxErrors.parity++;
                    else
                        g_nRxErrors.undefined++;
                }
                break;
    
            case USCI_UART_UCTXCPTIFG:
                if(!(HWREG16((0x05C0) + OFS_UCAxSTATW) & UCBUSY))
                {
                    // Disable RS-485 tx mode.
    			    do {HWREG16((GEN_PORT_BASE(3)) + OFS_PAOUT) &= \
                            ~((((3) & 1) ^ 1) ? (((0x0008)) << 8) : ((0x0008)));} while(0)
    
                    // Disable UART tx complete interrupt.
                    do {HWREG16((0x05C0) + OFS_UCAxIE) &= ~((0x0008)); _nop();} while(0);
                    do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0008)); _nop();} while(0);
                    
                    // Enable rx interrupt.
                    do {HWREG16((0x05C0) + OFS_UCAxIFG) &= ~((0x0002)); _nop();} while(0);
                    do {HWREG16((0x05C0) + OFS_UCAxIE) |= ((0x0001));} while(0);
                }
                break;
    
            case USCI_NONE:
                g_nRxErrors.ivZero++;
                break;
                
            case USCI_UART_UCTXIFG:
            case USCI_UART_UCSTTIFG:
            default:
                assert(0);
                break;
        }
    }

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

    问题可能出在配置 UART 和 DMAC 的代码中。

    我遇到此问题的代码还使用 DMAC 通过 RS485链路传输数据。 我需要关闭发送器、以便其他东西可以驱动总线。 我最后检查了 TXIFG。 这对我来说是可行的、但可能只是因为我使用的是低速(9600bps)。

        case USCI_UART_UCTXCPTIFG:
          /*
            There is a hardware bug (not mentioned in the errata) causing this
            interrupt to happen early and often. I check the transmit buffer
            register empty flag as well. This seems to control the problem.
           */
          if(UCA0IFG & UCTXIFG)
            {
              P3OUT &= ~0x10;          // disable RS485 transmitter
            }