赞
踩
迅为rk3568开发板用的SP3485E芯片,需要在应用程序中控制管脚的高低电平实现收发切换。
发送前先拉高电平,然后发送数据,数据发送完成后再拉低电平,使其处于接收状态。
在程序中,485发送数据后,根据波特率和数据长度计算延时时间,但是在实际应用中发现这个时间不太准确,而且不同的485设备,有的收到数据后延时10ms才返回数据,有的收到后是立即返回数据(延时很短)。如果写入后拉低电平的延时时间过长或过短都会导致通信失败。
在网上找了一些教程,将收发切换放到串口驱动程序中,不用在应用程序中控制。因为之前没有具体做过设备树和驱动程序修改,这里记录下过程。
因为这里用的板子硬件固定,所以偷懒在驱动程序里直接根据设备树里的控制管脚来判断是否进行管脚的拉高拉低。
主要修改的有两个地方:一是设备树,二是驱动程序。
设备树的修改:
迅为开发板默认的设备树里是将收发控制引脚单独加到了设备树文件里,需要先将其屏蔽掉。
/* 把这段屏蔽掉
rk_485_ctl: rk-485-ctl {
compatible = "topeet,rs485_ctl";
gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&rk_485_gpio>;
};
*/
&uart7 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart7m1_xfer>; // 迅为用的是uart7_m1,根据自己的实际情况修改
rts-gpio = <&gpio0 22 GPIO_ACTIVE_HIGH>; // 这个就是收发控制引脚,如果自己画的底板,根据实际情况修改
// rs485-rts-active-low;
// rs485-rts-delay = <5 100>;
linux,rs485-enabled-at-boot-time;
};
迅为开发板用的是8250的串口程序。这里一共需要修改以下3个文件。
/home/topeet/rk356x_linux/kernel/include/uapi/linux/serial.h
/home/topeet/rk356x_linux/kernel/drivers/tty/serial/8250/8250_dw.c
/home/topeet/rk356x_linux/kernel/drivers/tty/serial/8250/8250_port.c
文件serial.h,在结构体serial_rs485的定义中,增加一个rts_gpio的整型变量,用来存储上收发控制引脚的gpio号.
struct serial_rs485 { __u32 flags; /* RS485 feature flags */ #define SER_RS485_ENABLED (1 << 0) /* If enabled */ #define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for RTS pin when sending */ #define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for RTS pin after sent*/ #define SER_RS485_RX_DURING_TX (1 << 4) #define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus termination (if supported) */ __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ __u32 padding[5]; /* Memory is cheap, new structs are a royal PITA .. */ // 2023.11.13 新增 __u32 rts_gpio; // 2023.11.13 新增 }; #endif /* _UAPI_LINUX_SERIAL_H */
文件8250_dw.c,一共需要修改2处,一处是增加头文件,一处是获取收发切换的管脚编号。.
1、增加头文件包含
#include <linux/gpio.h>
#include <linux/of_gpio.h>
2、在static int dw8250_probe()函数里,增加如下代码,用来获取收发控制引脚的编号。
uart.port.rs485.rts_gpio = of_get_named_gpio(p->dev->of_node, "rts-gpio", 0);
if(22 == uart.port.rs485.rts_gpio)
{
gpio_direction_output(uart.port.rs485.rts_gpio, 0);
gpio_set_value(uart.port.rs485.rts_gpio, 0); // defalut low-level
}
文件8250_port.c,一共需要修改2处,一处是增加头文件,一处是发送前拉高,发送后拉低的控制。.
1、增加头文件包含
#include <linux/of_gpio.h>
2、增加收发切换控制代码。在函数serial8250_tx_chars中增加以下代码
int lsr; // 用于获取状态
int i; // 用于循环计数
发送前先拉高
if(22 == up->port.rs485.rts_gpio)
{
gpio_set_value(up->port.rs485.rts_gpio, 1);
udelay(2); // 这个延时好像可以不用
}
发送后,循环判断是否结束,结束后拉低。
1873 if(22 == up->port.rs485.rts_gpio)
1874 {
1875 for(i = 0; i < 200; i++)
1876 {
1877 mdelay(3);
1878 lsr = serial_in(up, UART_LSR);
1879 if(UART_LSR_TEMT == (lsr & UART_LSR_TEMT))
1880 {
1881 printk("[%d] wait finished: %d, lsr: %d\n", i, (lsr & UART_LSR_TEMT) == UART_LSR_TEMT, lsr);
1882 break;
1883 }
1884 }
1885 gpio_set_value(up->port.rs485.rts_gpio, 0);
1886 }
全部修改完成后,重新编译生成boot.img文件,烧写到板子上。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。