LINUX.ORG.RU

Проблема с uart в режиме rs485.

 , ,


0

1

Всем привет !

Имеется плата на Allwinner A40i на которой на uart4 подключеа микросхема rs485. Для переключения приема и передачи (RTS) используется отдельный пин процессора. Столкнулся со странным поведением uart приём происходит нормально, но при передаче первая отправка работает, пин автоматически поднимается, но после отправки не опускается. При этом порт виснет, ни приём ни передача не происходят. Если перезапустить приложение через которое отправляю данные, состояние rts не меняется, но можно отправлять данные, но так же один раз, а потом виснет. Долгое копание в исходниках драйвера порта и попытки отловить где проблема, привели к функции прерывания serial8250_handle_irq в файле linux/drivers/tty/serial/8250/8250_port.c. Если именно в начале или в конце прерывания вставить вывод в консоль любого текста, dev_err(port->dev, «Hello \n»); например, то все работает отлично, только консоль и логи забиваются сообщениями. Никак не могу понять в чем проблема. Зависание происходит в прерывании из-за функции spin_lock_irqsave(&port->lock, flags); Она почему-то уходит в deadlock. Вот настройка порта в dts.

&uart4 {
	compatible = "snps,dw-apb-uart";
	pinctrl-names = "default";
	pinctrl-0 = <&uart4_ph_pins>;
	status = "okay";
	rts-gpios = <PH 13 GPIO_ACTIVE_HIGH>;
	rs485-rts-delay = <0 0>;
	rs485-rts-active-high;
	linux,rs485-enabled-at-boot-time;	
};

Ядро пробовал 6.0, 6.2, 6.4 сейчас 6.5.8. Не отсылайте в гугл, я был на его последней странице по данному вопросу, ничего не принесло результатов. Подскажите в чем проблема и как ее решить ?!


Если именно в начале или в конце прерывания вставить вывод в консоль любого текста, dev_err(port->dev, «Hello \n»); например, то все работает отлично, только консоль и логи забиваются сообщениями.

Sleep поставь эквивалентной длительности 🤡🤡🤡

aol ★★★★★
()
Ответ на: комментарий от aol

Sleep крашит ядро при загрузке, ndelay помогает, если собрать ядро без SMP. Такая ситуация наблюдается на скорости 115200, понижать затруднительно, т.к. остальные устройства, с которым работает плата, работают на этой скорости.

TeX
() автор топика
Ответ на: комментарий от TeX

ну, не надо всё так буквально понимать ;)

намякиваю: https://unix.stackexchange.com/a/5095

The Linux kernel uses spin locks for many things, such as when sending data to a particular peripheral. Most hardware peripherals aren’t designed to handle multiple simultaneous state updates.

aol ★★★★★
()
Ответ на: комментарий от aol

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

TeX
() автор топика
Ответ на: комментарий от TeX

при первой отсылке в прерывании происходит спинлок, но по какой-то причине не отрабатывает функция, которая завершает передачу

при этом вывод в консоль это дело как-то побеждает. не приходится ли он по случаю какой-то точкой синхронизации? вот я о чем…

косяки в коде, однозначно. осталось найти )

aol ★★★★★
()
Ответ на: комментарий от aol

Если взглянуть в код драйвера, там и кода особо нет, который может сбоить, но как-то же его утвердили в ядро. Код должен был быть оттестирован.

TeX
() автор топика

Могу пространно порассуждать, может натолкнет на мысли.

Насколько я помню, использовать напрямую RTS для управления направлением в популярных rs485-транссиверов нельзя. Нужно инвертировать ногу. При этом, если мы работаем в обычном режиме rs232, это нога должна активно переключаться. И тут вы со своей инверсной логикой для этой ноги. Есть ощущение (я туда не заглядывал), что два ядерных процесса тянут эту ногу каждый на себя.

Предлагаю вернуть настройку в дефолт и логическим анализатором посмотреть как она (RTS) управляется. Если активно дергается, то это + в пользу моей теории. Как еще один тест, можно попробовать взять другую ногу (совсем свободный GPIO) для управления 485 и посмотреть на анализаторе как она будет дергаться совместно с RTS. Если в противофазе, то это еще один довод в пользу моей гипотезы.

Это все гипотезы, не более того.

yax123 ★★★★★
()
Последнее исправление: yax123 (всего исправлений: 1)
Ответ на: комментарий от yax123

Я как раз использую отдельную ногу. Тот uart, который Я использую (uart4), он не полный в нем только rx/tx, поэтому не получится посмотреть что на железном rts. Rts пин настраивал и в инверсном режиме, реакция такая же, после первой отсылки нога инвертируется и обратно не возвращается.

TeX
() автор топика
Ответ на: комментарий от yax123

Эта нога определяется через dts, выше конфиг. Она никем не используется. Весь взрыв мозга в том, что вывод в консоль из прерывания, исправляет ситуацию и все начинает работать.

TeX
() автор топика
Ответ на: комментарий от alysnix

отличная мысль, только поставить задержку не 200 ms, а на длительность байта, не больше. А то начнете терять байты от ведомого.

yax123 ★★★★★
()
Последнее исправление: yax123 (всего исправлений: 1)
Ответ на: комментарий от yax123

это уже тюнинг :) сначала надо попробовать 100-200ms, чтобы вообще заработало.

я кстати сам не очень понимаю, почему у них 200 ms. это многовато

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)