嵌入式实时操作系统复习提纲
一、基本概念
1.嵌入式系统是以应用为中心,以计算机技术为基础,并且软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统。
2.嵌入式系统的组成部分是嵌入式系统硬件平台、嵌入式操作系统和嵌入式系统应用。其中,嵌入式系统硬件平台为各种嵌入式器件、设备(如ARM、PowerPC、Xscale、MIPS等);嵌入式操作系统是指在嵌入式硬件平台上运行的操作系统,目前主流的嵌入式操作系统有嵌入式Linux、?CLinux、WinCE、?C/OS-Ⅱ、VxWorks等。RTOS有QNX,pSOS,vxworks,RT-Linux等.
Linux内核主要是由进程调度、内存管理、虚拟文件系统、网络接口和进程间通信等组成。
3.Linux用户进程:进程控制块、系统堆栈、用户堆栈、程序代码及数据段组成;Linux可以管理512个进程,进程调度的police域有:SCHED_OTHER; SCHED_FIFO; SCHED_RR。Linux的进程控制相关的系统调用函数有:fork,exit,vfork,wait,execve等。
Linux系统定义了五种状态进程状态
就绪状态 TASK_RUNNING 0
可中断等待状态 TASK_INTERRUPTIBLE 1
不可中断等待状态 TASK_UNINTERRUPTIBLE
停止状态、僵尸状态 TASK_ZOMBIE 4
中止状态 TASK_STOPPED 8
2 从Linux的调度来看,支持非实时(普通)和实时两种进程。
4.Linux 虚拟文件系统维护描述整个虚拟文件系统以及实际已挂装的文件系统的数据结构。嵌入式Linux系统中常见的文件系统有:yaffs, jsffs, cramfs等。文件系统的安装必须调用mount命令,把其他子系统安装到已经存在于文件系统的空闲节点上。文件系统类型的注册函数为register filesystem,超级用户卸载文件系统使用umount命令。
5.考虑到中断处理的效率,Linux的中断处理程序分为两个部分:上半部(top half)和下半部(bottom half)。由外部设备引发的中断叫外部中断,处理器响应中断请求而执行的程序模块叫中断服务例程
6.交换机制:将不用或暂不用的页框中的页移出,装上新的页面;linux三级分页结构
7.进程的通信与同步机制有管道、信号、消息队列、共享内存和信号量集等el 中。Linux的管道有:匿名管道和命名管道;从信号的可靠性方面,信号可以分为:可靠信号和不可靠信号。
8.linux设备驱动注册的基本参数有设备名称,设备驱动的数据结构、设备号
和 次设备号。lsmod 把现在 kernel 中已经安装的modules 列出来;insmod 把某个 module 安装到 kernel.
二、基本原理和方法
基于虚拟内存技术的程序执行两次映射:
1.应用程序向虚拟内存映射:用虚拟地址为程序编址,映射到虚拟内存空间;确定其代码段、数据段和堆栈段的地址空间,系统以逻辑地址访问虚拟内存中的某个程序段;
2.把要运行的程序段复制到物理内存,映射到物理内存空间,确定程序的物理地址。虚拟内存逻辑地址与物理地址的对应记录表;系统自物理内存地址读取所需数据。
Buddy算法-伙伴算法
Linux对空闲内存空间管理采用Buddy算法。
Buddy算法
把内存中所有页面按照2n划分,其中n=0~5,每个内存空间按1个页面、2个页面、4个页面、8个页面、16个页面、32个页面进行六次划分。
划分后形成了大小不等的存储块,称为页面块,简称页块。包含1个页面的页块称为1页块,包含2个页面的称为2页块,依此类推。
每种页块按前后顺序两两结合成一对Buddy“伙伴”
系统按照Buddy关系把具有相同大小的空闲页面块组成页块组,即1页块组、2页块组……32页块组。
每个页块组用一个双向循环链表进行管理,共有6个链表,分别为1、2、4、8、16、32页块链表。分别挂到free_area[] 数组上。
内存分配时,系统按照Buddy算法,根据请求的页面数在free_area[]对应的空闲页块组中搜索。
若请求页面数不是2的整数次幂,则按照稍大于请求数的2的整数次幂的值搜索相应的页面块组。
当相应页块组中没有可使用的空闲页面块时就查询更大一些的页块组,在找到可用的空闲页面块后,分配所需页面。
当某一空闲页面块被分配后,若仍有剩余的空闲页面,则根据剩余页面的大小把它们加入到相应页块组中。
内存页面释放时,系统将其做为空闲页面看待。检查是否存在与这些页面相邻的其它空闲页块,若存在,则合为一个连续的空闲区按Buddy算法重新分组。
Slab分配器思想
小对象的申请和释放通过slab分配器来管理。
slab分配器有一组高速缓存,每个高速缓存保存同一种对象类型,如i节点缓存、PCB缓存等。
内核从它们各自的缓存种分配和释放对象。系统分配对象时就从slab中取得。首先从这个cache中部分满的slab中分配,如果没有这样的slab, 便从空的slab中分配,如果也没有,就创建一个新的slab来分配即可。由于每个对象在释放时几乎处于分配好并且初始化好的状态,还可以节省不少初始化的时间。
每种对象的缓存区由一连串slab构成,每个slab由一个或者多个连续的物理页
面组成。这些页面种包含了已分配的缓存对象,也包含了空闲对象。
Linux 内核的主要组成部分
Linux内核主要是由进程调度、内存管理、虚拟文件系统、网络接口和进程间通
信五部分组成。
(1) 进程调度负责控制进程对CPU的访问,调度程序使用一种策略确保所有的
进程都能公平的访问CPU,并且确保内核在任意时刻能执行必要的硬件操作。
(2) 内存管理负责管理系统的物理内存,实现多进程安全享享计算机的内存。
(3) 虚拟文件系统通过将各种设备抽象为一种公共接口,从而屏蔽了各种硬件
设备的细节。虚拟文件系统可以分为逻辑文件系统和设备驱动程序两部分。
(4) 网络接口提供了对各种网络标准的存取和各种网络硬件的支持,实现了对
各种网络标准和网络硬件的访问。网络接口可分为网络协议和网络驱动程序。
网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与
硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。
(5) 进程间通信子系统实现了系统内部进程间的多种通信机制。
这五个子系统互相依赖,但相对来说进程调度处在比较重要的地位。其
他子系统需要挂起和恢复进程的运行都必须依靠进程调度子系统的参与。
Linux的中断处理程序
Linux系统进程调度的总体思想。
实时进程优先于普通进程,实时进程以进程的紧急程度为优先顺序,普通进程以进程平等占用CPU时间为基本调度原则。
三、Linux内核程序理解
1. Linux使用内核函数goodness()对进程进行加权处理:
Static inline goodness (struct task_struct * pint this_cpu, struct mm_struct *this_mm)
{Int weight;
Weight=-1;
If (p->policy & SCHED_YIELD)// /*判断如果任务的调度策略被置为SCHED_YIELD的话,则置权值为-1,返回。
goto out;
If (p->policy==SCHED_OTHER) /*先对普通进程进行处理(由于多数是普通进程,这样做有利于提高系统效率)*/
{weight=p->counter; /*返回权值为进程的counter值*/
If (! weight)
Goto out;
#Ifdef CONFIG_SMP
If (p->processor==this_cpu)
Weight+=PROC_CHANGE_PENALTY;
#Endif
If (p->mm==this_mm||! p->mm)
Weight+=1; /*对进程权值进行微调,如果进程的内存空间使用当前正在运行的进程的内存空间,则权值额外加1*/
Weight+=20-p->nice; /*将权值加上20与进程优先级nice的差。普通进程的权值主要由counter值和nice值组成*/
Goto out;
}
Weight=1000+p->rt_priority; //对实时进程进行处理,返回权值为
rt_priority+1000,确保优先级高于普通进程*/
Out:
return weight;}
2.小任务是指对要推迟执行的函数进行组织的一种机制。其数据结构为
tasklet_struct,每个结构代表一个独立的小任务,其定义如下:
struct tasklet_struct {
struct tasklet_struct *next; /*指向链表中的下一个结构*/ unsigned long state; /* 小任务的状态 */
atomic_t count; /* 引用计数器 */
void (*func) (unsigned long); /* 要调用的函数 */ unsigned long data; /* 传递给函数的参数 */
};
3.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
void testirq_interrupt(int,void *,struct pt_regs *);
static int testirq_init(void);
/**********************************************************/
void testirq_interrupt(int irq,void *d,struct pt_regs *regs)
{ /*clear interrupt register for EINT5*/
SRCPND &= (~0x00000010); //(1)中断源待决寄存器赋值
INTPND = INTPND;
EINTPEND &= (~0x00000020); //(2) 外部中断待决寄存器赋值
printk("Entered an interrupt! Beginning interrupt
service!\n");}
/****************************************************/
static int __init testirq_init(void)
{ static int result;
unsigned long gpfup;
set_external_irq(IRQ_EINT5, EXT_FALLING_EDGE, GPIO_PULLUP_DIS);// (3)中断配置安装
gpfup = ioremap(0x56000058,4); //(4) gpfup寄存器地址映射
(*(volatile unsigned long *)gpfup) = 0;
disable_irq(IRQ_EINT5);// (5)关中断
enable_irq(IRQ_EINT5);// (6)开中断
result=request_irq(IRQ_EINT5,&testirq_interrupt,SA_INTERRUPT,"testirq",NULL);// (7)中断注册
if (result)
{printk("Can't get assigned irq %d,result=%d\n",IRQ_EINT5,result); return result;}
printk("Testirq interrupt registered ok!!!\n");
return 0;}
static void __exit testirq_exit(void){
disable_irq(IRQ_EINT5);
free_irq(IRQ_EINT5, NULL);// (8)释放中断
printk("exit ok\n");}
module_init(testirq_init);// (9)模块初始化
module_exit(testirq_exit);// (10) 模块退出
实训总结
(1) ARM简介
(2) ARM处理器模式
(3) ARM的寄存器
(4) ARM的异常
(5) 存储器I/O
详细内容参加ARM体系结构PPT。
1. 将虚拟iso文件解压缩(或者用虚拟光驱装载),双击setup.exe进行安装
2. 安装即将结束的时候,会出现一个窗口,上面有“下一步”按钮
3. 此时,将rvds4cr.crack文件夹的内容,拷贝到C:\Program Files\ARM\文件夹
4. 开始—运行—输入cmd,点击确定
5. 输入ipconfig/all,并回车
6. 记下“本地连接”的Physical Address,例如00-25-3D-5B-7C
7. 将C:\Program Files\ARM\下的rvds.dat以记事本方式打开
8. 将“HOSTID=”后的字符串替换为6中找到的Physical Address, 不要横杠。
9. 保存关闭。
10. 在2中的窗口内点击下一步,之后点击“...”按钮,选择好rvds.dat之后,点击Add按钮,点击两次(或一次)“是”之后继续安装。
11. 最后运行C:\Program Files\ARM\下的Crack.bat(齿轮)
开始—程序—ARM—ARM Workbench IDE v4.0启动RealViewIDE
File—New—Realview Project输入ProjectName点击下一步,调试和发行都选中,点击下一步,不需要选择Targets,直接点击下一步,体系结构选择Cortex-A8,其他不用改变,点击下一步,再点击下一步,之后选择Finish,即可创建一个RealView工程。
在工程上点击右键可以添加文件夹(例如src),也可以添加文件,注意汇编文件扩展名为.s,C语言文件为.c。
汇编语言的例子和C语言的例子见“ARM汇编语言实验”压缩包。
首先编译工程(Project—BuildAll),之后点击菜单栏的Debug按钮(虫子样子),选择加载到RealView Debugger中,即可开始调试。点击Step in按钮,即可单步跳入,点击Step over按钮即可过程调试。
有可能需要查看Register的内容,这时需要点击View菜单下的Register项,打开寄存器查看窗口。
常用指令集见参考资料“ARM指令集详解”。
共有四种混合编程方式,详细信息可以参考资料“ARM中C语言和汇编语言混合编程”中的内容。
串口的基本概念,串口通信的方式,通信的数据包格式等。详细内容请参考“串口通信”PPT。
由于各个开发板的使用方法并不相同,因此需要参考用户手册。一般使用过程为:
1. 调至NorFlash方式启动,连接超级终端。根据超级终端中的选项,选择操作
2. 格式化NandFlash
3. 选择下载bootloader,可能会使用到DNW,注意按照手册安装usb驱动
4. 选择下载操作系统内核
5. 选择下载根文件系统
6. 选择下载Logo
3. 选择下载Bootloader或者STEPLDR
4. 下载EBoot到NandFlash
5. 调到NandFlash,并在开机时按空格键
6. 选择下载WinCE的镜像文件
1. 解压缩交叉编译器(EABI),tar xvfj EABI….tar.bz2 –C /
2. 用gedit /etc/profile 添加一条pathmunge,详细请参见手册
3. 解压缩qt-embedded-opensource…tar.bz2,tar xvfj qt-embedded...tar.bz2 –C /
7. 进入/opt/EmbedSky/qt-4.5下,./arm_qt4.5_build进行安装,需要大约1小时进行安装,之后使用source setARM_Env来设置环境变量。
8. qt-x11的安装:
a) 从ftp://ftp.trolltech.com/的ftp上下载qt-x11-opensource-src-4.5.3.tar.gz
b) 解压缩tar xvzf qt-x11-opensource-src-4.5.3.tar.gz -C /
c) 进入解压后的qt目录(qt-x11-opensource-src-4.5.3),运行命令./configure -qvfb -prefix /opt/qt-x11-4.5.3
i) -qvfb参数说明需要编译qvfb设备
ii) -prefix /opt/Qt-x11-4.5.3为改变安装安装目录
d) 运行命令gmake
e) 运行gmake install,大约需要1小时左右
f) gedit /etc/profile打开profile文件,在该文件的最末尾加上以下语句:
export PATH=/opt/qt-x11-4.5.3/bin:$PATH
export QTDIR=/opt/qt-x11-4.5.3
export MANPATH=/opt/qt-x11-4.5.3/man:$MANPATH
export LD_LIBRARY_PATH=/opt/qt-x11-4.5.3/lib:$LD_LIBRARY_PATH
export QMAKESPEC=/opt/qt-x11-4.5.3/mkspecs/linux-g++
g) 注销重新登陆
h) 编译qvfb
# cd /qt-x11-opensource-src-4.5.3/tools/qvfb/
# make
9. Qtcreator的安装是图形化的,下一步即可,安装好后,打开QtCreator后,依次点击菜单Tools-Options-Qt4-QtVersion,之后需要设置编译器的路径,可参考手册设置。
1. 打开QtCreator,点击File-new File or Project
2. 选择Qt4 Gui Application点击Ok
3. Name中填入项目名称,可任取;Create in中填入目录,可用Browse按钮选择一个路径,点击Ok
4. Required Modules中按需求选取,如果不需要可以不用选取,点击Next
5. Classname中填入类名,可任取;Base Class中选择QWidget,或根据需要选择其他,单击Next按钮继续
6. 点击Finish完成创建项目
1. 在工程窗口中的Forms文件夹下,有至少一个.ui文件,是界面设计文件
2. 双击这个.ui文件,可以在右侧的窗体上添加按钮等控件
3. 可以修改控件的objName,Text等属性,注意,objName是程序中用的名字,而Text是显示给用户的
4. 在按钮等控件上单击右键,点击Go to slot,可以添加槽函数,可以根据自己需要选择信号和槽函数
5. 实现槽函数,完成需要的功能,例如响应用户按键信息等
更多的示例程序请参见压缩包“qtshili”
硬件编程最关键的是应用驱动程序。首先需要编写硬件驱动程序,或者利用已有的驱动进行QT程序编写。因此,需要仔细参阅驱动程序文档,认真查看每个函数各个参数的含义。开发硬件相关QT程序流程:
1. 添加fcntl.h、unistd.h和sys/ioctl.h三个头文件
2. 添加一个private变量,例如int fd;
3. 一般在构造函数中,使用open函数打开设备并存下设备标识符,如fd=open(“/dev/PWM-Test”, O_RDWR); O_RDWR是一种设备读取的方法,此处也可以为只读(O_RDONLY),只写(O_WRONLY),或者可读可写(O_RDWR)等
4. 可用ioctl函数操作设备,进行IO操作,也可用read函数进行读取,write函数进行写入,需要根据具体应用确定
5. 在析构函数中加入::close(fd); 关闭设备,这样在程序结束的时候自动关闭设备
6. 注意,如果需要判断设备是否可用,可以用if语句判断fd >= 0,例如在关闭设备时,经常需要这个操作,即,if (fd >= 0) { ::close(fd); }
示例程序见压缩包“apps”
1. 解压缩uboot源代码,例如tar xvfj uboot-1.1.6.tar.bz2 –C /
2. 在uboot目录下修改一些文件,并添加支持自己的板子的源代码,天嵌的uboot已经改好,我们不需要自己修改
3. 在uboot目录下执行make EmbedSky,配置uboot使它适用于我们的板子
4. 执行make进行编译,编译出uboot.bin文件即可烧录
1. include/cmd_confdefs.h中需要添加一个自定义命令的宏定义,例如
#define CFG_CMD_HELLOWORLD 0x8000000000000000ULL
2. 在common文件夹下创建一个命令的源码文件,如cmd_helloworld.c
3. 编写命令源码文件内容,可以参照cmd_cache.c等
4. 在include/configs/EmbedSky.h中的CONFIG_COMMANDS宏定义的最后一个元素,括号前加入| \ 添加刚才在cmd_confdefs.h中定义的宏,如添加CFG_CMD_HELLOWORLD以使能命令
5. 重新编译uboot即可使用新命令
1. 打开common/cmd_menu.c文件,找到main_menu_usage函数,在printf("Enter your selection: ");前面加入自己的printf,例如printf(“[h] Helloworld command”);
2. 找到menu_shell函数,在case ‘Q’: case’q’ {…} 之后添加自己的case ‘H’: case ’h’: {…}
3. 括号 { } 中填写run_command(“Helloworld”, 0); 即可
1. 使用命令tar xvfj linux-2.6.30.4.tar.bz2 –C / 对内核进行解压缩
2. 在内核目录下,输入make menuconfig ARCH=arm CROSS_CMPILE=arm-linux-打开配置页面
3. 可用load an alternate file加入一个已经配置好的文件
4. 可使用键盘方向键和空格、Y、N、M对其中选项进行勾选和清除
5. 配置好后,在顶级菜单中选择Save an alternate,并将文件保存为.config文件
6. 退出
使用make zImage即可编译内核,会花费一些时间,编译好的内核可通过超级终端及DNW烧写到板子中。
更多的详细信息,请参考开发版的移植手册。
1. 文件系统移植需要工具BusyBox,需要先解压缩并编译BusyBos,使用命令tar xvfj busybox…tar.bz2 –C / 进行解压缩
2. 之后使用命令make menuconfig ARCH=arm CROSS_CMPILE=arm-linux- 对BusyBox进行配置,并用Save选项保存配置,名字任意
3. 之后使用make命令进行编译
4. 使用make install命令进行安装,会生成一个_install文件夹
5. 建立一个自己的文件夹,名为root-2.6.30.4(可任取)
6. 将_install文件夹全部内容拷贝到自己的root-2.6.30.4文件夹下
7. 添加一系列目录(文件夹),详细请参考开发板移植手册
8. 将一些必要的配置文件加入上述文件夹中
9. 进入root-2.6.30.4的上级目录,输入命令mkyaffs2image root-2.6.30.4 roor.bin即可生成根文件系统
10. 可将自己的根文件系统烧写到板子上进行测试
1. 编写驱动程序的源文件,如helloworld.c,并添加到内核源码(内核移植中解压缩出的)的相应目录下,例如,字符设备需要添加到drivers/char/
2. 修改drivers/char/中的Kconfig,在menu “Character devices”,后面加入一个菜单项,如
config HELLOWORLD
tristate “Helloworld driver”
depends on ARCH_S3C2440
3. 修改drivers/char/中的Makefile文件加入目标文件,如obj-$(CONFIG_ HELLOWORLD) += helloworld.o,注意文件名字的大小写
4. 使用make menuconfig ARCH=arm CROSS_CMPILE=arm-linux-配置内核,在Drivers菜单项下的Character Devices下会出现Helloworld驱动程序,用键盘M按键选中
5. 在内核源码目录下使用命令 make SUBDIR=drivers/char/ modules对驱动模块进行编译,会在drivers/char/生成helloworld.ko文件
6. 通过超级终端发送到板子上,即可使用insmod命令加载,如insmod helloworld.ko
7. 可以使用rmmod命令卸载驱动,如rmmod helloworld.ko
程序解释见源码注释。
可能问的问题:
1. 程序如何运行?
程序首先运行的是mian函数,由main函数中创建一个应用程序类,和一个电子书的窗体类,通过调用电子书窗体类的show()方法,让这个电子书窗口显示出来,同时调用应用程序的exec()方法,让应用程序运行起来。
2. 电子书如何读取存储器中的文件?
首先调用QT中打开文件的函数,显示一个打开对话框,让用户选择一个文件,之后使用Qfile类对文件进行打开操作。由于需要支持中文,所以采用QTextStream类读取文本,采用QTextCodec类提供GBK的编码器,使用read函数进行读取。
3. 电子书如何显示文字?
采用QPlainTextEdit控件显示文字,并通过这个空间的QScrollBar(滚动条类)控制文字的位置,实现上滚和下滚。
4. 电子书如何翻页,如何查看上一行、下一行?
电子书翻页和上一行、下一行的实现靠嵌入式开发板的四个按钮实现,用户按上下按钮时,则实现上翻一行或下翻一行,按左右按钮时实现上翻一页或下翻一页操作
5. 电子书是如何响应按键操作的?
电子书采用按键驱动程序实现按键的响应。并且为了能够正常响应用户的操作,新建了一个线程专门用来监听是否有按键按下,如果有按键按下,则判断是哪一个按键按下了,并且针对不同的按键情况,选择不同的操作。例如上翻一行,下翻一行等。翻行或翻页通过改变QPlainTextEdit空间的QScrollBar的value属性实现。此外,驱动程序中,采用中断的方式取得按键信息,并用阻塞方式进行读取。
上文中可能存在表述不当地方,请见谅!谢谢。
嵌入式系统总结嵌入式计算机嵌入式系统是专用计算机以核心部件的形式出现在各种装置设备产品和系统中例如监控设备移动电话家电机器人视听设…
一为什么学习嵌入式1就业前景近几年嵌入式系统产品日臻完善并在全世界各行业得到广泛应用嵌入式系统产品的研制和应用已经成为我国信息化带…
一嵌入式系统原理与应用课程总结这个学期我学习了嵌入式原理与应用这门课程虽然这个学期马上就要结束了对嵌入式的学习也要告一段落了但是我…
第一章1嵌入式系统定义以应用为中心以计算机技术为基础软件硬件可裁剪对功能可靠性成本体积功耗严格要求的专用计算机系统2四个基本要素1…
什么叫嵌入式系统以应用为中心以计算机技术为基础软件硬件可裁剪适应应用系统对功能可靠性成本体积功耗严格要求的专用计算机系统什么叫嵌入…
第一章嵌入式系统概述1、嵌入式系统的定义、特点1)定义以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、…
学习嵌入式系统心得说实在话在没有学习之前,以及在学之前通过一些口中得知这是一门很不错,很有意思的一门课。而且目前是十分吃香的一门课…
一为什么学习嵌入式1就业前景近几年嵌入式系统产品日臻完善并在全世界各行业得到广泛应用嵌入式系统产品的研制和应用已经成为我国信息化带…
嵌入式总结1嵌入式的定义广义的说嵌入式系统就是一个具有特定功能或用途的计算机软硬件集合体从狭义上说嵌入式系统紧紧指装入另一个设备并…
重庆航天技术职业学院题目嵌入式系统Android选题性质设计报告其他院系电子系专业物联网班级120xx071学号20xx0027学…
嵌入式实训总结20xx年x月我参加了学校安排的课题实训,基地在北京,学院安排我们集体坐火车一同前去,浩浩荡荡的队伍开始出发了。刚来…