关于uart的操作的阻塞和非阻塞

最近在一个项目中用到uart的使用问题,对阻塞和非阻塞有了硬件级的理解。

需求描述:该项目中AP侧使用uart和某个外设通讯。

通讯起始阶段,AP和外设的默认波特率均为115200,二者可以顺利通讯。

第二阶段,AP会发给外设一个请求,该请求要求外设切换到2000000的波特率。然后AP立刻修改自己的波特率为2000000

第三阶段,外设收到该请求,并将自身切换到2000000的波特率,并以该新的波特率发送一个ACK

第四阶段,AP收到上述ACK,双方完成速率更新


出现的问题:

 在第二阶段,当AP发出要求外设更新速率的数据包后,AP立刻切换自身的波特率,这种情况下外设收到的该数据包是错误的。怀疑AP切换自身波特率的时机太早,可能当时uart总线上正在传输该数据包,此时切换必然导致正在传输的数据被破坏。因此在AP调用write(uart_fd,send_buffer,data_size); 后做sleep(1); 问题解决,外设可以收到正确的数据包。

考虑到我们在AP侧打开该uart接口时采用的是非阻塞模式:uart_fd = open("/dev/ttyS0", O_RDWR | O_NONBLOCK );因此出现上述问题也可以理解,即在非阻塞模式下write调用会立刻返回,所以在write后直接修改AP侧uart的波特率会破坏正在发送的数据。那么,在调用write之前,我们将其操作模式改为阻塞方式,问题不就解决了吗?因为在阻塞模式下,只有数据真正发送完毕write才会返回,此时我们再去切换AP侧uart的波特率就不会破坏数据了,因为数据已经发送完毕了!我用以下的方式修改了该uart的操作属性:

//=====
int flags;
flags = fcntl(uart_fd, F_GETFL);
flags &= ~O_NONBLOCK;
if (fcntl(uart_fd, F_SETFL, flags) == -1) {
printf("fcntl set F_SETFL error!\n");
exit(1);
} else {
printf("fcntl set F_SETFL success!\n");
}
//=====

在上述修改之后我们才调用write发送数据,然后在write返回后不做等待操作,直接改变AP侧uart的波特率。

但是结果和我期望的相反,还是出现了数据包被破坏的现象,看来在阻塞模式下,write函数还是会立刻返回!如此看来write之后是必须加延时的!

为什么阻塞不住呢?

uart控制器是一个有发送和接收FIFO的控制器,对于其驱动而言,一个write操作只要把数据全部推入发送FIFO后就可以返回了,它并不需要等到FIFO中的数据在总线上完全送出。所以只要该write要发送的数据量小于FIFO中的空闲空间大小,write就会立刻返回,哪怕是阻塞模式!只有当该write要发送的数据比较多,FIFO被填满了还不够,此时阻塞模式就会起作用,write必须要等待FIFO中的数据被发出后才能将后续的数据继续填入FIFO中,直到所有的数据被填入FIFO后,write才会返回!

由以上分析可以得出所有类似的含有FIFO的控制器都会有这个现象,如I2C等。


关于fcntl函数,请参考:https://akaedu.github.io/book/ch28s06.html






  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风中之哨

再来一杯西湖龙井。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值