RK3576开发板UART驱动实战教程,基于触觉智能开发板演示
触觉智能Purple Pi OH2开发板,板载2x20Pin的GPIO排针(兼容树莓派),可拓展UART串口等设备。本文基于Purple Pi OH2开发板讲解和调试UART概念、原理、代码示例、调试方法等
一、UART基本概念
1.1什么是UART?
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是最常用的串行通信接口,用于:
•调试输出:打印内核启动信息
•设备通信:与GPS、蓝牙、WiFi等模块通信
•数据透传:与上位机或其他MCU交换数据
1.2 UART通信原理
参数 |
说明 |
常用值 |
波特率 |
每秒传输的比特数 |
115200, 9600 |
数据位 |
每个字符的数据位数 |
8 bits |
停止位 |
字符结束标志 |
1 bit |
校验位 |
错误检测 |
None/Even/Odd |
1.3 RK3576 UART资源
RK3576提供12路UART,触觉智能Purple Pi OH2配套核心板SOM7609系列全引脚引出:
•uart0~uart11
•uart0通常用作调试串口(Debug)
从设备树别名可见:
serial0 = &uart0; // 通常 Debug 串口 serial1 = &uart1; serial2 = &uart2; ... serial11 = &uart11;
二、UART硬件连接
2.1 Purple Pi OH2板载UART接口(GPIO排针)
2.2 UART引脚定义
信号 |
方向 |
说明 |
TX |
输出 |
发送数据 |
RX |
输入 |
接收数据 |
RTS |
输出 |
请求发送(流控) |
CTS |
输入 |
清除发送(流控) |
2.3 UART双工模式
UART支持两种通信模式,由硬件设计和软件配置决定。
模式 |
特点 |
硬件要求 |
应用场景 |
全双工 |
TX、RX同时工作,独立传输 |
TX、RX分开连接 |
调试串口、蓝牙、GPS |
半双工 |
TX、RX分时工作,共享总线 |
需要方向控制引脚 |
RS-485、Modbus |
全双工配置
设备树配置(全双工):
&uart2 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart2m0_xfer>; /* TX/RX 分开 */ };
半双工配置
软件实现(半双工RS-485):
/* 发送数据 */ void rs485_send(struct uart_dev *priv, u8 *data, int len) { /* 拉高 DE 引脚,切换到发送模式 */ gpio_set_value(priv->de_gpio, 1); /* 发送数据 */ uart_write(priv, data, len); /* 等待发送完成 */ uart_wait_tx_complete(priv); /* 拉低 DE 引脚,切换到接收模式 */ gpio_set_value(priv->de_gpio, 0); }
设备树配置(半双工+方向控制):
&uart2 { status = "okay"; pinctrl-names = "default", "rs485"; pinctrl-0 = <&uart2m0_xfer>; pinctrl-1 = <&uart2m0_rs485>; rs485-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>; rs485-rts-active-high; linux,rs485-enabled-at-boot-time; };
流控模式(硬件流控)
设备树配置(硬件流控):
&uart2 { status = "okay"; pinctrl-names = "default"; /* 包含 TX/RX/RTS/CTS */ pinctrl-0 = <&uart2m0_xfer &uart2m0_ctsn &uart2m0_rtsn>; /* 启用 CTS/RTS 流控 */ cts-cts-cts; rts-cts-rts; };
双工模式对比
特性 |
全双工 |
半双工 |
硬件流控 |
数据线 |
TX/RX分开 |
TX/RX共用 |
TX/RX + RTS/CTS |
同时收发 |
支持 |
不支持 |
支持 |
方向切换 |
不需要 |
需要GPIO |
自动 |
速率限制 |
高 |
低(切换开销) |
高 |
应用场景 |
调试、蓝牙 |
RS-485、Modbus |
高速可靠传输 |
三、UART设备树配置
3.1使能UART节点
编辑ido-evb7609-v1a.dtsi:
&uart2 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart2m0_xfer &uart2m0_ctsn>; };
3.2 UART蓝牙配置
wireless_bluetooth: wireless-bluetooth { compatible = "bluetooth-platdata"; clocks = <&hym8563>; clock-names = "ext_clock"; uart_rts_gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>; pinctrl-names = "default", "rts_gpio"; pinctrl-0 = <&uart2m0_rtsn>; pinctrl-1 = <&uart2_gpios>; BT,reset_gpio = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>; BT,wake_gpio = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; BT,wake_host_irq = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; status = "okay"; };
status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart3m0_xfer>; };
3.2 pinctrl引脚配置
&pinctrl { uart2 { uart2m0_xfer: uart2m0-xfer { rockchip,pins = /* uart2_rxm0 */ <4 RK_PA4 8 &pcfg_pull_up>, /* uart2_txm0 */ <4 RK_PA5 8 &pcfg_pull_none>; }; }; uart3 { uart3m0_xfer: uart3m0-xfer { rockchip,pins = /* uart3_rxm0 */ <3 RK_PC6 9 &pcfg_pull_up>, /* uart3_txm0 */ <3 RK_PC7 9 &pcfg_pull_none>; }; }; };
四、UART驱动开发
4.1内核空间UART操作
#include #include #include struct my_uart_dev { struct uart_port port; struct clk *clk; void __iomem *regs; int irq; }; /* UART 寄存器偏移 */ #define UART_TX 0x00 #define UART_RX 0x00 #define UART_IER 0x04 #define UART_IIR 0x08 #define UART_LSR 0x14 /* 发送数据 */ static void my_uart_tx_char(struct my_uart_dev *priv, unsigned char ch) { /* 等待发送 FIFO 空 */ while (!(readl(priv->regs + UART_LSR) & 0x20)) cpu_relax(); /* 写入数据 */ writel(ch, priv->regs + UART_TX); } /* 接收中断处理 */ static irqreturn_t my_uart_irq(int irq, void *dev_id) { struct my_uart_dev *priv = dev_id; unsigned int iir, status; unsigned char ch; iir = readl(priv->regs + UART_IIR); /* 处理接收中断 */ if (iir & 0x04) { status = readl(priv->regs + UART_LSR); while (status & 0x01) { /* 数据就绪 */ ch = readl(priv->regs + UART_RX); /* 将数据推送到 TTY 层 */ tty_insert_flip_char(&priv->port.state->port, ch, TTY_NORMAL); tty_flip_buffer_push(&priv->port.state->port); status = readl(priv->regs + UART_LSR); } } return IRQ_HANDLED; } /* UART 操作接口 */ static const struct uart_ops my_uart_ops = { .tx_empty = my_uart_tx_empty, .set_mctrl = my_uart_set_mctrl, .get_mctrl = my_uart_get_mctrl, .stop_tx = my_uart_stop_tx, .start_tx = my_uart_start_tx, .stop_rx = my_uart_stop_rx, .enable_ms = my_uart_enable_ms, .break_ctl = my_uart_break_ctl, .startup = my_uart_startup, .shutdown = my_uart_shutdown, .set_termios = my_uart_set_termios, .type = my_uart_type, .release_port = my_uart_release_port, .request_port = my_uart_request_port, .config_port = my_uart_config_port, .verify_port = my_uart_verify_port, };
4.2使用Platform UART驱动框架
#include #include static int my_uart_probe(struct platform_device *pdev) { struct my_uart_dev *priv; struct resource *res; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* 获取寄存器资源 */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); /* 获取中断 */ priv->irq = platform_get_irq(pdev, 0); if (priv->irq < 0) return priv->irq; /* 获取时钟 */ priv->clk = devm_clk_get(&pdev->dev, "baudclk"); if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); clk_prepare_enable(priv->clk); /* 初始化 uart_port */ priv->port.iotype = UPIO_MEM; priv->port.membase = (void __iomem *)priv->regs; priv->port.mapbase = res->start; priv->port.irq = priv->irq; priv->port.ops = &my_uart_ops; priv->port.dev = &pdev->dev; priv->port.line = pdev->id; /* UART 编号 */ /* 注册 UART */ ret = uart_add_one_port(&my_uart_driver, &priv->port); if (ret) goto err_clk; platform_set_drvdata(pdev, priv); return 0; err_clk: clk_disable_unprepare(priv->clk); return ret; }
4.3用户空间UART操作
#include #include #include #include #include int uart_open(const char *device) { int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { perror("Failed to open UART"); return -1; } /* 清除非阻塞标志 */ fcntl(fd, F_SETFL, 0); return fd; } int uart_config(int fd, int baudrate) { struct termios options; /* 获取当前配置 */ tcgetattr(fd, &options); /* 设置波特率 */ switch (baudrate) { case 115200: cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); break; case 9600: cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); break; default: return -1; } /* 8N1 配置 */ options.c_cflag |= (CLOCAL | CREAD); /* 本地连接,使能接收 */ options.c_cflag &= ~CSIZE; /* 清除数据位掩码 */ options.c_cflag |= CS8; /* 8 数据位 */ options.c_cflag &= ~PARENB; /* 无校验 */ options.c_cflag &= ~CSTOPB; /* 1 停止位 */ /* 原始模式 */ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; /* 设置新配置 */ tcsetattr(fd, TCSANOW, &options); return 0; } int uart_send(int fd, const char *data, int len) { return write(fd, data, len); } int uart_receive(int fd, char *buf, int len) { return read(fd, buf, len); } int main() { int fd; char buf[256]; int n; /* 打开 UART2 */ fd = uart_open("/dev/ttyS2"); if (fd < 0) return -1; /* 配置 115200 8N1 */ uart_config(fd, 115200); /* 发送数据 */ const char *msg = "Hello UART!\n"; uart_send(fd, msg, strlen(msg)); /* 接收数据 */ while (1) { n = uart_receive(fd, buf, sizeof(buf) - 1); if (n > 0) { buf[n] = '\0'; printf("Received: %s\n", buf); } usleep(10000); } close(fd); return 0; }
五、调试方法
5.1查看UART设备
# 查看注册的 UART cat /proc/tty/drivers # 查看串口设备 ls -la /dev/ttyS* # 查看 console 配置 cat /proc/consoles
5.2测试串口通信
# 配置串口参数 stty -F /dev/ttyS2 115200 cs8 -cstopb -parenb # 发送测试数据 echo "test" > /dev/ttyS2 # 接收数据(阻塞模式) cat /dev/ttyS2 # 使用 minicom 工具 minicom -D /dev/ttyS2 -b 115200
5.3抓取串口波形
六、常见问题
# 使用逻辑分析仪工具 # 或查看内核日志 dmesg | grep tty
6.1串口无法打开
•检查设备节点是否存在:ls /dev/ttyS*
•检查权限:chmod 666 /dev/ttyS2
6.2数据乱码
•波特率配置是否正确
•检查数据位/停止位/校验位
6.3无法接收数据
•检查RX引脚连接
•确认中断是否正常触发
•检查流控设置(RTS/CTS)
参考文档
•RKDocs/common/UART/
•Documentation/serial/driver
本教程适用于Android14/Linux6.1内核
- RK3576开发板UART驱动实战教程,基于触觉智能开发板演示
- SZ100 云台式激光甲烷遥测仪:基于 TDLAS 技术的燃气场站全域泄漏监测方案
- 你身边藏着多少陶瓷天线? 它们默默连接着你一天的无线生活
- 香蕉派开源社区 Banana Pi BPI-M7S采用瑞芯微RK3588s芯片设计
- 明晚19:30首播!DA14535/DA14531 BLE开发实战!还有大量开发板周边等你来拿!
- 稳先微电子超级PMOS系列智能功率开关产品介绍
- 全链路安全方案,助力CRA合规与IEC 62443认证-MYC-LR3576核心板
- 代码从失控到可控 | 阿里云Qoder开源Better Harness
- 智能硬件方案开发公司哪家好?做过消费电子产品的推荐这几家
- 从“数字世界”到“物理世界”——稳石机器人AI赋能智能物流的产业实践
- 一文讲透做智能家居产品,语音提示芯片怎么选
- 工业视觉传感器多维对比:一机多用场景下如何选择可靠方案?
- 阿里云灵骏真武M890超节点实例现已开放邀测
- 简化工业组网|GW 串口服务器对接智嵌云,串口数据云端统一管理
- 艾德克斯分享WAIC 2026世界人工智能大会观察
- 升级!艾感科技推出80L亚克力密封腔体测试系统,320通道并行测试