linux rs485功能增加

news2024/10/6 6:42:41

目录

串口驱动层级结构

485配置流程

dts相关

配置注册

初始化

485收发切换

delay_after_send


       

目前linux 内核中已经支持了485的实现,但由于底层驱动的支持情况,导致我们采用不同芯片时需要对底层驱动进行修改,以满足内核485的各个回调接口,进而实现485功能。

485 主要在于收发控制切换的时间。本文以 8250为示例,描述485配置及切换的流程。

串口驱动层级结构

不讨论tty,tty以下分为三层

1)串口通用层

2)8250通用层

3)具体的8250芯片驱动层 

    8250_dw为具体芯片层。在解析到dts中有对应的配置时,则调用此去的probe接口。如果dts里面有三个串口,则调用三次probe接口。而后依次调用上一层的接口将串口信息上报。

485配置流程

dts相关

   在 8250_dw向8250注册串口时,8250层回调用通用的485 dts解析函数 uart_get_rs485_mode,以获取该串口对485的支持情况,该函数的代码 如下。通过此代码,我们可以看到几个dts参数,其功能分别为:

dts功能
rs485-rts-delay485收发切换后的延时,单位ms
rs485-term切换GPIO管脚定义
linux,rs485-enabled-at-boot-time是否默认使能485,后续也可以通过ioctl改配

  


/**
 * uart_get_rs485_mode() - retrieve rs485 properties for given uart
 * @port: uart device's target port
 *
 * This function implements the device tree binding described in
 * Documentation/devicetree/bindings/serial/rs485.txt.
 */
int uart_get_rs485_mode(struct uart_port *port)
{
	struct serial_rs485 *rs485conf = &port->rs485;
	struct device *dev = port->dev;
	u32 rs485_delay[2];
	int ret;

	ret = device_property_read_u32_array(dev, "rs485-rts-delay",
					     rs485_delay, 2);
	if (!ret) {
		rs485conf->delay_rts_before_send = rs485_delay[0];
		rs485conf->delay_rts_after_send = rs485_delay[1];
	} else {
		rs485conf->delay_rts_before_send = 0;
		rs485conf->delay_rts_after_send = 0;
	}

	/*
	 * Clear full-duplex and enabled flags, set RTS polarity to active high
	 * to get to a defined state with the following properties:
	 */
	rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED |
			      SER_RS485_TERMINATE_BUS |
			      SER_RS485_RTS_AFTER_SEND);
	rs485conf->flags |= SER_RS485_RTS_ON_SEND;

	if (device_property_read_bool(dev, "rs485-rx-during-tx"))
		rs485conf->flags |= SER_RS485_RX_DURING_TX;

	if (device_property_read_bool(dev, "linux,rs485-enabled-at-boot-time"))
		rs485conf->flags |= SER_RS485_ENABLED;

	if (device_property_read_bool(dev, "rs485-rts-active-low")) {
		rs485conf->flags &= ~SER_RS485_RTS_ON_SEND;
		rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
	}

	/*
	 * Disabling termination by default is the safe choice:  Else if many
	 * bus participants enable it, no communication is possible at all.
	 * Works fine for short cables and users may enable for longer cables.
	 */
	port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
							GPIOD_OUT_LOW);
	if (IS_ERR(port->rs485_term_gpio)) {
		ret = PTR_ERR(port->rs485_term_gpio);
		port->rs485_term_gpio = NULL;
		return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n");
	}

	return 0;
}

配置注册

最底层芯片驱动需要注册:

  1) serial层的回调接口

  int            (*rs485_config)(struct uart_port *,   struct serial_rs485 *rs485);

     完成485相关的初始化

 2)8250层的回调接口:

    void            (*rs485_start_tx)(struct uart_8250_port *);
    void            (*rs485_stop_tx)(struct uart_8250_port *);

   用于控制 485的收发切换

 

初始化

uart_set_rs485_config--》驱动的rs485_config回调

serial8250_em485_config-,除了基本的结构成员初始化,这里主要起了两个高精度定时器的处理函数,用于处理延时后的切换。

static int serial8250_em485_init(struct uart_8250_port *p)
{
	if (p->em485)
		return 0;

	p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
	if (!p->em485)
		return -ENOMEM;

	hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
		     HRTIMER_MODE_REL);
	hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
		     HRTIMER_MODE_REL);
	p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
	p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
	p->em485->port = p;
	p->em485->active_timer = NULL;
	p->em485->tx_stopped = true;

	p->rs485_stop_tx(p);

	return 0;
}

485收发切换

