在内核中增加串口发送数据延时

Kernel: v3.0.36
Device: rk3188
Platform Version: Android 4.4.2

前言:

内核向外发送串口数据的时候,发送数据比较快,数据包是连在一起的,每个包之间的时间间隔可能小于1ms,如果接收方控制不好,来不及接收。有的时候需要给特殊的包增加延时。

menuconfig配置UART:

Device Drivers
---->Character devices
-------------->Serial drivers

1

源文件:

vim kernel/drivers/tty/serial/rk_serial.c

module_init;
—>serial_rk_init
------->serial_rk_driver
------------>serial_rk_probe
----------------->serial_rk_pops
------------------>serial_rk_startup

//注册中断,收到数据,发送数据都会触发此中断,再处理相应数据,每次处理32字节。
retval = request_irq(up->port.irq, serial_rk_interrupt, up->port.irqflags, up->name, up);

----------------------------->serial_rk_interrupt
------------------------------>serial_rk_handle_port
--------------------------------->receive_chars(处理接收数据)
--------------------------------->transmit_chars(处理发送数据)

static void transmit_chars(struct uart_rk_port *up)
{
	...
	 do {//依次发送32字节数据(可在此处给特殊的包增加延时)
    	serial_out(up, UART_TX, xmit->buf[xmit->tail]);//一个一个字节发送出去
    	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
    	up->port.icount.tx++;
    	if (uart_circ_empty(xmit))
        break;
	} while (--count > 0);
}	  		

转载请注明出处:http://www.wolfnx.com/2019/01/23/KernelAddSerialDelay

作者 : wolfnx
邮箱 : wolfnx@outlook.com
邮箱2 : lostnx@gmail.com

