Serial driver limitations on iMX processor

2k views Asked by At

I'm developing on an embedded Linux device that uses an ARM iMX6 processor. The main purpose is to read an incoming serial stream from an external source.

Due to the atypical nature of the serial stream, I've run into a few roadblocks with the Linux serial driver for imx processors. But nothing that is beyond the capability of the iMX6. For example, the incoming serial stream is inverted logic. The iMX6 has a specific register setting to invert the RX signal. From what I can tell, the Linux driver does not expose it.

Another complication is that the incoming serial data arrives in 3ms bursts. The external source transmits continuously for 3ms, then 3ms of idle, then 3ms of data, then idle, etc. In order to sync up with the first byte of each burst, it's very useful to be able to detect when the line is idle. Again, the iMX6 has a register value specifically for indicating that the RX line is idle, but the Linux driver doesn't expose it.

I am also very confused how buffering works in the driver. I know the iMX6 has a 32byte FIFO buffer, but I can't tell if the driver uses that buffer or uses external RAM for buffering. I'm running into an issue where the read command hangs for a second every so often when I'm in blocking mode, which should never happen because the data stream is continuous.

For reference, here's how I configured the serial port in my C code and read 50 bytes (I've changed it to non-blocking for now):

#include <stropts.h>
#include <asm/termios.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
  int fd;
  struct termios2 terminal;
  unsigned char v[50];

  fd = open ("/dev/ttymxc2", O_RDONLY | O_NOCTTY | O_NONBLOCK );
  ioctl(fd, TCGETS2, &terminal);
  terminal.c_cflag |= (CLOCAL | CREAD) ;
  terminal.c_cflag |= PARENB ; //enable parity
  terminal.c_cflag &= ~PARODD ; //even parity
  terminal.c_cflag |= CSTOPB ;  //2 stop bits
  terminal.c_cflag &= ~CSIZE ;
  terminal.c_cflag |= CS8 ;
  terminal.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG) ;
  terminal.c_oflag &= ~OPOST ;
  terminal.c_cflag &= ~CBAUD;
  terminal.c_cflag |= BOTHER;
  terminal.c_ispeed = 100000;  //100kHz baud
  terminal.c_ospeed = 100000;
  ioctl(fd, TCSETS2, &terminal);
  ...
  for(i=0;i<50;i++)
  {
      read(fd,v+i,1)
  }
  ...
}

So I have two questions:

  1. What is the "proper" way to get the capability out of the serial port that the processor has available but the driver doesn't expose? I can't imagine I'm the first person to want to use such basic functionality of the processor, but I don't want to reinvent the wheel. Do I need to get into writing my own drivers?

  2. Does comprehensive documentation on the iMX serial driver exist anywhere? The code is poorly commented and I get lost quickly trying to find my way around it. For example, I don't know where to start investigating the buffering problem that causes it to hang when receiving a continuous stream of data.

1

There are 1 answers

0
Dan Laks On BEST ANSWER

I've forgone with the serial driver entirely and instead wrote some functions to access the register memory directly (modeled after devmem2.c source code). Now I can directly set the INVR bit to invert the RX signal, use the IDLE bit to detect when the line has gone idle, and retrieve the incoming data bytes as soon as they arrive without delay.

I found something on another forum about the UART DMA needs the RX line to go idle for at least 8ms before it services the buffer. That was apparently the cause of the 1sec lag I was experiencing.