Armadilloフォーラム

Armadillo640にてD-Subシリアルポートの制御線が機能していない

tamatsu_tme

2018年10月2日 13時39分

松本と申します。

早速ですが、
下記の状況に関して、同様な状況が発生されている方や、解決法をご存知の方がおられましたら、ご教授いただけたらと思います。

【主題】
Armadiollo640でのCON3(D-Sub)において制御線(入力)の状態が取得できず、制御線(出力)の状態を制御できないので、フルハンドシェイクでの通信ができない。

【背景】
Armadillo440にで動作を確認しているDSub-9Pinシリアル通信をフルハンドシェイクで行う当方作成の通信ソフトウエア(以後 通信ソフトと呼ぶ)をArmadillo640に移植しているが、Armadillo640では表題の状況が生じている。
Armadillo640(440)の通信対向となる機器はArmadilloと同様のDTEであるので、いわゆるクロス接続となりDCD信号は与えられられておらず、通信ソフトはこれを無視をしている。
なお、シリアルの状態取得・制御にはtermios/ioctlを用いている。

【認知事項】
・通信ソフトはArmadillo440では正しく制御線(入力)の状態を取得でき、かつ制御線(出力)には意図する状態を出力でき、通信に支障はない。
・Armadillo640 CON3の制御線(出力)にはRS-232Cレベルの出力がある。
・Armadillo640では、CON3の制御線(入力)が任意の状態であってもソフトウエア的には”真”の状態だと誤認している。
・Armadillo640では、CON3の制御線(出力)を任意の状態にソフトウエア的に制御するも常に”偽”の状態と出力する。
・対向機器は、Armadillo640出力するRTSが常に”偽”状態であるので、データ送信を行わない。
・Armadillo640と対向機器の双方で一時的に全て制御線を無視する設定を用いるデータ線だけの通信とすれば、データの送受は可能になる。
(がしかし、制御線を用いないのは通信仕様違反となるので実用不可)
・Armadillo640製品マニュアル(Ver 1.1.0)のインターフェース仕様 14.4節では、例として「データ端末レディ、i.MX6ULL のGPIO1_IO00 ピンに接続、CON4 の7ピンと共通」のような記述がある。(仕様上は無配線ではない)
・Armadillo640を最新のカーネルに更新し、比較実験として、CON3に替りFTDI社チップのUSBシリアル変換器を用いてのシリアル通信を試すと、Armadillo440の時と同様に正常に制御線の状態を認識・制御して、フルハンドシェイクでの通信が行えた。
・「Armadillo-640:ser2net(シリアルポートをtelnet/TCPに接続するソフト)を動かす」(https://users.atmark-techno.com/blog/615/3187)を用いてCON3を用いると、CON3の制御線(出力)の状態が”偽”を維持したままであり対向装置で制御線を無視する設定にすれば、データが流せる。
一方、CON3に替りFTDI社チップのUSBシリアル変換器を用いると、制御線(出力)の状態が”真”に変化するなどして、データも流せる。
この挙動の差異は通信ソフトで観測する事象と同一である。

【考察】
・Armadillo440でOKでArmadillo640でも非CON3ではOKである故、通信ソフト~カーネル(システムコール)までの問題である可能性はほぼ無いと推定できる。
・さらにser2netでもまったく同じ状況が観測されるので、さらに可能性はゼロに近いと確信できる。
・Armadillo640製品マニュアルの14.4節の記述が誤り?
・Armadillo640製品マニュアルの14.4節の記述は正しいが、Armadillo640でのCON3のドライバー未対応であり、結果マニュアとは異なる未接続と同様な状況が観測される?
・Armadillo640製品マニュアルは正しいく、Armadillo640でのCON3のドライバーも対応しているが、構成が出荷状態では正しく構成されておらず、結果マニュアとは異なる未接続と同様な状況が観測される?
・マニュアル、ドライバーおよび構成は正しい。当方所有の当該Armadillo640の固有の問題(不良品?)
・DSub9pinであるCON3が使えずUSBシリアル変換が必要なのであれば、Armadillo640を製品化に際しで選定する理由がなくなる。
それを認めればさらに安価なBBBやRPiが逆に視野に入る。
(高価価格帯ではOBSA7もありかも)

コメント

y.nakamura

2018年10月3日 12時54分

中村です。

ざっとソースのDeviceTree(まだat5をDLしてないのでat4)を見たところでは、
CON3のUART3で設定があるのはTXとRXだけで、
CTS,RTS,DSR,DTR,CD,RIは何も書いてないような。。。

--
なかむら

at_ohsawa

2018年10月17日 16時03分

> Armadiollo640でのCON3(D-Sub)において制御線(入力)の状態が取得できず、制御線(出力)の状態を制御できないので、フルハンドシェイクでの通信ができない。

中村樣のレスにあるとおり、今のバージョンにはDeviceTreeに制御線を有効にする
設定を書いていません。linux-4.14-at5に対する差分が次のようになります。

(必ずat5以降で使ってください、at5以前だと一部のピン設定に対応する変数の定義がありません。)

この差分を適用したat5向けのdtsとdtb(dtsをコンパイルしたもの)を添付します。
この変更は今月のアップデートに取り込む予定です。

diff --git a/arch/arm/boot/dts/armadillo-640.dts b/arch/arm/boot/dts/armadillo-640.dts
index 0f0983cf075e..0fafd14673a3 100644
--- a/arch/arm/boot/dts/armadillo-640.dts
+++ b/arch/arm/boot/dts/armadillo-640.dts
@@ -104,8 +104,13 @@
 &uart3 {
     pinctrl-names = "default";
     pinctrl-0 = <&pinctrl_uart3>;
     status = "okay";
+    uart-has-rtscts;
+    dtr-gpios = <&gpio1 00 GPIO_ACTIVE_LOW>;
+    dsr-gpios = <&gpio5 00 GPIO_ACTIVE_LOW>;
+    dcd-gpios = <&gpio5 02 GPIO_ACTIVE_LOW>;
+    rng-gpios = <&gpio5 01 GPIO_ACTIVE_LOW>;
 };
 
 &uart5 {
     pinctrl-names = "default";
@@ -148,8 +153,14 @@
     pinctrl_uart3: uart3grp {
         fsl,pins = <
             MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x00008
             MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1
+            MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS 0x1b0b1
+            MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS 0x00008
+            MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x00008 /*DTR*/
+            MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x1b0b1/*DSR*/
+            MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b1/*DCD*/
+            MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x1b0b1/*RI*/
         >;
     };
 
     pinctrl_uart5: uart5grp {
ファイル ファイルの説明
armadillo-640.dtb コンパイル済みdevicetree blob
armadillo-640.dts uart3制御線有効化devicetree

tamatsu_tme

2018年10月23日 12時25分

松本です。

> 中村樣のレスにあるとおり、今のバージョンにはDeviceTreeに制御線を有効にする
> 設定を書いていません。linux-4.14-at5に対する差分が次のようになります。
>
> (必ずat5以降で使ってください、at5以前だと一部のピン設定に対応する変数の定義がありません。)
>

ご提示いただいたパッチを適用してみました。
1つの差異を除き「制御線(入力)の状態が取得できず、制御線(出力)の状態を制御できない」状況は改善しました。

(差異)
TERMIOSのtermios構造体のtcflag_t c_cflagにてCRTSCTSを(tcsetattr()で)セットしないとRTS出力が”偽”の状態に固定されてしまうようです。
Armadillo440のCON3(DSub)やArmadillo640に接続したUSBシリアルコンバーターではこのような事象は発生せず、CRTSCTSをセットしなくてもRTSは”真”の状態になる。

この結果RTS/CTSによるフローコントロールが強制されてしまいます。
これが仕様であれば仕方ないですが、あまり見かけないケースだと思います。

y.nakamura

2018年10月23日 14時00分

中村です。

> TERMIOSのtermios構造体のtcflag_t c_cflagにてCRTSCTSを(tcsetattr()で)セットしないとRTS出力が”偽”の状態に固定されてしまうようです。
> Armadillo440のCON3(DSub)やArmadillo640に接続したUSBシリアルコンバーターではこのような事象は発生せず、CRTSCTSをセットしなくてもRTSは”真”の状態になる。
>
> この結果RTS/CTSによるフローコントロールが強制されてしまいます。
> これが仕様であれば仕方ないですが、あまり見かけないケースだと思います。

これを仕様とするのは、使う側としてはちょっとつらいですね。
ソースを見てませんが、たぶん、CRTSCTSがセットされていないときに
RTSを真にする(activeのlowにする)という処理が抜けているのでしょう。

とりあえず
ioctl(fd, TIOCMBIS, TIOCM_RTS);
で逃げる、とかですかね。

--
なかむら

y.nakamura

2018年10月23日 14時20分

中村です。

すみません。訂正です。

> ioctl(fd, TIOCMBIS, TIOCM_RTS);

は、

int modem = TIOCM_RTS;
ioctl(fd, TIOCMBIS, &modem);

でした。

--
なかむら

y.nakamura

2018年10月23日 22時34分

中村です。

> ソースを見てませんが、たぶん、CRTSCTSがセットされていないときに
> RTSを真にする(activeのlowにする)という処理が抜けているのでしょう。

気になったので、ソースを見てみました。
どちらもimx_set_termios()の中です。

Armadillo-440のinux-3.14-at11/drivers/tty/serial/imx.c

        if (termios->c_cflag & CRTSCTS) {
                ...
        } else {
                if (port->rs485.flags & SER_RS485_ENABLED) {
                        /* disable transmitter */
                        if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
                                ucr2 |= UCR2_CTS;
                } else {
                        ucr2 |= UCR2_CTS;
                }
        }

// UCR2_CTSがRS-232CのRTS信号になります

Armadillo-640のlinux-v4.14-at6/drivers/tty/serial/imx.c

        if (termios->c_cflag & CRTSCTS) {
                ...
        } else if (port->rs485.flags & SER_RS485_ENABLED) {
                /* disable transmitter */
                if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
                        imx_port_rts_active(sport, &ucr2);
                else
                        imx_port_rts_inactive(sport, &ucr2);
        }

--
なかむら

y.nakamura

2018年10月23日 23時41分

中村です。

> > ソースを見てませんが、たぶん、CRTSCTSがセットされていないときに
> > RTSを真にする(activeのlowにする)という処理が抜けているのでしょう。

と書きました。

で、ソースを調べたところ、
> Armadillo-440のinux-3.14-at11/drivers/tty/serial/imx.c
>

>         if (termios->c_cflag & CRTSCTS) {
>                 ...
>         } else {
>                 if (port->rs485.flags & SER_RS485_ENABLED) {
>                         /* disable transmitter */
>                         if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
>                                 ucr2 |= UCR2_CTS;
>                 } else {
>                         ucr2 |= UCR2_CTS;
>                 }
>         }
> 

> // UCR2_CTSがRS-232CのRTS信号になります

となっていました。

ですが、他のバージョンなどをいろいろ見てみたところ、
Armadillo-640のように、
「CRTSCTSがセットされていないときにはRTSは何もしない」
というのが正解(仕様?)なのかもしれません。

オープンしたときにRTSとDTRを上げる(アクティブにする)
というコードがserial_coreにあるようです。
これに頼るか、2つくらい前の投稿に書いたように、
ioctl()のTIOCMBISで、自分でRTSをアクティブにするのが正しい
のかも、です。

--
なかむら

at_mizo

2018年11月7日 9時42分

溝渕です。

> ・対向機器は、Armadillo640出力するRTSが常に”偽”状態であるので、データ送信を行わない。

ハードウェアフロー無効時に、RTSを”真”状態にするパッチを作成してみま
した。お手数ですがご確認いただけますか。

ファイル ファイルの説明
linux-v4.14-at_rts-active.patch

tamatsu_tme

2018年11月24日 13時36分

> 溝渕です。
>
> > ・対向機器は、Armadillo640出力するRTSが常に”偽”状態であるので、データ送信を行わない。
>
> ハードウェアフロー無効時に、RTSを”真”状態にするパッチを作成してみま
> した。お手数ですがご確認いただけますか。
>

CRTSCTSを0とした後にioctl()のTIOCMBIS/TIOCMBICをするかよって改善するケースとないケースがありました。
具体的にはioctl()でTIOCM_DTRをTIOCMBICしないと駄目でした。(ほかにもあるかもしれませんが確認したのはこれだけ)

ざくっとコードの眺めたところ、imx_set_termios()の中からimx_port_rts_xxxxでcsr2”変数”のCTSCとCTSを操作していますが、その結果のそれらのビットは実際のH/WのCSR2レジスタに的確に反映されていない(1→0が伝わっていない?)ような気がします。

y.nakamura

2018年11月24日 17時50分

中村です。

> ざくっとコードの眺めたところ、imx_set_termios()の中からimx_port_rts_xxxxでcsr2”変数”のCTSCとCTSを操作していますが、その結果のそれらのビットは実際のH/WのCSR2レジスタに的確に反映されていない(1→0が伝わっていない?)ような気がします。

ucr2のことですよね? 変数"csr2"ではなくて。
"CSR2レジスタ"は、UCR2レジスタ。

imx_port_rts_xxxx()で引数で渡したucr2変数を変更した後、
そのあとの方でUCR2の他のビット設定し、
最後にimx_set_termios()の出口付近で
writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
してます。

そりよりも、もっと気になる部分を見つけました。

static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
{
        *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
 
        sport->port.mctrl |= TIOCM_RTS;
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
 
static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
{
        *ucr2 &= ~UCR2_CTSC;
        *ucr2 |= UCR2_CTS;
 
        sport->port.mctrl &= ~TIOCM_RTS;
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}

activeとinactiveとでUCR2_CTSのset/clearが逆になってます。
imxのリファレンスマニュアルをみると、
0 The CTS_B pin is high (inactive)
1 The CTS_B pin is low (active)
です。

G3系Armadilloのlinux-4.9-x1-at3のimx.cでは次のようになっています。

static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
{
        *ucr2 &= ~UCR2_CTSC;
        *ucr2 |= UCR2_CTS;
 
        sport->port.mctrl &= ~TIOCM_RTS;
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
 
static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
{
        *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
 
        sport->port.mctrl |= TIOCM_RTS;
        mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}

Armadillo-640で使っている4.14のこの部分がバグっているとは考えにくいので、
この部分が修正された経緯を調べました。
これ(↓)のようです。
[serial: imx: Fix the CTS_B polarity in RS485 mode]
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…

説明文を引用しておきます。

When userspace passes the SER_RS485_RTS_ON_SEND flag it means that the
CTS_B pin should go to logic level high before the transmission begins.

CTS_B goes to logic level high when both CTSC and CTS bits are cleared.

When userspace passes the SER_RS485_RTS_AFTER_SEND flag it means that the
CTS_B pin should go to logic level low after the transmission finishes.

CTS_B goes to logic level low when CTSC bit is cleared and CTS bit is set.
So fix the CTS_B polarity logic.

つまり、imx_port_rts_active()とimx_port_rts_inactive()は、
RS-485モードのときに(のみ)使用することを想定しているようで、
imx.c全体を通してimx_port_rts_active()とimx_port_rts_inactive()が
コールされているところを探すと、
port->rs485.flags & SER_RS485_RTS_AFTER_SEND
なときだけでした。(at_mizoさんのパッチ以外)

なので、2018/11/07のat_mizoさんのパッチはではダメなようです。

--
なかむら

y.nakamura

2018年11月24日 20時45分

中村です。

ソースのコピペミスの訂正です。

> imx.c全体を通してimx_port_rts_active()とimx_port_rts_inactive()が
> コールされているところを探すと、
> port->rs485.flags & SER_RS485_RTS_AFTER_SEND
> なときだけでした。(at_mizoさんのパッチ以外)

誤:
port->rs485.flags & SER_RS485_RTS_AFTER_SEND
正:
port->rs485.flags & SER_RS485_ENABLED
です。

port->rs485.flags は rs485conf->flags のときもあります。

--
なかむら

y.nakamura

2018年11月24日 22時24分

中村です。

RS-485の話なので、このスレッドの質問とは関係はないのですが、
先ほどの
> この部分が修正された経緯を調べました。
> これ(↓)のようです。
> [serial: imx: Fix the CTS_B polarity in RS485 mode]
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…
>
> 説明文を引用しておきます。
>
> When userspace passes the SER_RS485_RTS_ON_SEND flag it means that the
> CTS_B pin should go to logic level high before the transmission begins.
>
> CTS_B goes to logic level high when both CTSC and CTS bits are cleared.
>
> When userspace passes the SER_RS485_RTS_AFTER_SEND flag it means that the
> CTS_B pin should go to logic level low after the transmission finishes.
>
> CTS_B goes to logic level low when CTSC bit is cleared and CTS bit is set.
> So fix the CTS_B polarity logic.

の説明が何かおかしいような気がして、調べてみました。

> When userspace passes the SER_RS485_RTS_AFTER_SEND flag it means that the
> CTS_B pin should go to logic level low after the transmission finishes.
は、間違っているようです。

Documentation/serial/serial-rs485.txtのその部分:
| /* Set logical level for RTS pin equal to 1 when sending: */
| rs485conf.flags |= SER_RS485_RTS_ON_SEND;
| /* or, set logical level for RTS pin equal to 0 when sending: */
| rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
|
| /* Set logical level for RTS pin equal to 1 after sending: */
| rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
| /* or, set logical level for RTS pin equal to 0 after sending: */
| rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);

で、"RTS pin equal to 1" (パッチの説明での"logic level high")といのが、
imx_port_rts_active()となるような実装に修正されたのが、
このパッチのようです。

2つ前の投稿に書いたようにG3系Armadilloのkernel-4.9での実装は
このパッチがあたる前のものなので、imx_port_rts_active()と
imx_port_rts_inactive()をコールする側が逆になってました。
たとえば、imx_start_tx()の中で、A-640の4.14では、

        if (port->rs485.flags & SER_RS485_ENABLED) {
                temp = readl(port->membase + UCR2);
                if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
                        imx_port_rts_active(sport, &temp);
                else
                        imx_port_rts_inactive(sport, &temp);

となっているころがG3の4.9では

       if (port->rs485.flags & SER_RS485_ENABLED) {
                temp = readl(port->membase + UCR2);
                if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
                        imx_port_rts_inactive(sport, &temp);
                else
                        imx_port_rts_active(sport, &temp);

となっています。

このactive()とinactive()が逆になったのは、
[serial: imx: Fix the CTS_B polarity in RS485 mode]
の1つ前に(同じ日に)コミットされている次(↓)の修正です。
[serial: imx: Fix the RTS GPIO polarity in RS485 mode]
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…

この修正は、GPIOのRTSを使ったときに、
Documentation/serial/serial-rs485.txtに書いてあるのと逆になってるので
inactiveとactiveの呼び出しを逆にするように直しました、
ということみたいです。
この修正で、GPIOのRTS方はOKになったけれどもimxのCTS_Bピンを
使う方が逆になってしまったので、その次のコミットでCTS_Bピンの方も
直しました、とのことのようです。

それから、GPIOのRTSのときの処理で、A-640のimx_port_rts_active()が
sport->port.mctrl |= TIOCM_RTS;
となっていて、これはカーネルソースのgitものと一致しているのですが、
G3系のlinux-4.9-x1-at3のimx_port_rts_active()が
sport->port.mctrl &= ~TIOCM_RTS;
となっていて、この部分が逆になっています。
カーネルのgitの履歴にこの修正は見当たりませんでした。
上に書いたロジック反転の問題に対して、アットマークテクノさん独自の
修正がされたものなのかな?と思っています。

--
なかむら

at_mizo

2018年11月26日 12時31分

溝渕です。

ご指摘いただき有難うございます。パッチを修正しました。

>

> static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
> {
>         *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
> 
>         sport->port.mctrl |= TIOCM_RTS;
>         mctrl_gpio_set(sport->gpios, sport->port.mctrl);
> }
> 
> static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
> {
>         *ucr2 &= ~UCR2_CTSC;
>         *ucr2 |= UCR2_CTS;
> 
>         sport->port.mctrl &= ~TIOCM_RTS;
>         mctrl_gpio_set(sport->gpios, sport->port.mctrl);
> }
> 

>
> activeとinactiveとでUCR2_CTSのset/clearが逆になってます。
> imxのリファレンスマニュアルをみると、
> 0 The CTS_B pin is high (inactive)
> 1 The CTS_B pin is low (active)
> です。

上記、確かにご指摘の通りで、

> [serial: imx: Fix the RTS GPIO polarity in RS485 mode]
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…

から、関数名"imx_port_rts_*"は、RS485のtransmitterを示しているように見えます。

しかし、このように読むと"imx_port_rts_auto()"は明かにRS232CのRTS制御を意図しており辻褄が合いません。

このことから、"imx_port_rts_[in]active()"はimxのリファレンスマニュアルの通りに実装された上で、

#define imx_rs485_transmitter_enable    imx_port_rts_inactive
#define imx_rs485_transmitter_disable    imx_port_rts_active

のように実装されていることで可読性が向上すると思いますが、そのようにはなってはいません。

以上より、修正パッチでは"imx_port_rts_*"をRS485モード専用とせずに実装しています。

> それから、GPIOのRTSのときの処理で、A-640のimx_port_rts_active()が
> sport->port.mctrl |= TIOCM_RTS;
> となっていて、これはカーネルソースのgitものと一致しているのですが、
> G3系のlinux-4.9-x1-at3のimx_port_rts_active()が
> sport->port.mctrl &= ~TIOCM_RTS;
> となっていて、この部分が逆になっています。
> カーネルのgitの履歴にこの修正は見当たりませんでした。
> 上に書いたロジック反転の問題に対して、アットマークテクノさん独自の
> 修正がされたものなのかな?と思っています。

ご推測の通りです。

RTS信号と、mctrlの論理は一致している必要があります。以下のcommitでは、
RTS信号の論理が修正されていますが、弊社ではmctrlの論理を修正しています。

> [serial: imx: Fix the CTS_B polarity in RS485 mode]
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…

あえてmainlineと別実装にした訳ではなく、mainlineを追い切れなかったのが
別実装となった原因と思います。

ファイル ファイルの説明
linux-v4.14-at_rts-active-v2.patch

y.nakamura

2018年11月26日 17時26分

中村です。

出先でスマホしかないので、手短になります。

CTSCのことは一昨日の投稿前に気づいて、
修正履歴も調べました。
使い方として謝りはあるのですけど、
今回はここは流しました。
rxfifoが空なら、意図したロジックレベルになります。

auto()関数の件がおかしいのも気づいてましたが、
これも履歴を見ると修正者の意図はわからずでもなく。

それから、修正者は、GPIOの時に
アクティブハイとアクティブローを
自由に設定できることを無視している
ような気がします。

A640ではRS485は関係ないですが、
メインラインを無視して綺麗にせいりするのが
いいのかもしれません。

--
なかむら

y.nakamura

2018年11月26日 21時13分

中村です。

> auto()関数の件がおかしいのも気づいてましたが、
> これも履歴を見ると修正者の意図はわからずでもなく。

まだソースみれないのですが、
これ、少し補足しておきます。

activeとinactiveはRS485でRTS制御が有効になっている時用、
autoは非RS485でCRTSCTSとする時用、
非RS485で非CRTSCTS用の関数はなし、
(非autoにする関数なく直接レジスタ制御)
となっていたと思います。

モデム制御の関数での直接レジスタ操作のところにも
CTSC問題があったかと。

--
なかむら

tamatsu_tme

2018年11月26日 11時20分

松本です。

> ucr2のことですよね? 変数"csr2"ではなくて。
> "CSR2レジスタ"は、UCR2レジスタ。
>
ごめんなさい、ご指摘のとおりUCR2です。

また、論理が逆ではとのご意見には私は賛同しません。
これは、いわゆる”(レガシーな)シリアル専用チップ”では制御線は負論理で入出力していました。
GPIOな入出力でであればソフト側で反転して読書き(読替え)をしてるのではないでしょうか?

さらに、
下記(添付)の修正を行うことで、残っていたRTSCTSの問題は解消したように動作しました。
なお、imx_set_mctrl()にてTIOCM_RTSをみてUCR2_CTSCも操作していましたがこれは誤りではと考えて修正しました。
今回TIMCM_DTRでRTS信号が影響を受けたのはこれが原因かと思います。TIOCM_DTRを0とするときだけimx_set_mctrl()が呼ばれ、偶然にも(imx_set_termios()のucs2変数でとり残された)UCR2のUCR2_CTSCが完了する方向に倒れたのだと思われます。

--- drivers/tty/serial/imx.c.save    2018-11-22 17:47:06.283371101 +0900
+++ drivers/tty/serial/imx.c    2018-11-26 10:39:12.261026518 +0900
@@ -899,10 +899,9 @@
     unsigned long temp;
 
     if (!(port->rs485.flags & SER_RS485_ENABLED)) {
-        temp = readl(sport->port.membase + UCR2);
-        temp &= ~(UCR2_CTS | UCR2_CTSC);
+        temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS);
         if (mctrl & TIOCM_RTS)
-            temp |= UCR2_CTS | UCR2_CTSC;
+            temp |= UCR2_CTS;
         writel(temp, sport->port.membase + UCR2);
     }
 
@@ -1564,7 +1563,7 @@
     old_ucr2 = readl(sport->port.membase + UCR2);
     writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
             sport->port.membase + UCR2);
-    old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
+    old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN | UCR2_CTSC);
 
     /* custom-baudrate handling */
     div = sport->port.uartclk / (baud * 16);
ファイル ファイルの説明
imx.c.patch

y.nakamura

2018年11月27日 0時50分

中村です。

やっとパソコンが使える環境に戻りました。
// スマホでフォーラム投稿は、するもんじゃないですね。

> なお、imx_set_mctrl()にてTIOCM_RTSをみてUCR2_CTSCも操作していましたがこれは誤りではと考えて修正しました。

> --- drivers/tty/serial/imx.c.save    2018-11-22 17:47:06.283371101 +0900
> +++ drivers/tty/serial/imx.c    2018-11-26 10:39:12.261026518 +0900
> @@ -899,10 +899,9 @@
>      unsigned long temp;
>  
>      if (!(port->rs485.flags & SER_RS485_ENABLED)) {
> -        temp = readl(sport->port.membase + UCR2);
> -        temp &= ~(UCR2_CTS | UCR2_CTSC);
> +        temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS);
>          if (mctrl & TIOCM_RTS)
> -            temp |= UCR2_CTS | UCR2_CTSC;
> +            temp |= UCR2_CTS;
>          writel(temp, sport->port.membase + UCR2);
>      }

これなんですが、「誤り」としていいいのかどうかは、
検討が必要だと思っています。

週末に調べておいたブックマークを張り付けておきます。
[serial: imx: fix throttle/unthrottle callbacks for hardware assisted flow control]
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit…

説明と差分も引用しておきます。
=======================================
when the 'CTSC' bit is negated. 'CTS' has no function when 'CTSC' is asserted.
0: The CTS pin is high (inactive)
1: The CTS pin is low (active)

For throttle, it needs to clear 'CTS' and 'CTSC' bits.
For unthrottle, it needs to enable 'CTS' and 'CTSC' bits.

The patch just fix the issue.
=======================================

--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -817,11 +817,9 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
     struct imx_port *sport = (struct imx_port *)port;
     unsigned long temp;
 
-    temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
-
+    temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC);
     if (mctrl & TIOCM_RTS)
-        if (!sport->dma_is_enabled)
-            temp |= UCR2_CTS;
+        temp |= UCR2_CTS | UCR2_CTSC;
 
     writel(temp, sport->port.membase + UCR2);

この修正がされたのが2014年9月で、4年間もこのままになっています。
imx.cは世界でたくさん使われているのに(G3系Armadilloもこのソースです)、
メインラインで誰も修正していないのは、何か理由があるのではないかと。

--
なかむら

at_mizo

2018年11月27日 10時19分

溝渕です。

私の主観、推測を含みますが、

> メインラインで誰も修正していないのは、何か理由があるのではないかと。

i.mxのuart driverでは、RTS/CTSの有効/無効によって次のようにRTSの論理が
決まっています。

RTS/CTSフロー有効時: uartコアでRTSを制御
RTS/CTSフロー無効時: RTSをinactiveに固定

対向機器とのRTS/CTSフロー設定が一致(有効:有効 or 無効:無効)している場
合は問題無いかと思います。

対向機器とのRTS/CTSフロー設定が不一致(有効:無効 or 無効:有効)の場合は、
少なくともi.mx側への送信が不能になります。仮に、i.mx側への送信が可能で
ある場合は対向機器からi.mxとの通信設定に不一致が生じていることの検出が
不可能になります。

対向機器との通信設定は通常「一致させるもの」なので、設定不一致の検出と
いう目的があったとしても不思議では無いと思います。

また、(TX/RXを除く信号の挙動に定めが無いため)RS232Cの仕様として認めら
れるものであり、RTS/CTSフロー無効時にRTSがinactiveに固定される挙動が明
確にバグであるとは言い堅いと感じます。

また、対向機器がRTS/CTSフロー設定を無効化できない場合は、RTS/CTSがルー
プバックされたシリアルクロスケーブルが存在するのも、この挙動が問題視さ
れない一因かと思います。

tamatsu_tme

2018年11月27日 10時53分

松本です。

> > なお、imx_set_mctrl()にてTIOCM_RTSをみてUCR2_CTSCも操作していましたがこれは誤りではと考えて修正しました。
>
> これなんですが、「誤り」としていいいのかどうかは、
> 検討が必要だと思っています。
>

はいそう思います。その意味で「誤りでは」との若干の濁した表現にしてしまいました。

まず最初に、
残っていたRTS/CTSが固定されてしまうケースがある問題は、私のパッチで今中村様にご指摘いただいているチャンクとは別のimx_set_termios()に適用してるチャックだけで修正できると思います。

話をもどして、
ここでUCR2_CTSCを操作するのであれば、termios.c_cflagのCRTSCTSの状態”も”検証した上ででなければ矛盾が生じるケースがあるのではないかと思った次第です。
この辺りは他とのバランスだと”も”思います。例えば「mctrl変数のTIOCM_RTSがCRTSCTSの状態を加味して他で操作されている」ケースもありえる(ありえた)とも考えられます。
しかし、現状のimx.cのソースの他の部分などをざくっと見回した限りでは上記可能性は無さそうなので、単純にUCR2_CTSCの操作はtermios.c_flagsのCRTSCTSを見ている部分だけに留めるのが矛盾となるリスクが少ないのでは、との思考ロジックです。

ただ、今回の私の観点は”制御線の状態操作”で思考ロックしている可能があり、本当に「RTS/CTSでフローコントロールが機能してオーバーランしていないか?」までのテストはできていない点があるのは申し添えておきます。

最後に、
一ユーザーとして通りがかりでドライバーのコードを覗いた程度ですので主張を強く言うつもりは全くありません。日頃この部分に触れられている皆々様のご意見・ご判断を尊重します。
一方ユーザーとしては、11月24日に指摘させていただいた「ioctl()でTIOCM_DTRをTIOCMBICするとRTS信号が(偶然にも正しい方向に)変化する」という挙動は「DTRを制御したのにRTS”も”変わる!?」との凄く気持ち悪い居心地の悪い感覚であり「他にも何かあるんじゃないか?」との疑心悪鬼にもなります。

y.nakamura

2018年11月27日 17時16分

中村です。

溝渕さん、
> 私の主観、推測を含みますが、

ありがとうざいます。

松本さん、
> 一ユーザーとして通りがかりでドライバーのコードを覗いた程度ですので主張を強く言うつもりは全くありません。日頃この部分に触れられている皆々様のご意見・ご判断を尊重します。

私も今回の問題部分については、いろいろと情報の提供はしましたが、
どのように修正するのがよいのか、「これ!」という主張はありません。

最後に・・・
溝渕さんの2つのパッチの違いを本文に引用しておきます。

--- imx.c-save  2018-11-24 15:39:28.298522263 +0900
+++ imx.c       2018-11-27 17:05:07.581246658 +0900
@@ -1497,7 +1497,7 @@
                        else
                                imx_port_rts_inactive(sport, &ucr2);
                } else {
-                       imx_port_rts_active(sport, &ucr2);
+                       imx_port_rts_inactive(sport, &ucr2);
                }
        }

--
なかむら

at_mizo

2018年11月28日 16時07分

松本様、

> TERMIOSのtermios構造体のtcflag_t c_cflagにてCRTSCTSを(tcsetattr()で)セットしないとRTS出力が”偽”の状態に固定されてしまうようです。

今更で申し訳ございませんが、上記現象を再現可能なソースコードをご提供いただくことは可能でしょうか。

linux-v4.14-at8で以下のプログラムを実行してみましたが、上記現象が再現できませんでした。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
 
int main(void)
{
    int fd;
    struct termios t;
 
    fd = open("/dev/ttymxc2", O_RDWR);
 
    tcgetattr(fd, &t);
    t.c_cflag &= ~CRTSCTS;
    tcsetattr(fd, TCSANOW, &t);
 
    while (1);
 
    return 0;
}

再現できない要因は、中村様がご教授くださった、

> オープンしたときにRTSとDTRを上げる(アクティブにする)
> というコードがserial_coreにあるようです。

にあると思われ、openした際に以下の場所を通るためです。

drivers/tty/serial/serial_core.c:
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
{
  :(snip)
            uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);