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.

[参考译文] EK-TM4C1294XL:在通过UART利用DMA时处理部分帧

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1099877/ek-tm4c1294xl-handling-partial-frames-when-leveraging-dma-with-uart

部件号:EK-TM4C1294XL


概述:

这在某种程度上是基于 上一个线程的结果的延续,重点是TM4C上的特定UART用例。


使用案例:
在此TI-RTOS应用程序中,将有一个主要的高优先级任务。 其 唯一 目的是 通过UART @ 11.52万 8-N-1接收32字节有效负载,每隔10毫秒。

在此有效负载中,有一个2字节的标头和2字节的脚注,它们是固定值,不会更改。

标题 正文 页脚
字节[0:1] 字节[2:29] 字节:[30:31]

TM4C将运行其他优先级较低的任务,但除了看门狗之外,此UART RX任务在优先级方面将排在下一。

选项:
正如我所看到的,我有三个主要选项来有效接收和处理此数据。 我已将每个 选项作为概念验证实施,但基于这些实施, 其中两个选项有 一个通用错误路径,这就是发布此帖子的原因。 以下选项按性能顺序列出,其中#1是性能最低的解决方案。

  1. 创建一个任务,为通过UART接收的每个字符触发Hwi。 根据字符序列,检测页眉,数据,页脚并相应地进行解析。 这种办法的主要缺点是需要改变背景。 由于这些中断将以Hwi的形式触发,并且Hwi在RTOS中具有最高优先级,因此您将在接收数据时不断中断其他任务。

  2. 创建一个利用具有UART的DMA的任务, 类似于 TI提供的现有UART Echo示例。 在这种情况下,您需要手动设置读取和休眠(非阻塞),直到UART_INT_DMARX Hwi触发器。 触发后,您可以拉出32个字节并根据需要进行解析。

  3. 创建一个与上面第2个任务非常相似的任务,但 通过使用 UDMA_MODE_Pingpong进行了优化。 基本上,当一个缓冲区被填满(B)时,您可以处理以前收集的缓冲区(A),反之亦然。  


结果:
在选项2和选项3中,在"快乐之路"情景中,他们表现良好。 但是,它们都存在相同的问题;如果您未收到完整的32字节有效负载,该怎么办? 由于我们使用DMA来促进UART RX,因此只有当DMA缓冲区已满(每32字节)时,Hwi才会触发。 如果您只收到32个字节中的10个字节,然后又收到一个新帧,那么从分析角度来看,您将不同步。

我尝试使用中断掩码,如 UART_INT_RT和 UART_INT_be,我想,也许通过启用这些位, 如果FIFO不是空的,并且在(n)个周期后没有收到数据,则会触发HWi。 但是,我想,由于我使用DMA, 从FIFO到目标地址的传输几乎会立即发生,这意味着FIFO永远不会真正处于剩余数据的状态(我这么说是否正确? 对该项不是太自信)

问题:
所以我想这是一个很长的问题,当将DMA与UART一起使用时,有没有办法知道预期的有效负载何时不完整。例如,您希望读取32字节,但只收到8字节? 我的第一个想法是简单地使用计时器来跟踪接收到的字节之间的增量,但再次强调,由于我使用的是DMA,我只能在收到所有32个字节时获得Hwi,而我要尝试捕获它们不是的用例。

我觉得这个问题以前已经解决了,所以我想我会在尝试重新发明车轮之前提出这个问题。

