Linux内核早期打印机制与RS485通信技术

往期内容

本专栏往期内容:Uart子系统

  1. UART串口硬件介绍
  2. 深入理解TTY体系:设备节点与驱动程序框架详解
  3. Linux串口应用编程:从UART到GPS模块及字符设备驱动
  4. 解UART 子系统:Linux Kernel 4.9.88 中的核心结构体与设计详解
  5. IMX 平台UART驱动情景分析:注册篇
  6. IMX 平台UART驱动情景分析:open篇
  7. IMX 平台UART驱动情景分析:read篇–从硬件驱动到行规程的全链路剖析
  8. IMX 平台UART驱动情景分析:write篇–从 TTY 层到硬件驱动的写操作流程解析
  9. 深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现
    10.Linux 内核日志系统—printk的机制与应用

interrupt子系统专栏:

  1. 专栏地址:interrupt子系统
  2. Linux 链式与层级中断控制器讲解:原理与驱动开发
    – 末片,有专栏内容观看顺序

pinctrl和gpio子系统专栏:

  1. 专栏地址:pinctrl和gpio子系统

  2. 编写虚拟的GPIO控制器的驱动程序:和pinctrl的交互使用

    – 末片,有专栏内容观看顺序

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有专栏内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有专栏内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有专栏内容观看顺序

img

目录

  • 往期内容
  • 前言
  • 1.early_printk和earlycon
    • 1.1 内核信息的早期打印
    • 1.2 early_printk
    • 1.3 earlycon
  • 2.RS485简单讲解
    • 2.1 RS485线路图
    • 2.2 RS485应用编程
      • 2.2.1 标准用法
      • 2.2.2 自己控制引脚
    • 2.3 驱动速览
      • 2.3.1 使用GPIO的RS485驱动

前言

本文围绕Linux内核早期打印机制和RS485通信技术展开,详细解析了early_printk和earlycon的实现与使用场景,以及RS485的基础原理和应用实践。在早期打印部分,阐明了early_printk和earlycon的区别:前者通过手动实现打印函数实现早期日志输出,后者则结合设备树实现灵活硬件映射,适用于现代系统。在RS485部分,介绍了其差分信号传输、抗干扰能力强等技术特点,并结合SP3485芯片说明了发送与接收的硬件原理,同时提供了Linux环境下的标准驱动编程示例,涵盖RTS控制模式与GPIO实现方式。

1.early_printk和earlycon

linux 4.9.88

  • arch\arm\kernel\early_printk.c📎early_printk.c
  • drivers\tty\serial\earlycon.c📎earlycon.c

1.1 内核信息的早期打印

console驱动,它属于uart_driver的一部分。

注册了uart_driver、并调用uart_add_one_port后,它里面才注册console,在这之后才能使用printk。

如果想更早地使用printk函数,比如在安装UART驱动之前就使用printk,这时就需要自己去注册console。

更早地、单独地注册console,有两种方法:

  • early_printk:自己实现write函数,不涉及设备树,简单明了
  • earlycon:通过设备树传入硬件信息,跟内核中驱动程序匹配

earlycon是新的、推荐的方法,在内核已经有驱动的前提下,通过设备树或cmdline指定寄存器地址即可。

1.2 early_printk

源码为:arch\arm\kernel\early_printk.c,要使用它,必须实现这几点:

  • 配置内核,选择:CONFIG_EARLY_PRINTK
  • 内核中实现:printch函数
  • cmdline中添加:earlyprintk

img

1.3 earlycon

arch\arm\kernel\early_printk.c📎early_printk.c

drivers\tty\serial\earlycon.c📎earlycon.c

提供硬件信息的两种方法:

earlycon就是early console的意思,实现的功能跟earlyprintk是一样的,只是更灵活。

我们知道,对于console,最主要的是里面的write函数:它不使用中断,相对简单。

所以很多串口console的write函数,只要确定寄存器的地址就很容易实现了。

假设芯片的串口驱动程序,已经在内核里实现了,我们需要根据板子的配置给它提供寄存器地址。

怎么提供?

  • 设备树
  • cmdline参数
