UART blocks on read

c++raspberry-piuart

I have a problem with my uart read (on raspberry pi). It works ok but it stops in a loop and waits on data…
I made an option O_NDELAY but is stops even so.

I use two terminal windows:

  • one is used for uart program
  • on the second i write:

    echo '123445' > /dev/ttyAMA0
    (raspberry Pi uart port)

Complete code is below.

#include <stdio.h>
#include <unistd.h>             //Used for UART
#include <fcntl.h>              //Used for UART
#include <termios.h>        //Used for UART


int main(int argv, char * argc[])
{
// Setting Up The UART

    //-------------------------
    //----- SETUP USART 0 -----
    //-------------------------
    //At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie         the alt0 function) respectively
    int uart0_filestream = -1;

    //OPEN THE UART
    //The flags (defined in fcntl.h):
    //  Access modes (use 1 of these):
    //      O_RDONLY - Open for reading only.
    //      O_RDWR - Open for reading and writing.
    //      O_WRONLY - Open for writing only.
    //
    //  O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
    //                                          if there is no input immediately available (instead of blocking). Likewise, write requests can also return
    //                                          immediately with a failure status if the output can't be written immediately.
    //
    //  O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.


    uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);      //Open in non blocking read/write mode
    if (uart0_filestream == -1)
    {
        //ERROR - CAN'T OPEN SERIAL PORT
        printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
    }

    //CONFIGURE THE UART
    //The flags (defined in termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
    //  Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
    //  CSIZE:- CS5, CS6, CS7, CS8
    //  CLOCAL - Ignore modem status lines
    //  CREAD - Enable receiver
    //  IGNPAR = Ignore characters with parity errors
    //  ICRNL - Map CR to NL on input
    //  PARENB - Parity enable
    //  PARODD - Odd parity (else even)
    struct termios cfg;

  //get existing configuration setup
  tcgetattr(uart0_filestream, &cfg);

  //fcntl(deviceFD, F_SETFL, FNDELAY);
  fcntl(uart0_filestream, F_SETFL, 0);

  ////set both incoming and outgoing baud rates...
  cfsetispeed(&cfg, B115200);
  cfsetospeed(&cfg, B115200);

  cfg.c_cflag |= (CLOCAL | CREAD);

  ////8N1 (8 data bits, No parity, 1 stop bit)
  cfg.c_cflag &= ~PARENB;
  cfg.c_cflag &= ~CSTOPB;
  cfg.c_cflag &= ~CSIZE;
  cfg.c_cflag |= CS8;

  cfg.c_cflag &= ~CRTSCTS;  //~CNEW_RTSCTS; //disable hardware flow control

  //use RAW unbuffered data mode (eg, not canonical mode)
  cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IGNBRK);

  cfg.c_iflag &= ~(IGNPAR | IXON | IXOFF | IXANY);

  //raw (unprocessed) output mode
  cfg.c_oflag &= ~OPOST;

  tcsetattr(uart0_filestream, TCSANOW, &cfg);

    //Transmitting Bytes

    //----- TX BYTES -----
    unsigned char tx_buffer[20];
    unsigned char *p_tx_buffer;

    p_tx_buffer = &tx_buffer[0];
    *p_tx_buffer++ = 'H';
    *p_tx_buffer++ = 'e';
    *p_tx_buffer++ = 'l';
    *p_tx_buffer++ = 'l';
    *p_tx_buffer++ = 'o';

    if (uart0_filestream != -1)
    {
        int count = write(uart0_filestream, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0]));      //Filestream, bytes to write, number of bytes to write
        if (count < 0)
        {
            printf("UART TX error\n");
        }
    }
    //Receiving Bytes

    //----- CHECK FOR ANY RX BYTES -----
    while(1) {

    printf("loop\n");

    if (uart0_filestream != -1)
    {
        // Read up to 255 characters from the port if they are there
        unsigned char rx_buffer[256];
        int rx_length = read(uart0_filestream, (void*)rx_buffer, 255);      //Filestream, buffer to store in, number of bytes to read (max)


        if (rx_length < 0)
        {
            //An error occured
            printf("UART RX error\n");
        }
        else if (rx_length == 0)
        {
            //No data waiting
          printf("no data UART RX   test commit\n");
        }
        else
        {
            //Bytes received
            rx_buffer[rx_length] = '\0';
            printf("%i bytes read : %s\n", rx_length, rx_buffer);
            //break;
        }
    }
    sleep(1);
}
//Closing the UART if no longer needed

    //----- CLOSE THE UART -----
    close(uart0_filestream);

  return 0;
}

Best Solution

I used to have the same problem, and problem is not related with code and solution is just disable login on serial port, there is a file at /etc/inittab open this file with nano and find this line:

 T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

and put a # char at begining this line than save and reboot and it is working weirdly.

Related Question