1、系统概念1、嵌入式系统的定义?以应用为中心、以计算机技术为基础、软硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。 “嵌入” 、 “专用” 、 “计算机”2、嵌入式系统的软、硬件组成?以及主要特点?软件:从底层到上层:bootloader 等系统初始化引导程序、设备驱动层(包括驱动程序、板级支持包 BSP 等) 、操作系统、用户应用程序。 (底层为上层提供服务)开发软件:即集成开发环境(asemmbler通知编译器该标号为一个外部标号AREA Init,CODE,READONLY ;定义一个代码段ENTRY ;定义程序的入口点LDR R0,=0x3FF0000
2、 ;初始化系统配置寄存器LDR R1,=0xE7FFFF80STR R1,R0LDR SP,=0x3FE1000 ;初始化用户堆栈BL Main ;跳转到 Main()函数处的 C/C+代码执行END ;标识汇编程序的结束以上的程序段完成一些简单的初始化,然后跳转到 Main()函数所标识的C/C 代码处执行主要的任务,此处的 Main 仅为一个标号,也可使用其他名称。17、程序代码段的组成分析、例如:标注下面程序各条语句中的含义AREA Init , CODE , READONLY ;已定义代码段ENTRY;程序入口LDR R0, =0x3ff5000;R0 赋寄存器地址值LDR R1, 0
3、x0f;要给寄存器赋的值STR R1,R0;赋值LDR R0, =0x3ff5008LDR R1, 0x01STR R1,R0;给另一个寄存器赋值的过程BL PROC;跳转至标号为 PROC 的程序出执行:PROC:MOV PC, LR /将 LR 保存的程序指针返回,即跳到 BL 下一句接着执行:END2410 设计18、阐述 CPU、外设、外设控制器、时序、寄存器的相互关系?CPU 与外设控制器构成微处理器,微处理器在核心板(最小系统)上发挥作用,将引脚集合成外设接口加上电平转换等就是外围板,外设通过外围板连接至外设控制器。CPU 通过寄存器编程控制外设控制器产生时序控制外设。若是没有外设
4、控制器,则需要 CPU 自己产生时序来与外设交互,这种时序相当于一种约定好的意思表示,相当于“语言”或者“通信协议” ,例如若是 2410 与一个带有 IIC 接口的器件通信,只需要连接起来,对 IIC 进行寄存器编程,控制它们之间的工作模式,可能收发数据就变成了在中断中读写寄存器操作,屏蔽了 IIC规定的通信细节。若是 51 单片机要与 IIC 通信的话,就复杂多了,首先要仔细阅读 IIC 的协议,不容丝毫差错,然后用 IO 口模拟时序,CPU 的工作量很大。19、寄存器编程的本质?如何获取寄存器的配置?寄存器编程的本质是 CPU 控制外设寄存器工作模式的方法。可以想象寄存器的每一位肯定是外
5、设控制器功能模块中的一个个“开关” ,给某一位赋值 0 或者 1,就相当于使能或关闭某一个功能。20、2410 最小电路设计?(晶振选择、启动选择、数据宽度)与一般的 ARM 系统相同,都需要微处理器、电源、晶振、复位、存储器(flash、SDRAM) 、JTAG 接口等,具体情况如下:(需要对 OM0 和 OM1 配置电平以决定启动方式,对 OM2 和 OM3 配置电平以决定时钟源。 )电源设计:处理器用 1.8V,RTC 给时钟模块供电 1.8V,存储器和普通 IO 用3.3V,ADC 模块用 3.3V,可见最小系统最少要用 3.3 和 1.8 两种直流稳压。课程实验中电源电压 5V,分别
6、用 LM1085 稳压 3.3V,用 AS1117 稳压 1.8V。晶振设计2410 的时钟控制逻辑可以产生系统所需要的时钟,包括 CPU 的 FCLK,和AHB 总线的 HCLK,APB 的 PCLK。内部有两个锁相环 PLL,MPLL 提供前三个,UPLL 给 USB 提供 48MHZ 的时钟。主时钟源(UPLL 和 MPLL 的时钟源)可以选择是来自外部时钟还是外部晶振,这是由 OM2 和 OM3 的管脚确定的,可以 OM2 和 OM3 同时接低电平,选择外部晶振,12M 晶振加上 15pF 起振电容(经过锁相环倍频可以达到 203M) 。复位电路设计可以在 nRESET 端设计像 51
7、 单片机那样的阻容复位电路,但为了稳定,可以使用复位芯片如 MAX811 或 IMP811。JTAG 接口设计有 20 针和 14 针两种 JTAG 接口。存储器设计2410 有自己的存储器控制器,并且规定了哪些 bank 空间是 RAM 哪些是FLASH,存储器芯片严格按照 DATASHEET 上的要求和标明的引脚连接方式与存储器控制器的存储器接口相连就可以,控制器会根据地址产生读写存储器芯片的时序,完成存取数据的操作。21、2410nor 和 nand 启动过程分析 ?NOR flash:读取速度高、而擦写速度低,容量小,价格高,地址线和数据线分开,采用 SRAM 接口。NAND flas
8、h :读速度不如 NORflash 但是擦写速度高,容量大,价格低,有取代硬盘的趋势,但是地址线和数据复用,需要程序配合才能读写数据。可以通过跳线设置时从 NAND FLASH 启动还是从 NOR FLASH 启动。NAND 启动的优势:便宜、容量大。但是读写逻辑不能用硬件产生,也就是没办法接到 BANK 空间里,必须有程序配合才能读写(有专门的控制器接口,肯定要寄存器编程加上程序配合才能读写,没有 PC 的根正苗红) ,所以理论上它是不可以用来启动系统的,因为那之前什么程序都没有,要想读写它必须是系统装载完了而且有程序了。但是三星采用了 SRAM 映射解决了这个问题,下面就是这个过程:电路中
9、使 OM1 和 OM0 都接低电平,从 NAND FLASH 中启动。 (2410 有NAND FLASH 控制器,连接 NAND Flash 芯片,产生读写时序)在该模式下,2410 的前 4KB 地址空间对应一个名字叫做 “起步石”的SRAM,系统启动时,自动将 NAND FLASH 的前 4KB 数据加载到起步石中,然后系统自动执行这些启动引导代码,CPU 从内部 RAM 的 0x00000000 位置开始启动。这个过程不需要程序干涉。也就是类似于 STARTUP.S 的功能,初始化异常向量表、堆栈、将 NAND FLASH 中的代码 (有代码支持喽)拷贝到SDRAM 中运行。NOR F
10、LASH 采用的的是 SRAM 接口,可以直接到存储器控制器上, ARM 内核产生的时序能对其读写。将 bank0 上接上 NORflash 芯片。上电产生复位异常后会自动从 NOR flash 中启动。22、S3C2410 的中断处理流程 ?首先应该明确 2410 与 ARM 内核的异常处理系统的角色,根据之前的 ARM 异常处理流程,我们清楚明了了哪些是 CPU 的硬件机制。2410 通过中断控制器允许以优先级的方式将几十个中断源共同用一个 IRQ。一个中断申请提出后,IRQ 异常发生,切换模式、保存 CPSR、保存 PC,然后跳转到 handleIRQ 函数,然后跳转到 ISRIRQ(这
11、只是一个大概流程,也许会定义更多的跳转)根据中断源向量表的首地址和偏移量寄存器找出到底是哪个中断发生了。然后跳转到相应的中断处理函数,比如跳到串口中断,还可以根据挂起位(即中断标志位)再次判断到底是接收中断还是发送完成中断。也就是说 2410 处理流程除了 ARM对异常的响应是硬件机制外,其余的都是代码实现的。我们在编程的时候没有写的话,那也是编译器加进去的。2410 对嵌套的处理比起 2410 的处理流程不同的是,因为有了中断控制器,这就是实现高优先级嵌套的硬件基础,因为每一次进入异常模式用户都会保存环境,这就是中断嵌套的软件基础。CPU 的异常处理机制总是那些,很明确的。我正在执行一个中断
12、服务程序,然后再次发生异常,保存,跳转(CPU) 、再次判断是哪个中断,进去之后压栈,运行另一个中断的服务程序,运行完返回,这是就是返回到上一个中断了。上一个中断运行完,一返回就是返回发生异常前的状态。23、S3C2410 的串口、端口、外部中断、 AD 等及寄存器的编程能力(会读datasheet、会编程、作业、实验的相关代码)ARM 的汇编语言程序.PPT仔细阅读 DATASHEET,记住 寄存器的赋值指令。LDR R0,=GPHCONLDR R1,=0X2AFAAASTR R1,R024、时钟、看门狗的相关概念时钟为整个系统提供同步脉冲,像人的脉搏一样。看门狗:其实是一个计数器,当它计数
13、溢出的时候,会使系统复位,所以它的作用是防止系统死机。打开看门狗之后,当代码跑飞或者陷入死循环之后,就不能喂狗,也就是不能清除计数值,那么它就会使系统重启。VIVI25、什么是 bootloaderBootloader,为引导加载程序,是嵌入式系统加电后运行的第一段代码,相当于 PC 机的BIOS。 Bootloader 在系统中的位置通常固化在硬件上的某个固态存储设备上,加电后自启动。Bootloader 功能初始化,给 CPU 合适的工作环境(相当于 STARTUP.S) ,以便为最终调用操作系统内核或用户应用程序境。加载内核下载内核或者根文件系统。Bootloader 操作模式 有启动加
14、载和下载两种模式。启动加载模式是 Bootloader 的正常工作模式,在嵌入式产品发布的时侯, Bootloader 必须工作在这种模式下。即初始化 CPU 的工作环境之后,将内核如 RAM 执行。下载模式:目标机上的 Bootloader 将通过串口连接或网络连接等通信手段从主机下载文件。主要是下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Bootloader 保存到目标机的 RAM 中,然后再被 Bootloader 写到目标机上的 FLASH 类固态存储设备中。Bootloader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用到这种工作
15、模式。Bootloader 启动过程上电之后,先启动 CPU 即执行 startup.s 类似功能代码(配置中断、初始化堆栈、拷贝代码等) ,然后进行加载内核的准备1、至少初始化一个串口,以便向终端用户反馈数据。2、检测系统内存映射,哪些是可用的 RAM?在这一步之后,将检测外部按键,有按键按下将进入下载模式,没有按键的话将执行下面的步骤,加载内核:3、将 kenel 和根文件系统从 flash 调入 RAM4、为内核启动设置参数5、调用内核。UCOS_II26、概念分析可重入函数可以被一个以上的任务调用,而不必担心数据的破坏。可重入型函数任何时候都可以被中断,一段时间以后又可以运行,而相应数
16、据不会丢失。可重入型函数或者只使用局部变量, (关中断、只用局部变量、用互斥型信号量可以使函数变成可重入的)互斥任务在处理共享数据时的排它性,以避免竞争和数据的破坏。也就是任务在某一个时间段独占共享资源,在释放之前别的任务没有该资源的运行权。满足互斥条件的方法:1、 关中断:最简便快捷的办法,即处理共享资源属于临界区代码。2、使用测试并置位指令3、禁止做任务切换4、利用信号量 ,其中 2 和 4 的道理是相似的,标志位。死锁死锁也称作抱死,指两个任务无限期地互相等待对方控制着的资源,不然都不会执行。两个任务都是“你不给我,我就不给你”的心态。最简单的防止发生死锁的方法是让每个任务都:先得到全部
17、需要的资源再做下一步的工作。一般内核会允许在申请信号量时定义申请超时。剥夺型与不可剥夺型内核即占先式还是非占先式。不可剥夺:合作型内核,即除非自己主动放弃 CPU 的运行权,不然没办法被切换。不知道什么时候最高优先级的任务才能拿到 CPU 的控制权,完全取决于应用程序什么时候释放CPU。 (顾名思义:每个任务不会被其它任务剥夺去,除非中断的到来,即便如此,当中断结束后,还是会回到原来被中断的程序,而不会切换到具有高优先级的任务中去。 )可剥夺:最高优先级的任务一旦就绪,总能得到 CPU 的控制权。可以被挂起,可以再中断退出时失去对 CPU 的运行权。使用占先式内核时,应用程序不应直接使用不可重
18、入型函数非占先式内核的一个特点是几乎不需要使用信号量保护共享数据。运行着的任务占有CPU,而不必担心被别的任务抢占,什么时候释放,自己说了算。可剥夺型的内核是实时系统所必须的。即实时不在于立即,而在于可预测性,高优先级得到 CPU 的时刻是可以预测的。进程上下文是进程运行寄存器环境的总和:对 arm 而言,RO-R12,LR,PC,CPSR ,SPSR。STMFD sp!, pc ; save pcSTMFD sp!, lr ; save lrSTMFD sp!, r0-r12 ; save registers and ret addressMRS r4, CPSRSTMFD sp!, r4
19、; save current PSRMRS r4, SPSRSTMFD sp!, r4 ; save SPSR27、实时系统本质是:可预测性28、内核的相关知识初始化:OSINT(); 系统初始化,创建系统任务、创建链表,等待将 TCB 赋值后放进去。启动:OSStart(); 就是将就绪的状态的任务中找到优先级最高的出栈运行,调用OSStartHighRdy()。(在启动之前要调用 OS_Taskcreat()规定一创建就进入就绪态(初始化就绪态表)它一定是对 TCB 赋值 (调用 TCBinit)放到链表里,从空闲链表头取一个链表,放在使用链表里。)任务组成:任务由三个部分构成1、任务控制
20、块 TCB,保存着任务的所有属性, 可以说内核对任务的管理就是对 TCB 的管理。它包含了一个任务的前一个任务、后一个任务、指向任务代码的指针、指向任务堆栈的指针、任务优先级、任务状态、延时值等等。对任务的控制都是通过访问任务控制块来实现的。2、任务栈保存任务的工作环境。3、任务代码。状态:任务(无限循环代码)的五个状态:休眠态:没有加入运行队列。挂起态(waiting,等待,最复杂,有很多种情况) ,在等待满足运行条件,如一个信号量、 或者延时结束等。就绪态(ready):具备运行的一切条件,等待切换,只是有更高级的任务占据着 CPU。运行态:正在占用 CPU 的运行权被中断态。五种状态间的
21、转换在课件中的图里说的比较清楚。注意:一个任务在运行态时被挂起时清除就绪态,变成挂起态。而被占先时则虽然不运行但保持就绪态。任务的调度(占先式,就绪表)UCOS 的就绪表实现:就绪表的实现依靠两个变量一张表实现:OS_Rdy_Tbl7(8 个 8 位数)和OS_Rdy_Grp。 OSMapTbl 相当于掩码表。由优先级找到对应位:64 个优先级最高 6 位。高三位右移三位,确定 GRP,即在第几行,低三位,找到行中的某位。如优先级 12,001100,则第 1 行,第 4 个单元(从 0 开始计数,这个转换由 OSMAPTbl 掩码表完成) ,实现的代码如下:OSRdyGrp |=OSMapT
22、blprio3; (行标)OSRdyTblprio3 |=OSMapTblprio (由低三位找到行,由高三位找到列)有对应位找到优先级:另一种巧妙的查表算法。任务的切换:就是有更高优先级的任务处于就绪态,需要让其得到 CPU 的运行权,我们所要做的就是保存当前任务的上下文(进行压栈操作) ,保存当前的 TCB,根据优先级找到要运行任务的 TCB 地址,切换当前堆栈,将堆栈中保存的内容弹出,并运行。优先级管理:共有 64 任务,每个任务都有一个优先级,0-63,数字越大,优先级越低。中断退出(sourcecode)29、相关任务管理、时间管理内核代码分析30、移植代码分析:任务调度函数void
23、 OS_Sched (void) /*os_core.c 中*/INT8U y;OS_ENTER_CRITICAL(); 临界区代码,关中断if (OSLockNesting =0)获得最高优先级的高三位OSPrioHighRdy = (INT8U)(y OSTCBSTKPtr;将 R4,R3,R2 及 R1 从新堆栈中弹出;执行中断返回指令;任务级切换函数汇编代码void OS_TASK_SW(void) /任务:保存当前任务上下文,装入新任务上下文 /; Perform a context switch.; On entry, OSTCBCur and OSPrioCur hold the
24、 current TCB and priority; and OSTCBHighRdy and OSPrioHighRdy contain the same for the task; to be switched to.OS_TASK_SWSTMFD sp!, pc ; save pc,保存当前的任务环境。压栈上下文STMFD sp!, lr ; save lrSTMFD sp!, r0-r12 ; save registers and ret addressMRS r4, CPSRSTMFD sp!, r4 ; save current PSRMRS r4, SPSRSTMFD sp!,
25、r4 ; save SPSR改变当前任务的优先级值LDR r4, addr_OSPrioCurLDR r5, addr_OSPrioHighRdyLDRB r6, r5 ;优先级仅为一个字节STRB r6, r4; Get current task TCB address;找到当前 TCB,并将 SP 指针保存进去。LDR r4, addr_OSTCBCurLDR r5, r4STR sp, r5 ; store sp in preempted taskss TCB; Get highest priority task TCB addressLDR r6, addr_OSTCBHighRdy
26、注意这是在传送变量地址,该地址内存储的是所要的地址LDR r6, r6LDR sp, r6 ; get new tasks stack pointer; 改变当前运行的 TCB 地址,即 OSTCBCur = OSTCBHighRdySTR r6, r4 ; set new current task TCB address; restore tasks mode regsiters/将当前任务的上下文出栈,注意这是压栈和出栈的顺序。LDMFD sp!, r4MSR SPSR, r4LDMFD sp!, r4MSR CPSR, r4; return in new task contextLDMF
27、D sp!, r0-r12, lr, pc中断服务子程序示意代码(注意中断栈和任务栈)保存全部 CPU 寄存器;/即将被打断的进程上下文保存在中断堆栈。调用 OSIntEnter()或 OSIntNesting 直接加 1;/中断层次标示。if(OSIntNesting=1)OSTCBCur-OSTCBStkPtr=SP;清中断源;重新开中断;执行用户代码做中断服务;调用 OSIntExit();恢复所有 CPU 寄存器;执行中断返回指令;中断退出函数汇编代码void OSIntExit (void)OS_ENTER_CRITICAL();if (OSIntNesting 0) /* Prev
28、ent OSIntNesting from wrapping */OSIntNesting-; /只在没有嵌套的情况下,进行任务切换 。if (OSIntNesting = 0) /* . and not locked. */OSPrioHighRdy = (INT8U)(OSIntExitY OSTCBStkPtr=SP;调用 OSTimeTick(); 功能根据链表遍历每个 TCB,将非零的延时值- ,有减到零,若非 suspend 状态,则置就绪位。清发出中断设备的中断;重新允许中断(可选用)调用 OSIntExit();恢复处理器寄存器的值;执行中断返回指令;中断节拍函数void OS
29、TimeTick (void)OS_TCB *ptcb;OSTimeTickHook(); /*OS_CFG 中#define OS_CPU_HOOKS_EN 1*/ptcb = OSTCBList; (2)while (ptcb-OSTCBPrio != OS_IDLE_PRIO) (3)OS_ENTER_CRITICAL();if (ptcb-OSTCBDly != 0) if (-ptcb-OSTCBDly = 0) if (!(ptcb-OSTCBStat (5) 否则就绪到 OSRdyTblptcb-OSTCBY |= ptcb-OSTCBBitX; else ptcb-OSTCBD
30、ly = 1;ptcb = ptcb-OSTCBNext;OS_EXIT_CRITICAL();OS_ENTER_CRITICAL(); (6)OSTime+; (7)累加从开机以来的时间,用的是一个无符号 32 位变量 OS_EXIT_CRITICAL();任务控制块初始化函数 OS_TCBInit()在创建任务时调用,它获得 TCB 控制块并对其进行初始化,并让对应任务就绪,完成任务创建的大部分任务。Delay()和节拍中断的对应关系Delay 函数是自行挂起,等待延时时间到的函数,它的功能就设置 TCB 中的延时值,清除自己的就绪位。而在每个节拍中断处理函数中,会将延时值-。减到零时重新就绪。并在中断退出时进行任务切换,有可能再次得到 CPU 的运行权。