默认接收,切换发送通过 接口 start_tx_rs485 ,相对比较容易。

再切换回接收时,由于存在发送FIFO的情况,需要处理,内核代码中加了判断处理,代码如下:

static inline void __stop_tx(struct uart_8250_port *p)
{
	struct uart_8250_em485 *em485 = p->em485;

	if (em485) {
		unsigned char lsr = serial_in(p, UART_LSR);
		/*
		 * To provide required timeing and allow FIFO transfer,
		 * __stop_tx_rs485() must be called only when both FIFO and
		 * shift register are empty. It is for device driver to enable
		 * interrupt on TEMT.
		 */
		if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
			return;

		__stop_tx_rs485(p);
	}
	__do_stop_tx(p);
}

这里主要判断了LSR寄存器,如果lsr寄存器没有实现 ,则485的切换一直不会进行。笔者就遇到了这种不支持的情况。

delay_after_send

   由于没有lsr的支持,这时需要靠延时来处理何时切换。内核代码已经支持,即delay_after_send,单位为ms。

    比如发640个字节,发送fifo大小为64,那我们可以将此delay设置为

   10bit*1000ms*len/baud

   =10*1000*64/115200= 5.56~~6ms

   实际测试:配置发送FIFO 为空时触发,每次发送64个,则延时配置7ms

    如果发送650个字节,则最后一次发送10个字节,

  10*1000*10/115200=0~1ms  ,则延时配置2ms

  __stop_tx用户在用户缓存数据发送完毕后调用

由此可见,delay和芯片的FIFO大小及触发门限强相关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/478824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux-基本指令2

文章目录 touch(新建一个文件)whoami(查看当前用户名)概念:1.你是如何看待指令的?2.我们在执行指令之前,我们应该先做什么? 概念:/tree . (树状显示文件夹和文件)rmdir && rmrmdirrm ctrl c通配符…

【MFAC】基于全格式动态线性化的无模型自适应控制(Matlab代码)

例题来源:侯忠生教授的《无模型自适应控制:理论与应用》(2013年科学出版社)。 👉对应书本 4.4 单输入单输出系统(SISO)全格式动态线性化(FFDL)的无模型自适应控制(MFAC) 上两篇博客分别介绍了基于紧格式和偏格式动态线…

软件分享--安卓纯文本记事本软件,支持多记事本与密码

文章目录 软件名字:LS记事本支持多记事本安全性:备份和恢复:搜索功能:显示功能:字体调节:轻量绿色下载地址 软件名字:LS记事本 支持多记事本 安全性: 1.每个记事本支持设置访问密码…

【Elasticsearch】几点核心概念

文章目录 核心概念系统架构分布式集群单节点集群故障转移水平扩容应对故障 路由计算(确定哪个主分片)分片控制(确定哪个节点)创建个集群如何查看数据呢?写流程读流程更新流程 分片原理倒序索引文档搜索动态更新索引持久化变更 文档分析内置分…

“Lunar Lobster “现已经可以下载

Canonical近日发布了Ubuntu 23.04(Lunar Lobster)操作系统,这是对其流行的GNU/Linux发行版的一次重大更新,带来了一些最新和最伟大的技术和开源软件。 被称为 “Lunar Lobster”,Ubuntu 23.04由最新的Linux 6.2内核系列…

【计算机网络】学习笔记:第五章 传输层【王道考研】

基于本人观看学习b站王道计算机网络课程所做的笔记&#xff0c;不做任何获利 仅进行交流分享 特此鸣谢王道考研 若有侵权请联系&#xff0c;立删 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0c;如有疑问欢迎…

【数据结构与算法】哈希—— 位图 | 布隆过滤器 | 哈希切割

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《数据结构与算法》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 哈希是一种映射思想&#xff0c;这里再讲解两种应用哈希思想的数据结构。 哈希—— 位图 | …

边学边记——数据结构☞堆(包括优先级队列的介绍)

目录 一、堆&#xff08;二叉堆&#xff09; 堆是用来干什么的&#xff1f; 堆是用什么存储结构存储的&#xff1f; 1. 堆的概念 2. 堆的性质 3. 堆的存储方式 下标之间的规则&#xff1a; 4. 堆的基本操作 (1). 向下调整/堆化操作 (2).堆的创建 (3).堆的插入 (4…

2023-04-30:用go语言重写ffmpeg的resampling_audio.c示例,它实现了音频重采样的功能。

