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.

[参考译文] Linux/AM4378:来自 UART 的杂散 EDMA 触发器

Guru**** 2587365 points


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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/632011/linux-am4378-spurious-edma-trigger-from-uart

器件型号:AM4378

工具/软件:Linux

我使用的是基于 TI EVM 的 AM437x 定制板。

我已经使用 ti-processor-sdk-linux-am437x-evm-04.00.04中的 Linux 内核以及 Linux 主线复制中的更新版本(4.12.y、4.3.4.3.y、4.14.y)进行了测试。  都表现出以下行为。

我需要通过 UART (ttyS2)接收"高速"(1.5Mbs - 3Mbs)数据。  我使用默认的中断驱动接收器获得 RX 溢出、因此我在器件树中为该 UART 启用了 DMA。  串行端口已配置为传递原始数据、并且所有流控均已关闭。  我在逻辑分析仪上捕获了串行数据、传输的数据是正确的。

启用 DMA 后、传输包含额外的 NULL 字节。  也就是说、当我发送8192字节的有效载荷时、我有时会接收到更多的8192字节。  额外的字节始终为0x00、并且保留的数据是正确的。

为了进行测试、我生成了一个8k 文件、其中包含重复512次的以下字符串"0123456789ABCDEF"。  以下是源文件的 hexdump:

hexdump -C /root/8k
00000000 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 |0123456789ABCDEF|
*
00002000

我使用以下命令发送和接收了数据:

CAT /dev/ttyS2 >/tmp/dump & Sleep 1;cat /root/8k >/dev/ttyS4;Sleep 10;kill -HUP %1;Sleep 2;wc /tmp/dump;hexdump -C /tmp/dump 

休眠只是为了确保流程"就绪"。  以下是捕获额外的0x00时上述命令的输出示例:

0 1 8248 /tmp/dump
 00000000 30 31 33 34 35 36 37 38 39 41 42 44 45 46 |0123456789ABCDEF|
*
000000c0 00 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 |.0123456789ABCDE|
000000d0 46 30 31 32 33 35 36 37 38 39 41 42 43 44 45 |F0123456789ABCDE|
*
00000140 46 00 00 00 00 30 31 32 33 34 35 36 37 38 39 41 | F....0123456789A|
00000150 42 43 45 46 30 31 33 34 35 36 38 39 41 | BCDEF0123456789A|
*
0000042 43 44 45 46 30 31 00 00 00 00 32 33 34 35 | BCDEF01..... 2345|
00000730 36 37 38 39 41 42 43 44 45 46 30 31 33 34 35 |6789ABCDEF012345|
*
00001380 36 37 38 39 41 42 43 44 45 46 00 00 00 00 00 00 00 |6789ABCDEF... |
00001390 00 30 31 33 34 35 36 37 38 39 41 42 43 44 45 |.0123456789ABCDE|
000013a0 46 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 |F0123456789ABCDE|
*
000015d0 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | F. |
000015e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.......... |
000015f0 00 30 31 33 34 35 36 37 38 39 41 42 43 44 45 |.0123456789ABCDE|
00001600 46 30 31 33 34 35 36 37 38 39 41 42 43 44 45 |F0123456789ABCDE|
*
00001970 46 00 00 00 00 00 00 00 00 00 00 00 30 31 32 33 34 35 36 37 | F. 01234567|
00001980 38 39 41 42 43 44 45 46 30 31 32 33 34 35 36 37 |89ABCDEF01234567|
*
00002038

额外的56个字节是0x00。  其他8192个字节与源文件匹配。  如上所示、额外的0x00被插入多个位置的流中。

使用标准内核模块、Rx DMA 大小设置为48字节、具有48字节 FIFO 阈值和48字节 DMA 突发大小。  在一个 DMA 传输结束时、驱动程序直接从 UART FIFO 读取任何剩余的字节、然后启用另一个 DMA 传输。

使用自定义内核、我确定了额外的0x00发生在从 UART FIFO 到存储器的数据 DMA 期间、而不是直接读取期间。  此外、在第一个 DMA 传输中(在打开串行端口之后)没有出现额外的0x00。  我认为0x00是由从空 FIFO 读取 DMA 引起的。

我还使用1k 的较大 DMA 缓冲区大小进行了测试、具有各种 FIFO 阈值并匹配 DMA 突发大小。  在这些测试中、前1k 数据始终正常、在一个 DMA 传输结束和下一个传输开始之间从 FIFO 直接读取的字节始终良好。  在 DMA 传输期间、额外的0x00可能会出现在任何位置(例如、从252字节开始进入1k 缓冲区、阈值= 16突发= 16)。

似乎在 FIFO 有足够的数据之前触发了 DMA。  也许在随后的传输开始时 DMA 被错误地触发、并且需要几个传输来"捕捉"并取代 FIFO。

