UART4 read in pthread not working

237 views
Skip to first unread message

Regina Choi

unread,
Jul 20, 2016, 2:56:50 AM7/20/16
to BeagleBoard

Hi,

I have programmed (in C) UART4 read in thread with blocking read, the code as below: I confirmed that the UART receive port does have data through oscilloscope, but somehow there is no data in read( ), the return count always zero ? 

The strange thing is if minicom is open on the Uart4, then the read( ) in receive thread started to run as normal.  However, the regular file write become weird.  The string won't be able to be written into file ?!

Btw, my BBB version is 3.8.13-bone47


#include<stdio.h>
#include<stdlib.h>        // required for fopen, exit()
#include<fcntl.h>
#include<termios.h>
//#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include "readerComm.h"


pthread_t uartRxT , uartTxT;
int file, file2;

int main (int argc, char* argv[])
{
    int count;
 
    pthread_attr_t attr;
    void *status;
    FILE *fdata;


    if(argc != 2)
    {

        printf("Invalid number of arguments, exiting!");
        return -2;

    }

    if((file = open("/dev/ttyO4", O_RDWR | O_NOCTTY | O_NDELAY ))< 0)
    {
        perror("UART: Failed to open the file");
        return -1;
    }

    fcntl(file, F_SETFL, 0);     // blocking read
    struct termios options; //oriopt
    tcgetattr(file, &options);
    options.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
    options.c_iflag = IGNPAR | ICRNL;

    options.c_iflag &= ~IGNBRK;
    options.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    options.c_cc[VMIN]  = 2;    // Non Canonical input mode (as we didnt set ICANON for c_lflag)
    options.c_cc[VTIME] = 10;    // 1 sec timeout


    tcflush(file, TCIFLUSH);

    tcsetattr(file, TCSANOW, &options);


    unsigned char cmd[] = {0x11, 0x00, 0x32};    //"Tx From Beaglebone ";

    if ((count = write(file, (char*)cmd, 3))<0){
          perror("Failed to write to the output\n");
          return -1;
     }else{
         printf("Byte sent: %d \n", count);
     }

    fdata = fopen("capture.dat", "w");
    if (fdata == NULL) {
            printf("I couldn't open capture.dat for writing.\n");
            exit(0);
    }

    // save in file ( cannot print to file ??)
    fprintf(fdata, "%s", "test");
    perror("UART: Test comment");


    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&
attr, PTHREAD_CREATE_JOINABLE);

    // Create UArt Tx thread
    if(pthread_create(&uartTxT, &attr, &uartTxWait, NULL)){
        perror("GPIO: Failed to create the tx thread");

        return -1;
    }

    // Create Uart Rx thread
    if(pthread_create(&uartRxT, &attr, &uartRxWait, NULL)){
        perror("GPIO: Failed to create the rx thread");

        return -1;
    }

    pthread_attr_destroy(&attr);
    pthread_join(uartRxT,&status);
    pthread_join(uartTxT,&status);

    close(file);    // close first file descriptor

    // capture.dat file close
    fclose(fdata);

    return 0;

}

// UART RX thread
void* uartRxWait(void *param){

    unsigned char receive[100];
    int count, n;
    fd_set input;
    struct timeval timeout;

    //initialize input set
    FD_ZERO(&input);
    FD_SET(file, &input);

    timeout.tv_sec=0;
    timeout.tv_usec=0;

    while(1){
      
            if ((count = read(file, (void *)receive, 100))<0)
            {
                perror("Failed to read from input \n");
                printf("count = %d\n", count);
            }else{

                if(receive[2]==0x32){
                    printf("Header received \n");
                }
                    printf("Byte received [%d] \n", count);
                    printf("Value of Pi = 0x%.2x\n", receive[0]);

          }
 
    }

    pthread_exit(0);
}


void* uartTxWait(void *param){

    usleep(1000000);
    pthread_exit(0);
}

Karl Karpfen

unread,
Jul 20, 2016, 3:21:44 AM7/20/16
to BeagleBoard
Serial interface initialisation on Linux systems is a mess and it is easy to forget something. That's why I would recommend to use a library which does all the work for you like liboapc from https://sourceforge.net/p/oapc/code/ci/master/tree/liboapc/

Regina Choi

unread,
Jul 20, 2016, 4:39:37 AM7/20/16
to BeagleBoard
Hi Karl,

Thanks for suggestion.

