7

シリアル通信 (つまり、物理またはエミュレートされたシリアル ポートの RS-232/RS-422) を介して外部デバイスに接続されているコンピュータを使用しています。それらは頻繁なデータ交換 (30Hz) によって相互に通信しますが、小さなデータ パケット (各パケットが 16 バイト未満) しか使用しません。

通信の最も重要な要件は、送信と受信の間の低レイテンシーまたは遅延です。

データ交換パターンはハンドシェイクに似ています。1 つのホスト デバイスが通信を開始し、クライアント デバイスで通知を送信し続けます。クライアント デバイスは、ホスト デバイスからのすべての通知に可能な限り迅速に応答する必要があります (これはまさに、低遅延を達成する必要がある場所です)。通知と応答のデータ パケットは明確に定義されています。つまり、データ長はわかっています。そして、基本的にデータの損失は許されません。

次の一般的な Win API 関数を使用して、I/O の読み取り/書き込みを同期的に実行しました: CreateFile、ReadFile、WriteFile

クライアント デバイスは ReadFile を使用して、ホスト デバイスからデータを読み取ります。クライアントは、長さがわかっている完全なデータ パケットを読み取ると、WriteFile を使用して、ホスト デバイスに対応するデータ パケットで応答します。読み取りと書き込みは、同時実行なしで常にシーケンシャルです。

なんというか通信速度が遅い。つまり、データの送信と受信の間の時間が長すぎます。シリアルポートのバッファリングまたは割り込みに問題がある可能性があると思います。

ここでは、遅延を改善するために考えられるアクションをいくつかまとめます。いくつかの提案と修正をお願いします:)

  1. FILE_FLAG_NO_BUFFERING フラグを指定して CreateFile を呼び出しますか? このフラグがこのコンテキストに関連しているかどうかはわかりません。
  2. 各 WriteFile の後に FlushFileBuffers を呼び出しますか? またはシリアルポートに通知/割り込みしてデータをすぐに送信できるアクションはありますか?
  3. シリアル通信を扱うスレッドやプロセスの優先度を高くする
  4. エミュレートされたデバイスのレイテンシタイマーまたは転送サイズを設定します (ドライバーを使用)。しかし、物理シリアル ポートはどうでしょうか。
  5. Linux での setserial/low_latency のような Windows での同等のものはありますか?
  6. FIFO を無効にしますか?

前もって感謝します!

4

2 に答える 2

6

私の場合、通信タイムアウトを に設定することでこれを解決しました{MAXDWORD,0,0,0,0}

これに何年も苦労した後、まさにこの日、MicrosoftのCDCクラスUSB UARTドライバー(USBSER.SYS、現在Windows 10に組み込まれており、実際に使用できるようになっています)を使用して、シリアル通信端末を十分に高速にすることができました。

どうやら、前述の値のセットは、最小限のタイムアウトと最小限の待ち時間を設定する特別な値であり (少なくとも Microsoft ドライバーでは、とにかく私にはそう思われます)、新しい文字が受信にない場合は ReadFile がすぐに返されるようにします。バッファ。

ポートを開くコードは次のとおりです (Visual C++ 2008、ポート名の LPCWSTR 型キャストの問題を回避するために、プロジェクトの文字セットが「Unicode」から「未設定」に変更されました)。

static HANDLE port=0;
static COMMTIMEOUTS originalTimeouts;

static bool OpenComPort(char* p,int targetSpeed) { // e.g. OpenComPort ("COM7",115200); 
    char portname[16];
    sprintf(portname,"\\\\.\\%s",p);
    port=CreateFile(portname,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
    if(!port) {
        printf("COM port is not valid: %s\n",portname);
        return false;
    }
    if(!GetCommTimeouts(port,&originalTimeouts)) {
        printf("Cannot get comm timeouts\n");
        return false;
    }
    COMMTIMEOUTS newTimeouts={MAXDWORD,0,0,0,0};
    SetCommTimeouts(port,&newTimeouts);
    if(!ComSetParams(port,targetSpeed)) {
        SetCommTimeouts(port,&originalTimeouts);
        CloseHandle(port);
        printf("Failed to set COM parameters\n");
        return false;
    }
    printf("Successfully set COM parameters\n");
    return true;
}

static bool ComSetParams(HANDLE port,int baud) {
    DCB dcb;
    memset(&dcb,0,sizeof(dcb));
    dcb.DCBlength=sizeof(dcb);
    dcb.BaudRate=baud;
    dcb.fBinary=1;
    dcb.Parity=NOPARITY;
    dcb.StopBits=ONESTOPBIT;
    dcb.ByteSize=8;
    return SetCommState(port,&dcb)!=0;
}

そして、これが動作しているUSBトレースです。OUT トランザクション (出力バイト) に続いて IN トランザクション (入力バイト)、さらに OUT トランザクション (出力バイト) がすべて 3 ミリ秒以内に発生することに注意してください。

最小限のタイムアウトによる USB UART パケット トレース

最後に、これを読んでいる場合は、UART 経由で文字を送受信する関数に興味があるかもしれません。

    unsigned char outbuf[16384];
    unsigned char inbuf[16384];
    unsigned char *inLast = inbuf;
    unsigned char *inP = inbuf;
    unsigned long bytesWritten;
    unsigned long bytesReceived;

    // Read character from UART and while doing that, send keypresses to UART.
    unsigned char vgetc() { 
        while (inP >= inLast) { //My input buffer is empty, try to read from UART
            while (_kbhit()) { //If keyboard input available, send it to UART
                outbuf[0] = _getch(); //Get keyboard character
                WriteFile(port,outbuf,1,&bytesWritten,NULL); //send keychar to UART
            }
            ReadFile(port,inbuf,1024,&bytesReceived,NULL); 
            inP = inbuf;
            inLast = &inbuf[bytesReceived]; 
        }
        return *inP++;
    }

大規模な転送は、コードの別の場所で処理されます。

最後に、どうやらこれは、1998 年に DOS を放棄して以来、私が書くことができた最初の高速 UART コードです。

これは私が関連情報を見つけた場所です: http://www.egmont.com.pl/addi-data/instrukcje/standard_driver.pdf

于 2019-09-04T04:37:03.953 に答える
2

シリアルポートで同様の問題が発生しました。私の場合、シリアル ポートの遅延を減らすことで問題を解決しました。コントロール パネルを使用して、すべてのポートの遅延を変更できます (デフォルトでは 16ms に設定されています)。ここで方法を見つけることができます: http://www.chipkin.com/reducing-latency-on-com-ports/

幸運を!!!

于 2015-12-01T09:22:26.530 に答える