我没有发现任何与上述问题直接相关的勘误表、TRM 对 UART 的 Rx 触发器有些模糊。

这是杂散触发器吗?  是否有解决方法?  还有人注意到这个问题吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我们将对此进行研究。 反馈将发布在此处。

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

    感谢您的耐心等待。

    您的 termios 设置是什么? 驱动程序可能注入 NULL 字符来指示中断条件、或奇偶校验或帧错误[1]。

    为了更好地确定您是否遇到了这些条件之一、我的理解是您可以将 termios c_iflag 设置为以下值:

    CONFIG.c_iflag &=~(IGNBRK | BRKINT | IGNPAR | istrip);
    CONFIG.c_iflag ||(PARMRK | INPCK);

    您会看到额外的字符来指示通信错误、而不是单个 NULL 字符、然后可以在代码中采取适当的操作。

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

    您好、Michael、

    我的 termios iflag 设置为:(IGNPAR | IGNBRK)。  我通过这种方式设置它、以获得"原始" 8位输入、并避免插入"标记"。 但我将使用您建议的设置尝试相同的测试。

    据我所知、线路上不会发生通信错误、因为我接收到流中插入了额外的0x00s 集的所有数据。

    我还使用一个修改后的驱动程序进行了测试、该驱动程序在端口关闭时报告统计信息(Rx、溢出、奇偶校验、组帧等)、这些信息表明测试期间未发生通信错误。

    以下是具有上述建议设置的捕获的六转储:

    00000000 36 37 38 39 41 42 43 44 45 46 30 31 32 33 34 35 |6789ABCDEF012345|
    *
    00000110 36 37 38 39 41 42 00 43 00 00 00 00 00 00 00 00 00 00 |6789AB.C. |
    00000120 44 45 46 30 31 32 33 34 35 36 37 38 39 41 42 43 | DEF0123456789ABC|
    *
    00000800
    

    您可以看到、没有0xFF 标记指示通信错误、所有数据都存在、并且在流中插入了额外的0x00。

    我将尝试使用循环 DMA 传输的驱动程序版本(基于 John Ogness 提供的补丁 :http://lkml.iu.edu/hypermail/linux/kernel/1601.2/04139.html)

    Patrick

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

    我尝试使用上面提到的循环 DMA 传输、但该驱动程序遇到了相同的额外0x00。  当线路空闲时间足够长、足以在更多数据到达之前触发 RX_TIMEOUT 中断时、就会出现这种情况。

    为了解决该问题、我使用了 Fsl_lpuart 代码作为指南、并执行了以下操作:

    • 将 DMA 突发大小和 FIFO 触发电平减少为1 (以避免由于 FIFO 中的"过时"数据而导致 RX_TIMEOUT)
    • 在配置的波特率下、将 DMA 长度设置为大约10ms 的数据值。
    • DMA 完成中断将数据翻转为 TTY 级别
    • 添加了 Linux 定时器中断、以便在20ms 后将数据翻转为 TTY 级别(粒度为10ms)。
    • 发生 DMA 中断时重新启动计时器。

    借助上述功能、我能够以3MBaud 的速率将数据从一个端口流式传输到另一个端口、而不会丢失数据、或在吞吐量约为284kB/s 时额外增加0x00s

    我仍然找不到一种将 DMA 与 RX_TIMEOUT 中断正确配合使用的方法。  有什么建议吗?

    Patrick

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Patrick、
    我们最近添加了通报27
    www.ti.com/.../sprz408c.pdf

    我想知道您是否达到了此勘误表。

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

    您好、Mukul、

    我在调查的早期就考虑了该勘误表。  我验证了库存驱动程序已经检查并确认了这些虚假中断。  当一个实际的 RX_TIMEOUT 中断发生时、这个问题出现。

    我能够避免这个问题的唯一方法是使用一个值为1的 FIFO 阈值、这样就不会发生 RX_TIMEOUT 中断。

    Patrick

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

    与内部其他工程师讨论时、这个问题最近出现、并且正在进行调试。

    UART 实例1-3实际实现为 USART、而 UART 实例0、4和5为标准 UART。 此时、此问题似乎与 USART 实例隔离。 您是否能够使用其中一个 UART 实例进行测试?

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

    尊敬的 Mike:

    我修改了器件树文件以在 UART 4上启用 DMA、并 再次运行测试(3Mbs)、从 UART2到 UART4。  我没有在这个方向上看到额外的0x00、所以结果支持你的 USART 与 UART 假设。

    接收时确实出现溢出错误、但这是可以预料的、因为该驱动程序必须每48字节发出一个新的 DMA 传输、并且在此数据速率下对延迟的容限很小。

    这些测试使用从 TI git repo (Linux 版本4.9.59-05832-g153e6c41224f)构建的库存驱动程序。

    Patrick

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

    Patrick、

    感谢您分享您的测试结果!

    此致、
    Mike