怎么样解决嵌入式linux移植过程中“串口终端”的问题?

怎么样解决嵌入式linux移植过程中“串口终端”的问题?

Pxa27x的板子,最近在移植到linux2.4.21过程时,碰到一个串口终端无法输出信息的问题,bootloader引导时能够输出信息,但引导kernel时就停在那了,没有任何显示。

在网上搜索到一些资料,也排除了那些可能的原因,但还是没能够解决这个串口终端输出的问题。通过分析bootloaderkernel内核引导的这一过程,最后把目标锁定在了kernel解压缩的过程中,估计大伙使用的kenel都是经过压缩的内核,在BootLoader完成系统的引导以后并将Linux内核调入内存之后,跳转到kernel的起始位置。如果kernel没有压缩,就可以启动了(进入arch/arm/kernel/head_armv.S)。如果kernel压缩过,则要进行解压,在压缩过的kernel头部有解压程序。压缩过得kernel入口第一个文件源码位置在arch/arm/boot/compressed/head.S。它将调用函数decompress_kernel(),这个函数在文件arch/arm/boot/compressed/misc.c中,decompress_kernel()又调用proc_decomp_setup(),arch_decomp_setup()进行设置,然后使用在打印出信息“Uncompressing Linux...”后,调用gunzip()。将内核放于指定的位置。

decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,int arch_id)

{

output_data = (uch *)output_start; /* Points to kernel start */

free_mem_ptr = free_mem_ptr_p;

free_mem_ptr_end = free_mem_ptr_end_p;

__machine_arch_type = arch_id;

arch_decomp_setup();

makecrc();

puts("Uncompressing Linux...");

gunzip();

puts(" done, booting the kernel./n");

return output_ptr;

}

其中的puts就是通过串口输出信息,再看一下puts的定义(在include/asm-arm/arch-pxa/uncompress.h中):

#define FFUART ((volatile unsigned long *)0x40100000)

#define BTUART ((volatile unsigned long *)0x40200000)

#define STUART ((volatile unsigned long *)0x40700000)

 

#define UART FFUART

 

static __inline__ void putc(char c)

{

while (!(UART[5] & 0x20));

UART[0] = c;

}

 

/*

* This does not append a newline

*/

static void puts(const char *s)

{

while (*s) {

putc(*s);

if (*s == '/n')

putc('/r');

s++;

}

}

 

发现问题了,这里UART定义为FFUART 而我在bootloader中初始化用来串口输出的是STDUART,因此puts调用的putc中的while语句一直会处于循环中,内核启动就停在此处了。

解决方法很简单,让UART指向STDUART就可以了(#define UART STDUART)

保存,重新编译,下载,上电,OK!

 

下面是网上找的一些资料:

boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:

(1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。

(2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如 s3c44b0x 这样的 CPUCPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。

(3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000,但你的 boot loader却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。