Getting serial communication to be reliable (aka garbled input and M4 Sketch STOP failed)

Discussion in 'UDOO NEO' started by Maurice, Dec 8, 2016.

  1. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    I try to communicate from a Java process to the M4 and a daisy chained Mega. After a couple of sends the input on the M4 seems to get garbled (nonsense) and if I try to re-load code via the Arduino IDE the IDE responds with the dreaded M4 Sketch Stop (or Start) failed.

    I started out with a baud rate of 115200 and have dropped to 9600, but it doesn't make a difference. I also have had this problem before I chained another Mega.

    Can data be sent too quick? Should a different setup be done on the port? Does the string handling become a problem?

    In Java I have created with the help of the GNU rxtx library the following code to communicate with the M4 from the i.MX6:

    Code:
        private static SerialPort openPort(CommPortIdentifier identifier, int block)  throws PortInUseException {
           if (identifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {
               SerialPort port = (SerialPort)identifier.open(SerialComm.class.getName(), block);
               try {
                   port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                   // port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
                   port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT);
                   port.setOutputBufferSize(3 * 80);
                   port.setInputBufferSize(3 * 80);
               } catch (UnsupportedCommOperationException e) {
                   throw new AssertionError(String.format("Cannot configure serial port %s", identifier.getName()));
               }
    
               return port;
           }
    
           throw new IllegalArgumentException(String.format("Port %s is not a serial port", identifier.getName()));
       }
    
    public void println(String identifier, String value) {
           try {
               if (writeLock.tryLock(50, TimeUnit.MILLISECONDS)) {
                   try {
                       System.out.println(identifier + ":" + value);
                       out.write(identifier.getBytes(StandardCharsets.US_ASCII));
                       out.write(':');
                       out.write(value.getBytes(StandardCharsets.US_ASCII));
                       out.write('\r');
                       out.flush();
                   } finally {
                       writeLock.unlock();
                   }
               }
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
    
    The lock and the System.out are attempts at debugging....

    On the M4 I read the code in the following way:
    Code:
    void loop() {
      const unsigned long now = millis();
      static String imxInput;
      static String megaInput;
    
      if (checkSerial(imxSerial, imxInput)) {
        megaSerial.println(imxInput);
        imxSerial.println(imxInput);
        dispatchCommand(imxInput);
        imxInput = "";
      }
    
      if (checkSerial(megaSerial, megaInput)) {
        imxSerial.println(megaInput);
        megaInput = "";
      }
    
      for (Module **mpp = modules; *mpp; mpp++) {
        (*mpp)->loop(now, imxSerial);
      }
    }
    
    void dispatchCommand(String command) {
      int index = command.indexOf(':');
      if (index > 0) {
        String id = command.substring(0, index);
        String data = command.substring(index + 1);
    
    
        for (Module **mpp = modules; *mpp; mpp++) {
          if ((*mpp)->isModule(id)) {
            (*mpp)->processCommand(data);
            break;
          }
        }
      }
    }
    
    
    bool checkSerial(Stream& stream, String& string) {
      int incoming = stream.read();
      if (incoming > 0 && incoming != '\n' && incoming != '\r') {
        string += (char)incoming;
      }
    
      return incoming == '\r';
    }
    
    On the Arduino I have the following:
    Code:
    HardwareSerial& neoSerial = Serial1;
    
    void setup() {
      neoSerial.begin(57600);
      Serial.begin(9600);
      for (Module **mpp = modules; *mpp; mpp++) {
        (*mpp)->begin();
      }
    }
    
    void loop() {
      const unsigned long now = millis();
      static String neoInput(80);
    
      if (checkSerial(neoSerial, neoInput)) {
        dispatchCommand(neoInput);
        neoInput = "";
      }
    
      for (Module **mpp = modules; *mpp; mpp++) {
        (*mpp)->loop(now, neoSerial);
      }
    }
    
    void dispatchCommand(String command) {
      Serial.print("dispatch command ");
      Serial.println(command);
      int index = command.indexOf(':');
      if (index > 0) {
        String id = command.substring(0, index);
        String data = command.substring(index + 1);
    
        for (Module **mpp = modules; *mpp; mpp++) {
          if ((*mpp)->isModule(id)) {
            (*mpp)->processCommand(data);
            break;
          }
        }
      }
    }
    
    bool checkSerial(Stream& stream, String& string) {
      int incoming = stream.read();
      if (incoming > 0 && incoming != '\n' && incoming != '\r') {
        string += (char)incoming;
      }
    
      return incoming == '\r';
    }
    
     
  2. waltervl

    waltervl UDOOer

    Joined:
    Dec 12, 2015
    Messages:
    2,314
    Likes Received:
    580
    Between what devices starts the garbling? mega-m4? m4-a9? What if you use minicom -D /dev/ttyMCC to monitor the m4-a9 communication?
     
  3. waltervl

    waltervl UDOOer

    Joined:
    Dec 12, 2015
    Messages:
    2,314
    Likes Received:
    580
    Do you have a 5V level shifter in between M4-Mega that hold things up?
     
  4. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    Yes, I have a level shifter in between. In my test I have the LCD connected to the Mega, and after a few commands for the LCD the data received is incorrect.

    In my tests with minicom I did not encounter a problem. I'll add some debugging tomorrow.
     
  5. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    @waltervl I am fairly sure it is the Neo M4 crashing. Just tried some quick things and the Neo M4 seems not to keep up, and then fails to work as I get a stop or start failed error.

    @Andrea Rovai, is my assumption correct?
     
  6. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    I tried to keep reading the serial input faster, but it doesn't help. By faster I meant, as long as there is input:
    Code:
    QueueArray<String> commands;
     while(checkSerial(imxSerial, imxInput)) {
        commands.enqueue(imxInput);
        imxInput = "";
      }
    
     if (!commands.isEmpty()) {
        String command = commands.dequeue();
        megaSerial.println(command);
        imxSerial.println(command);
        dispatchCommand(command);
      }
    
    This is the output on the Mega serial showing that it fairly quickly goes wrong (already after the first three):
    LCD received: 'PRINTAT0,0:i = 1 '
    LCD received: 'PRINTAT0,0:i = 2 '
    LCD received: 'PRINTAT0,0:i = 3 LCDLCDLCD:pRINTAT0,0:i = 24 RINTAT0,0:i = 25 '
    LCD received: 'PRINTAT0,0:i = 26 '
    LCD received: 'PRINTAT0,0:i = 27 '
    LCD received: 'PRINTAT0,0:i = 34 '
    LCD received: 'PRINTAT0,0:i = 50 LCD'
    LCD received: 'PRINTAT0,0:i = 66 '
    LCD received: 'PRINTAT0,0:i = 67 '
    LCD received: 'PRINTAT0,0:i = 68 LCDLCD:pRINTAT0,0:i = 74 LCD::pRINTAT0,0:i = 82 '
    LCD received: 'PRINTAT0,0:i = 86 '
    LCD received: 'PRINTAT0,0:i = 87 LCD:pRINTAT0,0:i = 96 LCT0,0:i = 127 '


    Edit: I think this is a flow control problem. However, I do not know if Arduino or Neo provides any flow control. I haven't found examples that do.
     
    Last edited: Dec 9, 2016
  7. waltervl

    waltervl UDOOer

    Joined:
    Dec 12, 2015
    Messages:
    2,314
    Likes Received:
    580
    When I was working on my tutorial about the webpage control I saw also that after the first reading of lines from /dev/ttyMCC the output was not correct but it stayed fine further on.
    If you think it is flow control perhaps put some small delays (couple of ms) in between println messages to see if it stabilises the output. If it does we can work on that further.
     
  8. waltervl

    waltervl UDOOer

    Joined:
    Dec 12, 2015
    Messages:
    2,314
    Likes Received:
    580
    I can't see how you declared/defined megaSerial and imxSerial but normally they are named Serial and Serial0. What if you just use these names? Perhaps your way of declaring changes some hidden settings.
     
  9. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    I've done some experimenting and the communication is ok if I stay above 75ms between each message. This confirms to me that it is a flow control problem. However, I do not know if the Neo implements flow control signals with RTS/CTS. At least, configuring the ports with a RTS/CTS flow didn't seem to help.

    Who has a more in depth explanation and, hopefully, a better solution than 'just wait a few milliseconds'...?

    Code:
           lcd.clear();
           Runnable command = () -> {
               lcd.print(0, 0, "Message " + (++i));
           };
           
           executor.scheduleAtFixedRate(command, 1, 75, TimeUnit.MILLISECONDS);
    
    @waltervl, the megaSerial and imxSerial are defined as follows:
    Code:
    HardwareSerial& imxSerial = Serial;
    HardwareSerial& megaSerial = Serial0;
    
     
  10. sirrab

    sirrab UDOOer

    Joined:
    Jul 26, 2014
    Messages:
    264
    Likes Received:
    32
    What about software control, like X-on and X-off?
     
  11. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    394
    Likes Received:
    87
    Yes, I think I have to switch to XON/XOFF flow control. I have done a test with a delayed send queue, but I saw that even with the delay an error occurred after a while. Too fragile for my liking.

    Do you happen know an example of implementing XON/XOFF?
     
  12. sirrab

    sirrab UDOOer

    Joined:
    Jul 26, 2014
    Messages:
    264
    Likes Received:
    32
    No, I wish I could help you. I'm still trying to learn this micro computer software stuff.
     

Share This Page