Author Topic: looking for a simple linux uart application that handles /dev/ttyUSB0 things  (Read 21059 times)

0 Members and 1 Guest are viewing this topic.

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
hi
i am having a lot of issue with an arduino 2009 interfaced to a linux host.
i haven't understand if the problem is related to the arduino side, or to the linux side, my problem is … data lost in the linux host, so it is going like a nightmare to understand why.

does anyone has a C source of a simple application that uses the serial port to communicate up to 115200bps ?

i'd like to be sure i have implemented everything correctly in the linux side, if so, i will investigate the arduino side

unfortunately i do not have any python machine on such a machine, the arduino is soldered to a SoC, so we are speaking about OpenWRT application not a laptop application and for other reasons i am far away from any practical possibility to unsolder things

let me know, more tests are needed
thanks  :-+
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
also, basically my linux side code is similar to this one
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6289
  • Country: 00
On mac osx I am using 'screen' to dump serial ports. E.g.

screen /dev/tty.usbmodemfa131 115200

You can try the same on Linux or just dump that serial device directly using cat or similar (Mac OSX has a problem with settty so cat didn't work for me).

If you go the Python way, here is a sample serial dumper

https://github.com/zapta/linbus/tree/master/tools/serial
 

Offline Scrts

  • Frequent Contributor
  • **
  • Posts: 798
  • Country: lt
On mac osx I am using 'screen' to dump serial ports. E.g.

screen /dev/tty.usbmodemfa131 115200

You can try the same on Linux or just dump that serial device directly using cat or similar (Mac OSX has a problem with settty so cat didn't work for me).

If you go the Python way, here is a sample serial dumper

https://github.com/zapta/linbus/tree/master/tools/serial

UART device is a char device in linux, so you just open it as a simple file in your application and do a read or write. Take any example of file reading/writing and use /dev/ttyUSB0 as your file.

In addition to screen:
you can also use echo "test" > /dev/ttyUSB0 to send data or cat /dev/ttyUSB0 to read everything from the console. The problem is that you need to send or receive ascii chars in order to see them on the console properly.
 

Offline suicidaleggroll

  • Super Contributor
  • ***
  • Posts: 1453
  • Country: us
kermit, minicom, screen, stty/echo/cat, or write your own in practically any programming language you want.  Lots of options, which one to choose depends on what type of data is being sent and how much effort you want to put into this.  For simple ascii I prefer either minicom or screen, for binary I typically write something in C.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6289
  • Country: 00
you can also use echo "test" > /dev/ttyUSB0 to send data or cat /dev/ttyUSB0 to read everything from the console. The problem is that you need to send or receive ascii chars in order to see them on the console properly.

You can pipe it to a binary to ascii converter such as 'od'.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
write your own in practically any programming language you want

have you read my first post ?
i can use ONLY C!
else way i would have used python + pySerial
unfortunately i can't
 

Offline suicidaleggroll

  • Super Contributor
  • ***
  • Posts: 1453
  • Country: us
write your own in practically any programming language you want

have you read my first post ?
i can use ONLY C!
else way i would have used python + pySerial
unfortunately i can't
Then use C, where is the problem?  There are hundreds of examples online that you can choose from, or you could actually post the code you're using here for people to debug.

Once the serial protocol is set up, it's a simple matter of reading from the device.

Here's the initialization routine from one of my codes that reads/writes to a serial port in C:
Code: [Select]
int serial_setup(const char *device)
{
  struct termios options;

  // Open the serial device
  sfd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
  if(sfd == -1)
  {
    fprintf(stderr, "Unable to open device: %s\n", device);
    return ERR_SERDEV;
  }

  fcntl(sfd, F_SETFL, FNDELAY); // Turn off buffering

  tcgetattr(sfd, &options); // Load the options struct

  // Set the I/O speed to 2400 baud
  cfsetispeed(&options, B2400);
  cfsetospeed(&options, B2400);

  cfmakeraw(&options);

  // Configure for 8 data bits, 1 stop bit, no parity, no flow control
  options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
  options.c_cflag |= (CLOCAL | CREAD | CS8);

  // Set it to raw mode
  options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OLCUC | OPOST);

  // Shut off echo
  options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);

  options.c_cc[VMIN] = 1; // Minimum number of characters for read = 1
  options.c_cc[VTIME] = 0; // Non-blocking read

  tcsetattr(sfd, TCSANOW, &options); // Commit the changes

  return 0;
}

This is 2400 8N1, no handshaking or flow control, non-blocking.  You'll have to adapt it as necessary to suit your application.
« Last Edit: December 09, 2014, 06:08:49 pm by suicidaleggroll »
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Then use C, where is the problem?  There are hundreds of examples online that you can choose from, or you could actually post the code you're using here for people to debug.


