This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to correctly read data from UART?
#1
The Wiring Pi library has an interrupt function, but it does not work for the UART. Now I use a separate thread that checks for data in the port every 50ms, but using multithreading because of UART is not very efficient. Maybe there is an example of working with interrupts ( flags for serialports )?
Reply
#2
I just suppose that there may be a Interrupt On Change on the RX pin. But the hardware should be able to gather the serial data without software intervention. It may get an interrupt when the buffer will be full. This is commonly used for aplenty of MCU.
Anyways linux OS is not a RTOS, so difficult to keep focus only for one task.
Light blue words might be a link. Have you try to click on them? Big Grin
Reply
#3
I used interrupt function for RX contact ( 10 pin ), no result. Checking the buffer takes a lot of CPU time it is implemented using the function "serialDataAvail (fd)" if you just put it on an infinite loop it is - 30% CPU load ( 1 core) you can pause the stream and then the load will be 1-2% but it is still not rational. The UART port is considered Linux as comport and may be can set flag to comport when data appears. On windows, this flag is EV_RXCHAR, but I haven't found any working examples for Debian.
Reply
#4
Sorry, I have a vague idea about what you're trying to accomplish. Even a little about wiringPI. I know a little more about wiring because of Arduino.
Anyway, it might help more if you post an example that shows your intents. I think that the wiring serial library sets a buffer of 64 bytes. But what you're are expecting to obtain from the serial port in so tight period is rather strange approach. There are just two conditions:
  • polling the buffer
  • set an interrupt when the buffer is full or when the RX line drop to low level. The keep polling until the reception has finished.
Light blue words might be a link. Have you try to click on them? Big Grin
Reply
#5
Here is an example in which I use a multithreading to check the UART. 

The Protocol method UART_Protokol::Event() is used for polling data:

Code:
#include "protokol_obmena_cherez_uart.h"

#include <wiringSerial.h>

#include <errno.h>

#include <QDebug>


UART_Protokol::UART_Protokol(){}

UART_Protokol::~UART_Protokol(){}


void UART_Protokol::StartProtokol( bool selftest )
{
   if ((fd = serialOpen ("/dev/ttyS1", 115200)) < 0)
   {
     qDebug()<<"error open port"<<strerror (errno) ;
   }
   sp_ResetAll();    
   if (selftest) sp_Send("Start");
}


void UART_Protokol::Event()
{
  qDebug()<<"Serial start";
  while ( true )
 {
   if(serialDataAvail (fd))   //check buffer
  {
     sp_Read();                
     if(sp_packetAvailable)            
     {
      ParseCommand();                  
      sp_ResetAll();                    
     }
  }
   std::this_thread::sleep_for(std::chrono::milliseconds(50));    //wait 50ms;
 }
}



void UART_Protokol::sp_Reset()

{
 sp_startMarkerStatus = 0;  
 sp_stopMarkerStatus = 0;  
 sp_dataLength = 0;    
 sp_packetAvailable = false;

}


void UART_Protokol::sp_ResetAll()
{
 sp_dataString = "";  
 sp_Reset();    
}



void UART_Protokol::sp_Read()
{
 while(serialDataAvail(fd) && !sp_packetAvailable)            
 {
   int bufferChar = serialGetchar(fd);                          
   if(sp_startMarkerStatus < sp_startMarker.length())        
   {
    if(sp_startMarker[sp_startMarkerStatus] == bufferChar)  
    {
      sp_startMarkerStatus++;                              
    }
    else
    {
      sp_ResetAll();                                        
    }
   }
   else
   {
      if(sp_dataLength <= 0)                                
      {
        sp_dataLength = bufferChar;
      }
     else                                                  
     {
       if(sp_dataLength > sp_dataString.length())          
       {
           sp_dataString += (char)bufferChar;                
       }
       else                                                
       {
         if(sp_stopMarkerStatus < sp_stopMarker.length())    
         {
             if(sp_stopMarker[sp_stopMarkerStatus] == bufferChar)  
           {
             sp_stopMarkerStatus++;                              

             if(sp_stopMarkerStatus == sp_stopMarker.length())
             {                                                         
               sp_Reset();
               sp_packetAvailable = true;                      
             }
           }
           else
           {
             sp_ResetAll();                                    
           }
         }
       }
     }
   }
 }
}



void UART_Protokol::sp_Send(QString data)
{
 serialPuts(fd, "");                            
 serialPuts(fd,sp_startMarker.toUtf8());          
 serialPutchar(fd,data.length());                
 serialPuts(fd,data.toUtf8());                    
 serialPuts(fd,sp_stopMarker.toUtf8());          
}



void UART_Protokol::sp_Send_integer(QByteArray data)
{
 serialPuts(fd, "");                                   //Set log 0 voltage                    
 serialPuts(fd,sp_startMarker.toUtf8());    // Write start marker
 serialPutchar(fd,data.length());              // Write length data  
 serialPuts(fd,data);                              //Write data
 serialPuts(fd,sp_stopMarker.toUtf8());   //Write stop marker       
}


void UART_Protokol::ParseCommand()
{
  MyServer myserver;
 if(sp_dataString == "Start") { TransmitData = "ready"; sp_Send(TransmitData); qDebug()<<"Self-test"; }
 if(sp_dataString == "ready") qDebug()<<"Self-test";
 if (sp_dataString =="MG1")  myserver.write("MG1");
 if (sp_dataString =="MG0")  myserver.write("MG0");
 if (sp_dataString =="MG")  qDebug()<<"Сalibration...";
}

Start streams TCP server and UART. Use the server in one stream with UART is not possible because it is very slow:
Code:
#include <QCoreApplication>

#include <myserver.h> 

#include <protokol_obmena_cherez_uart.h>

#include <QDebug>

#include <thread>


int main(int argc, char *argv[])

{

   QCoreApplication a(argc, argv);


   MyServer Server;

   Server.startserver();

   UART_Protokol Serial;

   Serial.StartProtokol( false );

   std::thread serial (&UART_Protokol::Event, Serial);  //Run Event in separate thread

   return a.exec();

}

If configure UART to work on interrupts as on a Tcp server, may be able to run them in a single thread and save CPU time.  At least replace the polling, interrupt and will not need to slow down the flow every 50ms.
Reply
#6
Hardly accomplished, Linux is not a RTOS, so the timing for your programs are under multitasking schedules. There won't be any task that will hold the system to switch to another task on the schedule.

You might find some documentation to get a RTOS. Further details are found if you put linux RTOS in a web search engine.
So for your case, I think you may set a flag when the interrupt triggers and let the rest of the program, later on, to check it and clear it once is accepted. This is a mixing within an interrupt and a polling method.
Just because of that, the time of reading the flag might be slightly postponed. Anyway a server over a UART is pretty choked situation.
The interrupt driven as you're intended to apply, I think is non feasible.

BTW, please limit your source code. 80 columns width is almost necessary to see correctly on all bulletin boards.
Light blue words might be a link. Have you try to click on them? Big Grin
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)