1
\$\begingroup\$

I am writing a serial communication program on LINUX to send command to PIC32 MCU. When I am sending two command one after another as given in program MCU will perform action on first one only and if I give one second delay between command1 and commad2 it will perform action on both command.Is there any way I can achieve same one without using delay?

serial.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>   
#include <termios.h>
#include <unistd.h>  
#include <errno.h>   
int main(int argc,char* argv[])
{
    int fd;/*File Descriptor*/
    fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY);                                                                                                                                                               
    struct termios SerialPortSettings; 
    tcgetattr(fd, &SerialPortSettings);
    cfsetispeed(&SerialPortSettings,B115200); 
    cfsetospeed(&SerialPortSettings,B115200); 
    SerialPortSettings.c_cflag &= ~PARENB;
    SerialPortSettings.c_cflag &= ~CSTOPB; 
    SerialPortSettings.c_cflag &= ~CSIZE;
    SerialPortSettings.c_cflag |=  CS8;    
    SerialPortSettings.c_cflag &= ~CRTSCTS;
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; 
    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);         
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); 
    SerialPortSettings.c_oflag &= ~OPOST;
    SerialPortSettings.c_cc[VMIN] = 10; 
    SerialPortSettings.c_cc[VTIME] = 0;
    if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) 
        printf("\n  ERROR ! in Setting attributes");
    else
        printf("\n  BaudRate = 115200 \n  StopBits = 1 \n  Parity   = none");

    char command1[]="\xAA\x55\xCC\xD0\x00\x00\x01\x00";
    char command2[]="\xAA\x55\xCC\xD0\x00\x00\x02\x00";
    int  bytes_written  = 0;  

    bytes_written = write(fd,command1,sizeof(command1));
    tcflush(fd, TCIFLUSH); 
    //sleep(1); 
    //if I not use one second delay MCU perform action on command1 only
    //if I use one second delay MCU perform action on both command1 and command2 
    bytes_written = write(fd,command2,sizeof(command2));
    tcflush(fd, TCIFLUSH); 
    close(fd);
    return 0;

                                                                                                                                                                                      1,1           Top
\$\endgroup\$
  • 2
    \$\begingroup\$ Your problem is in the way you're receiving on your PIC32, not in the way you're sending from Linux. \$\endgroup\$ – brhans Jan 26 at 4:22
  • \$\begingroup\$ It seems to me that you need to read the first response before you send the second command. In your program, you don't seem to be reading the responses at all -- how do you know when they occur? \$\endgroup\$ – Dave Tweed Jan 26 at 4:52
  • \$\begingroup\$ "MCU will response" - by 'response' do you mean the MCU turns on or blinks the particular LED? \$\endgroup\$ – Bruce Abbott Jan 26 at 6:24
  • \$\begingroup\$ Yes response means MCU is performing that action @BruceAbbott \$\endgroup\$ – raj123 Jan 26 at 6:36
  • \$\begingroup\$ Its a LED blinking and ON action so I can see MCU perform which particular action@DaveTweed \$\endgroup\$ – raj123 Jan 26 at 7:15
2
\$\begingroup\$

The PIC32 UART receiver has an internal buffer which can store up to 8 characters. If your code cannot read the data out of this buffer fast enough it will 'overrun' and further received characters will be lost until the overrun error is cleared.

Without seeing your receive code I can't say exactly why this is happening, but since the first command is apparently received and executed correctly I suspect the serial port is not being read fast enough (or at all) while processing the command, and this is taking so long that the UART buffer overruns before it finishes. There are several ways you can fix this:-

  1. Add a delay after sending each command, with a time period longer than the time it takes for the PIC to process the command (light LEDs etc.).

  2. Continue receiving data while processing the command. The normal way to do this is have each received character generate an interrupt. The interrupt halts your program wherever it may be, saves the machine state and jumps into your interrupt handler, which reads characters out of the UART buffer and stores them in a RAM buffer. On exit the machine state is restored and your program continues as if nothing happened, except you now have some characters in the RAM buffer waiting to be processed.

  3. After receiving and processing a command, send an 'acknowledge' character back to the Linux machine. The Linux machine is programmed to wait until until it has received this character before sending the next command. Different characters could be sent back depending on what the PIC wants to tell Linux about its status.

  4. 'Echo' back each character after it is received. The Linux machine waits for the echo and (if it matches the transmitted characters) knows that it has been received correctly. The PIC delays echoing back the last character until it has processed the command and is ready to receive the next command.

  5. Use a standard 'software' flow control protocol such as XON/XOFF, which uses two control codes to tell the transmitter when it can send data.

Several of these techniques could be combined for enhanced security and reliability.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.