Драйвер последовательно порта UART4 (w-apb-uart) - UART4 имеет только две линии - Rx и Tx.
Используется ядро 6.5.8.
Процессор Allwinner A40i.
Это именно RS485, UART подключен к микросхеме трансивера RS485. Пин RTS используется для организации полудуплексной передачи.
TxRx Diagram -
https://postimg.cc/BjVnxhD0
DTS:
В DTS файле он UART переопределен:
&uart4 {
pinctrl-names = "default";
compatible = "snps,dw-apb-uart";
pinctrl-0 = <&uart4_ph_pins>;
rts-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; //PH13
//rs485-rts-delay = <0 200>;
linux,rs485-enabled-at-boot-time;
status = "okay";
};
Порт GPIO PH13 используется в качестве RTS пина (это не аппаратный RTS).
В дереве устройств на четвертом порту мы включаем режим (linux,rs485-enabled-at-boot-time).
НАШИ ДЕЙСТВИЯ:
Открываем порт (с помощью SCREEN) - прием происходит нормально.
Но как только отсылаем первую строку или символ, происходит зависание порта, сразу после первой отсылки (она успешная, она приходит).
При отсылке порт становится в положение HIGH, но после неё не возвращается в положение LOW. Порт перестает работать и на прием и на передачу.
Скорости использовали разные - 9600 до 115200, не влияет на поведение порта.
При копании в глубинах драйвера порта (/linux-6.5.8/drivers/tty/serial/8250/8250_dw.c) и попытках отладить, выяснилось, что если вставить вывод в консоль //dev_err() или dev_info() - всё начинает работать, но при этом начинают приходить сообщения в консоль от портов.
Функция static int dw8250_handle_irq(struct uart_port *p) вызывает:
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
unsigned long flags;
u16 status;
if (iir & UART_IIR_NO_INT)
return 0;
//dev_err(port->dev, "Handle irq before breakpoint \n");//qq
spin_lock_irqsave(&port->lock, flags);
status = serial_lsr_in(up);
/*
* If port is stopped and there are no error conditions in the
* FIFO, then don't drain the FIFO, as this may lead to TTY buffer
* overflow. Not servicing, RX FIFO would trigger auto HW flow
* control when FIFO occupancy reaches preset threshold, thus
* halting RX. This only works when auto HW flow control is
* available.
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
!(port->read_status_mask & UART_LSR_DR))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
if (!up->dma handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
if (!up->dma up->dma->tx_err)
serial8250_tx_chars(up);
else if (!up->dma->tx_running)
__stop_tx(up);
}
uart_unlock_and_check_sysrq_irqrestore(port, flags);
return 1;
}
Если вывод dev_err() поставить перед spin_lock_irqsave(&port->lock, flags); то всё работает. Если после - то не работает, происходит spin_lock порта и в дальнейшем он не освобождается, происходит dead_lock.
uart_unlock_and_check_sysrq_irqrestore(port, flags); - не отрабатывает.
ВОПРОС:
Как решить проблему, чтобы порт работал адекватно, без отправок в консоль сообщений от портов? Виноват драйвер?