My problem in the code seems to be more specific to pthread, because if I have the read( )  in a while loop, then the UART receive is running normally. Data arrived at the receive buffer are able to be pick up. However, the problem begin when I create UART Rx thread that just continuously reading the UART buffer.



Regina

Wally Bkg

unread,
Jul 21, 2016, 1:46:56 AM7/21/16
to BeagleBoard


On Wednesday, July 20, 2016 at 1:56:50 AM UTC-5, Regina Choi wrote:

Hi,

I have programmed (in C) UART4 read in thread with blocking read, the code as below: I confirmed that the UART receive port does have data through oscilloscope, but somehow there is no data in read( ), the return count always zero ? 

// UART RX thread
void* uartRxWait(void *param){

    unsigned char receive[100];
    int count, n;
    fd_set input;
    struct timeval timeout;

    //initialize input set
    FD_ZERO(&input);
    FD_SET(file, &input);

    timeout.tv_sec=0;
    timeout.tv_usec=0;

    while(1){
      
            if ((count = read(file, (void *)receive, 100))<0)
            {
                perror("Failed to read from input \n");
                printf("count = %d\n", count);
            }else{

                if(receive[2]==0x32){
                    printf("Header received \n");
                }
                    printf("Byte received [%d] \n", count);
                    printf("Value of Pi = 0x%.2x\n", receive[0]);

          }
 
    }

    pthread_exit(0);
}

Try adding fflush(stdout) and fflush(stderr) as the last statements in your while loop so you can see the outputs while the thread is running.

You thread code looks funky,  main() launches the threads and then immediately drops into phtread_join to wait for the Rx thread to terminate, which doesn't look like it'll happen without killing the program.  Or have you left out some of your code?

Another potential problem is that it looks like you send the command in main before launching the thread to receive the reply.

Regina Choi

unread,
Jul 21, 2016, 11:10:11 PM7/21/16
to BeagleBoard

Hi Wally,

I have tried adding fflush(stdout and fflush(stderr) in the while loop, however, in the UartRxWait thread, the read( ) function is in block waiting for incoming data. Which doesn't output anything. In the case, after start and shut down minicom, the UartRxWait thread running as usual, there is no output from the fflush(stdout) and fflush(stderr) either.

yes, at the moment I have to kill the program to terminate.  I have modified the code such that it loop for only 5 times and terminate the thread.

// UART RX thread
void* uartRxWait(void *param){

    unsigned char receive[100];
    int count;
    static int n;

     while(n<5){

            if ((count = read(file, (void *)receive, 100))<0)
            {
                perror("Failed to read from input \n");
                printf("count = %d\n", count);
            }else{

                if(receive[2]==0x32){
                    printf("Header received \n");   
                }
                    printf("Byte received [%d] \n", count);
                    printf("Value of Pi = 0x%.2x\n", receive[0]);
            }
            n++;
            fflush(stdout);
            fflush(stderr);
    }

    pthread_exit(0);
}


One thing I observed is that, my regular file write is able to write something: I don't understand why?

    fdata = fopen("capture.dat", "w");
    if (fdata == NULL) {
            printf("I couldn't open capture.dat for writing.\n");
            exit(0);
    }
    // save in file
    fprintf(fdata, "%s", "test");


Yes, I send the command before launching the thread to receive the reply. I thought it doesn't matter as the receive byte will be stored in buffer.  Anyway, I tried placing the sending command after receive thread, but the problem still exist. 





 
  

Wally Bkg

unread,
Jul 22, 2016, 10:50:52 AM7/22/16
to BeagleBoard
I noticed you have options.c_cc[VMIN]  = 2;  If for some reason only one character comes in, it'll block forever.  Try using options.c_cc[VMIN]  = 0; so that each char can timeout if its not received.

How big are the Beaglebone uart buffers?

You may still have a race between your write of the data and starting your RX thread.  Try putting the write into your TX thread and launch it after you've launched the RX thread.

Regina Choi

unread,
Jul 24, 2016, 11:11:57 PM7/24/16
to BeagleBoard

Apology for late reply.

I've tried with options.c_cc[VMIN]  = 0; it's still the same issue.

From the datasheet of AM335x, uart rx/tx buffers are 64 bytes.

I've also tried putting tx command in tx thread that activated later than rx thread. Nothing changed as well.

void* uartTxWait(void *param){

    int count;
    usleep(1000000);
    unsigned char cmd[] = {0x10, 0x00, 0x32};    //"Tx From Beaglebone ";


        if ((count = write(file, (char*)cmd, 3))<0){
              perror("Failed to write to the output\n");
              //tcsetattr(file, TCSAFLUSH, &oriopt);         //before exit, undo raw setting
              //return -1;

         }else{
             printf("Byte sent: %d \n", count);
         }


    pthread_exit(0);

Wally Bkg

unread,
Jul 25, 2016, 2:30:12 PM7/25/16
to BeagleBoard
I'm stumped.  Are you now getting timeout error messages from the read thread?

Are you getting the Byte sent: message printf from the TX thread?

Regina Choi

unread,
Jul 25, 2016, 11:32:09 PM7/25/16
to beagl...@googlegroups.com
Thanks for reply. 

I'm not sure why, but I don't get timeout error messages from the read thread (though I have set it to 1 sec) !? It just freeze there waiting for UART input, even though there are UART input coming in.

Yes, I got the Byte sent message printf from TX thread. Please see the attachement.





 



--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to a topic in the Google Groups "BeagleBoard" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/beagleboard/p_v98aypDfk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to beagleboard...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/16a9b1d0-6c0e-4b31-ac7f-490bc091f751%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Screenshot from 2016-07-26 10:46:45.png

William Hermans

unread,
Jul 27, 2016, 1:00:10 AM7/27/16
to beagl...@googlegroups.com
Are you sure everything you're using code wise is thread safe ? There are a lot of library functions that are not thread safe.

You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/CAJ5%2BLfyKahyeih3Db50ZP7yOiLPUyKt0f6sn7dwnijJ6gEx07Q%40mail.gmail.com.

Regina Choi

unread,
Jul 27, 2016, 5:49:55 AM7/27/16
to BeagleBoard

I'm not aware of library functions that are not thread safe, can you give some example library function that is not thread safe?  So if the library function is not thread safe, what would be the effect if we accidentally use it in our program? 

Does that means we cannot use the library function completely in pthread if it is not thread safe and resort to polling mechanism? 

William Hermans

unread,
Jul 27, 2016, 6:11:21 AM7/27/16
to beagl...@googlegroups.com
If I recall correctly, typically anything that is related to interrupts, and blocking file reads( things of this nature - where you're waiting ) are not thread safe as these types of calls can be preempted by another thread. So, what I'd do to test if my assumption is correct.  Is to write a test app without threading. Or perhaps write a callback, but again, callbacks are definitely not thread safe.

I'm not seeing all the posts in this discussion for some reason. But is there a specific reason why you need threads ? Because if you need this sort of process segregation, it may be best to run entirely different processes( multiple executables ), and then use some form of IPC mechanism such as shared memory. Which POSIX shared memory really is fairly simple once you become familiar with it. I had to do this with an application I wrote several months back ,myself. Since a library I was using used callbacks extensively and was not playing nicely on the stack ( preempting my own code routinely ).

Regina Choi

unread,
Jul 27, 2016, 7:17:39 AM7/27/16
to BeagleBoard

Actually I had tried using the sigaction(SIGIO, &saio, NULL) with signal handler function on UART receive. Still there is no triggering/running on the signal handler function. I believe this is quite similar to the callback function that you mention. 

The reason of me using the pthread is that I would like the UART receive to run in asynchronous while my main function can do other stuff, and not polling on UART receive.  Anyway, your suggestion of running multiple executables is insightful. I've never used that before, any get started material can you recommend?  

William Hermans

unread,
Jul 27, 2016, 8:03:34 AM7/27/16
to beagl...@googlegroups.com
perhaps this: http://www.ibm.com/developerworks/aix/library/au-spunix_sharedmemory/index.html there is better material out there, but it may take a while to find it. Something I'll have to do later. But in the meantime you can just google "shm_open()" and read around.

Micka

unread,
Jul 27, 2016, 9:01:45 AM7/27/16
to beagl...@googlegroups.com
My application on the beaglebone black are multithread and for the reception there is a thread. And I don't have any problem receiving data on this thread. Don't forget to use mutex and semaphore. 

William Hermans

unread,
Jul 27, 2016, 4:43:15 PM7/27/16
to beagl...@googlegroups.com
Yeah, this is not something I've personally experienced or tested. Was simply a guess on my behalf. However, I am seeing a lot of code in the groups here lately that over complicates reading, and writing to / from UARTs on the Beaglebone.

For example, this is how simple it is to read from a serial device in Nodejs: https://github.com/wphermans/Bonejs/blob/master/examples/serial-read-example.js

Granted, C is not exactly event driven like javascript. It could be, but essentially it all boils down to polling via a "message pump" ( a loop ).

So basically, all one needs to do is open() on the serial device path, and perform a blocking read(), or write a callback that acts on received data *somehow*. Both methods have similar issues, at least in the context that this process should be handled, or run all by it's self.

As far as setting serial device parameters. This can be done via an external cmd line tool such as getty, fgetty, or similar. If it must be dynamic . . . then you could even wrap these same already existent cmd line tools. I think that ideally, a very simple demo app, should be less than 100 lines of code, and very easy to read.

SO yeah, maybe I'll eventually write up an example in C, and blog on it. But it probably won't be today.

William Hermans

unread,
Jul 27, 2016, 4:52:13 PM7/27/16
to beagl...@googlegroups.com
@Regina,

Here is a discussion I started on the subject last year as I was experimenting with POSIX shared memory. On 43oh.com forums. I have lots of examples here as I was experimenting: http://forum.43oh.com/topic/8686-posix-ipc-shared-memory-mmap/

Regina Choi

unread,
Jul 27, 2016, 11:00:24 PM7/27/16
to beagl...@googlegroups.com
@Micka

Can you share the snippet of your code that configure the UART?  Is it using blocking read on UART?   I suspect maybe the problem may have to do with the incorrect configuration, as after start/shutdown minicom, then the UART C program start to run properly. 






 






Regina Choi

unread,
Jul 27, 2016, 11:02:04 PM7/27/16
to beagl...@googlegroups.com
@ William

Thanks for information, I will have a look at it.

Wally Bkg

unread,
Jul 31, 2016, 11:58:51 AM7/31/16
to BeagleBoard
Since you are not getting the timeout errors from your read thread, there is definitely something wrong with your UART initilization.  And since you need to kill your program with Ctr-C, your read thread would seem to be running and blocking main() in the pthread_join().

Have you read through this guide:

While your device is not a modem, odds are you want to talk to it as if it were, but instead of using  "AT commands" your device will have its own command-response protocol for your program to implement.

The suggestion to use separate programs communicating by shared memory protected by a named semaphore is viable but should not be necessary.  But I often first write a thread function as main() in a stand alone program and move it into a thread function once I've got it basically working.

Regina Choi

unread,
Aug 8, 2016, 1:10:16 AM8/8/16
to BeagleBoard


I tried the transmit and read in one thread, ie main(), the problem I notices is that after my transmit bytes (3 bytes), the read is able to read in the echo from the uart device attached to Beaglebone, then the process terminated where the terminal seemingly waiting for input uart message. Noted that, the uart device echo each byte received. 

As I use command: ps ax | grep readComm in another terminal, and it only shows

2179 pts/1 S+ 0:00 grep readComm

where I know the process readComm has terminated.

I'm wondering, can uart in beaglebone support full duplex?  Because if the device does not echo byte, the uart read is normal.

William Hermans

unread,
Aug 8, 2016, 2:39:46 AM8/8/16
to beagl...@googlegroups.com

I'm wondering, can uart in beaglebone support full duplex?  Because if the device does not echo byte, the uart read is normal.

I think that realistically. Nothing in linux is full duplex - period. You can only be doing one thing at one point in time. However, why don't you show us your code. Maybe someone can spot something you do not realize is happening.

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/b1bcf558-75c9-43ed-aa5a-44b297c8c82a%40googlegroups.com.

toyo

unread,
Jun 23, 2018, 7:13:35 PM6/23/18
to BeagleBoard

I have this same sort of problem with UART4. A Skywire cellular cape lite(from Nimbelink) uses  UART4 to communicate with the beaglebone. I'm not able to receive ATmd responses. I know it is sending because when I minicom to UART4 I see the AT cmd echoed on minicom and the OK response as well. However I dont see the OK response in the application. Here's my init, transmit, receive (all in one C++ class) and main =>


UART_devices::UART_devices(unsigned int bus) {
 this->file = -1;
 this->bus = bus;
 //this->recvAvailable = false;
 this->openUart();
 }


int UART_devices::openUart(void) {
 std::string name;
 struct termios newOpts, oldOpts;

 if (this->bus == 5)
 name = BBG_UART_5;
 else if (this->bus == 4)
 name = BBG_UART_4;


 if ((this->file = open(name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
 perror("\r\nUART: Failed to open the file");
 return -1;
 }


 tcgetattr(this->file, &oldOpts);          //save current port settings
 bzero(&newOpts, sizeof(newOpts));   //clr struct for new port settings

 // Set up the communications options:
 // 115200 baud, 8-bit, enable receiver, no modem control lines
 
 newOpts.c_cflag = B115200 | CS8 | CREAD | CLOCAL;
 newOpts.c_iflag = IGNPAR | ICRNL;     //ignore partity errors
 newOpts.c_oflag = 0;   //raw output
 newOpts.c_lflag = 0;   //non-canonical input
 

 newOpts.c_cflag = (newOpts.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
 // disable IGNBRK for mismatched speed tests; otherwise receive break
 // as \000 chars
 newOpts.c_iflag &= ~IGNBRK;         // disable break processing
 newOpts.c_lflag = 0;                // no signaling chars, no echo,
 // no canonical processing
 newOpts.c_oflag = 0;                // no remapping, no delays
 newOpts.c_cc[VMIN] = 0;            // read doesn't block
 newOpts.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

 newOpts.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

 newOpts.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
 // enable reading
 newOpts.c_cflag &= ~(PARENB | PARODD);      // shut off parity
 //newOpts.c_cflag |= parity;
 newOpts.c_cflag &= ~CSTOPB;
 newOpts.c_cflag &= ~CRTSCTS;

 //init ctrl xters
 newOpts.c_cc[VINTR] = 0;   //ctrl c
 newOpts.c_cc[VQUIT] = 0;   //'ctrl-\'
 newOpts.c_cc[VERASE] = 0;   //del
 newOpts.c_cc[VKILL] = 0;   //@
 newOpts.c_cc[VEOF] = 4;   //ctrl d
 newOpts.c_cc[VTIME] = 0;   //inter-xter timer unused  - 0
 newOpts.c_cc[VMIN] = 1;   //blocking read until 1 xter arrives   - 1
 newOpts.c_cc[VSWTC] = 0;   //'\0'
 newOpts.c_cc[VSTART] = 0;   //ctrl q
 newOpts.c_cc[VSTOP] = 0;   //ctrl s
 newOpts.c_cc[VSUSP] = 0;   //ctrl z
 newOpts.c_cc[VEOL] = 0;   //'\0'
 newOpts.c_cc[VREPRINT] = 0;   //ctrl r
 newOpts.c_cc[VDISCARD] = 0;   //ctrl u
 newOpts.c_cc[VWERASE] = 0;   //ctrl w
 newOpts.c_cc[VLNEXT] = 0;   //ctrl v
 newOpts.c_cc[VEOL2] = 0;   //'\0'   


 tcflush(this->file, TCIFLUSH);              //discard file information not transmitted   
 tcsetattr(this->file, TCSANOW, &newOpts);   //changes occur immmediately

 return 0;
 }


 int UART_devices::transmitData(void)
 {
 int count;

 if ((count = write(this->file, &this->tranData, this->tranSize)) < 0)
 {
 perror("\r\nFailed to write to the output");
 return -1;
 }

 return 0;
 }


 int UART_devices::receiveData(void)
 {
 int count = 0;
 
 count = read(this->file, (void*)this->recvData, 100);
 this->recvData[100] = 0;
 this->recvSize = count;

 
 return 0;

 }

************************************************************************************************


Here's main =>

void sendAT_CMD(UART_devices device, unsigned char *payload, int size)
{
 //transmit AT cmd
 device.setTranData(payload, size);
 device.setTranSize(size);
 device.transmitData();
}

UART_devices cellularBeagle(4);

int main()
{

 unsigned char tempCellular[100];

 unsigned char arrSendAT[4] = { 'A', 'T', '\r', '\n' };
 unsigned char arrSendAT_SGACT[14] = { 'A', 'T', '#', 'S', 'G', 'A', 'C', 'T', '=', '1', ',', '0', '\r', '\n' };


 sendAT_CMD(cellularBeagle, arrSendAT_SGACT, 14);

 while(1)
{
 if (cellularBeagle.getRecvSize() > 0)
 {
 memcpy(tempCellular, cellularBeagle.getRecvData(), cellularBeagle.getRecvSize());
 for (int i = 0; i < cellularBeagle.getRecvSize(); i++)
 cout << "\t" << tempCellular[i] << endl;
Reply all
Reply to author
Forward
0 new messages