4

シンプルな UART 経由でデータを送信する FPGA を備えたデバイスがあります。データは 32 バイトのパケットで、ボーレートは 115200 です。UART-TTL/USB アダプターを介してラップトップに接続しているため、システム (Ubuntu 14.04) で からデータを読み取ることができますttyUSB。データを受信し、計算を行い、結果をテキスト ファイルに保存するための簡単なアプリケーションを GTK/C で作成しました。32 バイトのパケットを送信する頻度を毎秒 5 回から毎秒 100 回に増やすまで、すべてが正常に機能していました。問題は、1ダースまたは数ダースに1つのパケットが間違ったバイト順になっていることです。FPGA が毎回正しくデータを送信することをロジック アナライザーで確認しました。

たとえば、FPGA はパケットを送信します。

1 2 3 4 5 6 7 8 9

しかし、私のアプリケーションは時々受け取る:

1 2 7 3 4 5 6 8 9

この関数を使用してシリアルポートを開きます:

int rs232_open(char *com_name, int baudrate, int databits, char *parity, int stopbits)
{
    serial_fd = open(com_name, O_RDWR | O_NOCTTY | O_NDELAY); //open port
    if(serial_fd==-1)
    {
        perror("unable to open comport ");
        return 1;
    }
    error = tcgetattr(serial_fd, &old_settings); //save actual port settings
    if(error==-1)
    {
        close(serial_fd);
        perror("unable to read portsettings ");
        return 2;
    }
    memset(&new_settings, 0, sizeof(new_settings));
    new_settings.c_iflag = 0; //without in processing
    new_settings.c_oflag = 0; //without out processing
    new_settings.c_lflag = 0; //without line processing
    new_settings.c_cflag = CLOCAL | CREAD; //without flow control, receiver active
    switch(baudrate) //baudrate
    {
        case 9600:      new_settings.c_cflag |= B9600; break;
        case 19200:     new_settings.c_cflag |= B19200; break;
        case 38400:     new_settings.c_cflag |= B38400; break;
        case 115200:    new_settings.c_cflag |= B115200; break;
        default:        return 3; break;
    }
    switch(databits) //number of data bits
    {
        case 5: new_settings.c_cflag |= CS5; break;
        case 6: new_settings.c_cflag |= CS6; break;
        case 7: new_settings.c_cflag |= CS7; break;
        case 8: new_settings.c_cflag |= CS8; break;
        default: return 3;
    }
    switch(parity[0]) //parity
    {
        case 'N': new_settings.c_iflag |= IGNPAR;  break;
        case 'E': new_settings.c_cflag |= PARENB; break;
        case 'O': new_settings.c_cflag |= PARENB | PARODD; break;
        default: return 3;
    }
    switch (stopbits) //stop bits
    {
        case 1: break; //1 bit
        case 2: new_settings.c_cflag |= CSTOPB; break; //2 bits
        default: return 3;
    }
    new_settings.c_cc[VMIN] = 1; //1 received char allows to read
    new_settings.c_cc[VTIME] = 0;
    tcflush(serial_fd, TCIOFLUSH); //clear port buffers
    error = tcsetattr(serial_fd, TCSANOW, &new_settings); //save new settings
    if(error==-1)
    {
        close(serial_fd);
        perror("unable to set portsettings ");
        return 4;
    }
    return 0;
}

私の GTK/C アプリケーションでは、「OPEN」ボタンをクリックすると上記の関数が呼び出されます。

rs232_open("ttyUSB0",115200,8,"N",2);

次に、シリアル ポート用のチャネルを作成し、そのコーディングを設定して、受信イベントのハンドラーを追加します。

int serial_fd; //serial port file descriptor
GIOChannel *serial_ch; //serial port channel
serial_ch = g_io_channel_unix_new(serial_fd); //attach channel to serial port
g_io_add_watch(serial_ch, G_IO_IN, read_channel, NULL); //attach read_channel handler function

関数read_channel()は次のようframeになります (文字bufferと整数フィールドのテーブルを持つ構造体ですbyte_number):

gboolean read_channel(GIOChannel *channel, GIOCondition condition, gpointer data)
{
    unsigned char i;
    gsize bytes_read;
    gchar chr;
    GString *recdata = g_string_new(NULL);
    if(g_io_channel_read_chars(channel, &chr, 1, &bytes_read, NULL) == G_IO_STATUS_NORMAL) //if reading a byte is successful
    {
        if(bytes_read) //1 byte received
        {
            //
            // here I search for 0x55 0x55 sequence (start tag of 32 bytes packet)
            // if start tag is received frame buffer is cleared and byte counter zeroed
            //
            frame.buffer[frame.byte_number++]=chr; //save received byte to buffer
            if(frame.byte_number > BUFFER_SIZE-1) //frame buffer full
            {
                if(frame.buffer[BUFFER_SIZE-1] == 0x0D) //end tag is correct (0x0D is end tag of my 32 bytes packet)
                {
                    //
                    // here I convert received data (some int16 numbers)
                    // and save them in readable form to text file
                    // also as a string of hex numbers for debugging
                    //
                }
                else //end tag not correct
                {
                    //
                    // here I increase error counter
                    //
                }
                for(i=0; i<BUFFER_SIZE; i++) frame.buffer[i]=0; //clear the buffer
                frame.byte_number=0; //reset byte counter
            }
        }
    }
    return TRUE;
}
4

0 に答える 0