so, if there are so many examples, provide me one which has been tested and it is known to be working !!!
 

Offline suicidaleggroll

  • Super Contributor
  • ***
  • Posts: 1453
  • Country: us
Then use C, where is the problem?  There are hundreds of examples online that you can choose from, or you could actually post the code you're using here for people to debug.


so, if there are so many examples, provide me one which has been tested and it is known to be working !!!

See my edit
 

Offline suicidaleggroll

  • Super Contributor
  • ***
  • Posts: 1453
  • Country: us
Here's one that logs from the serial port at 115200 and dumps everything that comes in to binary files that split every 1 MiB.
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>

//#define BREAK_SIZE 0xA00000 // Split to a new file every 10 MiB
#define BREAK_SIZE 0x100000 // Split to a new file every 1 MiB

int main ()
{
   int sfd, ofd;
   int n,n2;
   int bytes;
   int incr = 0;
   int bytesum = 0;
   char filename[255];

   struct termios options;
   char buff[10000];

   sfd = open("/dev/ttyO0", O_RDWR | O_NOCTTY | O_NDELAY);
   if (sfd == -1)
   {
      fprintf(stderr, "unable to open serial port\n");
      exit(1);
   }
   else
   {
      fcntl(sfd, F_SETFL, FNDELAY);
   }

   tcgetattr(sfd, &options);

   cfsetispeed(&options, B115200);
   cfsetospeed(&options, B115200);

   cfmakeraw(&options);

   options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
   options.c_cflag |= (CLOCAL | CREAD | CS8);

   options.c_oflag &= ~OPOST; // select raw output
   options.c_cc[VMIN] = 1;
   options.c_cc[VTIME] = 0;

   tcsetattr(sfd, TCSANOW, &options);

   n2 = sprintf(filename, "/data/imu/imu_data_%06d.dat", incr);

   ofd = open(filename, O_RDWR|O_CREAT);
   if (ofd == -1)
   {
      fprintf(stderr, "unable to open output file\n");
      exit(2);
   }

   while (1)
   {
      ioctl(sfd, FIONREAD, &bytes);
      if (bytes > 0)
      {
         n = read(sfd, buff, 10000);
         //fprintf(stderr, "available/read: %d/%d\n",bytes,n);
         if (n < 0)
         {
            fprintf(stderr, "read failed\n");
         }
         if (n > 0)
         {
            if (bytesum > BREAK_SIZE)
            {
               close(ofd);
               incr++;
               n2 = sprintf(filename, "/data/imu/imu_data_%06d.dat", incr);

               ofd = open(filename, O_RDWR|O_CREAT);
               if (ofd == -1)
               {
                  fprintf(stderr, "unable to open output file\n");
                  exit(2);
               }
               bytesum = 0;
            }

            write(ofd, buff, n);
            bytesum += n;
         }
      }
      usleep(1000);
   }
}

I've used this exact code to log from an IMU at 115200 for days straight, no errors, no gaps.

If you still have issues, then stick a logic analyzer on the bus and see if the uC is actually transmitting what you think it's transmitting.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
thank you  :-+
« Last Edit: December 09, 2014, 09:47:33 pm by legacy »
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3860
  • Country: de
If you are getting data but they are messed up every once in a while, the problem is most likely in your protocol. The driver, Linux, Arduino are obviously working.

Without seeing your code it is hard to say what could be wrong, but remember that you may not read a whole "packet" at once or you may read some bits of one packet and then some of the following one in a single read because of the buffering in the device driver. Basically, you have to either use delimiters and read until you find one or (better), design your protocol in such way that it sends the length of the data first and then reads exactly that many bytes. This is not Unix-specific, the same is true for any FIFO-like transport - e.g. a pipe, network socket, etc. unless some special measures are taken.

Btw, don't rely on stuff like fscanf() - you will get burned! It is safest to read the data into a buffer and then use sscanf() or whatever to parse them once you are sure you have got the complete packet.

Good basic examples are in the Linux Serial-Programming-HOWTO:
http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html#AEN129

Look at the non-canonical input part - canonical in Unix terminology means that some special characters are being handled specially (there is a "line discipline") - e.g. a DEL character will actually delete a character from your input buffer. This is old Unix heritage where the serial lines were used for dumb terminals, probably not what you want for transferring data!


 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
my code is perfectly working with a soft core i have developed on my fpga, i have an uart tap machine which communicates to the host at 115200 sending 16 byte of packet_out, and getting 16 byte of packet_in

