嵌入式开发Linux入门

嵌入式开发

  • 导语
  • 嵌入式基础概念
    • 交叉开发和自助开发
    • 嵌入式开发相关术语
      • 1.开发计算机(又名:主计算机)
      • 2.目标计算机(又名:目标板、目标)
      • 3.交叉编译器/汇编程序/链接器
      • 4.交叉库(又名:目标库)
      • 5.交叉调试器
    • 嵌入式开发的流程
      • 步骤1:开发引导加载程序
      • 步骤2:内核实现
      • 步骤3:创建模块(设备驱动程序)
      • 步骤4:创建应用程序
      • 步骤5(最后一步):系统调整
  • 结束语

导语

近年来,“嵌入式设备”对Linux的采用越来越多。
Linux标准拥有的许多功能都符合嵌入式产品的目的,这是最大的原因。
安装在嵌入式设备上的Linux通常被称为“嵌入式Linux”,并使用与传统PC上运行的Linux不同的表达式。
但是,Linux和嵌入式Linux没有明显的区别也是事实,在某种程度上环境完备的状态的话,特别是意识不到嵌入式Linux的软件开发可能。
但是,从环境整备没有实现的状态开始开发嵌入式Linux,必须把握嵌入式这个词的意思。

嵌入式基础概念

交叉开发和自助开发

“交叉开发”,这是嵌入式开发的基本方法。

自助开发:开发环境和执行环境相同。
交叉开发:开发环境和执行环境不同。

也就是说,在PC世界中,使用Visual C++等开发PC应用程序的形式是自我开发。另一方面,交叉开发意味着在另一个设备(其他架构)上运行创建的可执行文件。

那么,为什么在嵌入式开发中交叉开发是基本方法呢?最大的原因是执行环境中的处理器(CPU)和操作系统是不同的。如你所知,Windows可执行文件不会在Linux上运行(操作系统不同)。即使在相同的Linux应用程序中,PC/AT兼容机的可执行文件也不会在Macintosh(编注)上运行(CPU不同)。在不同的环境中运行软件需要相应的工作。嵌入式设备使用各种CPU和操作系统,因此交叉开发势在必行。

Macintosh是苹果公司开发和销售的PC的品牌名称。
1984年第一台机器发布。通常被称为“Mac”。

另外,嵌入式设备的CPU功率和内存安装量等资源有限,很多情况下不可能像PC这样的开发方法。在可以使用相对较多资源的PC和工作站上开发,可以缩短编译时间,高效。

嵌入式开发相关术语

在嵌入式开发中,出现了PC软件开发中不常用的独特术语。在了解交叉开发的地方,也请记住其他的关键词。

1.开发计算机(又名:主计算机)

指的是实际创建程序的PC。

2.目标计算机(又名:目标板、目标)

指嵌入式设备。在交叉开发中运行创建的可执行文件的环境。

3.交叉编译器/汇编程序/链接器

交叉编译器/汇编程序/链接器用于编译所创建的程序(主要以C语言等编写)为目标。

4.交叉库(又名:目标库)

在用术语3中所示的工具编译程序时,需要交叉库。例如,如果您创建了hello.c,那么如果您认为其中使用的printf()本身是存储的,那么就很容易理解了。

如果您准确地描述交叉库,您将为目标操作系统提供两个交叉库和一个独立于OS的交叉库。存储在库中的许多函数都是通过结合操作系统的功能来实现的。要连接到OS本身的库和稍后将描述的引导加载器使用OS独立交叉库。

5.交叉调试器

虽然实际创建的可执行文件将直接在目标上运行,但是如果有调试器来查明问题的原因,这是非常有用的。
除此之外,关于交叉开发的关键词有很多,经常使用的是上述的5个左右吧。

嵌入式开发的流程

那么,让我们来看看实际嵌入式Linux的开发步骤。

步骤1:开发引导加载程序

首先要做的是开发引导加载程序来在目标上运行Linux本身。内置领域的引导加载程序相当于PC/AT兼容机的BIOS(编注)。

PC世界中使用的“引导加载程序”通常被写入MBR中,通常指的是BIOS调用的程序。LILO、GRUB、Windows的OS Loader等很有名。

引导加载程序的作用是随着设备的打开,从任意位置取出内核映像,并将其部署到目标内存中并运行。
我们没有安排这个“任何地方”,但大多数设备都使用闪存ROM等作为内存。
因此,为了维护等,除了原来的功能以外,还可以编入对ROM的程序写入功能等。

