【问题标题】:C printf to custom hardware [closed]C printf到自定义硬件[关闭]
【发布时间】:2016-10-31 15:45:25
【问题描述】:

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

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

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

我试图通过重写 outbyte 代码来获取现有的 printf (xil_printf) 并创建我自己的 cc_printf,但只是无法深入研究代码以了解如何操作。 (坦率地说,我是 VHDL/硬件专家)。

总体代码大小为数万行 C 代码。我的部分可能是 3-4 千行代码。基本操作是系统的软件/硬件更新通过 USB 端口进入并移动到 FLASH 存储器。我的代码解析来自 USB 到串行链路的传入数据包。基本上有一个位告诉我在接收缓冲区中有一个准备好的数据包。我处理数据包并写入闪存。作为协议的一部分,有 ACK/NACKs/Aborts。我目前使用 printf 将状态打印到我的实验台版本的系统。

如上所述,我想将这些打印输出嵌入到我们的协议中。我没有与 printf 结婚,并且会使用其他一些打印功能。我想打印出消息和数据。如果其他东西会是一个更好的起点,我可以接受。对我来说,最大的问题似乎是获取打印的输出并将其指向何处。

【问题讨论】:

标签: c printf stdout


【解决方案1】:

不要直接使用printf,用于调试目的。

使用宏,可能类似于

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

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

因此,在您的其余代码中,将printf("debugging x=%d\n", x); 替换为DEBUGPRINTF("debugging x=%d", x);,但仅在调试 打印时这样做。 BTWK 4KLOC(对您而言)非常小,甚至 200KLOC(对整个事物而言)也足够小,可以“手动”进行替换(例如 Emacs“以交互方式查找和替换”)。

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

一旦您将所有 debug printf 转换为 DEBUGPRINTF(并且只有调试打印!)您可以重新定义该宏,也许是 inspired 通过

#define DEBUGPRINTF(Fmt,...) do \
  {snprintf(debugbuffer, sizeof(debugbuffer), Fmt, __VA_ARGS__); } while(0)

(我想您需要在该宏中添加更多内容 - 可能在右括号之前 - 以实际 发送 调试输出 - 这是 debugbuffer 的内容- 某处,但如何做到这一点是实施和系统特定的)

但您更有可能会禁用调试 printf

#define DEBUGPRINTF(Fmt,...) do{}while(0)

顺便说一句,嵌入式目标系统甚至可能没有任何snprintf ...

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

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

似乎对我来说最大的问题是获取打印的输出并将其指向何处。

可能使用snprintf,然后使用适当的原语将debugbuffer“发送”到适当的位置。使用snprintf,您知道消息的大小(例如,使用来自snprintf 的返回值和/或在格式控制字符串中使用%n)。或者拥有自己的日志记录或调试variadic function(使用<stdarg.h>va_start 等......)

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

【讨论】:

  • 这可能是个好建议,但实际上并不能回答问题;所以下一个搜索的人会发现这个问题,也许这个建议不适用于他的情况。也许是评论而不是回答imo的好信息
  • @MarkAdelsberger:这不适合评论,我对 OP 代码和目标系统一无所知(仅猜测)。
  • 原始答案中的基本信息(正如我评论时的样子)实际上适合评论。无论如何,它仍然没有回答所提出的问题;如果您不同意,请见谅。
  • OP 的问题实际上不够精确,无法得到任何有意义的答案。我要求(在对该问题的评论中)OP 编辑​​他的问题以改进它,但他(还没有)这样做。
  • 世界上所有的理由都不会改变基本事实,我不相信您的回答回答了所提出的问题。如果您说您无法按要求回答问题,那么我的解决方案是不发布某些内容作为答案。再次抱歉,如果您不同意。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多