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.

[参考译文] AM3351:RS485杂散接收数据问题和测试用例

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1502194/am3351-rs485-spurious-receive-data-problem-and-test-case

器件型号:AM3351

工具/软件:

我们正在使用 Linux SDK 9内核和工具链(ti-processor-sdk-linux-am335x-09.01.00.001、arm-noe-linux-gnueabihf-gcc 版本11.3.1 20220712、Linux 版本6.1.46-00001-g50c29ae5)观察 AM3351 (Linux 下配置为 RS485的 ttyS1)上 UART1接收缓冲区中的虚假数据。  在没有任何附加到端口的情况下(因此没有外部外围设备发回意外数据)、如果我们向 ttyS1发出 write()s、偶尔一次轮询/选择将返回 ready 而不是 timeout、并且 read()将成功、返回看似未初始化的数据。  我们按照严格的要求验证了我们的程序确实正在发出正在返回数据的读取 Sysall。  通过使用连接到 RS485收发器芯片 RX 线和示波器的 Flybuck 导线、我们已经确认没有任何数据从外部进入。  我们与"lsof"确认没有其他用户空间进程打开 ttyS1。
 我们已将测试用例简化为一个自包含文件(已附加)。  编译指令:"arm-linux-gnueabihf-gcc uart_test.c -o uart_test -wall -Wextra"。  3-30秒后、它会生成如下输出:
读取/写入尝试249:
读/写尝试250:
读/写尝试251:
读回10:7B 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b
预期行为:它应该无限期运行,而不报告从 read()返回的任何数据。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Thomas:

    您能否使用 Linux 串行测试(https://github.com/cbrake/linux-serial-test)来测试 UART 端口、看看是否仍然出现读取问题?

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

    尊敬的 Bin:

    (我与 Tom 合作、让董事会有问题。)  我运行了 linux-serial-test、如果我设置了较小的 TX 大小并添加了写入延迟、则会得到虚假读取、具体而言、linux-serial-test 似乎挂起(^C 可以取消它)。  通过 strace、它从读取中获得一个正向返回、然后旋转、调用 Read 并尽可能快地获取 EAGAIN。  输出:

    root@clairvoyant-E00016:~# ./linux-serial-test -p /dev/ttyS1 -w 10 -a 100
    Linux serial test app
    RS485 already enabled on port, ignoring delays if set
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    /dev/ttyS1: No data received for 6.0s.
    /dev/ttyS1: No data received for 7.0s.
    /dev/ttyS1: No data received for 8.0s.
    /dev/ttyS1: No data received for 9.0s.
    /dev/ttyS1: No data received for 10.0s.
    /dev/ttyS1: No data received for 11.0s.
    /dev/ttyS1: No data received for 12.0s.

    和转换时间附近的 strace 输出:

    poll([{fd=3, events=POLLIN|POLLOUT|POLLNVAL|POLLRDNORM|POLLMSG|POLLRDHUP|0x4000}], 1, 1000) = 1 ([{fd=3, revents=POLLOUT}])
    clock_gettime64(CLOCK_MONOTONIC, {tv_sec=36629, tv_nsec=900483111}) = 0
    poll([{fd=3, events=POLLIN|POLLOUT|POLLNVAL|POLLRDNORM|POLLMSG|POLLRDHUP|0x4000}], 1, 1000) = 1 ([{fd=3, revents=POLLOUT}])
    clock_gettime64(CLOCK_MONOTONIC, {tv_sec=36629, tv_nsec=901780314}) = 0
    write(3, "\350\351\352\353\354\355\356\357\360\361", 10) = 10
    poll([{fd=3, events=POLLIN|POLLOUT|POLLNVAL|POLLRDNORM|POLLMSG|POLLRDHUP|0x4000}], 1, 1000) = 1 ([{fd=3, revents=POLLOUT}])
    clock_gettime64(CLOCK_MONOTONIC, {tv_sec=36629, tv_nsec=903770472}) = 0
    poll([{fd=3, events=POLLIN|POLLOUT|POLLNVAL|POLLRDNORM|POLLMSG|POLLRDHUP|0x4000}], 1, 1000) = 1 ([{fd=3, revents=POLLIN|POLLOUT|POLLRDNORM}])
    clock_gettime64(CLOCK_MONOTONIC, {tv_sec=36629, tv_nsec=904943217}) = 0
    read(3, "llllllllllllllllllllllllllllllll"..., 1024) = 48
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)
    read(3, 0xbebd570c, 1024)               = -1 EAGAIN (Resource temporarily unavailable)

    发生这种情况时、没有来自 dmesg 或 journalctl 的输出。

    运行 linux-serial-test 时、除了端口之外没有其他参数、并添加短写入但不添加延迟、反之亦然、似乎可以按预期工作、至少要持续几分钟。

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

    尊敬的 Owen:

    在这个 Linux 串行测试中、您如何知道发生了虚假读取? 通过以下 strace log?

    读取(3、"llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

    如何在硬件中配置 AM335x UART1端口? 已连接 RS485收发器、但没有与此收发器连接?

    如何在内核器件树中配置此 UART 端口?

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

    尊敬的 Bin:

    对所有点都是正确的。 使用 linux-serial-test、我依靠 strace 来显示读取、因为它在 EAGAIN 循环中被"卡住"。  为了进一步验证,我刚刚修补了 linux-serial-test.c 以跳过在 EAGAIN 上的继续,我得到了这个:

    root@clairvoyant-E00016:~# ./linux-serial-test-noeagin -p /dev/ttyS1 -w 10 -a 100 -R
    Linux serial test app
    RS485 already enabled on port, ignoring delays if set
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    Read 48 bytes
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    /dev/ttyS1: No data received for 6.0s.
    /dev/ttyS1: No data received for 7.0s.
    /dev/ttyS1: No data received for 8.0s.
    /dev/ttyS1: No data received for 9.0s.
    /dev/ttyS1: No data received for 10.0s.
    /dev/ttyS1: No data received for 11.0s.
    /dev/ttyS1: No data received for 12.0s.
    Read 48 bytes
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.

    同样正确的连接:我们已将 UART1连接到 TI ISO1420隔离式 RS485收发器、没有任何连接到收发器。  原理图如下:

    对于设备树、UART1定义为:

    &uart1 {
    	status = "okay";
    	pinctrl-names = "default";
    	pinctrl-0 = <&uart1_pins>;
    	rts-gpios=<&gpio2 5 GPIO_ACTIVE_HIGH>;
    	dtr-gpios=<&gpio2 3 GPIO_ACTIVE_LOW>;
    	rs485-rts-active-high;
    	rs485-rts-delay = <0 0>;
    	linux,rs485-enabled-at-boot-time;
    };
    

    其中参考了 uart1引脚:

    &am33xx_pinmux {
    	uart1_pins: pinmux_uart1_pins {
    		pinctrl-single,pins = <
    				AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0) /* (D18) uart1_rxd.uart1_rxd */
    				AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0) /* (C19) uart1_txd.uart1_txd */
    				AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE7)	/* rs485_rxe (W9) gpmc_oen_ren.gpio2[3] */
    				AM33XX_IOPAD(0x89C, PIN_OUTPUT | MUX_MODE7)	/* rs485_txe (V8) gpmc_be0n_cle.gpio2[5]) */
    		>;
    	};
    
    	uart2_pins: pinmux_uart2_pins {
    		pinctrl-single,pins = <
    				AM33XX_IOPAD(0x92c, PIN_INPUT | MUX_MODE1) /* (N19) gmii1_txclk.uart2_rxd */
    				AM33XX_IOPAD(0x930, PIN_OUTPUT | MUX_MODE1) /* (M19) gmii1_rxclk.uart2_txd */
    		>;
    	};
    };
    

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

    此外、我还应该补充一点、RS485收发器连接了一个示波器、当发生虚假读取时、它绝不会在 RX 线上触发;RX 保持高电平。  (我已经确认、如果我连接 USB-RS485适配器并合法发送数据、确实会触发、因此我可以确信 Flybuck 和触发设置正确。)

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

    尊敬的 Owen:

    如果您在器件树中删除了与 RS485相关的设置并删除 UART1_RX 线路上的 R2300、48bytes 读取是否仍然发生? 我想看看问题是否与 RS485有关。

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

    尊敬的 Bin:

    我们移除了器件树中的电阻器和 RS485部分、不再看到48字节读取。  我们在重新启动后立即运行的第一次运行时看到了1字节读取、但在重新启动后没有看到。  linux-serial-test 的输出:

    root@clairvoyant-E0000B:~# ./linux-serial-test -p /dev/ttyS1 -w 10 -a 100 -R
    Linux serial test app
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    /dev/ttyS1: No data received for 6.0s.
    /dev/ttyS1: No data received for 7.0s.
    /dev/ttyS1: No data received for 8.0s.
    /dev/ttyS1: No data received for 9.0s.
    <...trimmed...>
    /dev/ttyS1: No data received for 1152.2s.
    /dev/ttyS1: No data received for 1153.2s.
    /dev/ttyS1: No data received for 1154.2s.
    ^CTerminating ...
    /dev/ttyS1: count for this session: rx=0, tx=114320, rx err=0
    /dev/ttyS1: TIOCGICOUNT: ret=0, rx=1, tx=196320, frame = 0, overrun = 0, parity = 0, brk = 1, buf_overrun = 0
    Exit handler: Cleaning up ...

    在我看来、这必须与 RS485功能相关、并在软件中的某个位置、因为收发器的 RX 线上没有活动。

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

    抱歉、我打算在最后一个帖子中包含修改后的设备树。 非 RS485 UART1看起来像:

    &am33xx_pinmux {
    	uart1_pins: pinmux_uart1_pins {
    		pinctrl-single,pins = <
    				AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE7)	/* rs485_rxe (W9) gpmc_oen_ren.gpio2[3] */
    				AM33XX_IOPAD(0x89C, PIN_OUTPUT | MUX_MODE7)	/* rs485_txe (V8) gpmc_be0n_cle.gpio2[5]) */
    		>;
    	};
    
    	uart2_pins: pinmux_uart2_pins {
    		pinctrl-single,pins = <
    				AM33XX_IOPAD(0x92c, PIN_INPUT | MUX_MODE1) /* (N19) gmii1_txclk.uart2_rxd */
    				AM33XX_IOPAD(0x930, PIN_OUTPUT | MUX_MODE1) /* (M19) gmii1_rxclk.uart2_txd */
    		>;
    	};
    };
    
    &uart1 {
    	status = "okay";
    	pinctrl-names = "default";
    	pinctrl-0 = <&uart1_pins>;
    };
    

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

    尊敬的 Owen:

    感谢您的测试。 现在我们知道 RS232不存在此类问题。 我们需要缩小导致问题的确切原因。

    您能否将所有软件更改恢复为与之前相同的状态、保持移除寄存器、然后查看 Linux 串行测试是否仍然显示问题?

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

    尊敬的 Bin:

    与之前一样、在电阻器仍移除但原始器件树后、它会生成虚假 RX 数据。  

    root@clairvoyant-E0000B:~# ./linux-serial-test-noeagin -p /dev/ttyS1 -w 10 -a 100 -R
    Linux serial test app
    RS485 already enabled on port, ignoring delays if set
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    /dev/ttyS1: No data received for 6.0s.
    /dev/ttyS1: No data received for 7.0s.
    /dev/ttyS1: No data received for 8.0s.
    /dev/ttyS1: No data received for 9.0s.
    /dev/ttyS1: No data received for 10.0s.
    /dev/ttyS1: No data received for 11.0s.
    /dev/ttyS1: No data received for 12.0s.
    /dev/ttyS1: No data received for 13.0s.
    /dev/ttyS1: No data received for 14.0s.
    /dev/ttyS1: No data received for 15.0s.
    /dev/ttyS1: No data received for 16.0s.
    /dev/ttyS1: No data received for 17.0s.
    /dev/ttyS1: No data received for 18.0s.
    /dev/ttyS1: No data received for 19.0s.
    /dev/ttyS1: No data received for 20.0s.
    /dev/ttyS1: No data received for 21.0s.
    /dev/ttyS1: No data received for 22.0s.
    Read 48 bytes
    /dev/ttyS1: No data received for 2.0s.
    /dev/ttyS1: No data received for 3.0s.
    /dev/ttyS1: No data received for 4.0s.
    /dev/ttyS1: No data received for 5.0s.
    /dev/ttyS1: No data received for 6.0s.
    /dev/ttyS1: No data received for 7.0s.
    /dev/ttyS1: No data received for 8.0s.
    /dev/ttyS1: No data received for 9.0s.
    /dev/ttyS1: No data received for 10.0s.
    Read 48 bytes
    

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

    好的、现在只需从器件树中删除"linux、RS485-enabled-at-boot-time;"、查看问题是否仍然发生。

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

    删除"linux、RS485-enabled-at-boot-time"行似乎可以消除问题。  我在 linux-serial-test 命令行中添加了"--RS485 1"参数以尝试确保它仍处于 RS485模式;它运行~10分钟而未接收到 RX 数据。  (我此时终止了它;问题似乎在前1到30秒内出现。)  移除电阻器后、整个电路板上仍然如此。

    我还尝试移除(一次移除一次) RS485-RTS 高电平有效和 RS485-RTS 延迟线路;这没有什么区别、它们仍然显示了虚假读取。

    所以这个问题似乎与 RS485支持启动时的参数有关;这似乎很令人惊讶、因为它添加了 SER_RS485_enabled 标志(我正在查看9.01.00.001 SDK 中的 serial_core.c 第3445行)、但证据很清楚。

    星期一、我将尝试删除 RS485 enabled-at-boot-time 参数、然后让我们的用户空间应用程序启用 RS485。

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

    感谢您的所有测试。

    因此问题似乎与启用了 RS485-at-boot-time 参数有关;

    在得出结论之前、我们还需要再进行几次测试。

    您能否在器件树中保留"RS485-enabled-at-boot-time"、但删除"dtr-GPIO"及其引脚多路复用? 我不确定内核 UART 驱动程序是否处理了收发器 RE 引脚的 DTR 引脚、我记得我在驱动程序中读取了任何相关代码。

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

    谢谢、这很好地提醒我们不要跳到结论上来。  感谢您与我一起解决这个问题!

    删除 dTR-GPIO 及其引脚多路复用(中保留的所有其他内容):仍会获取虚假数据。

    我还尝试删除(一次删除一次) RTS-GPIO (及其引脚多路复用)、pinctrl-0、pinctrl-name 和 status;也仍然会获取虚假数据。

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

    好的、现在似乎问题出在"RS485-enabled-at-boot-time"。

    您能否将其从器件树中删除、并在应用中启用 RS485 (与使用--RS485参数执行 linux-serial-test 的方式相同)来查看它是否解决了问题?

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

    我已从器件树中删除了这条线、如果我完全按照 Linux 串行测试的功能进行操作、那么这条线在我的测试应用中似乎能按预期工作(没有观察到虚假数据)。 添加了初始化代码:

    struct serial_rs485 rs485_settings = {0};
    rs485_settings.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX;
    int ioctl_result = ioctl(fd, TIOCSRS485, &rs485_settings);
    if (ioctl_result < 0) {
        perror("ioctl");
        return 2;
    }
    

    奇怪的是、这组确切的标志似乎是必需的;我最初尝试只是SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND(省略SER_RS485_RX_DURING_TX、因为我们不需要全双工)、但这确实会导致仍然存在虚假数据。

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

    其实、在多考虑之后、问题似乎是SER_RS485_RX_DURING_TX船旗的存在或缺失。 通过在设备树中使用 RS485-enabled-at-boot-time 参数、linux-serial-test 可检测到 RS485已启用且不会重新配置端口、因此从不设置 RX_Curd_tx 标志、因为我们在设备树中未指定该属性。

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

    感谢您缩小 SER_RS485_RX_DURING_TX 标志丢失的问题范围。

    如果您没有在应用程序中设置此标志、而是在内核器件树中添加"RS485-Rx-dur-TX"、您是否会看到相同的行为?

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

    我们可以实现:使用原始应用并将 RS485-Rx-dur-TX 添加到设备树后、我们不再看到杂散数据。

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

    好的、您可以将其用作解决方案。

    我将添加到备货订单中、以便了解为什么在没有 RS485-Rx-dur-TX 的情况下发生虚假 RX 数据、只是不确定在考虑到我拥有的工作负载的情况下何时会进行这些数据处理。

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

    谢谢! 对于我们的应用、我认为这可以满足我们的需求。

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

    感谢您与我一起完成所有调试工作。