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.

[参考译文] MSP-EXP430FR5994:DMA 争用 UART 接收

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1117325/msp-exp430fr5994-dma-race-with-uart-receive

器件型号:MSP-EXP430FR5994

您好!

我的设置为 EXP-MSP430FR5994 (用于时钟的外部晶振)、BQ76600 EVM (UART)、定制 BQ79616。 我使用 MSP430 DMA 进行 UART 接收。 我正在进入下面概述的比赛状态、并尝试解决方案。 唯一有助于实现 BQ 一致初始化的解决方案是在通过 UART 传输数据之前明确清除 DMAEN。

如果在 uartSend 中没有显式清除 DMAEN、BQ 初始化有时会在 BQ 自动寻址序列期间的第一次抛出读取后失败。
DMA 传输大小变量 uartRxLen 显示正确的值(并与寄存器宽度匹配);
本地 DMA 接收缓冲区 DMA_VALUE 的内容包含所有接收字节;但 DMA1SZ 寄存器中的值= 1、DMA ISR 不会触发。 我无法捕获故障发生的确切时刻。
下面列出的其他解决方案替代清除 DMAEN。 这些都不能帮助改善比赛条件:
1.在 DMA ISR 中从 LPM 中删除 EXIT (不存在 LPM 条目)
250ms BQ 测量时间(主计时器 ISR 当前为125ms)
3.在 UART ISR 上接收第一个字节;禁用 UART Rx ISR、然后为剩余的接收字节启动 DMA 传输。

我需要有关我可以尝试解决此问题的其他问题的指针。