early_param("earlycon", param_setup_earlycon);
//如上图所示,当在cmdline参数中有erlycon这个属性的时候,就会导致param_setup_earlycon被调用/* early_param wrapper for setup_earlycon() */
static int __init param_setup_earlycon(char *buf)
{int err;/** Just 'earlycon' is a valid param for devicetree earlycons;* don't generate a warning from parse_early_params() in that case*/if (!buf || !buf[0]) {if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {earlycon_init_is_deferred = true;return 0;} else {return early_init_dt_scan_chosen_stdout(); //1. earlycon不带参数,参数采用设备节点表示}}err = setup_earlycon(buf);  //2. earlycon = XX,带参数if (err == -ENOENT || err == -EALREADY)return 0;return err;
}
  • 如果cmdline中只有"earlycon",不带更多参数:对应early_init_dt_scan_chosen_stdout函数

    • 使用"/chosen"下的"stdout-path"找到节点

    • 或使用"/chosen"下的"linux,stdout-path"找到节点

    • 节点里有"compatible"和"reg"属性

      • 根据"compatible"找到OF_EARLYCON_DECLARE,里面有setup函数,它会提供write函数
      • write函数写什么寄存器?在"reg"属性里确定
  • 如果cmdline中"earlycon=xxx",带有更多参数:对应setup_earlycon函数

    • earlycon=xxx格式为:
<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
<name>,0x<addr>,<options>
<name>,<options>
<name>
    • 根据"name"找到OF_EARLYCON_DECLARE,里面有setup函数,它会提供write函数
    • write函数写什么寄存器?在"addr"参数里确定

imgimg

2.RS485简单讲解

Documentation\serial\serial-rs485.txt📎serial-rs485.txt

2.1 RS485线路图

RS485通信----基本原理+电路图-CSDN博客

RS485 是美国电子工业协会(Electronic Industries Association,EIA)于1983年发布的串行通信接口标准,经通讯工业协会(TIA)修订后命名为 TIA/EIA-485-A。

RS485 是一种工业控制环境中常用的通讯协议,其中RS 是 Recommended Standard 的缩写。

RS485 是 半双工异步 串行通信。

特点

  1. 支持多节点:一般最大支持 32 个节点。
  2. 传输距离远:最远通讯距离可达1200米。
  3. 抗干扰能力强:差分信号传输。
  4. 连接简单:只需要两根信号线(A+和B-)就可以进行正常的通信。

差分信号传输

RS485 通信采用差分信号传输,通常情况下只需要两根信号线就可以进行正常的通信。

在差分信号中,逻辑0和逻辑1是用两根信号线(A+和B-)的电压差来表示。

  • 逻辑 1:两根信号线(A+和B-)的电压差在 +2V~+6V 之间。
  • 逻辑 0:两根信号线(A+和B-)的电压差在 -2V~-6V 之间。

SP3485 芯片****是一款非常经典的+3.3V低功耗半双工RS485收发器

RS485使用A、B两条差分线传输数据:

  • 要发送数据时

    • 把SP3485的DE(Driver output Enable)引脚设置为高
    • 通过TxD引脚发送1给SP3485,SP3485会驱动A、B引脚电压差为+2~+6V
    • 通过TxD引脚发送0给SP3485,SP3485会驱动A、B引脚电压差为-6~-2V
    • SP3485自动把TxD信号转换为AB差分信号
    • 对于软件来说,通过RS485发送数据时,跟一般的串口没区别,只是多了DE引脚的设置
  • 要读取数据时

    • 把SP3485的nRE(Receiver Output Enable)引脚设置为低
    • SP3485会根据AB引脚的电压差驱动RO为1或0
    • RO的数据传入UART的RxD引脚
    • 对于软件来说,通过RS485读取数据时,跟一般的串口没区别,只是多了nRE引脚的设置

img

  • nRE和DE使用同一个引脚时,可以简化成这样:

    • 发送:RTS输出高 — 导致DE为高,使能发送,nRE为低,接收禁止
    • 接收:RTS输出低 ---- 导致nRE为低,使能接收,DE为低,发送禁止

img

img

引脚名称功能
1RO接收器输出----接RX
2RE接收器输出使能(低电平-接收使能)
3DE驱动器输出使能(高电平-发送使能)
4DI驱动器输入----接TX
5GND接地
6A驱动器输出/接收器输入(同相)
7B驱动器输出/接收器输入(反相)
8VCC芯片供电+3.3V

img

2.2 RS485应用编程

2.2.1 标准用法

在Linux的串口驱动中,它已经支持RS485,可以使用RTS引脚控制RS485芯片的DE引脚,分两种情况

  • 有些UART驱动:使用UART的RTS引脚
  • 有些UART驱动:使用GPIO作为RTS引脚,可以通过设备树指定这个GPIO

img

在使用RS485发送数据前,把RTS设置为高电平就可以。

通过serial_rs485结构体控制RTS,示例代码如下:

#include <linux/serial.h>/* 用到这2个ioctl: TIOCGRS485, TIOCSRS485 */
#include <sys/ioctl.h>struct serial_rs485 rs485conf;/* 打开串口设备 */
int fd = open ("/dev/mydevice", O_RDWR);
if (fd < 0) {/* 失败则返回 */return -1;
}/* 读取rs485conf */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {/* 处理错误 */
}/* 使能RS485模式 */
rs485conf.flags |= SER_RS485_ENABLED;/* 当发送数据时, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;/* 或者: 当发送数据时, RTS为0 */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);/* 当发送完数据后, RTS为1 */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;/* 或者: 当发送完数据后, RTS为0 */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);/* 还可以设置: * 发送数据之前先设置RTS信号, 等待一会再发送数据* 等多久? delay_rts_before_send(单位ms)*/
rs485conf.delay_rts_before_send = ...;/* 还可以设置: * 发送数据之后, 等待一会再清除RTS信号* 等多久? delay_rts_after_send(单位ms)*/
rs485conf.delay_rts_after_send = ...;/* 如果想在发送RS485数据的同时也接收数据, 还可以这样设置 */
rs485conf.flags |= SER_RS485_RX_DURING_TX;if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {/* 处理错误 */
}/* 使用read()和write()就可以读、写数据了 *//* 关闭设备 */
if (close (fd) < 0) {/* 处理错误 */
}