no problem at all, but in that application i was using a physical uart, while with arduino i am using an USB-SERIAL interface

different kernel modules (COM vs USB_serial/FTDI232), so may be different behavior (e.g. teensy-v2 has a very different behavior when you use it as USB-serial)

btw, in the application i am dealing now i have a lot of issues talking with arduino, and i want to be sure my linux C code is correct, it may be the problem is in the arduino side, or in the hw level

for such a reason i asked a working code linux--arduino


Look at the non-canonical input part - canonical in Unix terminology means that some special characters are being handled specially (there is a "line discipline") - e.g. a DEL character will actually delete a character from your input buffer. This is old Unix heritage where the serial lines were used for dumb terminals, probably not what you want for transferring data!

i do not want any old-school tty interpretation of the data on the serial port, the protocol is raw binary, it has a lot of functions but basically it looks like this
HOST -> 'T' (which means "shot, give me the full frame acquired"
Arduino -> '@', data[128x128],checksum   <---- here sometimes i got something missing, one or two byte lost, checksum obviously corrupted

'@' means "ok" -> function implemented
'!' means "no" -> function not implemented
« Last Edit: December 09, 2014, 07:41:03 pm by legacy »
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
it may be it doesn't matter, btw t have forced low latency

Code: [Select]
echo 1 > /sys/bus/usb-serial/devices/ttyUSB0/latency_timer
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Btw, don't rely on stuff like fscanf()

of course, i am using
- read ( std, buffer[], size)
- write ( std, buffer[], size)
 

Offline rob77

  • Super Contributor
  • ***
  • Posts: 2085
  • Country: sk
different kernel modules (COM vs USB_serial/FTDI232), so may be different behavior (e.g. teensy-v2 has a very different behavior when you use it as USB-serial)
oh ... really ? explain me please how it was meant... both uart and USB_uart are providing a tty device - that's the purpose of the drivers (kernel modules) to provide a unified interface (tty in this case)


Look at the non-canonical input part - canonical in Unix terminology means that some special characters are being handled specially (there is a "line discipline") - e.g. a DEL character will actually delete a character from your input buffer. This is old Unix heritage where the serial lines were used for dumb terminals, probably not what you want for transferring data!

i do not want any old-school tty interpretation of the data on the serial port, the protocol is raw binary,

exactly that's the reason why you should listen a and read the suggested documents ! you have to get rid of the line discipline to get your RAW data.


and quite honestly... you making too much noise around a trivial issue - sorry for saying this... but if you're not able to troubleshoot a trivial issue, then most likely you'll not succeed ;)

 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27746
  • Country: nl
    • NCT Developments
What is the USB interface speed? If it is the lowest speed (1.5Mb/s) the USB interface may not have enough bandwidth to get the packets across. Another problem could be insufficient buffering inside the FT232 or the Linux host reading data too slow. I'd start with setting the Arduino part to 9600 baud and see what that does.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
What is the USB interface speed?
If it is the lowest speed (1.5Mb/s) the USB interface may not have enough bandwidth to get the packets across. Another problem could be insufficient buffering inside the FT232 or the Linux host reading data too slow. I'd start with setting the Arduino part to 9600 baud and see what that does.

9600 works perfectly with arduino
19200 works perfectly with arduino
38400 works perfectly with arduino
115200 has data lost, sometimes

the SoC has a built-in USB1, so high speed, i suspect the problem is related to your suggestion
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Code: [Select]
sint32_t uart_open
(
    char_t port[],
    uint32_t baud,
    boolean_t is_timeout_enabled,
    uint32_t timeout
)
{
    sint32_t fd;

    /* Try to open the uart port */
    fd = open(port, O_RDWR | O_NOCTTY);

    if (fd == IO_error)
    {
        fprintf(stderr, "error, %s is unknown\n", port);
    }
    else
    {
        /*
         * Apply the proper port settings to the port
         */
        uart_setup(fd, baud, is_timeout_enabled, timeout);

        fprintf(stderr, "%s at %lubps, ", port, baud);
        fprintf(stderr, "opened\n");
    }
    return fd;
}

