嵌入式系统的原理及应用.ppt
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
17
VIVI 第2阶段介绍
第5步:mtd_dev_init()
mtd_dev_init()用来扫描所使用的NAND Flash的型号,构造 MTD设备,即构造一个mtd_info的数据结构。对于本开发板,它 直接调用mtd_init(),mtd_init又调用smc_init(),此函数在 drivers/mtd/maps/s3c2410_flash.c中。
嵌入式系统的原理及应用
3.3 嵌入式Linux系统的开发
编写BootLoader; 裁减嵌入式Linux内核; 裁减嵌入式Linux文件系统; 烧写BootLoader到目标板; 烧写嵌入式Linux内核和文件系统到目标板。
2
3.3.1 编写BootLoader
一个嵌入式Linux系统从软件角度看可以分为四个层次:
怎样编写BootLoader程序?
初学者最好采用拿来主义,在别人的BootLoader源代码基础上 进行修改、编译、调试。
19
18
VIVI 第2阶段介绍
第7步:misc()和init_builtin_cmds()
这两个函数都是简单地调用add_command函数,给一些命令 增加相应的处理函数。在vivi启动后,可以进去操作界面,这些命 令,就是供用户使用的。
第8步:boot_or_vivi()
此函数根据情况,或者启动“vivi_shell”,进入与用户进行交 互的界面,或者直接启动linux内核。
9
head.S通常完成如下几件事情:
(5) 检查是否从掉电模式唤醒,若是,则调用WakeupStart函数进 行处理——这是一段没用上的代码,vivi不可能进入掉电模式; (6) 点亮所有LED (7) 初始化UART0:
a.设置GPIO,选择UART0使用的引脚 b.初始化UART0,设置工作方式(不使用FIFO)、波特率 115200 8N1、无流控等,请参考实验:UART
依赖于CPU体系结构的代码,比如设备初始化代码等 ,通常都放在stage1中,而且通常都用汇编语言来实现, 以达到短小精悍的目的。
而stage2则通常用C语言来实现,这样可以实现给复 杂的功能,而且代码会具有更好的可读性和可移植性。
这里以韩国MIZI公司的VIVI为例来说明BootLoader 的主要任务。
及协议
4
3.3.1.2 BootLoader的主要任务
首先我们做一个假定,那就是:假定内核映像与 根文件系统映像都被加载到RAM中运行。之所以提 出这样一个假设前提是因为,在嵌入式系统中内核映 像与根文件系统映像也可以直接在ROM或Flash这样 的固态存储设备中直接运行。但这种做法无疑是以运 行速度的牺牲为代价的。
11
head.S通常完成如下几件事情:
(9) 跳到bootloader的阶段2运行——就是调用init/main.c中 的main函数:
a.重新设置堆栈 b.设置main函数的参数 c.调用main函数
12
VIVI的阶段2
请看其主程序: (在init/main.c中,它可以分为8个步骤)。 1 int main(int argc, char *argv[]) 2{ 3 int ret;
7
VIVI的阶段1
head.S程序
.s gcc可以编译的汇编语言源程序,但不进行预处理,即 不处理#define、#include、#undef等等。 .S gcc可以编译的汇编语言源程序,进行预处理,因为要 进行预处理,因此C语言中的宏、头文件和条件式编译均 可接受#define、 #include、 #undef、#ifdef ,C语言中的注 释也可以如 /**/、 //等。
13
VIVI的阶段2
14 /*第3步*/ 15 mem_map_init(); 16 mmu_init(); 17 putstr("Succeed memory mapping.\r\n"); 18 /* Now, vivi is running on the ram. MMU is enabled.*/
第2步:board_init() board_init调用2个函数用于初始化定时器和设置各GPIO引 脚功能(代码在arch/s3c2410/smdk.c中)。
第3步:建立页表和启动MMU mem_map_init函数用于建立页表,vivi使用段式页表,只需 要一级页表。调用3个函数(代码在arch/s3c2410/m2 BootLoader的主要任务
Boot parameters
kernel
Root file system
BootLoader 固态存储设备的典型空间分配结构
6
一个典型的BootLoader:VIVI
从操作系统的角度看,BootLoader的总目标就是正确 地调用内核来执行。
另外,由于BootLoader的实现依赖于CPU的体系结构 ,因此大多数BootLoader都分为stage1和stage2两大部分 。
事实上,heap就是使用一系列的blockhead数据结构来描述和操 作的。每个blockhead数据结构对应着一块heap内存。
假设一个blockhead数据结构的存放位置为A,则它对应的可分 配内存地址为“A + sizeof(blockhead)”到“A + sizeof(blockhead) + size - 1”。blockhead数据结构在lib/heap.c中定义。
引导加载程序。包括固化在固件(firmware)中的boot代码(可 选),和BootLoader两大部分。
Linux内核。特定于嵌入式目标板的定制内核以及内核的启动 参数。
文件系统。包括根文件系统和建立于Flash内存设备之上文件 系统。通常用ramdisk来作为rootfs。
用户应用程序。特定于用户的应用程序。有时在用户应用程 序和内核层之间可能还会包括一个嵌入式图形用户界面。常用 的嵌入式GUI有:Qt、MicroWindows和MiniGUI等等。
14
VIVI的阶段2
28 /*第6步*/ 29 init_priv_data();
30 /*第7步*/ 31 misc(); 32 init_builtin_cmds();
33 /*第8步*/ 34 boot_or_vivi(); 35 return 0; 36 }
15
VIVI 第2阶段介绍
第1步:reset_handler() reset_handler用于将内存清零(代码在lib/reset_handle.c中)。
19 /*第4步*/ 20 /* initialize the heap area */ 21 ret = heap_init(); 22 if (ret) { 23 putstr("Failed initailizing heap region\r\n"); 24 error(); 25 }
26 /*第5步*/ 27 ret = mtd_dev_init();
第6步:init_priv_data()
此函数将启动内核的命令参数取出,存放在内存特定的位置 中。这些参数来源有两个:vivi预设的默认参数,用户设置的参数( 存放在nand flash上)。init_priv_data先读出默认参数,存放在 “VIVI_PRIV_RAM_BASE”开始的内存上;然后读取用户参数, 若成功则用用户参数覆盖默认参数,否则使用默认参数。
10
head.S通常完成如下几件事情:
(8) 将vivi所有代码(包括阶段1和阶段2)从nand flash复制到 SDRAM中:
a.设置nand flash控制寄存器 b.设置堆栈指针——调用C函数时必须先设置堆栈 c.设置即将调用的函数nand_read_ll的参数:r0=目的地址 (SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度( 以字节为单位) d.调用nand_read_ll进行复制 e.进行一些检查工作:上电后nand flash最开始的4K代码被自 动复制到一个称为“Steppingstone”的内部RAM中(地址为 0x00000000-0x00001000);在执行nand_read_ll之后,这4K代码同 样被复制到SDRAM中(地址为0x33f00000-0x33f01000)。比较这两 处的4K代码,如果不同则表示出错。
8
head.S通常完成如下几件事情:
(1) 关WATCH DOG:上电后,WATCH DOG默认是开着的; (2) 禁止所有中断:vivi中没用到中断(不过这段代码实在多余 ,上电后中断默认是关闭的); (3) 初始化系统时钟:启动MPLL,FCLK=200MHz, HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为 “Asynchronous bus mode”; (4) 初始化内存控制寄存器(还记得那13个寄存器吗?);
3
3.3.1.1 基本概念
(1) BootLoader所支持的CPU和嵌入式板 (2) BootLoader的安装媒介(Installation Medium) (3) 用来控制BootLoader的设备或机制 (4) BootLoader的启动过程是单阶段(SingleStage)还是多
阶段(Multi-Stage) (5) BootLoader的操作模式(OperationMode) (6) BootLoader与主机之间进行文件传输所用的通信设备
4 /*第1步*/ 5 putstr("\r\n"); 6 putstr(vivi_banner); 7 reset_handler();
8 /*第2步*/ 9 ret = board_init(); 10 if (ret) { 11 putstr("Failed a board_init() procedure\r\n"); 12 error(); 13 }
16
VIVI 第2阶段介绍
第4步:heap_init()
heap——堆,内存动态分配函数mmalloc就是从heap中划出一 块空闲内存的,mfree则将动态分配的某块内存释放回heap中。
heap_init函数在SDRAM中指定了一块1M大小的内存作为heap( 起始地址HEAP_BASE = 0x33e00000),并在heap的开头定义了一个 数据结构blockhead。
VIVI 第2阶段介绍
第5步:mtd_dev_init()
mtd_dev_init()用来扫描所使用的NAND Flash的型号,构造 MTD设备,即构造一个mtd_info的数据结构。对于本开发板,它 直接调用mtd_init(),mtd_init又调用smc_init(),此函数在 drivers/mtd/maps/s3c2410_flash.c中。
嵌入式系统的原理及应用
3.3 嵌入式Linux系统的开发
编写BootLoader; 裁减嵌入式Linux内核; 裁减嵌入式Linux文件系统; 烧写BootLoader到目标板; 烧写嵌入式Linux内核和文件系统到目标板。
2
3.3.1 编写BootLoader
一个嵌入式Linux系统从软件角度看可以分为四个层次:
怎样编写BootLoader程序?
初学者最好采用拿来主义,在别人的BootLoader源代码基础上 进行修改、编译、调试。
19
18
VIVI 第2阶段介绍
第7步:misc()和init_builtin_cmds()
这两个函数都是简单地调用add_command函数,给一些命令 增加相应的处理函数。在vivi启动后,可以进去操作界面,这些命 令,就是供用户使用的。
第8步:boot_or_vivi()
此函数根据情况,或者启动“vivi_shell”,进入与用户进行交 互的界面,或者直接启动linux内核。
9
head.S通常完成如下几件事情:
(5) 检查是否从掉电模式唤醒,若是,则调用WakeupStart函数进 行处理——这是一段没用上的代码,vivi不可能进入掉电模式; (6) 点亮所有LED (7) 初始化UART0:
a.设置GPIO,选择UART0使用的引脚 b.初始化UART0,设置工作方式(不使用FIFO)、波特率 115200 8N1、无流控等,请参考实验:UART
依赖于CPU体系结构的代码,比如设备初始化代码等 ,通常都放在stage1中,而且通常都用汇编语言来实现, 以达到短小精悍的目的。
而stage2则通常用C语言来实现,这样可以实现给复 杂的功能,而且代码会具有更好的可读性和可移植性。
这里以韩国MIZI公司的VIVI为例来说明BootLoader 的主要任务。
及协议
4
3.3.1.2 BootLoader的主要任务
首先我们做一个假定,那就是:假定内核映像与 根文件系统映像都被加载到RAM中运行。之所以提 出这样一个假设前提是因为,在嵌入式系统中内核映 像与根文件系统映像也可以直接在ROM或Flash这样 的固态存储设备中直接运行。但这种做法无疑是以运 行速度的牺牲为代价的。
11
head.S通常完成如下几件事情:
(9) 跳到bootloader的阶段2运行——就是调用init/main.c中 的main函数:
a.重新设置堆栈 b.设置main函数的参数 c.调用main函数
12
VIVI的阶段2
请看其主程序: (在init/main.c中,它可以分为8个步骤)。 1 int main(int argc, char *argv[]) 2{ 3 int ret;
7
VIVI的阶段1
head.S程序
.s gcc可以编译的汇编语言源程序,但不进行预处理,即 不处理#define、#include、#undef等等。 .S gcc可以编译的汇编语言源程序,进行预处理,因为要 进行预处理,因此C语言中的宏、头文件和条件式编译均 可接受#define、 #include、 #undef、#ifdef ,C语言中的注 释也可以如 /**/、 //等。
13
VIVI的阶段2
14 /*第3步*/ 15 mem_map_init(); 16 mmu_init(); 17 putstr("Succeed memory mapping.\r\n"); 18 /* Now, vivi is running on the ram. MMU is enabled.*/
第2步:board_init() board_init调用2个函数用于初始化定时器和设置各GPIO引 脚功能(代码在arch/s3c2410/smdk.c中)。
第3步:建立页表和启动MMU mem_map_init函数用于建立页表,vivi使用段式页表,只需 要一级页表。调用3个函数(代码在arch/s3c2410/m2 BootLoader的主要任务
Boot parameters
kernel
Root file system
BootLoader 固态存储设备的典型空间分配结构
6
一个典型的BootLoader:VIVI
从操作系统的角度看,BootLoader的总目标就是正确 地调用内核来执行。
另外,由于BootLoader的实现依赖于CPU的体系结构 ,因此大多数BootLoader都分为stage1和stage2两大部分 。
事实上,heap就是使用一系列的blockhead数据结构来描述和操 作的。每个blockhead数据结构对应着一块heap内存。
假设一个blockhead数据结构的存放位置为A,则它对应的可分 配内存地址为“A + sizeof(blockhead)”到“A + sizeof(blockhead) + size - 1”。blockhead数据结构在lib/heap.c中定义。
引导加载程序。包括固化在固件(firmware)中的boot代码(可 选),和BootLoader两大部分。
Linux内核。特定于嵌入式目标板的定制内核以及内核的启动 参数。
文件系统。包括根文件系统和建立于Flash内存设备之上文件 系统。通常用ramdisk来作为rootfs。
用户应用程序。特定于用户的应用程序。有时在用户应用程 序和内核层之间可能还会包括一个嵌入式图形用户界面。常用 的嵌入式GUI有:Qt、MicroWindows和MiniGUI等等。
14
VIVI的阶段2
28 /*第6步*/ 29 init_priv_data();
30 /*第7步*/ 31 misc(); 32 init_builtin_cmds();
33 /*第8步*/ 34 boot_or_vivi(); 35 return 0; 36 }
15
VIVI 第2阶段介绍
第1步:reset_handler() reset_handler用于将内存清零(代码在lib/reset_handle.c中)。
19 /*第4步*/ 20 /* initialize the heap area */ 21 ret = heap_init(); 22 if (ret) { 23 putstr("Failed initailizing heap region\r\n"); 24 error(); 25 }
26 /*第5步*/ 27 ret = mtd_dev_init();
第6步:init_priv_data()
此函数将启动内核的命令参数取出,存放在内存特定的位置 中。这些参数来源有两个:vivi预设的默认参数,用户设置的参数( 存放在nand flash上)。init_priv_data先读出默认参数,存放在 “VIVI_PRIV_RAM_BASE”开始的内存上;然后读取用户参数, 若成功则用用户参数覆盖默认参数,否则使用默认参数。
10
head.S通常完成如下几件事情:
(8) 将vivi所有代码(包括阶段1和阶段2)从nand flash复制到 SDRAM中:
a.设置nand flash控制寄存器 b.设置堆栈指针——调用C函数时必须先设置堆栈 c.设置即将调用的函数nand_read_ll的参数:r0=目的地址 (SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度( 以字节为单位) d.调用nand_read_ll进行复制 e.进行一些检查工作:上电后nand flash最开始的4K代码被自 动复制到一个称为“Steppingstone”的内部RAM中(地址为 0x00000000-0x00001000);在执行nand_read_ll之后,这4K代码同 样被复制到SDRAM中(地址为0x33f00000-0x33f01000)。比较这两 处的4K代码,如果不同则表示出错。
8
head.S通常完成如下几件事情:
(1) 关WATCH DOG:上电后,WATCH DOG默认是开着的; (2) 禁止所有中断:vivi中没用到中断(不过这段代码实在多余 ,上电后中断默认是关闭的); (3) 初始化系统时钟:启动MPLL,FCLK=200MHz, HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为 “Asynchronous bus mode”; (4) 初始化内存控制寄存器(还记得那13个寄存器吗?);
3
3.3.1.1 基本概念
(1) BootLoader所支持的CPU和嵌入式板 (2) BootLoader的安装媒介(Installation Medium) (3) 用来控制BootLoader的设备或机制 (4) BootLoader的启动过程是单阶段(SingleStage)还是多
阶段(Multi-Stage) (5) BootLoader的操作模式(OperationMode) (6) BootLoader与主机之间进行文件传输所用的通信设备
4 /*第1步*/ 5 putstr("\r\n"); 6 putstr(vivi_banner); 7 reset_handler();
8 /*第2步*/ 9 ret = board_init(); 10 if (ret) { 11 putstr("Failed a board_init() procedure\r\n"); 12 error(); 13 }
16
VIVI 第2阶段介绍
第4步:heap_init()
heap——堆,内存动态分配函数mmalloc就是从heap中划出一 块空闲内存的,mfree则将动态分配的某块内存释放回heap中。
heap_init函数在SDRAM中指定了一块1M大小的内存作为heap( 起始地址HEAP_BASE = 0x33e00000),并在heap的开头定义了一个 数据结构blockhead。