img

2.2.2 自己控制引脚

发送之前,自己设置GPIO控制DE引脚。

2.3 驱动速览

源码为:Linux-4.9.88\drivers\tty\serial\imx.c:📎imx.c

img

2.3.1 使用GPIO的RS485驱动

这里只是举个例子。

源码为:Linux-4.9.88\drivers\tty\serial\omap-serial.c📎omap-serial.c

1. 从设备树获得用作RTS的GPIO

img

2.发送数据前设置GPIO

img

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

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

相关文章

汽车网络安全 -- IDPS如何帮助OEM保证车辆全生命周期的信息安全

目录 1.强标的另一层解读 2.什么是IDPS 2.1 IDPS技术要点 2.2 车辆IDPS系统示例 3.车辆纵深防御架构 4.小结 1.强标的另一层解读 在最近发布的国家汽车安全强标《GB 44495》,在7.2节明确提出了12条关于通信安全的要求,分别涉及到车辆与车辆制造商云平台通信、车辆与车辆…

如何利用内链策略提升网站的整体权重?

内链是谷歌SEO中常常被低估的部分&#xff0c;实际上&#xff0c;合理的内链策略不仅能帮助提升页面间的关联性&#xff0c;还可以增强网站的整体权重。通过正确的内链布局&#xff0c;用户可以更流畅地浏览你的网站&#xff0c;谷歌爬虫也能更快地抓取到更多页面&#xff0c;有…

工业—使用Flink处理Kafka中的数据_ChangeRecord2

使用 Flink 消费 Kafka 中 ChangeRecord 主题的数据&#xff0c;每隔 1 分钟输出最近 3 分钟的预警次数最多的 设备&#xff0c;将结果存入Redis 中&#xff0c; key 值为 “warning_last3min_everymin_out” &#xff0c; value 值为 “ 窗口结束时间&#xff0c;设备id” &am…

力扣第90题:带重复元素的子集

力扣第90题&#xff1a;带重复元素的子集 问题描述 给定一个整数数组nums&#xff0c;该数组可能包含重复元素。返回该数组所有可能的子集&#xff08;幂集&#xff09;&#xff0c;并且子集中的元素需要去重。返回的子集中的每个元素应按照非递减顺序排列。 例如&#xff0…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十九,ffmpeg封装

封装就是将 一个h264&#xff0c;和一个aac文件重新封装成一个mp4文件。 这里我们的h264 和 aac都是来源于另一个mp4文件&#xff0c;也就是说&#xff0c;我们会将 in.mp4文件解封装成一路videoavstream 和 一路 audioavstream&#xff0c;然后 将这两路的 avstream 合并成一…

LVS默认的工作模式支持哪些负载均衡算法?

LVS默认的工作模式支持哪些负载均衡算法? LVS&#xff08;Linux Virtual Server&#xff09;默认支持多种负载均衡算法&#xff0c;这些算法在不同的场景下具有各自的优势。以下是 LVS 默认支持的负载均衡算法及其特点&#xff1a; 1. 轮询调度&#xff08;Round Robin Sched…

汇编语言学习-二

好吧&#xff0c;已经隔了两天&#xff0c;下完班看了两天&#xff0c;在电脑上装了虚拟机版的MS_DOS,主要是怕折腾坏我的电脑系统&#xff1b; 这个第二天应该是称为第二章更为合适&#xff0c;目前第二章已经看完&#xff0c;基本的命令也是敲了敲&#xff1b; 下面就进行一…