Code: [Select]
void uart_setup
(
    sint32_t fd,
    uint32_t baud,
    boolean_t is_timeout_enabled,
    uint32_t timeout
)
{
    termios_t   ios;
    p_termios_t p_ios;
    uint32_t    iosbaud;

    p_ios = &ios;

    /* See what our baud rate is */
    switch (baud)
    {
    case 1200:
        iosbaud = B1200;
        break;
    case 9600:
        iosbaud = B9600;
        break;
    case 19200:
        iosbaud = B19200;
        break;
    case 38400:
        iosbaud = B38400;
        break;
    case 115200:
        iosbaud = B115200;
        break;
    case 230400:
        iosbaud = B230400; /* untested */
        break;
    case 460800:
        iosbaud = B460800; /* untested */
        break;
    default:
        /* no deal with this baud rate */
        fprintf(stderr, "[!] error: Unknown baud rate %lu\n", baud);
        exit(1);
        break;
    }

    /* Zero out the new port settings */
    memset(p_ios, 0, sizeof(ios));

    /* Create the new port settings */
    ios.c_iflag = IGNBRK;
    ios.c_oflag = 0;
    ios.c_cflag = iosbaud | CS8 | HUPCL | CREAD | CLOCAL;
    ios.c_lflag = 0;

    if (is_timeout_enabled == True)
    {
        /*
         * apply a timeout of 0.x sec (x deciseconds)
         */
        ios.c_cc[VMIN]  = 0;
        ios.c_cc[VTIME] = timeout;
    }
    else
    {
        /*
         * apply no timeout
         */
        ios.c_cc[VMIN]  = 1;
        ios.c_cc[VTIME] = 0;
    }
    uart_set_timeout(fd, is_timeout_enabled);

    /* Flush the input buffer to get rid of any lingering garbage */
    tcflush(fd, TCIFLUSH);

    /* Apply the new port settings */
    tcsetattr(fd, TCSANOW, p_ios);

    /* Flush the input buffer again */
    tcflush(fd, TCIFLUSH);
}

/*
 * POSIX Control Characters
 * The c_cc character array contains control character definitions
 * as well as timeout parameters.
 * Constants are defined for every element of this array.
 *
 * Setting Software Flow Control Characters
 *
 * The VSTART and VSTOP elements of the c_cc array contain
 * the characters used for software flow control. N
 * ormally they should be set to DC1 (17) and DC3 (19),
 * representing the defacto standard XON and XOFF characters.
 *
 * Setting Read Timeouts
 * UNIX uart interface drivers provide the ability
 * to specify character and packet timeouts.
 * Timeouts are ignored in canonical input mode.
 * Two elements of the c_cc array are used for timeouts: VMIN and VTIME.
 *
 * VMIN specifies the minimum number of characters to read.
 *      If it is set to 0, then the VTIME value specifies
 *         the time to wait for every character read.
 *      If it is non-zero, VTIME specifies
 *         the time to wait for the first character read.
 *         If a character is read within the time given,
 *         any read will block (wait) until all VMIN characters are read.
 *         That is, once the first character is read,
 *         the uart interface driver expects
 *         to receive an entire packet of characters (VMIN bytes total).
 *         If no character is read within the time allowed,
 *         then the call to read returns 0.
 * VTIME specifies the amount of time to wait for incoming characters
 *      in tenths of seconds.
 *      If VTIME is set to 0 (the default),
 *         calls to read will block (wait) indefinitely
 *         unless the NDELAY option is set on the port with open or fcntl
 */

void uart_set_timeout
(
    sint32_t fd,
    boolean_t is_timeout_enabled
)
{
    /*
     * Reading Data from the Port
     * Reading data from a port is a little trickier.
     * When you operate the port in raw data mode,
     * each read(2) system call will return
     * however many characters are actually available in the uart input buffers.
     * If no characters are available, the call will block (wait)
     * until characters come in, an interval timer expires,
     * or an error occurs.
     * The read function can be made to return immediately
     * by doing the following:
     * fcntl(fd, F_SETFL, FNDELAY);
     * The FNDELAY option causes the read function to return 0
     * if no characters are available on the port.
     *
     * To restore normal (blocking) behavior,
     * call fcntl() without the FNDELAY option:
     * fcntl(fd, F_SETFL, 0);
     *
     * This is also used after opening a uart port with the O_NDELAY option.
     */
    if (is_timeout_enabled isEqualTo True)
    {
        /*
         * don't block uart read
         */
        //fcntl(fd, F_SETFL, FNDELAY);
    }
    else
    {
        /*
         * blocking behavior
         */
        fcntl(fd, F_SETFL, 0);
    }
}

