Linux устанавливает более высокую скорость передачи данных и соответствующие настройки

Аппаратное обеспечение ввода: BeagleBone Black, на котором запущен какой-то дистрибутив GNU/Linux.

Чего я хочу добиться: я хочу установить для некоторого UART периферийного устройства значение 921600 в бодах и иметь возможность устанавливать другие параметры, связанные с последовательным портом (например, стартовые/стоповые биты, четность, биты данных, аппаратное управление потоком и т. д.).

На сегодняшний день в Linux я нашел как минимум три способа настройки этих параметров:

  1. Использование struct termios файла заголовка формы termios.h.
  2. Использование struct termios2 из заголовочного файла asm/termios.h.
  3. Использование утилиты stty(1) GNU/Linux.

В чем проблема:

С первым методом я не могу использовать значение скорости передачи 921600 (для такого более высокого значения нет определения, оно увеличивается только до 230400 baud. Так что этот метод не будет работать.

Второй метод предлагает мне один способ изменить пользовательские значения коэффициента baud, но он также сложен, потому что он не предлагает некоторые функции, такие как tcgetattr(), tcsendbreak(), tcflush() и так далее. Эти функции присутствуют в первом описанном методе, и я не могу включить оба заголовочных файла termios.h и asm/termios.h из-за (1).

Последний метод тоже не работает, или, по крайней мере, не работает для всех настроек, которые я хочу сделать. Это текущий метод, который я использую, я открываю целевой файл, я получаю один файловый дескриптор, для этого файлового дескриптора я устанавливаю параметры связи (бод (сначала я устанавливаю одно меньшее значение), четность, стартовые/стоповые биты и т. д.), используя первый метод, а затем я использую утилиту stty(1) для изменения (переопределения) значения скорости передачи данных на 921600 (для этого я делаю вызов функции system(...)).

Этот метод не будет работать, если я хочу, например, изменить HW flow control (он не переопределит этот параметр, как это происходит со значением baud).

Каковы решения?

Можно ли смешивать два метода установки параметров для UART-канала связи, как этот?


person bilserial    schedule 15.06.2016    source источник


Ответы (2)


Вы можете использовать консольную утилиту setserial:

1) Получить значение baud_base из setserial выхода

setserial -a /dev/<...>

2) Вычислить делитель = база_бод/желаемая_скорость_бода

Например, если baud_base = 3000000 (3 МГц):

baud_rate = 115200 -> divisor = 26.04 (approximately 26)
baud_rate = 230400 -> divisor = 13.02 (approximately 13)
baud_rate = 921600 -> divisor = 3.26

3.26 слишком много, чтобы установить делитель = 3, и слишком мало, чтобы установить делитель = 4.

Таким образом, в этом случае вы не можете использовать baud_rate=921600 из-за аппаратных ограничений. Вы можете выбрать divisor=3 (baud_rate=1000000) или divisor=4 (baud_rate=750000). Эти скорости передачи данных не являются стандартными, но возможны.

stty -F /dev/<...> 9600 -icrnl -ixon -crtscts -parenb # desired UART settings
setserial /dev/<...> spd_cust  # use custom value for divisor
setserial /dev/<...> divisor 3  # set custom value for divisor
stty -F /dev/<...> 38400 # activate setserial settings
# now baud_rate is (baud_base / divisor)
person petrmikheev    schedule 15.06.2016
comment
setserial выводит мне Cannot set serial info: Invalid argument при попытке установить параметр baud_base. - person bilserial; 15.06.2016
comment
Вы уверены, что ваше оборудование поддерживает скорость 921600 бод? Попробуйте setserial -a /dev/<...> просмотреть доступную информацию о последовательном порте. - person petrmikheev; 15.06.2016
comment
Вероятно, что baud_base фиксируется аппаратно, поэтому правильный путь: 1. Посмотреть текущую baud_base по setserial -a; 2. Рассчитать делитель для желаемой скорости передачи данных; 3. Используйте setserial ... spd_cust и setserial ... divisor для установки делителя - person petrmikheev; 15.06.2016
comment
Да, аппаратное обеспечение поддерживает это значение в бодах (я могу установить его с помощью инструментов minicom и stty). baud_base, о котором сообщил инструмент setserial, равен 3000000. - person bilserial; 16.06.2016
comment
Я обновил свой ответ. stty предлагает список стандартных скоростей передачи данных. Это не означает, что ваше устройство поддерживает его. - person petrmikheev; 16.06.2016
comment
Тогда почему связь работает со скоростью около ~921600бода (вариация +-2%), когда я установил ее на 921600 с помощью stty, если аппаратное обеспечение не поддерживает это? (Я измерял это с помощью осциллографа). - person bilserial; 17.06.2016
comment
Что ж. Это означает, что BeagleBone может изменять baud_base. Извините, я неправильно понял ваш вопрос. Не могли бы вы показать команду stty, которая не работает? Он печатает какое-то сообщение об ошибке? - person petrmikheev; 17.06.2016
comment
Я сделал следующее: я открыл файл, связанный с /dev/ttyO2 UART, через системный вызов open(2), затем я использовал struct termios, чтобы сделать настройки (количество битов данных - 8, аппаратное управление потоком - выкл и т. д.), применить настройки через системный tcsetattr(3) call, а затем, последний шаг, который я сделал, это запустить эту команду для установки такой более высокой скорости: sudo stty -F /dev/ttyS2 921600 с помощью вызова функции system(3). stty не выйдет из строя, я выполнил команду из командной строки, и вывода не было, что говорит мне, что все в порядке. - person bilserial; 17.06.2016
comment
Единственная проблема заключается в том, что утилита stty каким-то образом переопределит настройки, которые я ранее сделал с помощью struct termios. И я также сбит с толку, если я правильно делаю то, что я делаю, я нарушаю какую-то систему безопасности ОС? Я имею в виду, поскольку я open(2) некоторый файл, я ожидаю, что текущий процесс будет владеть этим ресурсом, и если какой-то другой процесс получит доступ к нему (например, stty в данном случае), не должно ли это привести к некоторому неопределенному поведению? - person bilserial; 17.06.2016
comment
Попробуйте позвонить stty до open(2) - person petrmikheev; 17.06.2016

ИМХО, использование system и stty из программы на C или C++ - не путь (system поначалу считается плохой практикой безопасности).

Прочитав связанные с вами вопросы, я бы посоветовал объявить только в вашем основном модуле, пространстве имен или классе некоторые функции-оболочки для всех функций, которые вы хотите использовать как из termios.h, так и из asm/termios.h. .

Затем вы определяете их в двух разных единицах компиляции (исходные файлы c или c++), сначала имея дело с termios.h, а затем с asm/termios.h.

Если это не сработает, последним способом будет тщательное объединение объявлений из termios.h и asm/termios.h в пользовательский файл local_termios.h, управляемый в ваших собственных источниках, и включение его. Это, конечно, приводит к непереносимости кода, но в любом случае, как только вы используете asm/termios.h, вы теряете совместимость.

person Serge Ballesta    schedule 15.06.2016