本帖最后由 JasonLee27 于 2019-12-6 11:45 编辑
硬件环境:通用开发板,ATC-LINK
软件环境:keil 5.23
突然发现我很多地方都喜欢用fifo了
有时候为了方便调试,我们会在代码里增加很多打印信息。使用官方提供的debug库虽然也能实现串口日志输出,但官方的库日志是采用polling方式输出,一个115200波特率的串口输出10个字节大概就要占用1ms的时间,如果我们的系统对时间要求严格,那么大量的打印必然就会占用我们很高的CPU使用权。所以我这里设计了(也不算我设计了,很早前我们做项目跑系统的时候就是这样用的)一个通过DMA+fifo缓存打印的方式来输出日志,这样可以大大降低日志打印对我们系统运行的影响。
实现的原理嘛也不复杂,就是通过一个vsprintf库函数,将你要输出的格式化字符串定向到一个数组buff中,再将这个buff插入fifo。
- /**
- * [url=home.php?mod=space&uid=42490]@function[/url] Debug_Print
- *
- * @param[in] fmt: format data
- * [url=home.php?mod=space&uid=266161]@return[/url] none
- *
- * [url=home.php?mod=space&uid=247401]@brief[/url] format data and insert to fifo
- */
- void Debug_Print(const char *fmt, ...)
- {
- uint8_t printBuffer[MAX_PRINT_LENGTH] = {0};
- uint8_t *pStr = NULL;
- va_list ap = {0};
- if (!s_debugState)
- return;
-
- pStr = printBuffer;
- /* if we use print in interrupt handler,must Disable interrupt
- or use mutex */
- DisableInterrupts
- /* unnamed_p point to first unnamed argument */
- va_start(ap, fmt);
- vsprintf((char *)pStr, fmt, ap);
- va_end(ap);
-
- if (printBuffer[MAX_PRINT_LENGTH - 1] != '\0')
- {
- /* print length is overflow, maybe a Array transboundary has been happened*/
-
- while(1)
- {
-
- }
- }
-
- pStr = &printBuffer[0];
- FIFO_Insert(&s_printFifo, pStr, strlen((const char *)pStr));
- EnableInterrupts
- }
然后在一个周期性运行的debugTask任务中去从fifo中取出打印数据,通过DMA将数据发送出去。
- /**
- * [url=home.php?mod=space&uid=42490]@function[/url] Debug_Task
- *
- * @param[in] none
- * [url=home.php?mod=space&uid=266161]@return[/url] none
- *
- * [url=home.php?mod=space&uid=247401]@brief[/url] Debug cycle function,execute this in cycle
- */
- void Debug_Task(uint8_t args)
- {
- uint32_t length;
- uint32_t validLen;
- if (!s_debugState)
- return;
-
- length = FIFO_GetLen(&s_printFifo);
- if (length > 0 && s_dmaTxFlag == 0)
- {
- s_dmaTxFlag = 1;
- validLen = FIFO_Retrieve(&s_printFifo, s_dmaBuffer, DUMP_LENGTH);
- UART_StartDMATransmit(2, 8, (uint32_t)s_dmaBuffer, validLen, DMA_CallbackHandler);
- }
-
- }
当然了,这份代码有其局限性以及一定的异常风险,比如格式化字符串重定向到一个数组,这个数组的大小因为是固定的,所以一旦打印的格式化字符串长度超过了数组,就会导致数组操作越界,有跑飞的风险。还有fifo也是有大小的,一旦某一时刻的日志产生速度超过了消耗速度,那也会产生溢出导致打印丢失的问题。这些就需要结合实际情况去设计合适的buff大小了。
但也有很方便的地方,在Debug_Print函数中,你可以设计打印等级(比如error,info等等),以及增加打印前缀等等,让你有选择的输出日志。
|