C printf到自定义硬件

时间:2016-10-31 15:45:26

标签: c printf stdout

我有各种调试消息的现有代码。我们的嵌入式系统没有终端的外部连接。我想修改printf,使其输出到达内存位置,而不是STDOUT,它映射到FIFO。我想我需要找到自己的outbyte / outnum。似乎无法找到我可以抓住东西的GNU代码。

我正在Xilinx FPGA内部运行一个微型光栅处理器。所有打印语句都用于调试。我们正在运行GNU工具(Xilinx SDK)。为了开发,能够在设计中使用UART并将uart连接到几个测试点。

随着我们准备部署,我将不再具备这种可见性。我们有一个USB到串口的连接,但它看起来像一个fifo,而不是嵌入式系统的串口。我们有一个通过此链接发送消息的协议。我正在考虑向我们的协议添加调试消息。我想将我的print语句重定向到缓冲区,然后处理这个缓冲区。

我试图通过重写outbyte代码来获取现有的printf(xil_printf)并创建我自己的cc_printf,但是却无法深入挖掘代码,看看怎么做。 (坦率地说,我是VHDL /硬件人员。)

总代码大小是数万行C代码。我的部分可能是3-4千行代码。基本操作是通过USB端口进入系统的软件/硬件更新并移至闪存。我的代码解析通过USB到串行链路传入的传入数据包。基本上有一个位设置告诉我在接收缓冲区中有一个数据包就绪。我处理数据包并写入FLASH。作为协议的一部分,有ACK / NACK / ABorts。我目前使用printf打印输出状态到我的实验室工作台版本。

如上所述,我想将这些打印输出嵌入到我们的协议中。我没有和printf结婚,并且会使用其他一些打印功能。我想打印出消息和数据。如果其他东西是一个更好的起点,我对此很好。对我来说,最大的问题似乎是抓住印刷品的输出并指导它去哪里。

2 个答案:

答案 0 :(得分:1)

不要直接使用printf 进行调试。

使用宏,可能类似

#define DEBUGPRINTF(Fmt,...) do \
   {printf("%s:%d: " Fmt "\n", __FILE__, __LINE__,  __VA_ARGS__);} while(0)

然后,一旦将所有调试printf(并且只有这些)转换为DEBUGPRINTF,您只需要更改该宏的定义(例如,在嵌入式系统上,可能使用{{1 } ...)。

因此,在其余代码中,将snprintf替换为printf("debugging x=%d\n", x);,但仅为调试打印执行此操作。 BTWK 4KLOC(就你而言)非常小,即使是200KLOC(整件用的东西)也足够小,可以让这种替代品变得可行而且#34;手工和#34; (例如Emacs"以交互方式查找和替换")。

(我猜你是在你的笔记本电脑上开发一小段代码 - 几千行 - 然后将它移植到嵌入式系统中)

将所有 debug DEBUGPRINTF("debugging x=%d", x);转换为printf(并且只打印调试版!)后,您可以重新定义该宏,也许启发通过

DEBUGPRINTF

(我想你需要在那个宏中添加更多东西 - 可能在结束之前 - 实际上发送调试输出 - 这是{的内容{1}} - 某处,但如何做到这一点是实施和系统特定的)

但您更有可能使用

禁用调试printf
#define DEBUGPRINTF(Fmt,...) do \
  {snprintf(debugbuffer, sizeof(debugbuffer), Fmt, __VA_ARGS__); } while(0)
BTW,嵌入式目标系统甚至可能没有任何debugbuffer ...

如果你想学习一些可读的 C标准库实现(在Linux上),请考虑查看musl-libc源代码。您需要了解system calls是什么。

实际上,您实际上应该在笔记本电脑上编写和调试代码(例如运行Linux),并且只在嵌入式系统上放置一些您认为没有错误的东西。在实践中,避免使用调试printfs部署代码(或者事先考虑更好的事情)。另请参阅this

  

对我来说,最大的问题似乎是抓住印刷品的输出并指导它去哪里。

可能使用#define DEBUGPRINTF(Fmt,...) do{}while(0) 然后&#34;发送&#34; snprintf使用适当的基元到适当的位置。使用snprintf,您可以知道邮件的大小(例如,使用snprintf的返回值和/或使用格式控制字符串中的debugbuffer。或者拥有自己的日志记录或调试variadic function(使用<stdarg.h>snprintf等等。)

请勿将调试消息与logging消息混淆。如果您想要记录,请仔细设计。但是在部署时可能应该删除调试消息。

答案 1 :(得分:1)

Posix函数fmemopen允许您像文件一样打开内存缓冲区,并返回可以与标准IO函数一起使用的FILE *,如fprintf。至于打印到不是串口的设备,我不知道你在运行什么操作系统(如果存在),但是如果存在,你可以为该自定义设备编写流设备驱动程序并设置{{1} }和stdout(也许stderr)。如果您在没有操作系统的情况下运行,那么有人创建了stdin结构,以某种方式与串行端口连接,FILE正在使用该结构。