当前位置:   article > 正文

迅为rk3568开发板RS485收发切换 linux485驱动修改_rk3568发送485信号

rk3568发送485信号

参考链接:

  1. Linux RS485串口驱动修改方法–基于Rockchip及Amlogic验证
  2. linux驱动 内核层适配485驱动控制引脚

起因

迅为rk3568开发板用的SP3485E芯片,需要在应用程序中控制管脚的高低电平实现收发切换。
发送前先拉高电平,然后发送数据,数据发送完成后再拉低电平,使其处于接收状态。

在程序中,485发送数据后,根据波特率和数据长度计算延时时间,但是在实际应用中发现这个时间不太准确,而且不同的485设备,有的收到数据后延时10ms才返回数据,有的收到后是立即返回数据(延时很短)。如果写入后拉低电平的延时时间过长或过短都会导致通信失败。

在网上找了一些教程,将收发切换放到串口驱动程序中,不用在应用程序中控制。因为之前没有具体做过设备树和驱动程序修改,这里记录下过程。

修改过程

因为这里用的板子硬件固定,所以偷懒在驱动程序里直接根据设备树里的控制管脚来判断是否进行管脚的拉高拉低。
主要修改的有两个地方:一是设备树,二是驱动程序
设备树的修改:

1、设备树文件屏蔽原有的描述

迅为开发板默认的设备树里是将收发控制引脚单独加到了设备树文件里,需要先将其屏蔽掉

/* 把这段屏蔽掉
rk_485_ctl: rk-485-ctl {
            compatible = "topeet,rs485_ctl";
            gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
            pinctrl-names = "default";
            pinctrl-0 = <&rk_485_gpio>;
        };
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、添加新的串口描述

&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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、修改驱动文件

迅为开发板用的是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.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 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

修改8250_dw.c

文件8250_dw.c,一共需要修改2处,一处是增加头文件,一处是获取收发切换的管脚编号。.
1、增加头文件包含

#include <linux/gpio.h>
#include <linux/of_gpio.h>
  • 1
  • 2

在这里插入图片描述

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

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

修改8250_port.c

文件8250_port.c,一共需要修改2处,一处是增加头文件,一处是发送前拉高,发送后拉低的控制。.
1、增加头文件包含

#include <linux/of_gpio.h>
  • 1

在这里插入图片描述

2、增加收发切换控制代码。在函数serial8250_tx_chars中增加以下代码

int lsr; // 用于获取状态
int i;   // 用于循环计数
  • 1
  • 2

发送前先拉高

 if(22 == up->port.rs485.rts_gpio)
 {
         gpio_set_value(up->port.rs485.rts_gpio, 1);
         udelay(2); // 这个延时好像可以不用
  }
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

发送后,循环判断是否结束,结束后拉低。

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                 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

全部修改完成后,重新编译生成boot.img文件,烧写到板子上。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/289635
推荐阅读
相关标签
  

闽ICP备14008679号