Priya

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

    1) 1)能否布置 main()函数? 在您到目前为止发布的内容中、我没有看到任何明显的控制流内容。

    2)由于条件看起来足够清晰(DMA 看起来完成后 DMAEN 仍然打开)、接下来我将尝试"mousetrap "、 可能类似于:

    if (BQUART_DMAxCTL & DMAEN) {   // We expect it isn't
        asm volatile (" nop ");     // Breakpoint here and see how we got here
        BQUART_DMAxCTL &= ~DMAEN;   // Keep things rolling nonetheless
    }

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

    这是主函数。 我将把"TRAP"代码放入 uartSend 函数中、查看我找到的内容。

    #include "bspFuncs.h"
    #include "timer.h"
    #include "clock.h"
    
    #ifdef BQ_SPI
       #include <BQSpiInitFuncs.h>
       #include <BQSpiMeasure.h>
       #include "spiCommands.h"
    #endif
    
    #ifdef BQ_UART
       #include <BQUartInitFuncs.h>
       #include <BQUartMeasure.h>
       #include "uartCommands.h"
    #endif
    
    
    /**
     * main.c
     */
    int main(void)
    {
    
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	
        Clock_Init();
    
       #ifdef BQ_UART
          configure_pins_BQUart();
          UART_Init();
          DMA_Init();
       #endif
    
       #ifdef BQ_SPI
          configure_pins_BQSpi();
          SPI_Init();
       #endif
    
        Timer_Init();
        TA0_Start();
    
        __enable_interrupt();
    
       #ifdef BQ_SPI
          SpiReadyComm();
       #endif
    
       #ifdef BQ_UART
          UartReadyComm();
       #endif
    
    
       while(1)
       {
          if(1==Get_TimerFlag())
          {
              Set_TimerFlag(0);
              #ifdef BQ_SPI
                  BQ_SPI_APP();      //make measurements every 125 ms
              #endif
    
              #ifdef BQ_UART
                  BQ_UART_APP();      //make measurements every 125 ms
              #endif
    
              updateTimers();
          }
    
        }
    
    }
    

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

    我无法在此感应断点处停止。 似乎 DMAEN 位上的转换正在帮助解决问题、否则 BQ 初始化过程有时会失败。

       if ((BQUART_DMAxCTL & DMAEN) == 1) {   // We expect it isn't
            asm volatile (" nop ");     // Breakpoint here and see how we got here
            BQUART_DMAxCTL &= ~DMAEN;   // Keep things rolling nonetheless
        }

    如果我将此代码放入 uartSend 中、BQ 初始化失败、但未达到断点。

    问题发生在 BQ 初始化序列的以下部分:

    //SYNCRHONIZE 具有立即读取功能的 DLL
    ReadReg (0、OTP_ECC_DATAIN1、autodr_RESPONSE_FRAME、1、0、 FRMWRT_STK_R);
    while (dmaDataReady = 0);

    这是发出的第一个 ReadReg 命令。 我在链接线程上上传的 uartCommands.c 文件中提供了高达 uartSend 的 ReadReg 命令流程。 其中大部分是 TI 提供的代码、修改后使用 MSP430 UART。

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

    由于 DMAEN 不为1、此表单失败。 如果您需要使用比较、您可以尝试:

    > if (((BQUART_DMAxCTL & DMAEN)!= 0){

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

        if ((BQUART_DMAxCTL & DMAEN) != 0) {   // We expect it isn't
             asm volatile (" nop ");     // Breakpoint here and see how we got here
             BQUART_DMAxCTL &= ~DMAEN;   // Keep things rolling nonetheless
         }
    

    如果我在此代码中使用断点进行调试、由于某种原因、IDE 会话会直接进入此断点并停止。 我不明白为什么。 在它停止时、uartRxLen 为0。 与没有这种检查的情况不同、DMAEN 看起来始终为1。

    除此之外、寄存器内容中没有任何问题。

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

    DMA_Init()执行以下操作:

    > BQUART_DMAxCTL |= DMADDT_0|DMADSTINCR_3|DMASRCINCR_0|DMASRCBYTE_WORD |DMADSTBYTE_WORD |DMADSTBYTE_WORD |DMA_TRIGGER_RISINGEDGE|DMAEN;

    我不知道这是否会触发您的特定症状、但通常在您需要 DMAEN 之前设置 DMAEN 并不是一个好主意。

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

    我将 DMA_Init 更改为  

    BQUART_DMAxCTL |= DMADD_0|DMADSTINCR_3|DMASRCINCR_0|DMASRCBYTE_WORD |DMADSTBYTE_WORD |DMADSTBYTE_WORD | DMA_TRIGGER_RISINGEDGE;

    一旦我启动调试会话、执行仍会在断点处停止。 为什么 DMAEN 默认为1?

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

    DMAEN 本身并不设为(1)、因此我的下一步是使用 CCS 搜索(工具栏项看起来像铅笔橡皮擦)来搜索 DMAEN、然后使用 uartSend 来查看我是否忘记了某些用法。

    接下来是 uartSend (唯一设置 DMAEN=1的代码)处的断点、以查看调用栈中是否存在一些意外调用方。 此步骤将会更复杂一些、因为断点可能会干扰串行接收、但(因为您正在关闭原因)您不必多次执行此操作。

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

    在项目中没有忘记调用 DMAEN 或 uartSend。  

    就调用堆栈而言、我该怎么做? 我在 DMA1CTL DMAEN 位上放置了一个连续的观察。 我可以看到 、在调试会话启动后、它很快变为1、并在断点处停止。 如何跟踪该写入 DMAEN 的源?

    这是 CCS 中的堆栈使用视图

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

    当您在断点处停止时、调用堆栈(我的 CCS 中的左上角视图)会显示名为 who 的用户列表、当前函数位于顶部。  

    我的操作假设是某些函数调用 uartSend、然后没有正确(或根本)等待 DMA 完成。 然后、对 uartSend 的下一个调用将跳过"悬空" DMAEN。 这意味着您正在尝试查找前一个调用方(可能是第一个调用方)、这在一般情况下并不容易、但您似乎具有非常可重复的序列、该序列会非常早地失败。

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

    是的、看看左上角的情况、可以获得极大的帮助! 虽然只在一个位置调用 uartSend、但 WriteReg 和 ReadReg 都使用 uartSend。 只需为 ReadReg 启动 DMA 传输。 感谢您的帮助、非常感谢。