dts 修改:
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_pins_a>;
rts-gpio = <&pio 4 10 GPIO_ACTIVE_HIGH>; //PE10
rs485-rts-active-high;
rs485-rts-delay = <0 0>;
linux,rs485-enabled-at-boot-time;
status = "okay";
};
https://gist.github.com/amarburg/07564916d8d32e20e6ae375c1c83a995
测试代码:
/*
* Test program Linux RS485-mode ioctls.
*
* cc -o rs485_mode rs485_mode.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <linux/serial.h>
/* RS485 ioctls: */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
int main( int argc, char **argv )
{
unsigned int i;
char buf[80];
if( argc < 3 ) {
printf("Usage: %s [port name] [0|1]\n", argv[0]);
exit(0);
}
int enable = atoi( argv[2] );
char *port = argv[1];
int fd = open(port, O_RDWR);
if (fd < 0) {
/* Error handling. See errno. */
fprintf( stderr, "Error opening port \"%s\" (%d): %s\n", port, errno, strerror( errno ));
exit(-1);
}
struct serial_rs485 rs485conf;
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
fprintf( stderr, "Error reading ioctl port (%d): %s\n", errno, strerror( errno ));
}
printf("Port currently RS485 mode is %s\n", (rs485conf.flags & SER_RS485_ENABLED) ? "set" : "NOT set");
if( enable ) {
printf("RS485 mode will be SET\n");
rs485conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
} else {
printf("RS485 mode will be UNSET\n");
rs485conf.flags &= ~SER_RS485_ENABLED;
}
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
fprintf( stderr, "Error sending ioctl port (%d): %s\n", errno, strerror( errno ));
}
/* Use read() and write() syscalls here... */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
fprintf( stderr, "Error reading ioctl port (%d): %s\n", errno, strerror( errno ));
}
printf("Confirm RS485 mode is %s\n", (rs485conf.flags & SER_RS485_ENABLED) ? "set" : "NOT set");
/* Do something on the serial port... */
for( i = 0; i < 100; ++i ) {
snprintf( buf,79, "%d\r\n", i );
write( fd, buf, strlen(buf));
sleep(1);
}
/* Close the device when finished: */
if (close (fd) < 0) {
fprintf( stderr, "Error closing port (%d): %s\n", errno, strerror( errno ));
}
exit(0);
}
测试命令:
# rs485test /dev/ttyS2 1
Port currently RS485 mode is NOT set
RS485 mode will be SET
Error sending ioctl port (25): Inappropriate ioctl for device
Confirm RS485 mode is NOT set
离线
serial_core.c 参与了编译, ioctl 命令实现了 TIOCGRS485, TIOCSRS485
https://github.com/torvalds/linux/blob/master/drivers/tty/serial/serial_core.c
/*
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
/*
* These ioctls don't rely on the hardware to be present.
*/
switch (cmd) {
case TIOCSERCONFIG:
down_write(&tty->termios_rwsem);
ret = uart_do_autoconfig(tty, state);
up_write(&tty->termios_rwsem);
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
if (tty_io_error(tty)) {
ret = -EIO;
goto out;
}
/*
* The following should only be used when hardware is present.
*/
switch (cmd) {
case TIOCMIWAIT:
ret = uart_wait_modem_status(state, arg);
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
mutex_lock(&port->mutex);
uport = uart_port_check(state);
if (!uport || tty_io_error(tty)) {
ret = -EIO;
goto out_up;
}
/*
* All these rely on hardware being present and need to be
* protected against the tty being hung up.
*/
switch (cmd) {
case TIOCSERGETLSR: /* Get line status register */
ret = uart_get_lsr_info(tty, state, uarg);
break;
case TIOCGRS485:
ret = uart_get_rs485_config(uport, uarg);
break;
case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg);
break;
case TIOCSISO7816:
ret = uart_set_iso7816_config(state->uart_port, uarg);
break;
case TIOCGISO7816:
ret = uart_get_iso7816_config(state->uart_port, uarg);
break;
default:
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);
break;
}
out_up:
mutex_unlock(&port->mutex);
out:
return ret;
}
接下来再跟踪一下
离线
可以实现,不过我没走linux 485框架,直接魔改驱动实现的
离线
我都用全自动的,省io,
最近编辑记录 zhenfanhei (2019-08-20 10:25:31)
离线
实现代码不方便放出来了,不过思路还是很简单的。先在串口发送中断进入时修改到2分之一fifo,将发送置位,在最后中断触发先修改fifo到empty触发,再去判断lsr的最后位有没有发送,接着置位为接收。和ti的实现不同全志串口呵呵呵...
离线
实现代码不方便放出来了,不过思路还是很简单的。先在串口发送中断进入时修改到2分之一fifo,将发送置位,在最后中断触发先修改fifo到empty触发,再去判断lsr的最后位有没有发送,接着置位为接收。和ti的实现不同全志串口呵呵呵...
我的RS485 驱动控制GPIO半双工控制问题也解决了, 在此抛砖引玉: https://whycan.cn/t_4012.html#p39120
离线
@shaoxi2010
请问是如何修改的fifo为1/2触发?我改了之后又立马读,发现改不动。看了用户手册,它是这样说的:
“TFT
TX Empty Trigger
Writes have no effect when THRE_MODE_USER = Disabled. This is used to
select the empty threshold level at which the THRE Interrupts are
generated when the mode is active. lt also determines when the
dma_tx_req_n signal is asserted when in certain modes of operation.
00: FIFO empty
01: 2 characters in the FIFO
10: FIFO 1/4 full
11: FIFO 1/2 full”
离线