NXPサポートチーム様
当社は i.MX LPUART ペリフェラルを RS-485 モードで使用しており、RTS 信号に影響するハードウェア レベルの問題を特定しました。私たちはその根本的な原因を理解し、利用可能な緩和策について話し合いたいと思っています。
--- ハードウェアコンテキスト ---
私たちの設計では、LPUART RTS ピンは RS-485 トランシーバの送信イネーブル (DE) 入力に直接接続されています。TXRTSE ハードウェア機能は、LPUART が送信している間のみ RTS/DE ラインが自動的にアサートされ、最後のストップ ビットの直後にアサート解除されるように使用され、ソフトウェア オーバーヘッドなしで適切な半二重 RS-485 バス方向制御が可能になります。
この直接的な電気的接続のため、ドライバーの初期化中であっても RTS ピンの誤ったアサーションにより RS-485 トランシーバーが有効になり、バスが駆動され、他のバス参加者からの進行中の通信が破損する可能性があります。
--- デバイスツリー構成 ---
以下は、i.MX93 上の影響を受ける LPUART インスタンスの DTS 構成です。RTS_B パッドは、ハードウェア LPUART RTS 機能に多重化され、RS-485 トランシーバーの DE ピンにルーティングされます。RE (レシーバ有効化、アクティブ ロー) は、rs485-rx-during-tx-gpios を使用して別の GPIO 経由で制御されます。
&lpuartX {
ステータス = "正常";
pinctrl-0 = <&pinctrl_lpuart_rs485_0>;
uart-has-rtscts;
linux、起動時に rs485 を有効化;
rs485-rx-during-tx-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
};
&lpuartY {
ステータス = "正常";
ピンコントロール-0 = <&ピンコントロール_lpuart_rs485_1>;
uart-has-rtscts;
linux、起動時に rs485 を有効化;
rs485-rx-during-tx-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
};
pinctrl_lpuart_rs485_0: lpuart_rs485_grp0 {
fsl、ピン = <
MX93_PAD_GPIO_IO05__LPUART6_RX 0x31e
MX93_PAD_GPIO_IO04__LPUART6_TX 0x31e
MX93_PAD_GPIO_IO07__LPUART6_RTS_B 0x31e
MX93_PAD_GPIO_IO06__GPIO2_IO06 0x31e
>;
};
pinctrl_lpuart_rs485_1: lpuart_rs485_grp1 {
fsl、ピン = <
MX93_PAD_GPIO_IO13__LPUART8_RX 0x31e
MX93_PAD_GPIO_IO12__LPUART8_TX 0x31e
MX93_PAD_GPIO_IO15__LPUART8_RTS_B 0x31e
MX93_PAD_GPIO_IO14__GPIO2_IO14 0x31e
>;
};
この設定では、Linux,rs485-enabled-at-boot-time により、ポートの起動時に RS-485 モード (および TXRTSE) がアクティブ化され、システムの起動時またはポートのオープン イベントごとにスプリアス RTS パルスが発生します。
--- 観察された行動 ---
UARTMODIR レジスタの TXRTSE ビット (トランスミッタ送信要求有効化) が設定され、UARTCTRL のトランスミッタ有効化ビット (TE) が 0 から 1 に遷移すると、その時点ではデータが送信されていないにもかかわらず、RTS/DE ラインには約 3 ミリ秒続くスプリアス パルスが表示されます。
この動作は、アップストリームのNXP Linuxカーネルドライバ(drivers/tty/serial/fsl_lpuart.c)で明確に確認できます。ここで、lpuart32_setup_watermark_enable() には次のコメントと回避策があります。
/*
* RS-485 がアクティブな場合、TE の有効化を start_tx まで延期します。
* TXRTSE が設定された TE 0->1 により、約 3 ミリ秒の RTS パルスが発生します (シリコンの癖)。
* TEを最初の実際の送信まで延期することで、RTS
* アサーションは、ネットワーク上の実際のデータと一致します。
*/
if (!sport->rs485_te_deferred)
ctrl |= UARTCTRL_TE;
回避策では、TE の有効化を start_tx() まで延期し、実際のデータが送信されているときにのみ RTS/DE アサーションが発生するようにします。
--- 根本原因 — 段階的なメカニズム ---
スプリアスパルスを生成する内部シーケンスについては次のように理解しています。
1. lpuart_config_rs485() が呼び出され、UARTMODIR で TXRTSE=1 が設定され、TE=0 のままになります。RTS は低いです。
2. ポートオープン中に lpuart32_setup_watermark_enable() が呼び出され、UARTCTRL に TE=1 が書き込まれます。この時点では TX FIFO は空です。
3. LPUART ハードウェアは、TXRTSE = 1 のときに TE 0 -> 1 遷移を検出します。
4. シリコンの癖: TX FIFO が空であるにもかかわらず、ハードウェアは送信が開始されたかのように直ちに RTS HIGH をアサートします。
5.約 3 ミリ秒後、ハードウェアは TC (送信完了) を認識し、送信するものがないと判断し、RTS LOW をアサート解除します。
タイミング図:
時間 ──────────────────────────────────────────────►
config_rs485 open() 約3ミリ秒後
│ │ │
▼ ▼ ▼
TXRTSE=1 TE: 0→1 TC 認識
TE=0 TXRTSE=1
FIFO が空です!
│ │
RTS: ─── 低 ─────────┤ 高 ├──────────┤── 低 ───
│←─ 約3ミリ秒 ──→│
RTS 上のこの誤った HIGH パルスは、RS-485 トランシーバの DE 入力を約 3 ms 間直接有効にし、有効なデータなしでバスを駆動します。
--- 信号キャプチャ ---
RTS (DE) 信号と TXD 信号は、ロジック アナライザーを使用して RS-485 トランシーバ入力でキャプチャされました。2 つのテスト シナリオが表示されます。
--- キャプチャ 1 --- UART を開いてすぐに送信 ---
テスト アプリケーションは UART ポートを開き、遅延なくすぐに「Hello World」を書き込みます。
fd = open("/dev/ttyLPx", O_RDWR);
書き込み(fd, "Hello World", 11);
TE 0->1でスプリアスRTSパルスは依然として発生しますが、実際の送信はTE 0->1で発生するため、
マイクロ秒単位で、奇妙なパルスと正当な RTS アサーションが 1 つの連続したパルスに結合されます。
最初の部分の偽りの性質はキャプチャでは確認できません。
--- キャプチャ 2 --- UART を開き、約 3 ミリ秒以上待ってから送信します ---
テストアプリケーションはUARTポートを開き、Quirk期間(約3ミリ秒)よりも長くスリープします。
そして、その後に「Hello World」と書き込みます。
fd = open("/dev/ttyLPx", O_RDWR);
usleep(3000); /* > ~3ms、スプリアスパルスの持続時間よりも長い */
書き込み(fd, "Hello World", 11);
遅延がクワーク持続時間を超えるため、スプリアスパルスはデータが完全に送信される前に完了します。
と書かれています。これにより、バグが明確に明らかになります。
- open() のとき: RTS は対応する TXD アクティビティなしで HIGH をアサートします (スプリアス パルス、約 3 ms)
- TC が認識されると RTS は LOW をアサート解除します (TX FIFO はずっと空でした)
- スリープ後: アプリケーションがデータを送信し、RTSが再びHIGHをアサートし、TXDが「Hello World」ペイロードを伝送します。
2つのRTSパルス間のギャップにより、最初のパルスが原因ではないことが明白になる。
いかなるデータ送信によっても。
--- 質問 ---
1. この動作は、影響を受ける i.MX SoC の公式エラッタまたはテクニカル ノートに記載されていますか?もしそうなら、ドキュメント参照と影響を受けるデバイスのリストを提供していただけますか?
2. 影響を受ける i.MX SoC バリアント (例: i.MX7ULP、i.MX8ULP、i.MX8QXP、i.MX93、その他) はどれですか?
3. どのシリコン リビジョンでもハードウェア レベルの修正は利用可能でしょうか。それともソフトウェアによる回避策 (TE の延期) が唯一推奨される緩和策でしょうか。
4. 約 3 ミリ秒の持続時間はデターミニスティックですか (IDLECFG 設定またはボー レートに結びついています)、それともシリコン サンプル/リビジョンによって異なりますか?
5. 特に RS-485 モードでポートが繰り返し開閉される場合、遅延 TE 回避策で注意すべき副作用はありますか?
- - 環境 - -
- SoC: i.MX93
- カーネル: Linux (NXP ダウンストリームフォーク、lf-6.12.49-2.2.0 ベース)
- ドライバ: fsl_lpuart.c
- モード: RS-485、TXRTSE 有効、RTS_B パッドを RS-485 トランシーバ DE 入力に接続
ご協力ありがとうございます。
こんにちは、 @tapio_reijonen さん。
使用しているBSPのバージョンは何ですか?
それらのコメントが表示されているコードの具体的な箇所を教えていただけますか?
サードパーティ製の改造ドライバを使用しているかどうかは分かりませんが、UART IPには既知のバグがいくつかありますが、それらは既に公式のBSPリリースでソフトウェア的に修正されています。
弊社の公式Linuxディストリビューションをお試しください。
https://github.com/nxp-imx/linux-imx/blob/lf-6.12.y/drivers/tty/serial/fsl_lpuart.c
引き続きサポートを提供するため、追加情報をお寄せください。
よろしくお願いします、
チャビラ
こんにちは、 @Chaviraさん
BSPバージョン: NXP公式BSP lf-6.12.y(Linux 6.12.49、リリースlf-6.12.49-2.2.0)。
ドライバ: NXP 公式リポジトリhttps://github.com/nxp-imx/linux-imx/blob/lf-6.12.y/drivers/tty/serial/fsl_lpuart.cから変更されていない drivers/tty/serial/fsl_lpuart.c 。
この問題は、変更を加えていない公式のNXP BSPでも再現可能です。i.MX93で標準ドライバをRS-485モード(linux、rs485-enabled-at-boot-time、uart-has-rtscts、TXRTSE enabled)で使用すると、シリアルポートを開くと約3msの不要なRTSパルスが発生します。TE 0→1遷移は、TXRTSEが設定されている間、送信機プリアンブルをトリガーし、RS-485バス上でRTS/DEをアサートしますが、データは送信されません。
こんにちは、 @tapio_reijonen さん。
返信が遅くなり申し訳ありません。
私の方でも同様の現象を再現できたので、以下の結論に至りました。
この問題の根本原因は、LPUART IPの内部ステートマシンのシリコンレベルでの設計にある。RS-485モードを設定する際、UARTMODIRレジスタのTXRTSEビットを設定することで、RTSピンの物理的な制御をハードウェアに直接委ねることができます。その瞬間から、シリコンはUARTCTRLレジスタのTE(トランスミッタ・イネーブル)ビットの0から1への遷移に無条件で反応するようにハードワイヤリングされる。この遷移により、論理ゲートが作動し、RTSピンが即座にHIGHになり、Linuxカーネルからの制御がバイパスされます。
トランスミッタを有効にすると、ハードウェアは送信が間近であると判断し、プリアンブルを送信しようとしますが、送信バッファ(TX FIFO)が空であることが判明します。ステートマシンは既にRTS信号を発信しているため、データのシリアル化を待機している間、停止状態になります。処理すべきバイトがないため、ハードウェアが非アクティブ状態を理由に「送信完了」(TC)状態を独自に認識するまでに約3ミリ秒が経過し、その時点でようやくRTS信号をLOW状態に戻します。
公式のfsl_lpuart.cに含まれる回避策ドライバはこの電気的挙動を完全に排除するのではなく、単に時系列的に隠蔽するだけです。カーネルの戦略は、ポートの初期化(open())中はTEビットを無効にし、write()関数が呼び出され、start_tx()が実行されるまで、そのビットを1に遷移させることです。しかし、TXピンからデータを出力するには、TEビットを必ず1に設定する必要があります。この場合、ハードウェアは最初に発生した誤ったパルスを再び注入します。しかし、その直後に実際のデータペイロードが続くため、不規則なパルスは正当なRTSアサーションとほとんど知覚できないほどに融合してしまう。
デバイスツリーで`uart-has-rtscts`が使用されている場合、「このプロパティが存在するということは、UARTに専用ラインがあることを示しています」。つまり、制御にはGPIOではなく、iMX93の専用ピンが使用されるということです。
`fsl_lpuart.c` が確認できます。関連する`serial_mctrl_gpio`コードが欠落しています。たとえLinuxレベルでGPIOを制御できたとしても、このシリアルポートモジュールの状態遷移とは一致しないだろう。そして、運転手を混乱させる可能性もある。
別のシリアルポートドライバ(`drivers/tty/serial/imx.c`)と比較すると、`serial_mctrl_gpio`というコードが見つかります。
uart-has-rtscts:
$ref: /schemas/types.yaml#/definitions/flag
description:
The presence of this property indicates that the UART has dedicated lines
for RTS/CTS hardware flow control, and that they are available for use
(wired and enabled by pinmux configuration). This depends on both the
UART hardware and the board wiring.https://github.com/nxp-imx/linux-imx/blob/lf-6.12.y/drivers/tty/serial/imx.c
#include "serial_mctrl_gpio.h"
struct imx_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status; unsigned int have_rtscts:1;
unsigned int have_rtsgpio:1;
unsigned int dte_mode:1;
unsigned int inverted_tx:1;
unsigned int inverted_rx:1;
struct clk *clk_ipg;
struct clk *clk_per;
const struct imx_uart_data *devdata;
struct mctrl_gpios *gpios;
/* counter to stop 0xff flood */
int idle_counter;