Linux UART 驱动开发全解析:从原理到实战

UART(Universal Asynchronous Receiver/Transmitter)串口通信接口是嵌入式系统中最基础、最常用的外设之一,广泛用于系统调试、终端通信、外设互联等场景。本文将从通信原理、SoC 内部控制器结构、Linux 驱动架构、设备树配置、驱动实现与调试等多个方面,全面解析 UART 驱动的开发流程。


一、UART 通信原理简介

UART 是一种异步串行通信协议,通过 TX(发送)和 RX(接收)两根数据线进行数据传输。常见通信参数包括:

  • 波特率(Baud Rate):如 9600、115200 等,代表每秒传输的符号数;
  • 数据位(Data Bits):常为 8 位;
  • 校验位(Parity Bit):可选,支持奇偶校验;
  • 停止位(Stop Bit):通常为 1 位或 2 位。

通信时序如下:

复制代码
| 起始位(Start Bit) | 数据位(8位) | 校验位 | 停止位 |
|         0           |  10101010     |   1    |    1   |

UART 通信无需时钟同步,适用于点对点、低速通信,具有电路简单、开销低的特点。


二、SoC 中的 UART 控制器原理

UART 控制器是串口通信的核心硬件模块。在 SoC(System on Chip)内部,通常集成多个 UART 控制器,每个控制器通过片上总线(如 AMBA APB/AHB)与 CPU 通信,驱动程序通过映射的 MMIO 寄存器操作控制器。

1. UART 控制器结构组成

一个标准的 UART 控制器包含以下子模块:

模块 功能说明
波特率发生器(Baud Rate Generator) 通过分频器将主频转换为目标波特率
发送 FIFO(TX FIFO) 发送缓冲区,一般为 16~64 字节
接收 FIFO(RX FIFO) 接收缓冲区
中断控制器 支持 TX 空、RX 满等中断
状态管理逻辑 表示忙碌、错误等状态
配置/控制寄存器接口 供驱动程序控制和读取状态

2. 常见寄存器接口(以通用 UART 控制器为例)

寄存器名 功能说明
DR Data Register,读写数据
FR Flag Register,状态标志,如 FIFO 满/空
IBRD 整数分频设置(波特率)
FBRD 小数分频设置(波特率)
CR Control Register,启用 TX/RX、使能串口
IMSC Interrupt Mask,配置中断源

3. 数据传输流程

发送过程:
复制代码
CPU --> DR寄存器 --> TX FIFO --> 串口发送逻辑 --> TX 引脚输出
接收过程:
复制代码
RX 引脚输入 --> 接收逻辑 --> RX FIFO --> DR寄存器 --> CPU读取

支持中断方式和 DMA 模式。


三、Linux 串口驱动框架分析

在 Linux 内核中,UART 驱动属于字符设备驱动,其框架包括以下几个层级:

复制代码
应用层程序(终端/串口调试器)
         ↓
TTY 子系统(ttyS、ttyAMA、ttyPS 等)
         ↓
串口驱动(serial_core + UART 控制器驱动)
         ↓
硬件 UART 控制器(SoC 内部 IP)

1. 串口驱动层次结构

层级 说明
应用层 使用标准 I/O 接口打开 /dev/ttyS0
TTY 层 提供标准串口 API,如 open, read, write, ioctl
serial_core Linux 内核串口核心框架,统一管理 UART 驱动
UART 驱动 硬件控制器的具体实现,提供寄存器读写、FIFO 操作等
硬件层 SoC 内部 UART 控制器,接收 CPU 操作并驱动 TX/RX 引脚

2. 串口驱动关键结构体

  • struct uart_driver:注册给 serial_core,表示一个驱动;
  • struct uart_ops:操作函数集,如 start_tx, stop_tx, startup, shutdown
  • struct uart_port:描述一个 UART 控制器的所有状态,如地址、波特率、中断号等。

四、设备树配置 UART 控制器

现代 ARM 平台采用设备树描述硬件 UART 控制器。例如:

dts 复制代码
&uart2 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart2>;
    status = "okay";
};

设备树会通过 compatible 属性匹配驱动,驱动通过 of_match_table 自动加载。


五、UART 驱动代码实现(简化版)

以下为简化后的 UART 驱动骨架:

c 复制代码
static struct uart_ops my_uart_ops = {
    .startup = my_uart_startup,
    .shutdown = my_uart_shutdown,
    .tx_empty = my_uart_tx_empty,
    .start_tx = my_uart_start_tx,
    .stop_tx = my_uart_stop_tx,
    .set_termios = my_uart_set_termios,
    // ...
};

static struct uart_driver my_uart_driver = {
    .owner = THIS_MODULE,
    .driver_name = "my_uart",
    .dev_name = "ttyMY",
    .major = 204,
    .minor = 64,
    .nr = 1,
};

static int __init my_uart_init(void)
{
    uart_register_driver(&my_uart_driver);
    // 注册 port,调用 uart_add_one_port()
}

注意:完整驱动需实现中断处理函数、FIFO 操作逻辑、寄存器读写等。


六、UART 驱动调试方法

  1. 确认串口是否注册成功:

    bash 复制代码
    dmesg | grep tty
    ls /dev/ttyS*
  2. 查看设备树配置是否正确:

    bash 复制代码
    cat /proc/device-tree/soc/serial@xxxx/compatible
  3. 使用 minicom 或 picocom 测试通信:

    bash 复制代码
    picocom -b 115200 /dev/ttyS0
  4. 查看中断是否触发:

    bash 复制代码
    cat /proc/interrupts | grep uart
  5. 打印寄存器状态排查问题:

    在驱动中加入 readl/writel 打印,检查波特率、TX/RX FIFO 状态等。


七、总结与扩展

本文完整解析了 UART 的通信原理、SoC 控制器结构、驱动架构与实现方式,帮助你从零理解并实现一个 Linux 串口驱动。

推荐扩展学习方向:

  • DMA 模式串口传输
  • RS485/Modbus 协议支持
  • 异常处理与功耗管理
  • Console earlyprintk 支持(内核早期调试)
相关推荐
深夜情感老师44 分钟前
centos离线安装ssh
linux·centos·ssh
夸克App3 小时前
实现营销投放全流程自动化 超级汇川推出信息流智能投放产品“AI智投“
运维·人工智能·自动化
Rainbond云原生3 小时前
83k Star!n8n 让 AI 驱动的工作流自动化触手可及
运维·人工智能·自动化
木觞清3 小时前
深度对比评测:n8n vs Coze(扣子) vs Dify - 自动化工作流工具全解析
运维·自动化
中云时代-防御可测试-小余3 小时前
高防IP是如何防护DDoS攻击和CC攻击的
运维·服务器·tcp/ip·安全·阿里云·ddos·宽度优先
网硕互联的小客服4 小时前
如何模拟黑客攻击(Red Teaming)以测试服务器安全性
运维·服务器
樽酒ﻬق4 小时前
Kubernetes 常用运维命令整理
运维·容器·kubernetes
菜鸟射手5 小时前
QT creater和vs2017文件路径问题
linux·c++·windows·qt
wt_cs5 小时前
身份证实名认证:通往数字安全与便捷生活的钥匙
运维·服务器
@Aurora.6 小时前
【项目日记(三)】
linux·服务器·网络