这个软件使用目标(在嵌入式开发中,嵌入式设备通常被称为目标)上的 JTAG 端口,它是用于执行外部输入(通常来自主机机器)的指令的接口。JFlash-linux 是一种用于直接写闪存的流行工具。它支持为数众多的闪存芯片;它在主机机器(通常是 i386 机器 — 本文中我们把一台 i386 机器称为主机)上执行并通过 JTAG 接口使用并行端口访问目标的闪存芯片。当然,这意味着目标需要有一个并行接口使它能与主机通信。Jflash-linux 在 Linux 和 Windows 版本中都可使用,可以在命令行中用以下命令启动它:
某些种类的嵌入式设备具有微小的引导代码 — 根据几个字节的指令 — 它将初始化一些 DRAM 设置并启用目标上的一个串行(或者 USB,或者以太网)端口与主机程序通信。然后,主机程序或装入程序可以使用这个连接将引导装载程序传送到目标上,并将它写入闪存。
在安装它并给予其控制后,这个引导装载程序执行下列各类功能:
初始化 CPU 速度初始化内存,包括启用内存库、初始化内存配置寄存器等初始化串行端口(如果在目标上有的话)启用指令/数据高速缓存设置堆栈指针设置参数区域并构造参数结构和标记(这是重要的一步,因为内核在标识根设备、页面大小、内存大小以及更多内容时要使用引导参数)执行 POST(加电自检)来标识存在的设备并报告任何问题为电源管理提供挂起/恢复支持跳转到内核的开始 带有引导装载程序、参数结构、内核和文件系统的系统典型内存布局可能如下所示:
清单 1. 典型内存布局
/* Top Of Memory */
Bootloader
Parameter Area
Kernel
Filesystem
/* End Of Memory */
/* End Of Memory */
嵌入式设备上一些流行的并可免费使用的 Linux 引导装载程序有 Blob、Redboot 和 Bootldr(请参阅参考资料获得链接)。所有这些引导装载程序都用于基于 ARM 设备上的 Linux,并需要 Jflash-linux 工具用于安装。
Binutils — 用于操作二进制文件的实用程序集合。它们包括诸如 ar、as、objdump、objcopy 这样的实用程序。Gcc — GNU C 编译器。Glibc — 所有用户应用程序都将链接到的 C 库。避免使用任何 C 库函数的内核和其它应用程序可以在没有该库的情况下进行编译。 构建工具链建立了一个交叉编译器环境。本地编译器编译与本机同类的处理器的指令。交叉编译器运 行在某一种处理器上,却可以编译另一种处理器的指令。重头设置交叉编译器工具链可不是一项简单的任务:它包括下载源代码、修补补丁、配置、编译、设置头文 件、安装以及很多很多的操作。另外,这样一个彻底的构建过程对内存和硬盘的需求是巨大的。如果没有足够的内存和硬盘空间,那么在构建阶段由于相关性、配置 或头文件设置等问题会突然冒出许多问题。
因此能够从因特网上获得已预编译的二进制文件是一件好事(但不太好的一点是,目前它们大多数只限于基于 ARM 的系统,但迟早会改变的)。一些比较流行的已预编译的工具链包括那些来自 Compaq(Familiar Linux )、LART(LART Linux)和 Embedian(基于 Debian 但与它无关)的工具链 — 所有这些工具链都用于基于 ARM 的平台。
内核设置
Linux 社区正积极地为新硬件添加功能部件和支持、在内核中修正错误并且及时地进行常规改进。这导致大约每 6 个月(或 6 个月不到)就有一个稳定的 Linux 树的新发行版。不同的维护者维护针对特定体系结构的不同内核树和补丁。当为一个项目选择了一个内核时,您需要评估最新发行版的稳定性如何、它是否符合项目 要求和硬件平台、从编程角度来看它的舒适程度以及其它难以确定的方面。还有一点也非常重要:找到需要应用于基本内核的所有补丁,以便为特定的体系结构调整 内核。
OUTPUT_ARCH(<arch>) /* <arch> includes architecture type */
ENTRY(stext) /* stext is the kernel entry point */
SECTIONS /* SECTIONS command describes the layout
of the output file */
{
. = TEXTADDR; /* TEXTADDR is LMA for the kernel */
.init : { /* Init code and data*/
_stext = .; /* First section is stext followed
by __init data section */
__init_begin = .;
*(.text.init)
__init_end = .;
}
.text : { /* Real text segment follows __init_data section */
_text = .;
*(.text)
_etext = .; /* End of text section*/
}
.data :{
_data=.; /* Data section comes after text section */
*(.data)
_edata=.;
} /* Data section ends here */
.bss : { /* BSS section follows symbol table section */
__bss_start = .;
*(.bss)
_end = . ; /* BSS section ends here */
}
}
LMA 是装入模块地址;它表示将要装入内核的目标虚拟内存中的地址。TEXTADDR 是内核的虚拟起始地址,并且在 arch/<target>/ 下的 Makefile 中指定它的值。这个地址必须与引导装载程序使用的地址相匹配。一旦引导装载程序将内核复制到闪存或 DRAM 中,内核就被重新定位到 TEXTADDR — 它通常在 DRAM 中。然后,引导装载程序将控制转给这个地址,以便内核能开始执行。
unsigned long page_size; /* 0: Size of the page */
unsigned long nr_pages; /* 4: Number of pages in the system */
unsigned long ramdisk /* 8: ramdisk size */
unsigned long rootdev; /* 16: Number representing the root device */
unsigned long initrd_start; /* 64: starting address of initial ramdisk */
/* This can be either in flash/dram */
unsigned long initrd_size; /* 68: size of initial ramdisk */
}
struct <tag_tagname> {
u32 <tag_param>;
u32 <tag_param>;
};
/* Example tag for passing memory information */
#define ATAG_MEM 0x54410002 /* Magic number */
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
/* Example tag for passing memory information */
#define ATAG_MEM 0x54410002 /* Magic number */
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
在 Linux 下,用 mkfs.jffs2 命令创建 JFFS2 文件系统(基本上是使用 JFFS2 的 Ramdisk)。
清单 7. 创建 JFFS2 文件系统
mkdir jffsfile
cd jffsfile
/* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries
that are needed for the filesystem here */
/* Type the following command under jffsfile directory to create the JFFS2 Image */
./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image
联网功能部件至今没有经过适当地调整(特别是网络透明性)。还没有太多现成的应用程序可用。与 X 相比,Nano-X 虽然近来正在加速开发,但仍没有那么多文档说明而且没有很好的支持,但这种情形会有所改变。 Microwindows 上的 FLTK API 是一个简单但灵活的 GUI 工具箱,它在 Linux 世界中赢得越来越多的关注,它特别适用于占用资源很少的环境。它提供了您期望从 GUI 工具箱中获得的大多数窗口构件,如按钮、对话框、文本框以及出色的"赋值器"选择(用于输入数值的窗口构件)。还包括滑动器、滚动条、刻度盘和其它一些构件。
针 对 Microwindows GUI 引擎的 FLTK 的 Linux 版本被称为 FLNX。FLNX 由两个组件构成:Fl_Widget 和 FLUID。Fl_Widget 由所有基本窗口构件 API 组成。FLUID(快速轻巧的用户界面设计器(Fast Light User Interface Designer, FLUID))是用来产生 FLTK 源代码的图形编辑器。总的来说,FLNX 是能用来为嵌入式环境创建应用程序的一个出色的 UI 构建器。
面向对象的体系结构有助于更快地执行占用很少的资源,大约 800 K 抗锯齿文本和混合视频的象素映射。
它的缺点是:
Qt/Embedded 和 Qpe 只能在获得商业许可证的情况下才能使用。
结束语
嵌入式 Linux 开发正迅速地发展着。您必须学习并从引导装载程序和分发版到文件系统和 GUI 中的每一个事物的各种选项中作出选择。但是要感谢有这种选择自由度以及非常活跃的 Linux 社区,Linux 上的嵌入式开发已经达到了新的境界,并且调整模块以适合您的规范从未比现在更简单。这已经导致出现了许多时新的手持和微型设备作为开放盒,这是件好事 — 因为事实是您不必成为一个专家从这些模块中进行选择来调整您的设备以满足您自己的要求和需要。
我们希望这篇对嵌入式 Linux 领域的介绍性概述能激起您进行试验的欲望,并且希望您将体会摆弄微型设备的乐趣以满足您的爱好。为进一步有助于您的项目,请参阅下面的"参考资料",链接到有关我们这里已经概述的技术的更深入的信息。