请教一下串口printf的实现方案?

2019-08-23 15:43发布

这个问题已经想了很久了,一直没有一个好的方法,即使是在有RTOS的情况下。
这里说的串口printf,就是把printf retarget到串口上,但是不能用while(usart->tc!=1){}这样的代码来让CPU空转等待它完成。

到最后感觉应该靠DMA来完成,有两套方案,但是都有问题:

方案1、这个方案的时间不依赖实时系统的存在。建立一个buffer数组,在printf中寻找空的可用buffer,先用sprintf把 printf的内容传入这个可用buffer,然后开启DMA,在DMA的TC中断中再次检查buffer,如果有已经填充好的buffer,再次开启 DMA,然后形成这样一个循环。

问题:DMA传输虽然不占用CPU时间,但串口的DR寄存器是一直被占用了的,而且这个占用时间和直接用轮询等待的方式是一样的;如果在短时间内 连续大量的调用printf让缓冲区填满了,但DMA那边还在慢慢的传,串口DR寄存器还是被占用着,buffer又不能写了,丢失数据的问题就开始出现 了。

方案2:实现创建一个信号量。在printf函数中,先调用sprintf把内容传入字符串,开启DMA传送,然后无限时的等待获取信号量。这个 时候调用printf的这个任务事实上就被suspend了,系统可以切到其他任务执行。等DMA的TC中断发生了,释放这个信号量,printf那里的 阻塞被解除,调用printf函数的任务得以继续进行。

问题:很明显,单任务时没问题,多任务时直接完蛋。TC中断给出的信号量可能有好几个任务里的printf在等待,你到底要解除哪个printf 的阻塞呢?更严重的是,其他任务中的printf完全可能在第一个任务的printf对DMA的占用没有释放时就请求调用DMA,这个时候数据丢失也会发 生。

在有实时系统的情况下,到底要如何解决这种问题呢?目的很简单,printf本身的执行时间很短(不依靠轮询),执行后的等待由借助RTOS调度完成。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
13条回答
leavic
2019-08-23 18:16
哈哈,试过了各种方案,最后还是回到了原子在二楼的方案上来,队列实在是个好东西。
其他一些RTOS也自带了printf方案,不需要单独建立任务,但是系统本身却没几个可以让人满意的:

RTT的各种文档和支持都有限,用gcc工具链很多东西都要自己写;
ChibiOS/RT其实非常好,唯一的问题就是作者自己包干了太多事情,连启动文件、ld文件、向量表这些都重写了,所有的驱动和原子一个风格,全寄存器操作。驱动倒还好办,自己用库重写没问题,就是向量表全被改成了vector57、vector58这样的ISR名字实在头痛。

还是freertos这种只提供完善内核的比较好,可以比较自由的控制。不知道原子在用哪种rtos呢?

一周热门 更多>