等差数列末项计算

等差数列末项计算 C语言代码C 代码Java代码Python代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 给出一个等差数列的前两项a1&#xff0c;a2&#xff0c;求第n项是多少。 输入 一行&#xff0c;包含三个整数a1&#xff0c;a2&#x…

【笔记2-1】ESP32:基于vscode的espidf插件的开发环境搭建

主要参考b站宸芯IOT老师的视频&#xff0c;记录自己的笔记&#xff0c;老师讲的主要是linux环境&#xff0c;但配置过程实在太多问题&#xff0c;就直接用windows环境了&#xff0c;老师也有讲一些windows的操作&#xff0c;只要代码会写&#xff0c;操作都还好&#xff0c;开发…

Redis设计与实现第17章 -- 集群 总结2(执行命令 重新分片)

17.3 在集群中执行命令 接收命令的节点会计算出命令要处理的数据库键属于哪个槽&#xff0c;并检查这个槽是否指派给了自己&#xff1a; 如果是的话&#xff0c;直接执行这个命令 否则&#xff0c;节点向客户端返回一个MOVED错误&#xff0c;指引客户端转向redirect至正确的节…

基于Java Springboot蛋糕订购小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…

如何在GitHub上Clone项目:一步步指南

GitHub作为全球最大的代码托管平台&#xff0c;汇聚了无数开发者的智慧结晶。对于初学者和资深开发者来说&#xff0c;学会如何从GitHub上克隆&#xff08;Clone&#xff09;项目是一项基本且重要的技能。本文将详细介绍如何在GitHub上克隆项目的步骤&#xff0c;帮助你轻松将他…

使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限&#xff0c;校验过用户的用户名和密码后&#xff0c;会向用户响应一段经过加密的token&#xff0c;在这段token中可能储存了数据权限等&#xff0c;在后期的访问中&#xff0c;需要携带这段token&#xff0c;后台解析这段token才…

脚本数据库操作 -- 查表、增加字段、备忘录

一、查询数据库中所有表 在MySQL中&#xff0c;您可以使用INFORMATION_SCHEMA数据库来查询数据库中所有表的列表。INFORMATION_SCHEMA是一个特殊的数据库&#xff0c;它包含了关于其他所有数据库的元数据。 以下是查询当前数据库中所有表的SQL语句&#xff1a; SELECT TABLE…

H3C OSPF实验

实验拓扑 实验需求 按照图示配置 IP 地址按照图示分区域配置 OSPF &#xff0c;实现全网互通为了路由结构稳定&#xff0c;要求路由器使用环回口作为 Router-id&#xff0c;ABR 的环回口宣告进骨干区域 实验解法 一、配置IP地址 [R1]int l0 [R1-LoopBack0]ip add 1.1.1.1 32 […

LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型 Matlab代码注释清晰。 程序设计 完整程序和数据获取方式&#xff1a;私信博主回复LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型&#xff08;Matlab&#…

flutter 报错 error: unable to find git in your path.

项目issue&#xff1a;WIndows: "Unable to find git in your PATH." if terminal is not in admin mode Issue #123995 flutter/flutter 解决办法&#xff0c; 方法一&#xff1a;每次想要运行flutter的时候以管理员方式运行&#xff0c;比如以管理方式运行vsco…

Ai编程cursor + sealos + devBox实现登录以及用户管理增删改查(十三)

一、什么是 Sealos&#xff1f; Sealos 是一款以 Kubernetes 为内核的云操作系统发行版。它以云原生的方式&#xff0c;抛弃了传统的云计算架构&#xff0c;转向以 Kubernetes 为云内核的新架构&#xff0c;使企业能够像使用个人电脑一样简单地使用云。 二、适用场景 业务运…

CSS学习记录02

CSS颜色 指定颜色是通过使用预定义的颜色名称&#xff0c;或RGB&#xff0c;HEX&#xff0c;HSL&#xff0c;RGBA&#xff0c;HSLA值。 CSS颜色名 在CSS中&#xff0c;可以使用颜色名称来指定颜色&#xff1a; CSS背景色 您可以为HTML元素设置背景色&#xff1a; <h1 s…

用micropython 操作stm32f4单片机实现串口通讯

from buzzer import Buzzer import pyb import machine # 导入 machine 模块以访问硬件功能 import time # 导入 time 模块以使用与时间相关的函数 from TOFSense import TOFSense_F #导入TOFSense_F板块 import binascii #二进制到 ASCII 的转换&#xff08;编码&#xff09…