[学习笔记] 使用DMA+fifo的方式实现日志打印

[复制链接]
 楼主| JasonLee27 发表于 2019-12-6 11:45 | 显示全部楼层 |阅读模式
本帖最后由 JasonLee27 于 2019-12-6 11:45 编辑

硬件环境:通用开发板,ATC-LINK
软件环境:keil 5.23

突然发现我很多地方都喜欢用fifo了

有时候为了方便调试,我们会在代码里增加很多打印信息。使用官方提供的debug库虽然也能实现串口日志输出,但官方的库日志是采用polling方式输出,一个115200波特率的串口输出10个字节大概就要占用1ms的时间,如果我们的系统对时间要求严格,那么大量的打印必然就会占用我们很高的CPU使用权。所以我这里设计了(也不算我设计了,很早前我们做项目跑系统的时候就是这样用的)一个通过DMA+fifo缓存打印的方式来输出日志,这样可以大大降低日志打印对我们系统运行的影响。

实现的原理嘛也不复杂,就是通过一个vsprintf库函数,将你要输出的格式化字符串定向到一个数组buff中,再将这个buff插入fifo。
  1. /**
  2. * [url=home.php?mod=space&uid=42490]@function[/url] Debug_Print
  3. *
  4. * @param[in] fmt: format data
  5. * [url=home.php?mod=space&uid=266161]@return[/url]    none
  6. *
  7. * [url=home.php?mod=space&uid=247401]@brief[/url]  format data and insert to fifo
  8. */
  9. void Debug_Print(const char *fmt, ...)
  10. {
  11.     uint8_t printBuffer[MAX_PRINT_LENGTH] = {0};
  12.     uint8_t *pStr = NULL;
  13.     va_list ap = {0};
  14.     if (!s_debugState)
  15.         return;
  16.    
  17.     pStr = printBuffer;
  18.     /* if we use print in interrupt handler,must Disable interrupt
  19.        or use mutex */
  20.     DisableInterrupts      
  21.     /* unnamed_p point to first unnamed argument */
  22.     va_start(ap, fmt);
  23.     vsprintf((char *)pStr, fmt, ap);
  24.     va_end(ap);
  25.    
  26.     if (printBuffer[MAX_PRINT_LENGTH - 1] != '\0')
  27.     {
  28.         /* print length is overflow, maybe a Array transboundary has been happened*/
  29.         
  30.         while(1)
  31.         {
  32.             
  33.         }
  34.     }
  35.    
  36.     pStr = &printBuffer[0];
  37.     FIFO_Insert(&s_printFifo, pStr, strlen((const char *)pStr));
  38.     EnableInterrupts
  39. }
然后在一个周期性运行的debugTask任务中去从fifo中取出打印数据,通过DMA将数据发送出去。
  1. /**
  2. * [url=home.php?mod=space&uid=42490]@function[/url] Debug_Task
  3. *
  4. * @param[in] none
  5. * [url=home.php?mod=space&uid=266161]@return[/url]    none
  6. *
  7. * [url=home.php?mod=space&uid=247401]@brief[/url]  Debug cycle function,execute this in cycle
  8. */
  9. void Debug_Task(uint8_t args)
  10. {
  11.     uint32_t length;
  12.     uint32_t validLen;
  13.     if (!s_debugState)
  14.         return;
  15.    
  16.     length = FIFO_GetLen(&s_printFifo);
  17.     if (length > 0 && s_dmaTxFlag == 0)
  18.     {
  19.         s_dmaTxFlag = 1;
  20.         validLen = FIFO_Retrieve(&s_printFifo, s_dmaBuffer, DUMP_LENGTH);
  21.         UART_StartDMATransmit(2, 8, (uint32_t)s_dmaBuffer, validLen, DMA_CallbackHandler);
  22.     }
  23.    
  24. }


当然了,这份代码有其局限性以及一定的异常风险,比如格式化字符串重定向到一个数组,这个数组的大小因为是固定的,所以一旦打印的格式化字符串长度超过了数组,就会导致数组操作越界,有跑飞的风险。还有fifo也是有大小的,一旦某一时刻的日志产生速度超过了消耗速度,那也会产生溢出导致打印丢失的问题。这些就需要结合实际情况去设计合适的buff大小了。

但也有很方便的地方,在Debug_Print函数中,你可以设计打印等级(比如error,info等等),以及增加打印前缀等等,让你有选择的输出日志。


游客,如果您要查看本帖隐藏内容请回复

戊戌变法 发表于 2020-1-7 08:33 | 显示全部楼层
又发现好东西
carefull3357dc 发表于 2020-1-7 09:27 | 显示全部楼层
需要有发送完成中断吗?
 楼主| JasonLee27 发表于 2020-1-7 09:31 | 显示全部楼层
carefull3357dc 发表于 2020-1-7 09:27
需要有发送完成中断吗?

没有用发送中断,用的是DMA传输完成中断
carefull3357dc 发表于 2020-1-7 09:36 | 显示全部楼层
JasonLee27 发表于 2020-1-7 09:31
没有用发送中断,用的是DMA传输完成中断

这样的话,是不是直接比原来的printf();那种方式要省资源?省很多?我之前一直在STM32上做开发,尤其是开发电机的应用,发现这样定时器定时发送状态,非常的占用资源。
 楼主| JasonLee27 发表于 2020-1-7 13:34 | 显示全部楼层
carefull3357dc 发表于 2020-1-7 09:36
这样的话,是不是直接比原来的printf();那种方式要省资源?省很多?我之前一直在STM32上做开发,尤其是 ...

不是的,这种方式不省资源,但是省CPU,等于我通过一个fifo将所需要打印的数据都缓存起来,然后通过DMA发送出去,这样发送就几乎不占用CPU,但是增加了fifo,所以会增加内存的占用。还有就是要考虑打印数据高发的情况下是否会导致fifo不够而造成打印丢失。
carefull3357dc 发表于 2020-1-7 15:00 | 显示全部楼层
JasonLee27 发表于 2020-1-7 13:34
不是的,这种方式不省资源,但是省CPU,等于我通过一个fifo将所需要打印的数据都缓存起来,然后通过DMA发 ...

好的!了解了!学习学习!
weict125 发表于 2020-9-12 15:23 | 显示全部楼层
点赞
bird777 发表于 2020-11-21 13:23 | 显示全部楼层
GrootBrain 发表于 2021-1-6 16:29 | 显示全部楼层
好东西,收藏
zhdm 发表于 2021-1-23 21:01 | 显示全部楼层
谢谢分享
jcky001 发表于 2021-1-27 09:23 | 显示全部楼层

好东西,收藏
czq2317 发表于 2021-3-31 00:10 | 显示全部楼层
输出调试信息很好用
非谢家之宝树 发表于 2021-3-31 19:30 | 显示全部楼层
我用的是从rtt里面的抠出来的
ehua 发表于 2021-4-2 08:21 | 显示全部楼层
如果您要查看本帖隐藏内容请回复
caigang13 发表于 2021-4-2 09:18 来自手机 | 显示全部楼层
C语言把fifo实现好了会很香。
brightchl 发表于 2021-4-23 15:32 | 显示全部楼层

学习一下
sihan 发表于 2021-5-19 15:26 | 显示全部楼层
学习学习!
wsnsyy 发表于 2021-11-3 14:11 | 显示全部楼层
FBI快开门 发表于 2021-12-17 11:33 | 显示全部楼层
学习学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则

66

主题

415

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部

66

主题

415

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部