Armadillo-X1におけるシリアル受信動作について

お世話になっております。
山口と申します。

Armadillo-X1でRS232Cアドオンモジュールを使用し、
シリアル通信を行っております。

以下の通信条件にてシリアル通信を行っていますが、
キャラクタ間(バイト間)の時間が短い時(1~2msec)に
readバッファに受信データが存在せずreadで正しくデータを取得することができません。

---------------------------------------------------------
struct termios tio
int baudRate = B4800;

memset(&tio, 0, sizeof(tio));

tio.c_cflag = CREAD | CLOCAL | CS8 | CSTOPB | PARENB;
tio.c_cc[VMIN] = 0;
tio.c_cc[VTIME] = 0;
tio.c_iflag = INPCK;
tio.c_oflag = 0;
tio.c_lflag = 0;

cfsetispeed( &tio, baudRate );
cfsetospeed( &tio, baudRate );
---------------------------------------------------------

受信オーバーランのメッセージなどはありません。
TeraTermとArmadilloのシリアル間では、
ラインモニタ(通信条件同等)を繋ぎ、データが正しく送られていることは確認しています。
キャラクタ間の時間が100msec程度ある場合には正しく連続受信することができます。
ユーザーがTeraTerm上で都度キーを押下しデータを送信するような場合も同様に受信には問題ありません。

こちらで考えている原因としては、UARTの受信FIFOバッファからreadのバッファへデータが転送されていないためと
考えていますが、認識は正しいでしょうか。

症状の詳細として、ある程度データを受信しているとそれまで溜め込んでいた?データが一気に表示されることから、
UARTの連続受信動作を区切るために、タイムアウト値を調整しましたが、症状に変化ありませんでした。
 driver/tty/serial/serial_core.c(346行のport->timeoutを調整)
ボーレートが38400bps以上の設定の場合には本症状は発生しないため、4800bpsのタイムアウト値=10(Hz?)が
効いているのかと考えカーネルソールの変更を試みた次第です。

本シリアル通信設定における連続データ受信を成立させるための解決策をご教示いただきたく。

評価環境で使用している受信プログラムとTeraTermマクロ(使用の際には_.txtを削除してください)を添付いたします。
またArmadillo-X1のシステムVer.はv4.9-at7になります。

以上、よろしくお願いいたします。

ファイル名 ファイルの説明
ser_send.ttl_.txt
recv_test.c
製品: 
Armadillo-X1

後藤です。

本フォーラムのトピック『シリアル通信について』(下記URL参照)において、
https://users.atmark-techno.com/forum/armadillo/3520

中村さんが投稿されている差分、
https://users.atmark-techno.com/forum/armadillo/3520#comment-6525

あるいは、私が投稿したパッチ
https://users.atmark-techno.com/forum/armadillo/3520#comment-6333

を試してみては如何でしょうか?

後藤さん

早速のご回答をありがとうございます。
返信が遅れまして申し訳ありません。

内容をきちんと確認する前に質問をして申し訳ありませんが、
当方環境のat7でも本パッチ(at3)は効果が見込めるということでしょうか。

頂いた情報で検証を継続してみたいと思います。
---
山口

> 後藤です。
>
> 本フォーラムのトピック『シリアル通信について』(下記URL参照)において、
> https://users.atmark-techno.com/forum/armadillo/3520
>
> 中村さんが投稿されている差分、
> https://users.atmark-techno.com/forum/armadillo/3520#comment-6525
>
> あるいは、私が投稿したパッチ
> https://users.atmark-techno.com/forum/armadillo/3520#comment-6333
>
> を試してみては如何でしょうか?

後藤です。

> 当方環境のat7でも本パッチ(at3)は効果が見込めるということでしょうか。

効果が見込めるかどうかのお約束はできませんが、投稿したパッチは、
本トピックと似た状況(ただしRS-485通信でボーレートは1200bpsを使用)
に対応するために作成したものです。

