全部博文(105)
分类: 嵌入式
2015-06-10 16:46:03
这周突然需要调试 RS485 方向控制的问题,最开始想想应该问题不大,就加个GPIO口控制就好了,或者用UART 的RTS来作方向控制。当然很多事情都是想得简单,做起来的时候各种意外。
MX28串口的RTS 管脚无法正常使用,打开流控,PIN脚配置OK ,寄存器配置OK,然RTS管脚一直岿然不动。无果,找FAE,反馈也等于没有反馈。
用GPIO 飞线进行测试。应用层操作串口发送前后,分别控制GPIO口高低。惊喜又来了,GPIO口操作有时候会慢好几十个毫秒。应用层也查到tcdrain 这个函数来进行确认是否发送完成,发现
这个函数最大也有可能需要20多个毫秒。
以上种种故事,说明了原来的想法不行。就想着GPIO口在串口驱动中去操作。正题也就开始了。首先声明一下,最终这种方法是实现了,但也不是想的那么简单,道路是曲折的。
1,首先参考了如下做法:
http://kuafu80.blog.163.com/blog/static/122647180201431625820150/
修改完成后测试,发现xxx_start_tx , xxx_stop_tx 这两个函数在我所用的ARM 上,当发送数据的时候,只调用了xxx_start_tx ,而xxx_stop_tx 是没有调用的。这样该方法也就寿终正寝了。
2,开始发送已经能实现提前使能了,但发送完不能及时关闭。在驱动中查找发送完时的地方,然后添加GPIO口操作。因为串口驱动采用中断方式。
点击(此处)折叠或打开
到了这里,原本一切应该变得很简单,然而当然很多事情都是想得简单,做起来的时候各种意外。CPU 里面内部自带的串口功能没有FIFO为空或者TIMOUT 的中断。只有一个发送中断。
分析源码发现uart_circ_empty 是判断发送队列是否为空的宏。在tx_chars 中会调用 ,tx_chars 在 start_tx 中会调用,在irq_handle 会被调用。一切很明朗了,就在uart_circ_empty函数中调用 gpio_drection_output 就好 了。当然很多事情都是想得简单,做起来的时候各种意外。
uart_circ_empty函数中调用 gpio_drection_output 后,出现了一种情况,发现数据还没有发送完,GPIO口已经拉低了。具体原因是uart_circ_empty 中判断是不是已经加载完到了FIFO,实际并没有实时发送出去,晚了几 个毫秒。这样也满足不了要求。
怎么办啊,怎么办啊?无法知道串口什么时候才把数据完全丢出去,该CPU串口功能中有一个BUSY位是用于轮询模式查看是否发送完成的标志。天无绝人之路,在uart_circ_empty中一直查看BUSY,等待其发完。实验 测试结果,表示好坑爹啊。可能在中断中,轮询16+8=24 个字节的时间。这对于系统来说 ,要了其老命,没法用。这时候想到了中断的下半部操作。自然就是工作队列,任务队列,软中断等。这里就只能引出下一 篇了,linux 中断底半部机制的差异。
揭晓一下最终做的结果,是这样的。startup 相当于open 。打开的时候初始一个任务队列,然后uart_circ_empty中调用。工作队列还真不行,tasklet_hi_schedule 只有这个能达到所需要的实时性。但这里好像会损失CPU 的性能。
点击(此处)折叠或打开
leibornsean2021-03-08 22:28:31
ispsubb:不要好意,一直没有留意到你的留言,看起来你的问题是已经解决了。 已经贴在这里面了啊,主要就是tasklet ,你可以查看一下我的另一篇,rs485引发的血案。
楼主,您好,中断下半部中也是要判断判断数据是否发送完毕的吗?
回复 | 举报leibornsean2021-03-08 22:28:24
ispsubb:不要好意,一直没有留意到你的留言,看起来你的问题是已经解决了。 已经贴在这里面了啊,主要就是tasklet ,你可以查看一下我的另一篇,rs485引发的血案。
楼主,您好,中断下半部中也是要判断判断数据是否发送完毕的吗?
回复 | 举报