About embedded Linux serial port programming of AM335x AM62x


The serial port devices under Linux are mainly in the dev directory, such as ttySx or ttySUx or ttyOx. For example, am1808 is ttyS0-S2 SU0-SU7, and am335x is ttyO0-O5.


1. This basic programming API introduction, the most basic serial port settings include baud rate settings, parity bit and stop bit settings.


1.1 The setting of the serial port mainly involves setting the member values of the struct termios structure.

    struct termios 

    {

        unsigned short c_iflag; /* Input mode flag */

        unsigned short c_oflag; /* Output mode flag */

        unsigned short c_cflag; /* Control mode flag */

        unsigned short c_lflag; /* Local mode flag */

        unsigned char c_line; /* Control protocol */

        unsigned char c_cc[NCC]; /* Control mode character */

    };

    All operations on the serial port are implemented through the structure struct termios and several functions. The two most commonly used functions are tcgetattr() and tcsetattr(). In almost all cases, the program obtains the current settings of the device through the tcgetattr() function, then modifies these settings, and finally uses tcsetattr() to make these settings effective. Many programs will save the initial terminal settings and restore them before terminating.

The function returns 0 to indicate success.


1.2 tcgetattr and tcsetattr functions

    int  tcgetattr (int  fd ,struct termios *t)

    Used to obtain the current setting value of the device represented by the file descriptor fd and write it into pointer t


    int  tcsetattr    (int fd, int options ,struct termios *t)

    Used to assign the setting value in the termios structure pointer t to the device terminal currently represented by the file descriptor fd

    The options parameter determines when the change takes effect.

    TCSANOW——Modification takes effect immediately

    TCSADRAIN——All sent outputs take effect after being written to fd

    TCSAFLUSH——Take effect when the output queue is empty


    For example: Here is the code to change the baud rate: 

    struct  termios  Opt;

    tcgetattr(fd, &Opt); 

    cfsetispeed(&Opt,B19200); /*设置为19200Bps*/ cfsetospeed(&Opt,B19200);

    tcsetattr(fd,TCANOW,&Opt);


1.3 Baud rate setting

    The cfsetispeed() and cfsetospeed() functions are used to set the input and output speeds of the device respectively.

    int cfsetispeed(struct termios *t ,speed_t speed)

    int cfsetospeed(struct termios *t ,speed_t speed)

    The input and output speeds of the device are set to speed through the structure t. They only set the speed of the termios structure. If you want to modify the speed of the device, you need to call the tcsetattr() function. Let's take a look at an example of setting the baud rate:


    int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };

    int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };

    void set_speed(int fd, int speed)

    { 

        int i; int status; 

        struct termios Opt;

        tcgetattr(fd, &Opt); 

        for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) 

        { 

            if (speed == name_arr[i]) 

            { 

                tcflush(fd, TCIOFLUSH);

                cfsetispeed(&Opt, speed_arr[i]);                               

                cfsetospeed(&Opt, speed_arr[i]); 

                status = tcsetattr(fd1, TCSANOW, &Opt); 

                if (status != 0) 

                { 

                    perror("tcsetattr fd1");

                    return; 

                } 

                tcflush(fd,TCIOFLUSH); 

            }

         } 

     }


1.4 tcflush() function

    Used to discard some data on the device. The discarded data depends on the second parameter queue_selector    

    The prototype is: int tcflush (int fd, int queue_selector)

    TCIFLUSH - discards all data that has been received on the interface but not read in

    TCOFLUSH - discards all data that has been written to the interface but not sent

    TCIOFLUSH - discards all data that has not been read or sent on the input and output queues


1.5 Parity and stop bit settings

    No parity (8N1): 

    options.c_cflag &= ~PARENB; //No parity

    options.c_cflag &= ~CSTOPB; //1 stop bit

    options.c_cflag &= ~CSIZE; //No bit mask

    options.c_cflag |= CS8; //8 data bits


    Even parity (7E1): 

    options.c_cflag |= PARENB; //with parity

    options.c_cflag &= ~PARODD; //even parity

    options.c_cflag &= ~CSTOPB; //one stop bit

    options.c_cflag &= ~CSIZE; //no bit mask

    options.c_cflag |= CS7; //7 data bits


    Odd parity (7O1): 

    options.c_cflag |= PARENB; //with parity

    options.c_cflag |= PARODD; //odd parity

    options.c_cflag &= ~CSTOPB; //one stop bit

    options.c_cflag &= ~CSIZE; //no bit mask

    options.c_cflag |= CS7; //7 data bits


    CSIZE ——bit mask for data bits

    CS7——7 data bits

    CS8——8 data bits

    CSTOPB——2 stop bits (1 otherwise)

    PARENB——enable parity

    PARODD——use odd parity instead of even


1.6 Read and write serial port

    After setting up the serial port, it is very easy to read and write the serial port. You can read and write the serial port as a file

    Send data:

    char  buffer[1024];

    int    Length=1024;

    int    nByte;

    nByte = write(fd, buffer ,Length)


    Use the file operation read function to read. If the raw mode (Raw Mode) is set to transmit data, the number of characters returned by the read function is the number of characters actually received by the serial port.

    char  buff[1024];

    int    Len=1024;

    int  readByte = read(fd, buff, Len);



2. Specific Programming

    The specific program is in the code directory. There are a few points that need special attention.

    options.c_iflag &= ~ (IXON | IXOFF | IXANY);  The VSTART and VSTOP elements of the c_cc array are set to DC1 and DC3, representing the XON and XOFF characters of the ASCII standard. If these two characters cannot be transmitted, the software flow control needs to be disabled.

     

    options.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);  

    

    Sometimes, when sending data with write, if you do not type a carriage return, the information will not be sent out. This is mainly because we follow the standard mode when sending and receiving carriage returns or line feeds, but in most cases we do not need to type a carriage return or line feed. In this case, you should switch to line mode input and send it directly without processing.

    

    options.c_iflag &= ~ (INLCR | ICRNL | IGNCR);  options.c_oflag &= ~(ONLCR | OCRNL);

    

    There is also such a situation: when sending the character 0X0d, the character received by the receiving end is often 0X0a. The reason is that in the serial port settings, there is a mapping from NL-CR and CR-NL in c_iflag and c_oflag, that is, the serial port can treat carriage return and line feed as the same character. You can set it as follows to block it:


3.  The above serial ports are suitable for general-purpose processors such as AM335x, AM62x, G2L, etc.

    For example, the Visionox AM62x core board is an industrial-grade core board designed based on the TI AM62x processor and is widely used in various serial port servers, multi-serial port gateways and other application scenarios.

UART Programming.jpg

Tags: Array