<think>嗯,用户之前问过关于O_SYNC、O_DSYNC和O_ASYNC的区别,现在他转向了Linux串口通信中的write发送数据如何确保完整发送。看起来他对数据完整性和I/O操作有持续的兴趣,可能是在开发嵌入式系统或者需要可靠通信的应用。 首先,我需要回忆一下串口通信的基本知识。串口是异步通信,数据按字节传输,没有时钟信号,所以需要双方约定波特率、数据位、停止位等参数。用户的问题心是确保通过write函数发送的数据完整到达接收端。 用户可能已经遇到了数据丢失的问题,或者在开发中担心数据完整性,想要预防这类问题。需要考虑到硬件和软件两方面的因素。硬件方面,比如线路干扰、波特率不匹配可能导致数据丢失;软件方面,缓冲区管理、流控制设置是否正确,以及错误检测和处理机制是否到位。 接下来,我需要拆解问题。用户想知道如何确保write发送的数据完整发送。这里的“完整发送”可能指数据完全写入硬件发送缓冲区,并且成功传输到对方设备。在Linux中,write函数返回成功只能说明数据被复制到了内缓冲区,并不保证已经通过串口发送完毕。所以需要一些方法确保数据确实被发送出去。 可能的解决方案包括:使用同步I/O标志如O_SYNC或O_DSYNC,但这些在串口设备中可能不可用或效果不同;或者使用tcflush来清空缓冲区,确保数据被发送;或者检查写操作的返回值,处理可能的错误;调整串口参数,比如正确设置波特率、数据位、校验位等;使用硬件流控制(如RTS/CTS)来避免缓冲区溢出;循环写入直到所有数据发送完成。 另外,用户可能忽略了一些细节,比如串口配置是否正确,是否有足够的等待时间让数据发送完成,或者是否处理了信号干扰等硬件问题。需要提醒用户检查这些方面。 最后,要组织回答的结构,先讲基本原理,再分点列出方法,包括配置检查、同步机制、流控制、错误处理、循环写入、延时等待、校验机制等。同时要强调硬件和驱动的影响,可能建议使用示波器或逻辑分析仪验证数据实际发送情况。</think>在 Linux 中通过串口(UART)使用 `write` 发送数据时,确保数据完整发送需要综合考虑**硬件特性**、**驱动行为**和**软件控制**。以下是关键方法与实践: --- ### **1. 基础原理** - **`write` 函数的行为**: `write` 将数据从用户空间复制到内串口发送缓冲区,**返回成功仅表示数据进入内缓冲区**,不保证数据已通过物理线路发送完毕。 - **串口发送机制**: 数据通过 UART 控制器按字节逐个发送,依赖波特率、硬件流控等参数。 --- ### **2. 确保完整发送的关键方法** #### **(1) 正确配置串口参数** - **波特率匹配**:发送端和接收端的波特率必须**严格一致**(如 `115200`)。 - **数据格式**:设置正确的数据位(如 `8`)、停止位(如 `1`)、校验位(如 `NONE`): ```c struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); options.c_cflag |= (CLOCAL | CREAD); // 确保本地连接和启用接收 options.c_cflag &= ~PARENB; // 无校验 options.c_cflag &= ~CSTOPB; // 1位停止位 options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 8位数据 tcsetattr(fd, TCSANOW, &options); ``` - **硬件流控**:启用 RTS/CTS 流控(防缓冲区溢出): ```c options.c_cflag |= CRTSCTS; // 启用硬件流控 ``` --- #### **(2) 同步等待数据发送完成** - **使用 `tcdrain` 阻塞等待**: `tcdrain(fd)` 会阻塞直到内发送缓冲区的数据**全部通过硬件发送完毕**。 ```c write(fd, data, len); tcdrain(fd); // 阻塞直到发送完成 ``` - **清空缓冲区**: 发送前清空残留数据(慎用,可能丢失未发送数据): ```c tcflush(fd, TCOFLUSH); // 清空输出缓冲区 ``` --- #### **(3) 检查 `write` 返回值** - **处理部分写入**: `write` 可能因缓冲区满返回部分写入的字节数,需循环写入剩余数据: ```c ssize_t total_sent = 0; while (total_sent < len) { ssize_t sent = write(fd, data + total_sent, len - total_sent); if (sent < 0) { // 处理错误(如信号中断、硬件故障) break; } total_sent += sent; } ``` --- #### **(4) 使用非阻塞模式 + 轮询** - 若串口设为非阻塞模式(`O_NONBLOCK`),需结合 `select`/`poll` 等待写就绪: ```c fd_set write_fds; FD_ZERO(&write_fds); FD_SET(fd, &write_fds); select(fd + 1, NULL, &write_fds, NULL, NULL); // 等待可写 write(fd, data, len); ``` --- #### **(5) 降低发送速率** - **增加字节间延时**: 在高速或长距离传输时,适当增加字节间延时(通常由硬件自动处理,特殊场景可能需要软件干预)。 --- #### **(6) 启用校验机制** - **软件校验**: 在数据协议中添加校验字段(如 CRC、Checksum),接收端确认完整性。 - **应用层应答**: 实现应答机制(如接收端回复 ACK),超时重发未确认的数据。 --- ### **3. 常见问题与调试** 1. **数据丢失**: - 检查硬件连接(如电平、线缆干扰)。 - 确认流控是否生效(避免缓冲区溢出)。 2. **发送卡顿**: - 减少单次 `write` 的数据量(避免内缓冲区满)。 3. **验证实际发送**: - 使用示波器或逻辑分析仪抓取物理信号。 - 使用 `strace` 跟踪系统调用: ```bash strace -e trace=write,ioctl your_program ``` --- ### **总结** | **方法** | **作用** | **开销** | |-------------------------|----------------------------------------|----------| | `tcdrain()` | 阻塞等待数据发送完成 | 高 | | 循环 `write` | 确保所有数据进入内缓冲区 | 中 | | 硬件流控 (RTS/CTS) | 防止接收端缓冲区溢出 | 低 | | 校验 + 重传 | 保证应用层数据完整性 | 可变 | 实际应用中,通常**组合使用 `tcdrain`、硬件流控和校验机制**,具体取决于可靠性要求和性能限制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值