this is a part of my actual linux side, i have enabled the timeout support for the serial
« Last Edit: December 09, 2014, 08:54:59 pm by legacy »
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Code: [Select]
void test_artuino_serial()
{
    uint32_t n;
    sint32_t ans;
    uint8_t  buff[2]; /* useless, size = 1*/
    uint8_t  frame[16486+2+1];
    uint32_t i;
    uint32_t iframe_top;

    printf("sfd=%ld\n", uart_fd);

    iframe_top  = frame_size_y * frame_size_x;
    iframe_top += 1;

    n       = 1;
    buff[0] = CMD_PING;
    write(uart_fd, buff, n);
    if (ans < 1)
    {
        printf("write error\n");
        return;
    }

    n   = 1;
    ans = read(uart_fd, buff, n);
    printf("->%c\n", buff[0]);

    n       = 1;
    buff[0] = CMD_TAKE_FRAME;
    write(uart_fd, buff, n);
    if (ans < 1)
    {
        printf("write error\n");
        return;
    }

    buff[0] = '-';
    while (buff[0] != 'R')
    {
        n   = 1;
        ans = read(uart_fd, buff, n);
        printf("%d ", buff[0]);
        if (ans < 1)
        {
            printf("read error\n");
            return;
        }
    }

    printf("OK1\n");

    for (i = 0; i < iframe_top + 1; i++)
    {
        n = 1;
        read(uart_fd, buff, n);
        if (ans < 1)
        {
            printf("read error\n");
            return;
        }
        frame[i] = buff[0];
        printf("%d ", buff[0]);
    }
    i--;
    printf("\n");
    printf("checksum ->%d\n", frame[i - 1]);
    printf("ans      ->%c\n", frame[i]);
}

this is the easy-dummy-test using the above code: simply trying to read 128x128+2 bytes from arduino

results:

at 9600: success, no timeout, checksum is OK
at 38400: success, no timeout, checksum is OK
at 115200: failure, sometimes 2 bytes lost, checksum error
« Last Edit: December 09, 2014, 09:31:12 pm by legacy »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27746
  • Country: nl
    • NCT Developments
You may have to consider 115200 cannot work. Be sure to check the USB speed with the output from dmesg.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline f1rmb

  • Regular Contributor
  • *
  • Posts: 180
  • Country: fr
What kind of atmega your arduino embed?
Eg, you can't use 115200 with a Leonardo (32U4), the compiler will also tell you that begin() parameter is truncated.

---
Daniel
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10202
  • Country: nz
What crystal are you using on the arduino?
If it's not a multiple of the baud rate you can expect error rates as high as 8%
Greek letter 'Psi' (not Pounds per Square Inch)
 

Tac Eht Xilef

  • Guest
What crystal are you using on the arduino?
If it's not a multiple of the baud rate you can expect error rates as high as 8%

This.

Based on experience, and depending on the hardware & software, RS-232-alike serial comms starts getting hairy when the difference between expected & actual baud rate is more than 2%~3%. On a 16MHz Arduino, 115.2k is going to be 3%~4% off.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
this project has been developed by different guys
from the hardware guy i got a board which looks like the Yun
so there is a SoC (Atheros MIPS @400Mhz with built-in USB controller (1))
interfaced to an ATmega328 (datasheet) @ 16Mhz

SoC ---- built in USB (OHCI->USB1) -------- FTDI232 -------- serial 5V -------- ATmega328 @ 16Mhz

(1) the first problem is: why the firmware (linux side) guy has not used EHCI (USB2) instead of OHCI (USB1) ?
i have to understand it


btw, the Arduino side looks like a clone of the board "Arduino 2009"
wandering if i could get the same SoC around and the same board, in order to get more investigations

p.s.
the YUN seems to have higher uart speed

p.s.2
from my point of view, the "teensy-v2" hardware is better
i have tested it on my laptop  (laptop x86 ---USB2---teensy2 with built in USB device)
up to 900Kbyte/sec over the usb-serial with the same software i am talking about
no issues, no data corrupted, no timeout, everything works great

 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
You may have to consider 115200 cannot work. Be sure to check the USB speed with the output from dmesg.

dmesg says the USB is handled by OHCI (wandering why not EHCI instead? .. i will try to recompile the kernel and see what happens)
and the device3 (arduino) is USB1 full speed which should be 12M bit/sec
in theory it should be fine enough to handle 115K bit/sec

the first problem is: what happens if linux gets a long burst stream (128x128+2=16386byte)
in where every single URB/bulk has 1 byte instead of 64 ?

supposing the baud rate drift is not relevant
for 115200bit/sec  it means something like 10Kbyte/sec -> 10K URB / sec
i trust the kernel is perfectly able to handle it, even if …
… it's not an ideal situation and probably it is not the best optimized idea

teensy-v2 has no baud generator, so no drift issues
and the linux kernel side uses serial-class instead of a serial-driver, that permits to send 64byte per packet
it means that you know exactly what happens in the chain, so you could organize your firmware that way
and in the linux application side you could also use read(fd,buffer,64) instead of 64 times for {read(fb,&ch,1)}

