Ограничения последовательного драйвера для процессора iMX

Я занимаюсь разработкой на встроенном устройстве Linux, которое использует процессор ARM iMX6. Основная цель - прочитать входящий последовательный поток из внешнего источника.

Из-за нетипичной природы последовательного потока, я столкнулся с несколькими препятствиями с последовательным драйвером Linux для процессоров imx. Но ничего, что находится за пределами возможностей iMX6. Например, входящий последовательный поток имеет инвертированную логику. В iMX6 есть специальная настройка регистра для инвертирования сигнала RX. Из того, что я могу сказать, драйвер Linux не раскрывает его.

Еще одним осложнением является то, что поступающие последовательные данные поступают в виде пакетов по 3 мс. Внешний источник непрерывно передает данные в течение 3 мс, затем 3 мс в режиме ожидания, затем 3 мс данных, затем в режиме ожидания и т. Д. Для синхронизации с первым байтом каждого пакета очень полезно иметь возможность определять, когда линия находится в режиме ожидания. Опять же, iMX6 имеет значение регистра, специально предназначенное для указания того, что строка RX простаивает, но драйвер Linux не предоставляет его.

Я также очень запутался, как работает буферизация в драйвере. Я знаю, что iMX6 имеет 32-байтовый буфер FIFO, но я не могу сказать, использует ли драйвер этот буфер или использует внешнюю память для буферизации. Я сталкиваюсь с проблемой, когда read Команда часто зависает на секунду, когда я нахожусь в режиме блокировки, что никогда не должно происходить, потому что поток данных непрерывен.

Для справки, вот как я настроил последовательный порт в своем коде C и прочитал 50 байтов (пока я изменил его на неблокирующее):

#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)
  }
  ...
}

Итак, у меня есть два вопроса:

  1. Каков "правильный" способ получить возможность использования последовательного порта, который есть у процессора, но драйвер не предоставляет? Я не могу себе представить, что я первый, кто хочет использовать такую ​​базовую функциональность процессора, но я не хочу изобретать велосипед. Нужно ли мне писать собственные драйверы?

  2. Существует ли где-нибудь исчерпывающая документация по последовательному драйверу iMX? Код плохо комментируется, и я быстро теряюсь, пытаясь найти способ обойти его. Например, я не знаю, с чего начать исследование проблемы буферизации, которая вызывает его зависание при получении непрерывного потока данных.

1 ответ

Решение

Я полностью отказался от последовательного драйвера и вместо этого написал несколько функций для прямого доступа к памяти регистров (смоделирован по исходному коду devmem2.c). Теперь я могу напрямую установить бит INVR для инвертирования сигнала RX, использовать бит IDLE, чтобы определить, когда линия бездействует, и извлечь входящие байты данных, как только они поступят без задержки.

Я нашел что-то на другом форуме о том, что UART DMA нуждается в линии RX для простоя не менее 8 мс, прежде чем она будет обслуживать буфер. Это было очевидно причиной 1-секундного отставания, которое я испытывал.

Другие вопросы по тегам