中村さんが投稿された差分はDMAを無効にするというものですが、本件に
対して効果が有るかもしれません。

後藤さん

ご回答ありがとうございます。

承知いたしました。
内容に不明点などありましたら質問をさせてください。

結果は改めて報告させていただきます。

---
山口

後藤さん

ご教示いただいたDMA機能を無効とする内容を適用したところ、
当該現象は解消されました。
ありがとうございました。

自身の理解のために可能ならば教えて頂きたいのですが、
本現象はDMA機能が正しく働いていないために発生していたのでしょうか。
もしくは、低レート設定で発生する特徴からDMAの機能特性がマッチしないということでしょうか。

---
山口

後藤です。

> ご教示いただいたDMA機能を無効とする内容を適用したところ、
> 当該現象は解消されました。
> ありがとうございました。

ご報告ありがとうございます。解決して何よりです。

> 自身の理解のために可能ならば教えて頂きたいのですが、
> 本現象はDMA機能が正しく働いていないために発生していたのでしょうか。

mainlineカーネルのimx.cに対する修正ログ(下記にURL参照)を見ると、
idle condition detect(受信線のアイドル状態を検知する機能の事だと
思いますが)を有効にしてDMA転送を行うと問題が生じるようです。

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/tty/serial/imx.c?id=905c0decad28402aa166975023fb88c8f62f93c8
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/tty/serial/imx.c?id=392bceedb107a3dc1d4287e63d7670d08f702feb

> もしくは、低レート設定で発生する特徴からDMAの機能特性がマッチしないということでしょうか。

すみません、因果関係は追いきれていません。

後藤さん

ご回答ありがとうございます。承知いたしました。
レートとDMAとの関係は引き続き追ってみたいと思います。

引き続き動作検証を行っていったところ、別の現象が出てきましたので
相談に乗っていただけると幸いです。

現象は、1byte受信後に1byte送信(write)を行ったところ、
Write完了まで20msecの時間がかかっていることがわかりました。(時間はラインモニタで確認)
readtのあとにはsleepやデバッグprintなども行っていませんので、
20msecの処理時間がどこでかかっているのかが不明です。

1byte送信のみを繰り返す時には発生せず、受信直後の送信処理で遅延が発生しています。

imx.cは、中村さんのパッチのtx側のdma無効と有効をどちらも試しましたが結果に変化はありませんでした。

以上、よろしくお願いいたします。

---
山口

前述の件で評価で使用したソースを添付し忘れましたので、再投稿させていただきます。
---
山口

ファイル名 ファイルの説明
recv_and_send.c

中村です。

後藤さん、横から失礼します。

> 現象は、1byte受信後に1byte送信(write)を行ったところ、
> Write完了まで20msecの時間がかかっていることがわかりました。(時間はラインモニタで確認)
> readtのあとにはsleepやデバッグprintなども行っていませんので、
> 20msecの処理時間がどこでかかっているのかが不明です。
>
> 1byte送信のみを繰り返す時には発生せず、受信直後の送信処理で遅延が発生しています。
>
> imx.cは、中村さんのパッチのtx側のdma無効と有効をどちらも試しましたが結果に変化はありませんでした。

いずれもDMAを無効にした状態ですよね?
「中村さんのパッチのtx側のdma無効と有効」の部分は、
「TX側のDMA無効」ではなくて、
TX-FIFOの設定

+#if 0
        /* Can we enable the DMA support? */
        if (is_imx6q_uart(sport) && !uart_console(&sport->port))
                tx_fifo_trig = TXTL_DMA;
        else
+#endif
                tx_fifo_trig = TXTL;

のことでしょうか?

> 20msecの処理時間がどこでかかっているのかが不明です。

この20msecは、i.MX 7Dual のリファレンスマニュアルの
  15.3.4.6.2 Aging Character Detect
だと思います。