YES
NO
机器电源接入
硬件初期化
维护模式
Linux映像重写功能执行即ROM操作工具执行
Linux映像读取和内存部署
跳转到展开的内存即Linux启动

引导加载程序的实际开发主要是使用嵌入式软件开发专用设备的方法,例如电路模拟器(ICE)和JTAG模拟器。
以这种方式做的原因只是因为目标尚未实现软件,所以没有其他方法。
但是,从无状态开始开发引导加载程序的情况很少。
因为存在开源的引导加载程序,所以参考它们来开发是捷径。
另外,由于市售的单板计算机大多实现了引导加载功能,所以需要开发引导加载程序的只有自己制作目标板本身的情况。

步骤2:内核实现

在引导加载程序之后,它将是Linux的内核实现。

  1. 选择接近目标的内核
    从kernel.org(http://www.kernel.org/)等中选择特性接近目标的内核。
    特别是,体系结构(CPU等)不同的内核使用几乎不可能,所以一定要选择适合的体系结构的内核。如果对象外围设备相同的话就更方便了。
  2. 最大限度地减少嵌入的驱动程序
    使用内核配置(如make menuconfig)最大限度地减少静态链接模块(驱动程序)。
    这样一来,可以缩小动作时的问题调查范围。
    另外,由于驱动程序可以以模块的形式改装,所以内核启动后开发也来得及。在这个阶段,先推迟是明智的。
    一般情况下,嵌入式设备最低要求的是以下设备:
    ・串行(用于Linux控制台)
    ・以太网(用于TCP/IP网络)
    ・时钟(实现固定周期中断,而不是用于称为TOD的日期和时间管理)
    ・MTD(RAM磁盘实现)
  3. 驱动程序对应
    将源代码(如静态嵌入式驱动程序)与目标相关联。在这种情况下,需要注意的是对称为内存管理的部件的修改。目标的实现内存大小和各种设备的分配(注)决定的地方,所以这里弄错了设备驱动程序的动作等产生障碍,所以需要注意。

*注:
对于x86 CPU,用于控制设备的寄存器由端口号管理,并且可以通过读/写端口号来控制设备。
在其他CPU中,寄存器直接部署到内存中,因此通过读取和写入特定地址来实现设备控制。
这种内存分配有不同的情况,例如盲目(针对每个目标)确定,或者由内存管理机制软件式确定的情况下,等等。

  1. 创建RAM磁盘映像
    如你所知,Linux需要磁盘来运行。
    但是,需要驱动程序来运行硬盘等,并且内核必须运行以使驱动程序工作。
    但是,目前还处于运行内核的前一阶段,这是一个矛盾的状态。
    因此,暂时使用硬件依赖性低的RAM磁盘是最好的选择。
    因此,首先需要创建RAM磁盘映像。
    在这种情况下,需要注意的是,RAM磁盘是使用内存的磁盘,所以使用量是有限的。
    也就是说,乱放文件和命令是不合理的。
    您必须充分利用BusyBox(http://www.busybox.net/)等,尽量减小尺寸,避免超出目标装载内存。
    另外,请记住,命令等可执行文件需要与目标相同的CPU运行。
    到目前为止,我们将使用交叉编译器构建内核,并为目标创建内核映像。
    另外,我们建议您在这个时候装入RAM磁盘。
    使用上面提到的引导加载程序在目标上运行构建的内核映像,但RAM磁盘有助于简化当时的传输。
    由于内置了Linux控制台,所以如果内核开始工作,通常会在控制台上显示一些消息。
    但是,很少立即工作,大多数情况下,即使工作,也不会输出任何消息。
    为了避免这种情况,您需要使用printk()将调试消息放入内核的关键位置,并包含程序通过点的确认和变量显示。
    另外,使用ICE和JTAG仿真器等专用开发设备进行状态确认也是一种方法。

注:printf()和printk()。
对于printf()和printk(),我想大多数人都理解它只是使用的地方和目的是不同的函数,但是很少有人知道它的内容完全不同。
printf()顾名思义,是为标准输出输出字符串的函数,是操作系统支持功能的一部分。
printk()与printf()完全不同,其函数的内容是直接操作硬件输出字符串的结构。
因为printk()用于在任何状态下显示字符串,并将其作为解决问题的线索。
也就是说,如果printk()需要OS(Linux),也就是说,如果内核本身没有开始操作,它就不能使用了,但是它会导致内核准备工作的消息消失。
因此,printk()根据需要直接控制硬件来显示字符串。

步骤3:创建模块(设备驱动程序)

内核实现完成后,您将创建当前所需的驱动程序。
作为这个阶段的基本流程,这将是“尝试创建模块并尝试动作”的踏实工作的重复。
如果目标有可移动存储设备,建议您优先创建驱动程序。
我想如果你想起内核实现的故事,我会知道原因。
因为最初是只安装RAM盘,所以这样的话只需要一个模块的执行,
模块创建(文件创建)
↓↓。
RAM磁盘内容更改。
↓↓。
内核重新构建(带有RAM磁盘映像)。
↓↓。
目标重新启动(内核重新传输/执行)。
↓↓。
模块动作;模块动作。

这是一个非常长的步骤。如果您可以使用可移动存储,则只能实现模块的替换。

步骤4:创建应用程序

内核和模块的创建完成后,就是应用程序的开发。
关于这个也有各种各样的步骤。
基本上和模块开发一样,
制作。
↓↓。
转移到目标。
↓↓。
实行。

这就是说,这种方法大致分为以下两种类型

  1. 模拟开发
    大多数使用嵌入式Linux的开发不是这个方法吗?
    作为说明,准备安装Linux的PC(主计算机),首先开发在主计算机上的Linux上运行的程序。
    接下来,使用交叉编译器将程序编译为主机上的目标,并将其传送到目标并运行。
    这种方法在开发人员缺乏目标数量的情况下是有效的,因为在最后一个目标操作之前不需要使用目标(机器)。
    另外,当最终执行目标操作时,大多数问题都在主计算机上解决,所以在目标上运行时不会出现太多问题,这是有好处的。
    相反,这种方法存在可开发软件受限的问题。
    例如,很难开发一个程序来控制只存在于目标的设备。
    同样,Linux有不同的图片库(如X11),但在嵌入式设备上使用相同的图片库是罕见的,而且屏幕大小也不同,不能简单地在主计算机上进行所有开发。
    此外,当程序必须在固定时间运行时,即使主计算机以正确的时间分配运行,目标也可能会因处理器的能力差异而导致时间分配不同。因此,最终需要“实机开发”。
  2. 实机开发
    实机开发的步骤,简直就是交叉开发本身。
    换句话说,
    在主计算机上编写程序。
    ↓↓。
    编译(编译)。
    ↓↓。
    在目标上运行可执行文件。
    按照这样的步骤进行开发。
    请注意,将可执行文件传输到目标,称为“下载”。
    下载有不同的方法。
    还可以使用FTP等文件传输,使用NFS和Samba等网络文件系统共享文件。
    特别是,使用NFS和Samba等的方法可以在不知道下载过程的情况下在目标上执行文件,因此在相对较多的嵌入式Linux开发中使用。
    具体而言,主计算机的某些目录将通过NFS等共享发布。
    程序的创建是在目录下完成的,目标是通过NFS挂载直接使用公开的目录。
    即使是嵌入式Linux也有控制台的概念,所以在目标上也可以使用Linux命令。
    当然,相反,您也可以在NFS上发布目标端的任何目录,并在主计算机端实施NFS挂载。
    但是,由于许多目标在磁盘空间中没有太多的空间,所以共享主计算机的目录是常见的。
    除此之外,这是一种经典的方法,但也可以考虑使用可移动介质(如FD和USB存储)来每次交换可执行文件。
    但是,考虑到这一点,不得不说这是不切实际的。

步骤5(最后一步):系统调整

即使以上的开发工作结束了,也只是简单地做好了动作,要想完成的话,就是稍微快一点的状态。
这是因为这一点只是在原型机环境中运行,并不是在应该作为产品的状态下运行的。
那么,在什么样的状态下才能说完成了呢?
根据产品的不同,“完成”的定义千差万别,但最重要的是文件大小是否在规定范围内,应该运行的程序是否自动启动等。
文件大小非常重要,因为它会影响硬件的大小。
检查内核,每个模块,应用程序等文件大小以及磁盘的可用空间。
如果这些不在规定范围内,则更改程序的编译选项等,进行调整大小等作业。

结束语

这一次,描述了嵌入式Linux开发的整体情况。如有不足或错误,请告知我,谢谢。

你可能感兴趣的:(Linux,嵌入式,linux)