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.

[参考译文] LAUNCHXL-CC1352R1:计时器触发的 DMA 散聚在调试器断开时停止运行

Guru**** 2482105 points


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

https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/1235362/launchxl-cc1352r1-timer-triggered-dma-scatter-gather-stops-running-upon-debugger-detaching

器件型号:LAUNCHXL-CC1352R1

大家好!
这是我的第一篇文章,我希望有人可以帮助我解决这个非常奇怪的问题,我现在挣扎了大约2个月。
我试图在不使用 Bit-Bang (这是我为客户定制的协议、不使用任何标准总线、如 I2C、SPI、UART 等)的情况下、通过 GPIO 控制一些数据交换、差不多就像一个"多"单线协议。
为此、我将基于 driverlib 开发一个定制驱动程序、因为无法使用高级驱动程序、 基本上、我想使用散聚 DMA 传输、方法是创建一个任务列表、列出通过直接在 GPIO 数据寄存器上写入"1"或"0"直接驱动单独的 GPIO 的 DMA 请求。
为了避免使用 CPU (与电源管理相关的限制非常严格)、我想使用计时器来驱动 DMA、这种方法使用外设散聚模式、 我可以使用计时器的超时中断来触发每个 DMA 任务、并将 GPIO 与计时器同步控制、而无需使用 CPU 处理任何内容或使用软件延迟来满足协议时序。
我想要实现的是控制通信、方法是简单地启动计时器、从而触发 DMA 一次请求一个任务(因此它可以根据协议将单个 GPIO 驱动为高电平或低电平)、并通过在没有任何 CPU 干预的情况下停止计时器来终止它 (可以发送完整的消息以在特定时间内启用和禁用计时器)。
作为我使用本文档的代码的参考:"CC13x2、CC26x2 SimpleLink 无线 MCU 技术参考手册"、其中第14.3.6.6段介绍了外设散聚 DMA、第15.4.5段介绍了计时器触发的 DMA 请求功能。 作为计时器和 DMA 配置的参考代码、我还使用 ADCBufCC26X2驱动器、该驱动器使用基于乒乓模式的 DMA 管理、并且计时器触发 ADC、而不是直接触发 DMA。
我正在使用配置为16位连续计数定时器的 GPTimer 0和 DMA 的通道9 (由 GPT0的超时事件触发)。
一切似乎都很顺利、除了只有在连接了调试器的情况下运行固件时(我使用的是 Launchpad CC1352R1评估板)才能看到数据流、而如果在不调试的情况下运行数据流、DMA 将停止工作 (使用调试配置文件构建的相同固件不进行优化)。
我做了一些测试、同时使用逻辑分析仪来显示信号的状态、并添加了其他一些用作测试信号的 GPIO、以收集有关计时器状态以及中断是否被正确触发的信息。 我还可以使用 UART 控制台来访问寄存器、从而设置/获取寄存器值、以便查看在我未连接调试器时会发生什么情况。
我发现了 DMA 的主要区别是 REQDONE 状态、确切地说:当我激活计时器并且 DMA 开始处理散聚任务列表时、如果我在连接调试器的情况下运行固件、REQDONE 永远不会发生并且一切运行完美; 相反、如果我只需在 IDE 中按下"Stop"按钮、或者如果我在未连接调试器的情况下直接运行固件、则在第一个任务或最多第二个任务之后、REQDONE 会升高并且 DMA 会停止处理其余的任务来停止该序列。
我的问题是:这是预期行为吗? 在没有调试器的情况下运行固件时、我是否需要配置其他配置来避免发生此类事件?
出于 NDA 原因(我是我的客户的顾问)、我无法提供项目的完整源代码、但如有必要、我可以在此处复制/粘贴一些严格与 DMA 和计时器配置相关的部分; 无论如何、为了提供预期结果的样本、我附上了两张逻辑分析仪输出的屏幕截图、第一张是正确的行为(2个 GPIO 和定时器切换轨迹作为参考)和不良行为 (我注册了一个连接到计时器中断的 HWI/SWI 耦合、在 SWI 中、如果 REQDONE 标志提高、我只需重新启用 DMA 通道、但这会在协议中产生差距、因为 HWI 是随机触发的、因此我松散了一些 DMA 事务)。
很抱歉这么长的文本、我想提供尽可能多的信息、非常提前感谢您提出任何建议。
达里奥

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

    大家好,达里奥

    如果您在连接调试器的情况下按预期运行代码、但不是独立运行代码、则问题很可能与功耗模式有关。

    在连接调试器的情况下运行时、会阻止器件进入待机状态。

    独立运行时、它可能会进入待机状态、而且您可能会遇到问题、因为您没有以适当的方式处理不同域的电源。

    要验证问题是否出在此处、您可以尝试在代码中不允许待机模式(Power_setConstraint (PowerCC26XX_disallow _standby);)

    如果调试器断开连接时其运行正常、则表明问题与 功耗模式有关。

    Siri

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

    尊敬的 Siri:

    感谢您的答复、我在调查期间已经考虑了电源管理问题、并且按照您的建议设置了功率限制。
    让我们给出一个更清晰的观点: 我使用了一个类似 driverlib 的结构、一组* Init、* Open、* Close、* Start 和* Stop 函数、并在我的* Start 函数(启动计时器、因此启动 DMA)和一个 Power_release_Constraint (PowerCC26XX_disallow _standby 函数)调用中调用 Power_setConstraint (Power_setConstraint (Power_disallow _standby 函数)。

    此外、我在使用驱动程序时还尝试设置对相关外设的依赖、因此添加了:
       power_setDependency (PowerCC26XX_Periph_uDMA);
       power_setDependency (PowerCC26XX_Periph_GPT0);
    在我的*Open 函数中和:
       power_releaseDependency (PowerCC26XX_Periph_uDMA);
       power_releaseDependency (PowerCC26XX_Periph_GPT0);
    在我的*关闭函数中,但这些函数不涉及过程: 基本上、在我的线程启动时调用* Open (我在我的项目中使用 TI-RTOS)、并且在我的测试期间不调用*关闭(我可以通过 UART 控制台简单地调用*开始和*停止函数来启动和停止传输、因此我不关闭驱动程序)。

    我是否可以进行其他一些检查来验证电源管理是否有任何问题(例如某些寄存器配置)、以便排除 CPU 待机状态导致的行为?

    提前非常感谢您、
    达里奥


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

    很遗憾、我不知道如何以最好的方式对其进行调试。

    通常、我们仅支持使用我们的驱动程序、因此当您停止使用它们并自行实现驱动程序时、我们很难就具体内容提供建议。

    如果你只是 在代码的开头执行 Power_setConstraint (PowerCC26XX_disallow _standby)操作(无需再次发布)、那么在不使用调试器的情况下、你还会遇到什么问题吗? 您刚才说过您尝试过的方法、但没有说得到了什么结果。

    除此之外、我想我建议在调试时尽可能简化您的代码。 除了 DMA 之类的东西、您的代码中还有很多其他的东西、因此可以制作一个尽可能简单的演示示例。 也许还有一些其他的驱动程序等,正在混乱的事情。  

    你还可以尝试使用 energy trace 查看电流曲线、以便了解这是否能为你提供有关功率模式等的任何提示。

    我很抱歉,我不能提供更好的帮助。

    Siri

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

    尊敬的 Siri:

    感谢您的回复,我知道您不提供其他驱动程序的支持,在这种情况下,我的问题是没有任何驱动程序可以满足我当前的需求。

    不管怎样、我在代码的开头使用 Power_setConstraint (PowerCC26XX_disallow _standby)确认一下这个问题不会解决这个问题(我还禁用了约束的发布、可以对此重复一遍)。

    我还没有尝试使用能量跟踪进行分析、因为我在过去几天没有时间对此进行处理、我会尝试报告、感谢您的建议。

    最后一个问题:如果我使用我的驱动程序准备了一个简单的示例、我可以在此处发布该项目以获得一些额外的帮助、还是您不能/不能考虑的事情?

    再次感谢您的支持、

    达里奥

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

    大家好,达里奥

    例如、如果您使用我们最新 SDK 中的空示例并制作一个可以在 LP 上运行的小型演示代码来重现问题、我们将来看一下、但我不能保证我们能够解决这个问题。  

    然而、试图制作这样一个小示例也许对您也是有益的、所以在任何情况下都不会浪费时间。

    Siri

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

    尊敬的 Siri:

    非常感谢您的答复和支持。

    几天后、我将尝试用尽可能少的代码准备此类示例(即使是因为我与客户签订了 NDA)。

    再次感谢您、

    达里奥

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

    尊敬的 Siri:

    很抱歉这么晚才回复、但我有一些任务具有更高的优先级、无法准备代码。

    无论如何,我认为我发现了这个问题,即使我不能100%解释为什么。

    从根本上说、这似乎与我如何为散聚 DMA 请求配置任务列表有关、我在这里复制内容以使之更加清晰:

    static uint8_t outLevelHigh = 1;
    static uint8_t outLevelLow = 0;
    
    /* DMA Scatter-Gather tasks table */
    tDMAControlTable txTimerDmaTableEntry[] =
    {
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
    
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
    };
    

    主要思路是使用 DMA 外设直接驱动 GPIO 的状态(实际上更复杂、但由于 NDA、我无法复制整个代码)、 因此、源指针是一个变量、根据要驱动的状态包含"0"或"1"、目标是 GPIO 数据寄存器。
    每个状态都由一项散聚任务驱动、该任务在生成 DMA 请求的定时器每次切换时执行。
    在我的原始代码中、outLevelHigh 和 outLevelLow 变量被声明为"static const uint8_t"、这是导致问题的原因。

    我假设是"const"限定符、它链接到闪存中的变量而不是 RAM 中的变量、因此可能 DMA 无法正确访问指针、我不明白的是、它为什么在连接了调试器时运行完美、而在断开调试器时挂起。 (当 CPU 正在调试时、DMA 以不同的方式访问存储器吗?)。

    总之、建议提供示例代码对解决方案很有用、因为在我的原始项目中、编译器没有给出任何警告、 在项目中、我为您做准备时、编译器会使用"从指针目标类型中丢弃'const'限定符"消息对此发出警告、因此我尝试删除 const 限定符、一切都正常工作。

    非常感谢您的支持。

    此致、

    达里奥