谢谢!

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

    Bert,您好!

    之前没有解决太多问题,因为我们可以解释什么是可能的,什么是不可能的。 在较高级别上 ,您所需的确切功能不可用。

    在应用程序级别,由于您有一个非常明确的数据包样式,我认为您可以根据需要解析传入的数据,以获取您的信息。 但没有默认提供部分数据的机制。 超时是按照您所指示的方式刷新DMA的一个选项。

    1294 -artUARU"]使用DMA时,是否有任何方法可以知道收到的有效载荷不完整,但只有32个字节。

    遗憾的是,该功能不是硬件功能,需要由应用程序来确定,而不需要任何来自硬件的标志。

    1294 -UART]然而,我认为由于我使用 FIFO论坛/109.9877万/EK-tm4c1294xl-tm4c1294xl-handl-handling-handling-particle-bers-bers-bers-bers-bers-bers-bers-bers-bers-bers-</s>1294 1294对该产品不是很有信心)[/QUOT]

    这取决于您使用的是"连拍"模式。 如果不使用"连拍"模式,则永远不会留下剩余数据。 如果使用"连拍"模式,则在FIFO中的数据级别不是基于FIFO水印集的最后一个连拍请求时,可能会留下剩余数据。

    1294 -UART]如果您没有收到完整的32字节有效负载,该怎么办? 由于我们使用DMA来促进UART RX,因此只有当DMA缓冲区已满(每32字节)时,Hwi才会触发。 如果您只收到32个字节中的10个字节,然后又收到一个新帧,则从分析角度来看,您将不同步。[/QUOT]

    不确定获取部分数据包的使用情况如何,但您是否可以有这样的情况:当发生这种情况时,您可以让另一个应用程序在刷新DMA (如任何现有数据)后重新发送数据包以返回路径?

    一般来说,我们的建议通常遵循这样的行式:使用标头来表示预期的字节数,并使用该标头来获得正确的字节数。 在这种情况下,由于您总是得到32字节,因此您可以相应地操作,我认为,如果您得到不同的字节数,则方法是进行重新发送。

    另一种方法是在应用程序中使用辅助解析,其中页眉和页脚用于检查正确的数据。 可能接收多达64字节的数据,然后检查完整的32字节,然后再进行处理。

    只是尝试在此处提供一些应用程序级解决方案,以考虑如何处理这种情况-尽管您的设置比大多数情况下都要好,但问题是如何接收任意数量的数据,这远比了解数据困难得多 在典型情况下将以32字节数据包的形式提供。

    还想强调这条E2E线程也围绕这些主题进行了更多的讨论,可能是一个有趣的阅读: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/103.7828万/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3863189#3863189</s>386.3189万 386.3189万

    此致,

    Ralph Jacobi

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

    谢谢拉尔夫,这是非常有益的!

    关于部分数据包使用案例的问题,这是一个边缘案例,但当实际将数据传输到TM4C的设备关闭MID事务时,可能会发生这种情况。

    我有点像从髋部射门,但在阅读您的回答后,我可能会有一个潜在的解决方案。

    好奇您的想法:

    在有效负载不完整的情况下,如果我设置一个单触发计时器,它将在最后一次已知成功的有效负载之后开始计数,该怎么办。 由于每个32字节有效载荷以10ms的间隔接收,因此如果 该窗口中未接收到UART_INT_DMARX,则计时器可能会触发。

    如果 UART_INT_DMARX被触发 ,则计时器将被取消(如果可能的话?),如果中断  未被接收,则计时器将最终 失效,触发中断,从而处理故障。 从技术上讲,您可以读取当时DMA缓冲区中存储的字节数,以确定这实际上是一个不完整的有效负载,并将数据丢弃。

    今晚我要给大家一个机会看看情况如何。 从计时器的角度来看,我看到了一些选项,例如利用看门狗驱动程序,时钟驱动程序,计时器驱动程序,SWI,甚至在RTOS中使用时间戳API。

    我很 可能在杂草中,所以如果你认为这是一个坏主意,请告诉我:)

    谢谢!

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

    Bert,您好!

    1294 -UART/4075061#4075061"]那么407.5061万那么定时器407.5061万定时器将被取消(如果可能)[/quothere]

    是的,通常会通过停止,重新加载新的计数值和重新启动来看到这一点。 在裸机中执行此操作的代码非常精简-只有几个API -因此我不会期望RTOS版本会增加任何显著的开销。

    您所描述的方法对我来说很有意义。 计时器驱动程序可能是一种方法,但我之前也没有使用过时间戳API。

    无论如何,我认为您不会因为如何处理边缘情况(如传输中断)而不在杂草中。

    此致,

    Ralph Jacobi

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

    您好,Ralph,您只需环回。 我们在上面讨论的一般想法就像一个迷人的地方! 再次感谢!

    我唯一要了解的是如何重置DMA缓冲区。 'reset'可能不是正确的术语,因为我实际上并不在乎缓冲区是否被刷新,我真的只在乎DMA用来遍历缓冲区的索引,它被重置回0。

    显然,有一种强力方法,即完全重新初始化和重新配置DMA。 我必须对其进行分析,以了解重新配置所需的时间,但如果您知道一种更简单,更高效的方法,我只是好奇。

    在此期间,我今天上午正在进行一些测试,看看是否只是 简单地调用 uDMAChannelDisable,那么uDMAChannelEnable就会重置索引。

    好奇您的想法!

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

    Bert,您好!

    由于以下评论,我认为启用/禁用信道不会对此有所帮助:

    //! When a uDMA transfer is completed, the channel is automatically disabled by
    //! the uDMA controller.  Therefore, this function should be called prior to
    //! starting up any new transfer.

    你基本上要做的是有效地重置'指数'。 即,如果UDMA向32字节缓冲区发送12字节,并计划发送在索引12处接收的下一个数据字节(由于开始@索引0),则您需要将其配置为将下一个字节发送到索引0。

    对于基本或AUO模式,我认为唯一的方法是重新配置DMA,因为没有即时API来为DMA提供一个新的指向的缓冲区。

    但有一件事你可以考虑,那就是在Ping Pong模式下使用两个缓冲区。 然后,在中断时,您只需禁用通道,通过 uDMAChannelTransferSet设置另一个传输,并使用 uDMAChannelEnable再次启用通道。 在您的应用程序中,只需让它忽略不完整的缓冲区即可。

    您可以在EK-TM4C1294XL LaunchPad的ADC_UDMA_Pingpong中看到一个ping模式示例。

    此致,

    Ralph Jacobi