8 Replies Latest reply on Oct 29, 2015 4:12 AM by Ozmo

    Custom UART Baud Rates

    Ozmo

      I am looking for some way to read and write to an Edison UART via a non typical baud rate.

       

      Its a particular hardware I have - quite slow at about 1600 baud and I wish to create an Arduino sketch on the Edison to communicate with it.

       

      I have tried -

       

      1) Serial1.begin(1600); 

       

          On Edison its failing (works ok on Arduino Unos) -  Serial1 only supports certain fixed baud rates: 50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400 + some higher ones

       

          I've looked at the code - big switch statement to select a fixed constant (one per supported baud rate) and passes this to tcsetattr() which I have not yet found the code for.

       

      2) I have tried calling linux stty via system ( and also direct on the terminal command line)

         system("stty -F /dev/ttyMFD1 1600");
          Error given is:  stty: invalid argument '1600'    when anything other than the values above are displayed

       

      3) I have tried the Linux trick of calling  ioct (to use ASYNC_SPD_CUST aliasing (link)). But no matter what i specify, even standard baud rates -  TIOCSSERIAL command just does not seem to be implemented.

       

          ioctl(m_Socket_fd, TIOCGSERIAL, &serinfo);    //this is ok - reads all values.

          ioctl(m_Socket_fd, TIOCSSERIAL, &serinfo);     //even writing this data back without changing anything returns an error

       

      4) I have looked into SoftwareSerial - but its not supported on non AVR platforms.

       

      5) Also tried of course just using closest supported baud - but it just reads garbage.

       

       

      I think my best bet is (3) above if I anyone knows how to get the TIOCSSERIAL to work - but any other ideas considered.

       

        // Set non-standard baudrate (all my error checking removed)

        int baudrate = 1600;

        struct serial_struct serinfo;

        int r=ioctl(m_Socket_fd, TIOCGSERIAL, &serinfo);

        serinfo.flags &= ~ASYNC_SPD_MASK;

        serinfo.flags |= ASYNC_SPD_CUST;

        serinfo.custom_divisor = serinfo.baud_base / baudrate;

        r = ioctl(m_Socket_fd, TIOCSSERIAL, &serinfo);

        tcflush(m_Socket_fd, TCIFLUSH);

       

      Out of ideas now - would anyone know any way to set the UART to a nonstandard baud rate please?

       

      Thanks very much,

      A.

        • 1. Re: Custom UART Baud Rates
          Intel_Peter

          Hello Ozmo,

           

          Unfortunately as you mentioned in point 2, those non-standard baud rates are not supported by Edison. In theory they might be possible to achieve, if you modify the serial chip's driver or if you are able to design a library similar to software serial that works on Edison. Nevertheless, out of the box it is not possible to use such baud rate, to do so, it'll take major research and probably will be quite challenging however maybe possible.

           

          Peter.

          • 2. Re: Custom UART Baud Rates
            Ozmo

            Lots of code examining later.... I found a way of doing it!  Using the newer version of ioctl that has a BOTHER flag - this seems to work.

             

            I couldn't do this from the Arduino environment as it was conflicting with the libraries the Arduino code used - but I was able to create a separate program and call this from the Arduino code.

             

            1) I created a file sb.c in the Edison root with the contents below(tweek the settings as required) - and compiled it with "gcc sb.c -o setbaud"

             

            #include <stdio.h>

            #include <errno.h>

            #include <asm/termios.h>

            #include <fcntl.h>

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

                int port = open("/dev/ttyMFD1", O_RDONLY);

                int speedI = atoi(argv[1]);

                int speedO = atoi(argv[2]);

                struct termios2 te;

                ioctl(port, TCGETS2, &te);

                te.c_cflag = BOTHER; //the important bit!

                te.c_cflag |= (CLOCAL | CREAD | CS8 | CRTSCTS); //8 bit no hardware handshake

                te.c_cflag &= ~CSTOPB;   //1 stop bit

                te.c_cflag &= ~CRTSCTS;  //No CTS

                te.c_cflag &= ~PARENB;   //No Parity

                te.c_cc[VMIN]=0;         //min chars to read

                te.c_cc[VTIME]=0;        //time in 1/10th sec wait

                te.c_lflag = 0; //&= ~ICANON;   //dont wait for return

                te.c_iflag = IGNPAR | ICRNL;

                te.c_oflag = 0;

                te.c_ispeed = speedI;

                te.c_ospeed = speedO;

                //cfmakeraw(&tio);

                int ret = ioctl(port, TCSETS2, &te);

                close(port);

                if (ret != 0)

                    perror("Cannot change baud rate\n");

                else

                    printf("Successfully changed baud rate.\n");

            }

             

             

            2) I called this from the Arduino sketch in the init like this:

             

            Serial1.begin(9600);  //First Open the port

            system("./home/root/setbaud 1800 1800 > /dev/ttyGS0"); //and set it to custom baud rate (outputting results to Arduino Monitor)

             

             

            And Serial1 is now communicating at the custom non-standard baud rate..

             

             

             

            Note - if you query Serial1 for its baud using stty, stty incorrectly reports 0 baud. But I've found it to be actually functioning at the requested baud rate.

            • 3. Re: Custom UART Baud Rates
              Ozmo

              ...However... I encountered a new problem. This happens to me even when using standard baud rates... as shown in the code below.

               

              The device I am listening to is a long constant stream of data at a low baud rate, with no let-ups - and the Edison UART seems to want to keep listening and will not make the data available - until you disconnect the wire from RX or there is a communications error - then you get your all data available in one big chunk all at once.

               

              I think the problem can also be demonstrated with the following code (below) - Shorting out Pin 0&1 (RX&TX) I would have expected data out on the TX would appear on the RX - but it doesn't !

               

              - Although it appears to be going out fine (I can monitor data on the TX) - it is *Not* being received and you get no displayed input on the monitor...

               

              ..That is Unless you slow the data down, by adding the delay I have commented out in the code below - any lower a delay than 125mS at this baud rate and you don't get any data from Serial1.available or Serial1.read()

               

               

              Delays cannot help me with my problem though as the hardware Im listening to is constant stream - and I cannot get the Edison to read a constant stream of data ?

              Is this an Edison hardware issue - or is it something I'm doing wrong? Some flag I can set?

               

              My Edison is flashed with the latest (October 2015) Yocto 2.1 image (I have tried 2.0 also). I am using latest Edison downloaded IDEs.

               

              Thanks very much,

              A.

               

               

               

               

              //Pin 0 and 1 (RX & TX) are physically shorted to make a loopback
              void setup()
              {
                Serial.begin(115200);

                Serial1.begin(2400);

                Serial.println("Start");

              }

              void loop()

              {

                for(int n='A';n<'Z';n++)

                  Serial1.print((char)(n));

                Serial1.flush();

               

                //delay(125); //need 125 delay here or it chokes up and we receive nothing- but why?

               

                while(Serial1.available())

                { //  ****never gets to here****

                  char c = Serial1.read();

                  Serial.print(c);

                }

                Serial.println(".");

              }

              • 4. Re: Custom UART Baud Rates
                Intel_Peter

                I believe this might be related to what DiegoV_Intel mentions in Re: Serial connection seems to be refused (at least one way). The Edison seems to not be receiving data but it was due to how the data was being sent, Edison needs the carriage return and newline characters, otherwise something like your description will happen. Check the thread above, it might help you.

                 

                Peter.

                • 5. Re: Custom UART Baud Rates
                  Ozmo

                  Thanks - was a good idea to test - I have modified the code to the below to send a message with a return on the end to see if its the problem

                  - its really simple code and I cannot see anything wrong with it - just wont work though ?

                   

                  //This simple code transmits ok - but the UART fails to receive anything

                  //even though Pin 0 and 1 (RX & TX) are shorted to make a loopback

                  void setup()

                  {

                    Serial.begin(115200); //Open the Monitor Console in Arduino IDE to see debug messages

                    Serial1.begin(2400); //UART

                    Serial.println("Start");//To the Console

                  }

                  void loop()

                  {

                    Serial1.print("This is a test\r\n"); //Send Via UART (with return char) (it does send ok)


                    while(Serial1.available())

                    {//Never gets here

                      char c = Serial1.read();

                      Serial.print(c);

                    }

                    Serial.println("."); //just to prove loop is running

                  }

                   

                   

                   

                  The problem is I want to solve is I am seeing this same thing when I connected the Edison to the device I want to read from (no data RX when stream of data is constant with no breaks)

                  • 6. Re: Custom UART Baud Rates
                    Ozmo

                    Tonight I tried the above code with a real Leonardo Arduino and also a Mega Arduino - and the code worked on those hardware as expected - sending and receiving data ok.

                     

                    Also tried connecting the Mega's TX to the RX of the Edison and the Edison just cannot receive the data.

                     

                    Also tried all sorts of combinations of linux uart flags to make sure Edison was in a raw a state as possible and not expecting return characters...

                     

                    So, it appears to be some internal issue with the Edison UART RX handling - at a guess, it's as if ; once data is received an Interrupt for the next data items fires before the Edison has stored the previous bytes safely - and so the input continually gets overwritten before its used.

                     

                    Don't see any workaround  :/    UART appears to be not usable and no Software uart possible.

                    • 7. Re: Custom UART Baud Rates
                      Intel_Peter

                      I've been running some tests, and I've some conclusions based on what I saw. The data sent to Edison, even though it is at a low baud rate, is sent so often that it may be filling up the buffer. This might be causing the Edison to loose data.

                       

                      This behavior seems to be reduced by adding a delay of at least 25ms and up. So, a long constant stream might be possible if the data is not sent so often. A small delay between data streams that provides the serial port enough time to read the whole buffer before it's full again might help the Edison to not loose data.

                       

                      Also, results improved by using a different device to send the data (e.g. an Arduino UNO). I'm not sure why but the port tended to crash less if the same data was sent by a different device instead of just shorting Rx and Tx on the Edison.

                       

                      Peter.

                      • 8. Re: Custom UART Baud Rates
                        Ozmo

                        Thanks for replicating it - very same thing I'm seeing.

                         

                        Unfortunately in my case I cannot modify the pre-built final source hardware to add delays- (or Id pick a different baudrate for starters).

                        But other old-school devices handle this same stream fine.

                         

                         

                        I have tried installing Debian on the Edison now. No change - same error (nothing received when busy).

                        (I'm finding some very nice features on the Debian installation...)

                         

                        By my measurements at different baud rates - You seem to need 33% quiet time on the line to get it to work

                         

                         

                        - ie. if a message is taking 400ms on the RX line you need another 200ms quiet time on the line after that - any less quiet time and the RX driver doesn't have enough time to put-away the data before getting interrupted for the next message and you end up with no data received.

                         

                         

                        This would *not* be normal for a UART - has to be some bug in the serial driver.

                         

                        thanks.A.