2013-04-08 10 views
5

Sto tentando di leggere e scrivere dati da e verso una scheda FPGA. La scheda stessa è arrivata con un driver che crea un dispositivo terminale chiamato ttyUSB0 ogni volta che la scheda viene collegata. Sull'Fpga, sono stati implementati un ricevitore e un trasmettitore asincroni e sembrano funzionare.Come configurare correttamente la comunicazione seriale su Linux

Tuttavia, sembra esserci un problema sul lato C delle cose. Ho usato alcuni vettori di test per verificare se l'FPGA sta emettendo le informazioni corrette. Ho notato alcune cose cose:

  1. Il dispositivo a volte non si apre correttamente
  2. Il terminale attributi a volte non riescono a essere recuperata o impostata.
  3. La lettura a volte non è bloccante e non recupera il valore corretto.

Di seguito viene illustrato come impostare le opzioni del descrittore di terminale e di file. Gran parte di esso è stata presa da qui: http://slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming

Qualsiasi consiglio o commento sul perché il programma potrebbe fallire sarebbe di grande aiuto.

#include <stdio.h> // Standard input/output definitions 
#include <string.h> // String function definitions 
#include <unistd.h> // UNIX standard function definitions 
#include <fcntl.h> // File control definitions 
#include <errno.h> // Error number definitions 
#include <termios.h> // POSIX terminal control definitions 

int open_port(void){ 

    int fd; // File descriptor for the port 
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY); 

    if (fd == -1){ 
     fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    return (fd); 
} 

int main(void){ 

    int fd = 0;    // File descriptor 
    struct termios options; // Terminal options 

    fd = open_port(); // Open tty device for RD and WR 

    fcntl(fd, F_SETFL);   // Configure port reading 
    tcgetattr(fd, &options);  // Get the current options for the port 
    cfsetispeed(&options, B230400); // Set the baud rates to 230400 
    cfsetospeed(&options, B230400); 

    options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode 
    options.c_cflag &= ~PARENB;    // No parity bit 
    options.c_cflag &= ~CSTOPB;    // 1 stop bit 
    options.c_cflag &= ~CSIZE;    // Mask data size 
    options.c_cflag |= CS8;    // Select 8 data bits 
    options.c_cflag &= ~CRTSCTS;   // Disable hardware flow control 

    // Enable data to be processed as raw input 
    options.c_lflag &= ~(ICANON | ECHO | ISIG); 

    // Set the new attributes 
    tcsetattr(fd, TCSANOW, &options); 

    //////////////////////////////////// 
    // Simple read and write code here// 
    //////////////////////////////////// 

    // Close file descriptor & exit 
    close(fd) 
    return EXIT_SUCCESS 
} 

UPDATE Ho modificato il mio codice in base alla prima risposta. Questo è quello che ho adesso:

#include <errno.h>  // Error number definitions 
#include <stdint.h>  // C99 fixed data types 
#include <stdio.h>  // Standard input/output definitions 
#include <stdlib.h>  // C standard library 
#include <string.h>  // String function definitions 
#include <unistd.h>  // UNIX standard function definitions 
#include <fcntl.h>  // File control definitions 
#include <termios.h> // POSIX terminal control definitions 

// Open usb-serial port for reading & writing 
int open_port(void){ 

    int fd; // File descriptor for the port 
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY); 

    if (fd == -1){ 
     fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    return fd; 
} 

int main(void){ 

    int    fd = 0;  // File descriptor 
    struct termios options; // Terminal options 
    int    rc;   // Return value 

    fd = open_port();   // Open tty device for RD and WR 

    // Get the current options for the port 
    if((rc = tcgetattr(fd, &options)) < 0){ 
     fprintf(stderr, "failed to get attr: %d, %s\n", fd, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    // Set the baud rates to 230400 
    cfsetispeed(&options, B230400); 

    // Set the baud rates to 230400 
    cfsetospeed(&options, B230400); 

    cfmakeraw(&options); 
    options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode 
    options.c_cflag &= ~CSTOPB;   // 1 stop bit 
    options.c_cflag &= ~CRTSCTS;   // Disable hardware flow control 
    options.c_cc[VMIN] = 1; 
    options.c_cc[VTIME] = 2; 

    // Set the new attributes 
    if((rc = tcsetattr(fd, TCSANOW, &options)) < 0){ 
     fprintf(stderr, "failed to set attr: %d, %s\n", fd, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    //////////////////////////////// 
     // Simple Read/Write Code Here// 
     //////////////////////////////// 

    // Close file descriptor & exit 
    close(fd); 
    return EXIT_SUCCESS; 
} 

solo per chiarire, l'uso 8 bit ricevitore e trasmettitore di dati, 1 bit di stop e nessun bit di parità.

risposta

5

Preferisco Serial Programming Guide for POSIX Operating Systems.

È necessario eliminare l'istruzione fcntl(mainfd, F_SETFL), poiché non è richiesta e implementata in modo non corretto (F_GETFL non è stato eseguito in precedenza e manca il terzo argomento).

Provare a utilizzare cfmakeraw alla modalità di impostazione non canonico, dal momento che il codice di inizializzazione è incompleto:

options->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 
     | INLCR | IGNCR | ICRNL | IXON); 
options->c_oflag &= ~OPOST; 

Per il modo non canonico, è inoltre necessario definire

options.c_cc[VMIN] = 1; 
options.c_cc[VTIME] = 2; 

1 e 2 sono solo valori suggeriti.

Aggiungi test di stato restituito dopo tutte le chiamate di sistema.

rc = tcgetattr(mainfd, &options); 
if (rc < 0) { 
    printf("failed to get attr: %d, %s\n", mainfd, strerror(errno)); 
    exit (-3); 
} 

Provare con un baud rate più lento (ad esempio 115200 o anche 9600).

+0

Grazie, ci provo e ti aggiorno. – sj755

+0

Ho effettuato un aggiornamento e pubblicato il mio codice corrente. Per qualche ragione il programma non è in grado di leggere nulla dalla lavagna, attende solo la funzione di lettura. qualche idea? – sj755

+1

Non hai bisogno di 'c_cflag & = ~ PARENB' dato che' cfmakeraw() 'lo gestirà. Probabilmente hai bisogno di 'c_cflag & = ~ CSTOPB' e' c_cflag & = ~ CRTSCTS' che sono stati rimossi! Ognuno di questi potrebbe uccidere la lettura. – sawdust