この機能は(読んでもらえばそこに書いてあるとおりですが)、
ざっくりと説明すると・・・
RX-FIFOに最後のデータが入った後8文字分の時間待っても
RX-FIFOにデータが追加されないときに割り込みを発生させて、
RX-FIFOからデータを取り出せるようにする機能です。
この機能がないと、RX-FIFOに一定数のデータがたまるまで
受信割り込みが発生しなくなってしまいます。

4800bpsの8バイト分は、約16.6msecになります。
この時間まっても追加受信がなければ割り込みが発生して
ドライバがRX-FIFOからデータを取り出してカーネルの
受信バッファに入れます。
アプリケーションプログラム(添付されていたもの)は、
そのデータをread()で取り出した後にwrite()で送信なので、
受信から送信完了まで、だいたい20msecになると思います。

--
なかむら

中村さん

ご返信ありがとうございます。

リファレンスマニュアル 15.3.4.6.2項の内容、理解いたしました。
解説ありがとうございました。
大変助かりました。

8byte分のエージングタイマの仕様だったのですね。
通信設定から1キャラクターのビット長は12bitになりますので、
4800bpsで20msecとなること計算が合いました。

エージングタイマをキャラクタ数を変えること、もしくはタイマ値をユーザーで設定することは可能でしょうか。

こちらで開発している対抗機器との通信規約上、1キャラクタ(1コマンド)受信後に最大で2msec以内に
ACKを送信する仕様になっているため、可能ならばカーネル改修で乗り切りたい考えです。

以上、よろしくお願いいたします。

---
山口

中村です。

> 通信設定から1キャラクターのビット長は12bitになりますので、

山口さんのソースだと12ビットでしたね。
ソースの CSTOPB | PARENB を見落としていて、
10ビットで計算してました。

> こちらで開発している対抗機器との通信規約上、1キャラクタ(1コマンド)受信後に最大で2msec以内に
> ACKを送信する仕様になっているため、可能ならばカーネル改修で乗り切りたい考えです。

RXTLを1にすれば1文字受信で割り込みが発生します。
ドライバソース(imx.c)の次の部分です。
(RXTL_UARTのdefine値が16になっているところ)

#define TXTL 2 /* reset default */
#define RXTL 1 /* For console port */
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_UART 16 /* For uart */
 
static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
{
        unsigned int val;
        unsigned int tx_fifo_trig;
        unsigned int rx_fifo_trig;
 
        /* Can we enable the DMA support? */
        if (is_imx6q_uart(sport) && !uart_console(&sport->port))
                tx_fifo_trig = TXTL_DMA;
        else
                tx_fifo_trig = TXTL;
 
        if (uart_console(&sport->port))
                rx_fifo_trig = RXTL;
        else
                rx_fifo_trig = RXTL_UART;
 
        /* set receiver / transmitter trigger level */
        val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
        val |= tx_fifo_trig << UFCR_TXTL_SHF | rx_fifo_trig;
        writel(val, sport->port.membase + UFCR);
        return 0;
}

これを修正すれば1文字受信で割り込みが発生するようになりますが、
Linuxでは2msec後送信を保証することはできないと思います。
(ほとんどの場合は2msec以内に送信できるでしょうけど)

--
なかむら

中村さん

早速のご回答をありがとうございます。

修正箇所の情報、大変助かります。
試してみたいと思います。
結果は改めて報告させて頂きます。

> これを修正すれば1文字受信で割り込みが発生するようになりますが、
> Linuxでは2msec後送信を保証することはできないと思います。
> (ほとんどの場合は2msec以内に送信できるでしょうけど)
>
ご指摘ありがとうございます。
ご指摘いただいている通りで、この辺も今回の開発で検証をしたいところになります。
おかげさまでようやくここまで辿りつくことができまして、感謝しております。

カーネス修正後の検証結果も含めて改めて投稿したいと思いますので、
今後も何卒よろしくお願いいたします。

---
山口

> 中村です。
>
> > 通信設定から1キャラクターのビット長は12bitになりますので、
>
> 山口さんのソースだと12ビットでしたね。
> ソースの CSTOPB | PARENB を見落としていて、
> 10ビットで計算してました。
>
> > こちらで開発している対抗機器との通信規約上、1キャラクタ(1コマンド)受信後に最大で2msec以内に
> > ACKを送信する仕様になっているため、可能ならばカーネル改修で乗り切りたい考えです。
>
> RXTLを1にすれば1文字受信で割り込みが発生します。
> ドライバソース(imx.c)の次の部分です。
> (RXTL_UARTのdefine値が16になっているところ)
>
>

> #define TXTL 2 /* reset default */
> #define RXTL 1 /* For console port */
> #define TXTL_DMA 8 /* DMA burst setting */
> #define RXTL_UART 16 /* For uart */
> 
> static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
> {
>         unsigned int val;
>         unsigned int tx_fifo_trig;
>         unsigned int rx_fifo_trig;
> 
>         /* Can we enable the DMA support? */
>         if (is_imx6q_uart(sport) && !uart_console(&sport->port))
>                 tx_fifo_trig = TXTL_DMA;
>         else
>                 tx_fifo_trig = TXTL;
> 
>         if (uart_console(&sport->port))
>                 rx_fifo_trig = RXTL;
>         else
>                 rx_fifo_trig = RXTL_UART;
> 
>         /* set receiver / transmitter trigger level */
>         val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
>         val |= tx_fifo_trig << UFCR_TXTL_SHF | rx_fifo_trig;
>         writel(val, sport->port.membase + UFCR);
>         return 0;
> }
> 

>
> これを修正すれば1文字受信で割り込みが発生するようになりますが、
> Linuxでは2msec後送信を保証することはできないと思います。
> (ほとんどの場合は2msec以内に送信できるでしょうけど)
>
> --
> なかむら
>

中村さん

報告が遅れまして申し訳ありませんでした。

ご指摘いただいた箇所を修正
 RXTL_UARTのdefine値を 16 -> 1
とすることで問題視していた遅延現象はなくなりました。
まことにありがとうございました。

2点ほどご教示頂きたいことがあるのですが、ご回答いただけるとありがたいです。
 ・RXTL_UARTの値を個別(UART毎)に設定することは可能でしょうか。
  たとえば232Cアドオンモジュールで使用しているttymxc6のみ RXTLを1キャラクタとする
 ・UARTとコンソールポートでRXTLの値がわかれている理由はどのようなを気にされていてなのでしょうか。

以上、よろしくお願いいたします。

---
山口

 

中村です。
 
>  ・RXTL_UARTの値を個別(UART毎)に設定することは可能でしょうか。
>   たとえば232Cアドオンモジュールで使用しているttymxc6のみ RXTLを1キャラクタとする

今回の imx_setup_ufcr(struct imx_port *sport, unsigned int mode) の中ならば、
sport->port.line でポートを区別できます。
/dev/ttymxcN の N の部分がsport->port.lineの値になっています。

>  ・UARTとコンソールポートでRXTLの値がわかれている理由はどのようなを気にされていてなのでしょうか。

私の想像ですが、キーボードから1文字ずつ入力したときに、
そのエコーバックの遅延を少なくするためだと思います。

--
なかむら

中村さん

お世話になっております。

早速のご回答をありがとうございます。

> /dev/ttymxcN の N の部分がsport->port.lineの値になっています。
>

大変助かります。
実装試みたいと思います。

> >  ・UARTとコンソールポートでRXTLの値がわかれている理由はどのようなを気にされていてなのでしょうか。
>
> 私の想像ですが、キーボードから1文字ずつ入力したときに、
> そのエコーバックの遅延を少なくするためだと思います。
>

なるほど。承知いたしました。

後藤さん、中村さん

今回、後藤さん、中村さんにサポートして頂き、とても感謝しております。
ありがとうございました。
また今後も何かありましたらサポートのほどよろしくお願いいたします。

ありがとうございました。

---
山口