返回
北京信盈达单片机培训
置顶
该校与厚学网暂未合作,平台不保证课程的真实有效性,如有侵权等争议,请及时与厚学网联系处理
招生热线:400-800-2181

学校地址:北京市昌平区回龙观东大街天龙苑25号楼1单元201

在嵌入式开发中如何大限度利用printf

616 2017-06-21 16:59:00

学习笔记

嵌入式开发中传统可靠的调试技术是在软件中从头到尾都使用printf语句,以便随时了解系统的运行状况。但总是使用printf语句并不可取,因为它可能带来不可预料的实时性能影响。文章讨论了使用printf存在的一些基本问题,并提出了使用printf语句达到好性能的一些窍门。


与使用printf有关的问题

开发人员经常忽视使用printf带来的一些问题。首先这种技术要求开发人员在软件中嵌入标准C库,这无疑会增加ROM和RAM的使用量。


第二个问题是每次使用printf语句时,系统会进入阻塞状态,直到所有字符发送完毕。这种阻塞会导致实时性能显著下降。举个例子,以9600波特通过UART打印输出诸如“Hello World!”这个简单的字符串(这是很常见的事)。我在STM32处理器上进行了简单的时序测量,如图1所示,该字符串完成格式化并打印到终端上需要花12.5ms的时间。在这段时间内,系统什么事也不能做。


图1:打印“Hello World!”


增加任何字符串格式化的工作会使情况变得更加糟糕!使用printf语句将系统状态打印到终端上(“The system state is %d”, State)会导致21ms的应用程序延时,这个时间都用在了字符串的格式化和发送上面。有人可能会说以9600波特的速率运行太荒唐了,但即使提高到115200波特,发送这两条消息仍会导致1.05ms和1.75ms的延时。也就是说,即便对于使用程度低的信息,仍要浪费很多的处理器带宽和潜在的实时性能。


现在我们来看看如何解决这些问题。


性能窍门#1——创建非阻塞printf

目前为止我遇到的每一个printf版本都是阻塞类型的。一旦开始调用printf,应用程序都会停止执行,直到成功发送完每个字符。这太没有效率了!另外一种方法是创建非阻塞版本的printf。非阻塞printf版本将能够:

  • 格式化字符串

  • 将格式化后的字符串填充进发送缓冲区

  • 启动发送个字符

  • 让中断服务例程处理发送缓冲区中剩下的字符

  • 继续执行代码

非阻塞printf的关键之处在于建立时间,在STM32处理器上以9600波特速度执行时的建立时间在0.8至1.8ms之间。在初始建立时间后,大约每隔1ms产生一次发送中断。中断例程随即仅需35μs就能将下一个字符填充进UART的发送寄存器,然后就可以返回执行有用的任务。图2显示了周期性的中断和中断执行时间。记住,这个执行时间不包括中断开销,在这个案例中中断开销不到25个时钟周期。

图2:非阻塞型printf性能


性能窍门#2——提高波特率

令我感到奇怪的是,即使今天的串行硬件可以处理1Mbps甚至更高的波特率,仍有许多开发人员将他们的UART设置在默认的9600波特!偶尔我也会遇到胆大的开发人员将波特率设在115200。提高时钟速率可能会发生电气或硬件相关的问题,除此之外,将波特率设为1Mbps并尽可能快地输出调试消息不会有什么问题,这样可以大限度地减小实时性能问题。当波特率设为1Mbps时,用初的阻塞printf语句输出“Hello World!”只阻塞120μs,这要比12.5ms容易接受多了。


性能窍门#3——使用SWD

现代微控制器的设计者在开发芯片时都知道存在printf性能问题。例如那些想要利用ARM Cortex-M调试功能的开发人员会完全跳过UART,使用内部调试模块将printf消息通过调试器发送回集成开发环境。以这种方式跳过UART不仅节省了建立时间,其内部硬件机制也可大限度减少软件开销。内部缓冲区被填满消息,调试硬件自动处理调试探测器的消息发送,因此能够大程度地减小对应用程序实时性能的影响。


总结

很少有开发人员会完全抛弃他们喜爱而且非常有用的printf调试技术。在今天先进的微处理器硬件中,有诸多选项可以用来提高printf的性能和效率,大限度地减小对实时性能的影响。对于想要亲自体验这些改进的开发人员,我提供了一个可在STM32上运行的Keil项目,该项目演示了如何使用这些技巧。


文中图片素材来源网络,如有侵权请联系删除
来源:北京信盈达单片机培训
热门课程 全部课程

热门动态

申请免费试听

只要一个电话

我们为您免费回电

立即申请
刷新
图形验证
关闭
>>
拖动左边滑块完成上方拼图