just considerations … unfortunately i can ask the team to change the hardware
btw i am suspecting the problem is related to the % error due to the baud rate (frequency drift)
like you say, guys (thank your for your considerations)

or something in the hardware layer  :-//
 

Online Monkeh

  • Super Contributor
  • ***
  • Posts: 8048
  • Country: gb
(1) the first problem is: why the firmware (linux side) guy has not used EHCI (USB2) instead of OHCI (USB1) ?
i have to understand it

Because EHCI is used for high speed devices, and virtually every USB connected UART is a low speed or full speed device? This is not a choice made by your firmware guy.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Because EHCI is used for high speed devices, and virtually every USB connected UART is a low speed or full speed device?
This is not a choice made by your firmware guy.

you are absolutely right !

my point is: while i am waiting for the kernel sources (someone should send me sooner) i have looked a the Carambola's kernel because it looks very similar to the SoC i am talking about: the kernel support for v3.3.8 i see these choices

Code: [Select]
CONFIG_USB_EHCI_HCD:                                                                                                                                               ?
  ?                                                                                                                                                                    ?
  ? The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0                                                                                              ?
  ? "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.                                                                                                ?
  ? If your USB host controller supports USB 2.0, you will likely want to                                                                                              ?
  ? configure this Host Controller Driver.                                                                                                                             ?
  ?                                                                                                                                                                    ?
  ? EHCI controllers are packaged with "companion" host controllers (OHCI                                                                                              ?
  ? or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports                                                                                             ?
  ? will connect to EHCI if the device is high speed, otherwise they                                                                                                   ?
  ? connect to a companion controller.  If you configure EHCI, you should                                                                                              ?
  ? probably configure the OHCI (for NEC and some other vendors) USB Host                                                                                              ?
  ? Controller Driver or UHCI (for Via motherboards) Host Controller                                                                                                   ?
  ? Driver too.               

which has a combo EHCI/OHCI support and needs "EHCI support for AR7XXX/AR9XXX SoCs"

so i should see EHCI and OHCI in the dmesg, initialized during the boot, while i am seeing only OHCI … and i wander why  :-//

(and unfortunately the USB has no connector, everything is soldered on the PCB, so i can't plug an USB-hard drive to see what happens with a USB2 device, perhaps not without an hw hack  :-DD )

btw, these are the dmesg's line when the SoC sees Arduino

Code: [Select]
usb 4-1: new full speed USB device number 3 using ohci
usb 4-1: New USB device found, idVendor=0403, idProduct=6001
usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 4-1: Product: FT232R USB UART
usb 4-1: Manufacturer: FTDI
usb 4-1: SerialNumber: A700emu6
usb 4-1: usb_probe_device
usb 4-1: configuration #1 chosen from 1 choice
usb 4-1: adding 4-1:1.0 (config #1, interface 0)
usbserial_generic 4-1:1.0: usb_probe_interface
usbserial_generic 4-1:1.0: usb_probe_interface - got id
ftdi_sio 4-1:1.0: usb_probe_interface
ftdi_sio 4-1:1.0: usb_probe_interface - got id
ftdi_sio 4-1:1.0: FTDI USB Serial Device converter detected
usb 4-1: Detected FT232RL
usb 4-1: Number of endpoints 2
usb 4-1: Endpoint 1 MaxPacketSize 64
usb 4-1: Endpoint 2 MaxPacketSize 64
usb 4-1: Setting MaxPacketSize 64
usb 4-1: FTDI USB Serial Device converter now attached to ttyUSB0

it's OHCI, USB1, full speed

i'd like to test both endpoints with a maximal usage equal to MaxPacketSize, i mean 64byte per packet
in the afternoon i will try to change the Arduino firmware in order to test this feature
the current firmware has the endpoints maximal usage equal to 1 byte per packet
« Last Edit: December 10, 2014, 11:20:52 am by legacy »
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
about Arduino 2009, there 2 versions (due to the possibility to replace the DIP package MPU), the first with AtMega328, and the second with AtMega168, which looks quite similar (even if not exactly equals)

i am reading the AtMega168 data sheet: on page 197 it would seem to suggest that with a 16MHz clock the serial port can handle 1Mbps, in case … 1Mbps >> 115200bps, so it "should" be fine in my case, or not  :-//

which is the maximum baud rate you have successfully experimented with Arduino 328/168 and a linux SoC ?

 
« Last Edit: December 10, 2014, 11:22:06 am by legacy »
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3860
  • Country: de
Um, silly question - since it fails only at higher baudrates, are you sure that the Arduino is actually using a crystal and not a (cheap) ceramic resonator? Some clones have these!

 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27746
  • Country: nl
    • NCT Developments
Code: [Select]
usb 4-1: new full speed USB device number 3 using ohci
usb 4-1: New USB device found, idVendor=0403, idProduct=6001
usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 4-1: Product: FT232R USB UART
usb 4-1: Manufacturer: FTDI
usb 4-1: SerialNumber: A700emu6
usb 4-1: usb_probe_device
usb 4-1: configuration #1 chosen from 1 choice
usb 4-1: adding 4-1:1.0 (config #1, interface 0)
usbserial_generic 4-1:1.0: usb_probe_interface
usbserial_generic 4-1:1.0: usb_probe_interface - got id
ftdi_sio 4-1:1.0: usb_probe_interface
ftdi_sio 4-1:1.0: usb_probe_interface - got id
ftdi_sio 4-1:1.0: FTDI USB Serial Device converter detected
usb 4-1: Detected FT232RL
usb 4-1: Number of endpoints 2
usb 4-1: Endpoint 1 MaxPacketSize 64
usb 4-1: Endpoint 2 MaxPacketSize 64
usb 4-1: Setting MaxPacketSize 64
usb 4-1: FTDI USB Serial Device converter now attached to ttyUSB0

it's OHCI, USB1, full speed

i'd like to test both endpoints with a maximal usage equal to MaxPacketSize, i mean 64byte per packet
in the afternoon i will try to change the Arduino firmware in order to test this feature
the current firmware has the endpoints maximal usage equal to 1 byte per packet
Then there is your problem. You really need to fill USB packets to the max because in USB there is a roundtrip time for each packet. If you fill a packet with only one byte then you limit the USB bandwidth way below the maximum bandwidth.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Online Monkeh

  • Super Contributor
  • ***
  • Posts: 8048
  • Country: gb
so i should see EHCI and OHCI in the dmesg, initialized during the boot, while i am seeing only OHCI … and i wander why  :-//

Who cares? You don't need EHCI.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
right, too
just curious  :-+
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Um, silly question - since it fails only at higher baudrates, are you sure that the Arduino is actually using a crystal and not a (cheap) ceramic resonator? Some clones have these!

Good question!

The hardware may be described as "custom clone", practically speaking the Arduino side is like the "Arduino 2009 board" but developed by our hardware guys and integrated in the same PCB with an Atheros SoC: it looks like the Arduino Yun but it has a DIP-package MPU (AtMega 328)

ummm you are right about a thing i have not considered yet: the board has cheap ceramic resonator  :palm: :palm: :palm:
« Last Edit: December 10, 2014, 12:02:16 pm by legacy »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27746
  • Country: nl
    • NCT Developments
The baudrate doesn't have to be very accurate. There is a tolerance of 1% IIRC.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
@nctnico
you get the issue fixed, definitively !

i have changed both the arduino firmware and the linux application sides in order to packet things in 64byte (according to the size of the bulk endpoints)

results
  • 9600 still Ok
  • 19200 still Ok
  • 38400 still Ok
  • 115200bps stable, no errors, no data lost, no corruption, good checksum
  • 230400bps stable, no errors, no data lost, no corruption, good checksum
  • 460800bps and upper bauds rates are untested

it works better and faster, thank your for your help  :-+


now i have to contact the Arduino firmware guy, and make him to commit my patch
let me say, i am not the arduino firmware guy, about this project … in an ideal world my task should be related ONLY to the linux application, an more specifically to the algorithm model (using matlab to experiment and tune up ideas into code) to process all the stream from the arduino, which is connected to an optical sensor.

in the real world, as usual, i have to become the hardware/firmware/everythings guy  :-DD

no problem with this, except the fact that my knowledges are limited, so very very thanks for your help, really, guys  :-+
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3860
  • Country: de
The baudrate doesn't have to be very accurate. There is a tolerance of 1% IIRC.

If the board has only a resonator, then it is going to be marginal at 115200bps - those things have a tolerance +-0.5% (crystals have ~0.001% typical).

I would still change it for a crystal, just to be safe.
 

Online nfmax

  • Super Contributor
  • ***
  • Posts: 1596
  • Country: gb
'Asynchronous' serial communications actually synchronises each time a new start bit arrives, and most UARTs sample data during the middle third of each bit time. The bit times are based on the baud rate as set by the local UART clock; there is also a sampling uncertainty relative to this clock in knowing when the start bit arrived. Including parity and stop bits, a character is usually 10 bits long. For the sampling instant on the 10th bit not to have drifted out ofthe middle third, i.e. not by more than 1/6 bit time, the maximum clock error between sending & receiving clocks must be less than 1.667%. Allowing a margin for the uncertainty in the start bit detection time gives around 1.5% as the maximum tolerable error between the send & receive clocks. In practice, you can go a bit worse than this (in the absence of noise) as again most UARTs actually make multiple samples during each bit time & decide between 1 & 0 by the majority of the sample values.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4288
  • Country: us
Quote
If the board has only a resonator, then it is going to be marginal at 115200bps
I don't know why people keep repeating this.  The ability of a uart to accurately receive data when the clock is "not quite right" is NOT dependent on the speed.  Only on the percentage of error.

That said, a 16MHz (exactly) AVR as used on most arduinos is "marginal" at 115200bps  (2.1% off) because of the limitations of the bitrate generator.  It works fine on most modern Arduino boards, because the USB/Serial converter is ALSO an AVR with the same logic, and the code is very careful to make sure the error goes in the same direction.  If you happen to use some other USB/Serial logic that introduces error in the OTHER direction, you can easily have failures.
(My FTDI-based older arduinos and derivatives seem to work fine at 115200, but ... I'm continually nervous, and I'm not sure they'd pass a long-term data test.)

Also, 115200bps is one character every 86 microseconds (~1200 instruction times.)  It's pretty easy to write code  that doesn't service the uart often enough to avoid overruns.

 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
so, 115200bps is the upper limits ?
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
new tests applying the data-packet size patch (64 byte per packet over usb/BULK)


  • setting 460800 on arduino side, 460800 on linux side not correctly recognized by linux, so not working, time out, 100% data lost
  • setting 460800 on arduino side, 500000 on linux side, is working at 500Kbps, no corruption, no data lost, everything is OK from a long run test (10Mbyte sent)

wandering why 460800 on arduino side, and 500000 on linux
minicom is confirming that (not working if linux set to 460800bps, perfectly working if set to 500000)   :-//


btw, i am going faster (500000bps) than expected (115200bps), excellent guys  :-+
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4288
  • Country: us
Quote
115200bps is the upper limits?
No.  People have reported success with 1Mbps; in that case the 16MHz yields an exactly correct bit rate.
200k, 250k, and 500k should come out exactly work as well.
(Of course, you have to be even more careful that your code is fast enough to handle the bitrate.  The 1Mbps example I know if is the Arduino Optiboot Bootloader, which does ~256 byte flash sectors that it receives all at once (and nothing else at the same time, and not using interrupts), with "got it" and "send me the next" on either side.)
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3860
  • Country: de
Quote
If the board has only a resonator, then it is going to be marginal at 115200bps
I don't know why people keep repeating this.  The ability of a uart to accurately receive data when the clock is "not quite right" is NOT dependent on the speed.  Only on the percentage of error.

That said, a 16MHz (exactly) AVR as used on most arduinos is "marginal" at 115200bps  (2.1% off) because of the limitations of the bitrate generator.

Which is not in contradiction to what I have said. What you are saying is obviously true, but there is another thing to consider. If you have a resonator and its frequency is "wandering" with temperature, your bitrate is going to (obviously) wander as well.

It works fine on most modern Arduino boards, because the USB/Serial converter is ALSO an AVR with the same logic, and the code is very careful to make sure the error goes in the same direction.  If you happen to use some other USB/Serial logic that introduces error in the OTHER direction, you can easily have failures.
(My FTDI-based older arduinos and derivatives seem to work fine at 115200, but ... I'm continually nervous, and I'm not sure they'd pass a long-term data test.)

I am not so sure about the "error going in the same direction" - it is not only about the clockspeed being a multiple of the bitrate so that you minimize the error but also frequency stability. The USB AVR uses a regular crystal on the new Arduino Uno. The main AVR is using a resonator. So if their frequences drift, it is going to be tougher and tougher to keep things in sync and error-free over long transmissions at high bitrates.

 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Arduino vs Teensy

The atmega328p in the Arduino/Uno serie does serial transmit and receive, and a separate chip converts this into serial-over-USB. The Teensy uses a different AVR chip that has built-in USB support, so there is no need to go via serial. The manufacturer of the Teensy claims that the Teensy has direct 12 MBit/sec USB access and also claims for the RAWHID library functions:  You can send up to 1000 packets per second in each direction, where each packet is 64 bytes

my protocol is able to work at 500Kbps over usb-serial just because it has acknowledges (send data packet and wait, then go on), but it's a dirty trick
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Quote
The reason people have trouble with none-standard baudrates on Linux is because the kernel developers created 2 different interfaces to set none-standard baudrates and not all drivers/kernel version support both, and not all serial libraries support both. In this case, PySerial does not support Termios2.

from here, also … it seems the problem is kernel side and libc side, also i am not using the the termio2  :-//
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf