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.

[参考译文] MSP430FR5989-UART:如果在关键段内接收到一个字节、则 EP 通道停止从 UART A0 RX 触发中断

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1427934/msp430fr5989-ep-dma-channel-stops-triggering-interrupts-from-uart-a0-rx-if-a-byte-is-received-within-a-critical-section

器件型号:MSP430FR5989-MSP430FR5989-MSP430FR5989 EP

工具与软件:

我正在尝试了解我遇到的行为是否是勘误表 DMA7所描述的行为。  https://www.ti.com/lit/er/slaz523aa/slaz523aa.pdf?ts = 1729560620562&ref_url=https%253A%252F%252Fwww.google.com%252F 

我从勘误表中得到的是、如果在触发有效中断时访问包含寄存器的中断、它将丢弃该中断。 但只有那个中断、以及启用中断系统后的进一步中断才没有问题。 我也不知道 TI 在说"模块寄存器"时指的是什么、这是否仅表示 UCS A0 A1 B0 B1中断子系统? 它是否扩展到所有其他外设/CPU。 例如、如果我在传输完成时使用 dma 中断进行存储器到存储器 dma 传输、由于 dma 是具有寄存器的模块、这也属于所谓的"A 模块寄存器"下。  

我发现我自己的情况是、如果我按如下所示禁用中断、并且 在全局中断关闭的同时从外设生成一个中断请求。 再次启用中断后、DMA 通道将完全停止接收新的中断请求。  

目前、我使用以下函数来保护某些代码、以启用和禁用中断。

void enter_critical_section()
{
  __asm__ volatile(
      "DINT                     \n\t" /* Disable interrupts */
      "NOP                      \n\t" /* Ensure DINT takes effect */
      :
      :
      : "cc");
}

void exit_critical_section()
{
  __asm__ volatile(
      "NOP                      \n\t"
      "EINT                     \n\t" /* Re-enable interrupts */
      "NOP                      \n\t"
      :
      :
      : "cc");
}

我的 DMA 通道是 DMA0通道0 (最高优先级){我还对其他2个通道进行了测试、该行为是相同的}

我要通过中断将 UART A0 RX 连接到 DMA0通道0以进行字节传输。

在这一关键部分之外、DMA + UART 会按预期运行。 但是、如果它在临界区内触发、就会中断。

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

    您好、 

    我也不知道 TI 在说"模块寄存器"时指的是什么、这句话是仅指 UCS A0 A1 B0 B1中断子系统吗? 或者这是否扩展到所有其他外设/CPU

    根据勘误表中的说明、该模块寄存器可以指包含中断标志寄存器的模块。

    所有具有中断标志寄存器的外设都将触发此勘误表。

    a module register containing an interrupt flags

    -------

    例如、如果我要在传输完成时使用 DMA 中断进行存储器到存储器的 DMA 传输、这也可以归类为所谓的"A 模块寄存器"、因为 DMA 是一种具有寄存器的模块。  [报价]

    DMA 请求开始执行。

    CPU 使用 读取-修改-写入指令来访问模块的中断标志。

    触发同一模块的中断。

    那么该中断将丢失。

    ---

    [quote userid="617621" url="~/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1427934/msp430fr5989-ep-dma-channel-stops-triggering-interrupts-from-uart-a0-rx-if-a-byte-is-received-within-a-critical-section 我觉得自己属于这样一种情况:如果我按如下所示禁用中断、并且 在全局中断关闭时从外设产生一个中断请求。 再次启用中断后、DMA 通道将完全停止接收新的中断请求。  [报价]

    在[enter_critical_section]和[exit_critical_section]之后似乎会影响以下 DMA 触发。

    你是否尝试过在 DINT 之前清除和禁用受影响的中断并在 EINT 之后重新启用它们?

    从而确保系统在 DINT 期间不会生成未处理的中断请求。

    此致、

    Helic

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

    我尝试了对 DMA 寄存器的写入来禁用它的中断并在之后启用它、但是这并没有改变这个运行方式。

    尝试权变措施的代码如下所示。 我也尝试过不清除 IFG 字段、但没有区别。

    __attribute__((flatten)) __attribute__((optimize("-O3"))) void enter_critical_section()
    {
      /* Must manually disable DMA interrupts for errata DMA7 */
      /* Step 1: Wait for ongoing DMA transfers to complete (if applicable) */
      get_dma_channel_0()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::DISABLE);
      get_dma_channel_1()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::DISABLE);
      get_dma_channel_2()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::DISABLE);
    
      /* It is known that all 3 DMA channels WILL be used with interrupts so there is no checking required here */
      [[maybe_unused]] volatile auto throw_away = DMAIV;
      DMA0CTL &= ~DMAIFG;
      DMA1CTL &= ~DMAIFG;
      DMA2CTL &= ~DMAIFG;
      __asm__ volatile(
          "DINT                     \n\t" /* Disable interrupts */
          "NOP                      \n\t" /* Ensure DINT takes effect */
          :
          :
          : "cc");
    }
    
    __attribute__((flatten)) __attribute__((optimize("-O3"))) void exit_critical_section()
    {
      [[maybe_unused]] volatile auto throw_away = DMAIV;
      DMA0CTL &= ~DMAIFG;
      DMA1CTL &= ~DMAIFG;
      DMA2CTL &= ~DMAIFG;
      __asm__ volatile(
          "NOP                      \n\t"
          "EINT                     \n\t" /* Re-enable interrupts */
          "NOP                      \n\t"
          :
          :
          : "cc");
      /* Must manually disable DMA interrupts for errata DMA7 */
      /* It is known that all 3 DMA channels WILL be used with interrupts so there is no checking required here */
      get_dma_channel_0()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::ENABLE);
      get_dma_channel_1()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::ENABLE);
      get_dma_channel_2()->control.set_InterruptEnable(dma_control_register_t::InterruptEnable::ENABLE);
    }

    我还尝试了启用  

    DMACTL4 |= DMARMWDIS;
    但同样、行为也没有变化。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    1) 1)您的临界区函数似乎不优于编译器提供的函数。 GCC 提供了多个名称:__dint()、_dint()、_disable_interrupts()等等

    2) 2) DMA7需要一个非常具体的事件链。 首先、CPU 开始在一个 IFG 寄存器上执行一个读取-修改-写入指令。 在这一过程中、DMAC 进行接管。 最后、停止的 RMW 指令完成。

    考虑"UCA0IFG &=~μ s UCRXIFG;"之类的东西可能会发生什么情况。

    CPU 读取 IFG 寄存器、清除 RXIFG 标志、然后 DMAC 获得控制权。 当 DMAC 执行其传输时、会设置 IFG 中的另一个标志。 然后、当 DMAC 让 CPU 完成指令时、它在写入前不会再次读取 IFG 寄存器。 由于 IFG 中的该位在指令开始前被清零、因此它被清除并且中断丢失。