2023-04-30&#xff1a;用go语言重写ffmpeg的resampling_audio.c示例&#xff0c;它实现了音频重采样的功能。 答案2023-04-30&#xff1a; resampling_audio.c 是 FFmpeg 中的一个源文件&#xff0c;其主要功能是实现音频重采样。 音频重采样是指将一段音频数据从一个采样率…

duubo+zookeeper

1、Dubbo简介 1. Dubbo是什么&#xff1f; 高性能、轻量级、开源、基于java Dubbo 是阿里集团开源的远程服务调用的分布式框架&#xff08;告别Web Service模式中的WSDL&#xff0c;以服务者与消费者的方式在dubbo上注册&#xff09; 协议和序列化框架都可以插拔是及其鲜明…

【办公类-22-04】周计划系列(4)-生成“周计划”(提取旧docx指定段落的内容,写入EXCLE模板,再次生成新docx)

代码相当复杂&#xff0c;操作很繁琐&#xff0c;自己都要研究半天T_T 文件夹展示 01提取提取新表的已有内容&#xff08;提取大8班、大7班的新版本里面的额内容&#xff09; &#xff08;需要里面的一些反思&#xff0c;用来占位&#xff09; 这里有一份根据新模板用Python批…

spring2:创建和使用

目录 1.创建Spring项目 1.1创建Maven类 1.2添加Spring支持框架 1.3添加启动类 2.存储Bean对象 2.0 spring项目中添加配置文件(第一次) 2.1创建Bean 2.2把Bean注册到容器中 3.获取并使用Bean对象 3.1创建上下文 3.2获取指定Bean对象 getBean()方法 --> 获取什么…

双周赛103(模拟、网格图BFS、树状数组)

文章目录 双周赛103[6406. K 个元素的最大和](https://leetcode.cn/problems/maximum-sum-with-exactly-k-elements/)模拟 [6405. 找到两个数组的前缀公共数组](https://leetcode.cn/problems/find-the-prefix-common-array-of-two-arrays/)模拟 [6403. 网格图中鱼的最大数目](…

Java 基础进阶篇(一)——— static 静态关键字与单例模式

文章目录 一、static 静态关键字1.1 静态成员变量与实例成员变量1.2 静态成员方法与实例成员方法1.3 static 访问注意事项1.4 内存使用情况 二、工具类三、代码块四、单例模式4.1 饿汉单例4.2 懒汉单例 一、static 静态关键字 static&#xff1a;代表静态的意思&#xff0c;可…

【博学谷学习记录】超强总结,用心分享丨人工智能 AI项目 collate_fn函数理解与记录

目录 Dataloader取数据过程使用报错&#xff1a;默认collate_fn处理不同长度的数据自定义collate_fn伪代码示例 Dataloader取数据过程 取出大小等同于batch size的index列表;将列表列表中的index输入到dataset的getitem()函数中&#xff0c;取出该index对应的数据;对每个index…

一种基于坑位模版的分页方案

一. 概述 1.1 业务诉求 想象一个向用户展示数据的下拉列表&#xff0c;数据的来源有多种方式。支持在每一页都按固定的数据源类型及顺序展示。 1.2 业务场景 up主的主页展示带货商品列表 商品来源有多种&#xff1a;up主自选、官方推荐的、根据up主风格AI推荐用户推荐视频列表…

【编辑刷新数据-汽车品牌展示 Objective-C语言】

一、我们这个利用可重用cell展示汽车品牌案例,就说完了,然后我们再给大家说一个什么东西,就是这个刷新数据这个东西, 1.刷新数据这个东西,我们用的就是代理,再把代理相当于是再给大家复习一下,再把代理复习一下,顺便再说一下怎么刷新数据, 2.接下来,要实现一个什么功…

基于UDQ的并网单相逆变器控制【同步参考系下单相并网全桥正弦PWM逆变器闭环控制】(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

day9 实现UDP通信

目录 socket函数拓展 UDP通信实现过程 代码实现 socket函数拓展 send与recv函数&#xff1a; /*用于发送数据*/ ssize_t send(int sockfd, const void *buf, size_t len,int flags);/*用于接收数据*/ ssize_t recv(int sockfd, void *buf, size_t len,int flags);/*前三个…

无敌0代码ESP8266接入homeassistant的新方法,完美解决新版homeassistant无法自定义MQTT设备的问题

记得之前想要在homeassistant中添加MQTT设备只要在配置文件 configuration.yaml 中配置如下代码即可 但是现在这种方法已经行不通&#xff0c;设备也步显示出来&#xff0c;这给很多homeassistant的忠实粉丝带来巨大不便&#xff0c;作为粉丝的一份子&#xff0c;我绝步允许这种…