|  | 
 
| Learn lumit Step 5 : 实现 printf 输出 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 串口能够驱动起来之后,按照惯例我们就要 helloworld 了。其实格式化输出
 printf 的作用在嵌入式开发中的地位远不止此,它不仅是一个非常重要的调试手段,
 也是一个无法回避的技术细节。这一节对于很多做 ARM 开发的我相信都很重要,
 特别是对于使用 ADS1.2 上 ARMCC 编译器的开发者来说,这里提到的一个技巧也许
 能帮上你不少忙。
 
 我在知道怎么用技巧实现 printf 输出之前,一直都是用 SkyEye 里面的一个被
 起名为 skyeye_printf.c 的文件,它实际上是实现了一个自制简易可用的 printf ,
 其简单实用的程度好比 Wiggler Jtag 仿真调试头。这个文件是从水木清华 BBS 上
 wohaha 大侠的一篇帖子里面找出来的,虽然它在嵌入式应用场合也足够好用,不过
 还是有很多不足,我把它也放到附件里面,有兴趣的朋友可以下载来看。
 
 上面的 skyeye_printf.c 主要是自己实现了格式化输出那些 % 的输出格式,
 最终通过字符输出函数 skyeye_putc 这样一个 low-level 的输出接口获得实现的。
 但在 ARM ADS1.2 里面已经有了足够好的 C 库来实现格式化字符串的工作,它所缺的
 仅仅就是一个底层的输出接口函数。通常这个最底层的输出接口就是通过某一个串口
 把字符发送出来,在另一端用超级终端这样的工具显示出来就可以。
 
 在 ADS1.2 的安装目录下 ( 我的机器上是 C:\Program Files\ARM\ADSv1_2\PDF )
 有一篇非常好的文档教你怎么实现这个接口,文档名是 ADS_CompilerGuide_D.pdf ,
 在 The C and C++ Library 章节 4-76 (page166) 位置处,这是一个经典的不能再经典
 的关于 printf 实现的例子,我们所要做的就是把 fputc 实现为我们上一节里面已经做
 好的 uart_sendchar ,其他还有 ferror 和 __stdout 的声明也不可少。
 
 具体实现的代码如下:
 
 /* retarget code of printf low-level function */
 /* *************************************************************** */
 #include <stdio.h>
 struct __FILE { int handle;   /* Add whatever you need here */};
 FILE __stdout;
 
 int fputc(int ch, FILE *f)
 {
 if( ch == '\n' )
 {
 uart_putchar( UART0_BASE, '\r' );
 uart_putchar( UART0_BASE, '\n' );
 }
 else
 uart_putchar( UART0_BASE, ch );
 return ch;
 }
 
 int ferror(FILE *f)
 {
 return EOF;
 }
 /* *************************************************************** */
 
 只要把上面这一段代码嵌入到你的 main 之上,然后在调用 printf 之前把串口
 按照需要的波特率初始化好,就可以方便地使用 printf 提供的标准格式化输出功能了。
 
 附件里面是一个现成的例子,可以在 lumit4510 的板子上烧进去,运行输出的结果
 如下:
 printf
 hello, lumiter!
 test_rw = 0x2468, test_ro = 0x1357, test_bss = 0x0
 printf
 hello, lumiter!
 test_rw = 0x2468, test_ro = 0x1357, test_bss = 0x0
 
 特别要说明的是,它完成了从加电启动到实现 printf 的全部过程,不需要借助
 任何的系统调用,和 bootloader 无关。有点板子不需要这样实现也可以用 printf 输出,
 那主要是借助了板子上 SWI 软中断接口,其实我倒觉得这个顺序应该反过来,printf 是
 实现一个 bootloader 前必须经过的一个环节,不知大家是否赞同?
 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册  |