嵌入式课程作业记录(2)——ARM复习提纲(上)
教材:《ARM 9嵌入式系统设计与开发应用》(熊茂华,杨震伦编著)(清华大学出版社)
考试题型:选择题40分(20题),填空题10分(5题),简答题20分(4题),读程序20分(4题),写程序10分(1题)。
- 1. RTOS的定义与特点(P9)
- 2. 嵌入式计算机系统的中间层的组成和功能(P11)
- 3. RISC架构与CISC架构相比有哪些优点?(P8)
- 4. 哈佛结构和冯诺依曼结构
- 5. 大端存储法和小端存储法有什么不同?对存储数据有什么要求?(P22)
- 6. ARM微处理器支持哪几种运行模式?各运行有什么特点?(P23)
- 7. ARM体系结构支持几种类型的异常,并说明其异常处理模式和优先级状态?(P28)
- 8. CPSR的模式设置位具体含义,NZCVQ条件码标志含义(P28)
- 9. ARM微处理器处理异常的操作过程(P29)
- 10. 异常的返回过程(P29)
- 11. 异常向量表及异常优先级(P32)
- 12. 熟悉汇编指令(P32-57)
- 13. NOR Flash和NAND Flash的区别(P73)
- 14. S3C2410的UART的操作模式和功能(P79)
- 15. 与S3C2410的UART相关的寄存器有哪些?串口的初始化函数、驱动函数(考注释)?
- 16. 总线宽度和等待寄存器BWSCON、Bank控制寄存器BANKCONn的初始化程序,中断向量表、堆栈的初始化(考注释)?
1. RTOS的定义与特点(P9)
实时操作系统(Real-Time Operating System,RTOS):是指操作系统本身要能在一个固定时限内对程序调用(或外部事件)做出正确的反应,也就是对时序与稳定性的要求十分严格。
嵌入式系统除了任务调度、同步机制、中断处理、文件处理外,还有以下特点:
- 强稳定性、弱交互性:具有很强的稳定性。
- 较强的实时性:嵌入式操作系统实时性一般很强,可用于各种设备的控制当中。
- 可伸缩性:开放、可伸缩性的体系结构。
- 外设接口的统一性:提供各类设备驱动接口。
2. 嵌入式计算机系统的中间层的组成和功能(P11)
硬件层与软件层之间为中间层,也称为板级支持包(Board Support Package,BSP)。
中间层的作用是将系统软件与底层硬件部分隔离,使得系统的底层驱动程序与硬件无关。
BSP一般应具有相关硬件的初始化、数据的输入/输出操作和硬件设备的配置等功能。BSP是主板硬件环境和操作系统的中间接口,是软件平台中具有硬件依赖性的那一部分,主要目的是支持操作系统,使之能够更好地运行于硬件主板上。
3. RISC架构与CISC架构相比有哪些优点?(P8)
RISC的优点:
- 固定长度的指令格式,指令规整、简单,基本寻址方式有2——3种。
- 使用单周期指令,便于流水线操作执行。
- 大量使用寄存器,数据处理指令只对寄存器进行操作,只有加载/存储指令可以访问存储器,以提高指令的执行效率。
4. 哈佛结构和冯诺依曼结构
- 【存储器结构不同】哈佛结构:使用两个独立的存储器模块,分别存储程序指令和数据;冯诺依曼结构:将程序指令存储器和数据存储器合并在一起。
- 【总线不同】哈佛结构:独立两条总线,分别作为CPU与两个存储器之间的专用通信路径;冯诺依曼结构:没有总线,CPU与存储器直接相连。
- 【执行效率不同】哈佛结构:可以预先读取下一条指令,执行效率较快;冯诺依曼结构:不可以预先读取下一条指令,执行效率较慢。
5. 大端存储法和小端存储法有什么不同?对存储数据有什么要求?(P22)
大端格式中,字数据的高字节存储在低地址单元中,而字数据的低字节则存放在高地址单元中。
小端格式中,字数据的高字节存储在高地址单元中,而字数据的低字节则存放在低地址单元中。
在基于ARM920T内核的嵌入式系统中,常用小端格式来存储字数据。
6. ARM微处理器支持哪几种运行模式?各运行有什么特点?(P23)
ARM920T支持以下7种运行模式(除了用户模式外,其余6种为非用户模式或特权模式)(除了用户模式和系统模式外,其余5种为异常模式):
- 用户模式(usr):ARM处理器正常的程序执行状态。大多数应用程序运行在该模式下,某些被保护的系统资源是不能被访问的。
- 快速中断模式(fiq):用于高速数据传输或通道处理。
- 外部中断模式(irq):用于通用的中断模式。
- 管理模式(svc):操作系统使用的保护模式。
- 数据访问终止模式(abt):当数据或指令执行时进入该模式,可用于虚拟存储及存储保护。
- 系统模式(sys):运行具有特权的操作系统任务。
- 未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。
7. ARM体系结构支持几种类型的异常,并说明其异常处理模式和优先级状态?(P28)
支持7种类型的异常:
- 复位(优先级:1,最高),进入模式为管理模式
- 未定义指令(优先级:6,最低),进入模式为未定义模式
- 软件中断,进入模式为管理模式
- 指令预取中止(优先级:5),进入模式为中止模式
- 数据中止(优先级:2),进入模式为中止模式
- IRQ(外部中断请求)(优先级:4),进入模式为IRQ模式
- FIQ(快速中断请求)(优先级:3),进入模式为FIQ模式
8. CPSR的模式设置位具体含义,NZCVQ条件码标志含义(P28)
CPSR为当前程序状态寄存器。SPSR为其备份寄存器。
条件码标志的含义:
- N:运算结果为负数时,置位(1)。
- Z:运算结果为零时,置位。
- C:当运算结果产生进位、借位时,置位;对于移位操作,为移出值的最后一位。
- V:将运算结果视为带符号数时,如果运算结果为负数,则置位。
- Q:在ARMv5及以上版本的E系列处理器中,Q指示增强的DSP运算指令是否发生了溢出。在其他版本的处理器,则无意义。
CPSR的低5位为模式位,决定了处理器的运行模式。其具体含义:
- 0b10000:用户模式:正常的程序执行状态。
- 0b10001:FIQ模式(快速中断):高优先级中断产生时会进入。用于高速数据传输或中断。
- 0b10010:IRQ模式(外部中断):低优先级中断产生时会进入。用于通用的中断处理。
- 0b10011:管理模式:复位或软中断指令执行时会进入,供OS的保护模式。
- 0b10111:中止模式:存取异常时会进入,用于保护存储。
- 0b11011:未定义模式:执行未定义指令时会进入。
- 0b11111:系统模式:供需要访问系统资源的操作系统任务使用,运行具有特权的操作系统任务。
9. ARM微处理器处理异常的操作过程(P29)
当一个异常出现时,ARM微处理器会执行以下操作:
(1)将下一条指令的地址存入相应连接寄存器LR。若异常是从ARM状态进入,LR寄存器中保存的是下一条指令的地址;若异常是从Thumb状态进入,则在LR寄存器中保存当前PC偏移量。
(2)将CPSR(当前程序状态寄存器)复制到相应的SPSR(备份的程序状态寄存器)中。
(3)根据异常类型,强制设置CPSR的运行模式位。
(4)强制PC从相应的异常中断向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。还可以设置中断禁止位,以禁止中断发生。
(5)如果异常发生时处于Thumb状态,则当前异常向量地址载入PC时,处理器自动切换至ARM状态。
10. 异常的返回过程(P29)
异常处理完毕之后,执行以下操作返回:
(1)将连接寄存器LR的值减去相应的偏移量后送到PC中。
(2)将SPSR复制回CPSR中。
(3)若在进入异常处理时设置了禁止位,要在此清除。
11. 异常向量表及异常优先级(P32)
异常向量表存储着复位、未定义模式、软件中断、终止(指令预取)、终止(数据)、IRQ(外部中断请求)、FIQ(快速中断请求)的向量地址,基地址为0x0000。
当多个异常同时发生时,系统根据固定的优先级决定异常的处理次序,优先顺序见第7点。
12. 熟悉汇编指令(P32-57)
未分组寄存器R0-R7(不同运行模式下物理寄存器一样),分组寄存器R8-R14(在不同运行模式下访问的物理寄存器不同,可以视为每个运行模式都有自己独有的寄存器),程序计数器PC(R15),状态寄存器CPSR(R16),R13堆栈指针(SP),R14子程序连接寄存器。
ARM四种类型的堆栈 (与LDM连续载入、STM连续存储指令搭配使用):
- 满递增堆栈(FD):堆栈指针指向最后压入堆栈的数据,且由低地址向高地址生成
- 满递减堆栈(ED):堆栈指针指向最后压入堆栈的数据,且由高地址向低地址生成
- 空递增堆栈(FA):堆栈指针指向下一个要放入数据的空地址,且由低地址向高地址生成
- 空递减堆栈(EA):堆栈指针指向下一个要放入数据的空地址,且由高地址向低地址生成
除此之外,还能与LDM连续载入、STM连续存储指令搭配使用的:IA(每次先加地址后传输数据)、IB(每次先传输数据后加地址)、DA(每次先减地址后传输数据)、DB(每次先传输数据后减地址)。
arm汇编中存在一个神奇的可选后缀“!”,一般是在寄存器或寻址方式之后,对于加了叹号的情况,访问内存时先根据寻址方式更改寄存器的值,再按照该已经更新的值访问内存。
我不打算认真写这里的内容,因为真的没必要详细写,随便找本指令集手册就有了。也不用全部背下来,谁工作出来全记得,都是用到的时候再查的。如果哪个学校期末考闭卷考这个,那出题的学校可以关门了。
(1)跳转指令
条件码指的是,若CPSR中的相应标志位的值符合条件(置1),则要执行该指令。 如下所列:
EQ(Z=1)、NE(Z=0)、CS/HS(C=1)、CC/LO(C=0)、MI(N=1)、PL(N=0)、VS(V=1)、VC(V=0)、HI(C=1,Z=0)、LS(C=0,Z=1)、GE(N=V)、LT(N!=V)、GT(Z=0,N=V)、LE(Z=1或N!=V)、AL(忽略)
- B指令(可加条件码):跳转至相对当前PC的偏移量。
- BL指令(可加条件码):跳转,同时R14记住跳转前的PC。
- BLX指令:跳转,同时ARM状态变为Thumb状态。
- BX指令:跳转,目标地址既可以是ARM也可以是Thumb状态。
(2)数据处理指令
S后缀决定指令的操作是否影响CPSR中的条件标志位的值。加了S表示要影响CPSR。
若未备注,说明指令仅用两个参数。下同。
- MOV指令(可加条件码,可加条件标志位S):没什么好说的。
- MVN指令(可加条件码,可加条件标志位S):先取反,再传送。
- CMP指令(可加条件码):影响CPSR标志位。前面数减去后面数,但不存储结果。
- CMN指令(可加条件码):将后面数取反后进行CMP操作。
- TEQ指令(可加条件码):前面数与后面数进行按位异或运算。用于比较是否相等。
- TST指令(可加条件码):前面数与后面数进行与按位运算。后面数相当于掩码(掩码是什么?自己百度)。
- ADD指令(可加条件码,可加条件标志位S):寄存器=寄存器1+数2(这里意思是寄存器/被移位的寄存器/立即数,下同)。
- ADC指令(可加条件码,可加条件标志位S):寄存器=寄存器1+数2+CPSR中的C进位。
- SUB指令(可加条件码,可加条件标志位S):寄存器=寄存器1-数2。
- SBC指令(可加条件码,可加条件标志位S):寄存器=寄存器1-数2-CPSR中的C借位。
- RSB指令(可加条件码,可加条件标志位S):寄存器=数2-寄存器1。
- RSC指令(可加条件码,可加条件标志位S):寄存器=数2-寄存器1-CPSR中的C借位。
- AND指令(可加条件码,可加条件标志位S):寄存器=寄存器1 && 数2。
- ORR指令(可加条件码,可加条件标志位S):寄存器=寄存器1 || 数2。
- EOR指令(可加条件码,可加条件标志位S):寄存器=寄存器1 逻辑异或 数2。
- BIC指令(可加条件码,可加条件标志位S):寄存器=寄存器1 掩码运算 数2。数2作为掩码,若某位置位,则寄存器1中对应的位被清除。
(3)乘法指令与乘加指令
- MUL指令(可加条件码,可加条件标志位S):寄存器=数1X数2。
- MLA指令(可加条件码,可加条件标志位S):寄存器=数1X数2X数3。
- SMULL指令(可加条件码,可加条件标志位S):(有符号数) 寄存器1=(寄存器3X寄存器4)的低32位,寄存器2=(寄存器3X寄存器4)的高32位。
- SMLAL指令(可加条件码,可加条件标志位S):(有符号数) 寄存器1=(寄存器3X寄存器4)的低32位+寄存器1,寄存器2=(寄存器3X寄存器4)的高32位+寄存器2。
- UMULL指令(可加条件码,可加条件标志位S):(无符号数) 寄存器1=(寄存器3X寄存器4)的低32位,寄存器2=(寄存器3X寄存器4)的高32位。
- UMLAL指令(可加条件码,可加条件标志位S):(无符号数) 寄存器1=(寄存器3X寄存器4)的低32位+寄存器1,寄存器2=(寄存器3X寄存器4)的高32位+寄存器2。
(4)程序状态寄存器访问指令
- MRS指令(可加条件码):将状态寄存器传送到通用寄存器。
- MSR指令(可加条件码):将操作数的内容传送到状态寄存器的特定域中。操作数可为通用寄存器或立即数。<域>表示仅修改状态寄存器的哪个域。
(5)加载/存储指令
- LDR指令(可加条件码):从存储器中将一个32位的字数据传送到目标寄存器中。
- LDRB指令(可加条件码):从存储器中将一个8位的字节数据传送到目标寄存器中。
- LDRH指令(可加条件码):从存储器中将一个16位的半字数据传送到目标寄存器中。
- STR指令(可加条件码):从源寄存器中将一个32位的字数据传送到存储器中。
- STRB指令(可加条件码):从源寄存器中将一个8位的字节数据传送到存储器中。
- STRH指令(可加条件码):从源寄存器中将一个16位的半字数据传送到存储器中。
(6)批量数据加载/存储指令
- LDM/STM指令(可加条件码):从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据。
(7)数据交换指令
- SWP指令(可加条件码):将源寄存器2所指向的存储器中的字数据传送到目的寄存器,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。
- SWPB指令(可加条件码):将源寄存器2所指向的存储器中的字节数据传送到目的寄存器 (高24位清零),同时将源寄存器1中的字节数据传送到源寄存器2所指向的存储器中。
(8)移位指令
- LSL/ASL指令:对通用寄存器中的内容进行逻辑/算术左移,操作数可以是寄存器也可以是立即数。低位用零填充。
- LSR指令:对通用寄存器中的内容进行右移,操作数可以是寄存器也可以是立即数。左端用零填充。
- ASR指令:对通用寄存器中的内容进行右移,操作数可以是寄存器也可以是立即数。左端用第31位填充。
- ROR指令:对通用寄存器中的内容进行循环右移,操作数可以是寄存器也可以是立即数。
- RRX指令:对通用寄存器中的内容进行循环右移,操作数可以是寄存器也可以是立即数。左端用进位标志位C填充。
(9)协处理器指令
- CDP指令(可加条件码):ARM处理器通知协处理器执行特定的操作,若协处理器不能成功完成,则产生未定义指令异常。
- LDC指令(可加条件码):用于将源寄存器所指向的存储器中的字数据传送到目标寄存器,若协处理器不能成功完成,则产生未定义指令异常。
- STC指令(可加条件码):用于将源寄存器中的字数据传送到目标寄存器所指向的存储器中,若协处理器不能成功完成,则产生未定义指令异常。
- MCR指令(可加条件码):用于将ARM处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成,则产生未定义指令异常。
- MRC指令(可加条件码):用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成,则产生未定义指令异常。
(10)异常产生指令
- SWI指令(可加条件码):用于产生软件中断。
- BKPT指令(可加条件码):用于产生软件断点中断,可用于程序的调试。
(11)符号定义伪指令
- GBLA伪指令:用于定义一个全局的数字变量,初始化为零。
- GBLL伪指令:用于定义一个全局的逻辑变量,初始化为F(假)。
- GBLS伪指令:用于定义一个全局的字符串变量,初始化为空。
- LCLA伪指令:用于定义一个局部的数字变量,初始化为零。
- LCLL伪指令:用于定义一个局部的逻辑变量,初始化为F(假)。
- LCLS伪指令:用于定义一个局部的字符串变量,初始化为空。
- SETA伪指令:用于给一个数字变量赋值。
- SETL伪指令:用于给一个逻辑变量赋值。
- SETS伪指令:用于给一个字符串变量赋值。
- RLIST指令:用于给一个通用寄存器列表命名,以方便访问。
(12)数据定义伪指令
- DCB伪指令:用于分配一片连续的字节存储单元,并进行初始化。
- DCW伪指令:用于分配一片连续的半字存储单元,并进行初始化。
- DCD/DCDU伪指令:用于分配一片连续的字存储单元,并进行初始化。(DCDU并不严格字对齐)
- DCFD/DCFDU伪指令:用于为双精度浮点数分配一片连续的字存储单元,并进行初始化。(DCFDU并不严格字对齐)
- DCFS/DCFSU伪指令:用于为单精度浮点数分配一片连续的字存储单元,并进行初始化。(DCFSU并不严格字对齐)
- DCQ/DCQU伪指令:用于分配一片以8个字节为单位的连续存储单元,并进行初始化。(DCQU并不严格字对齐)
- SPACE伪指令:用于分配一片连续存储区域并初始化为零。
- MAP伪指令:用于定义一个结构化的内存表的首地址。
- FIELD伪指令:用于定义一个结构化内存表中的数据域。
(13)汇编控制伪指令
- IF/ELSE/ENDIF伪指令:根据条件成立与否决定是否执行某个指令序列。
- WHILE/WEND伪指令:根据条件成立与否决定是否循环执行某个指令序列。
- MARCO/MEND伪指令:可将一段代码定义为一个整体,称为宏指令,然后可以在程序中通过宏指令多次调用该代码。
- MEXIT伪指令:用于从宏定义中跳出。
(14)其他常用伪指令
- AREA伪指令:用于定义一个代码段或数据段。后面需指出其属性。
- ALIGN伪指令:可通过添加填充字节的方式,使当前位置满足一定的对齐方式。可取的值是2的幂。
- CODE16/CODE32伪指令:前者为16位的Thumb指令,后者为32位的ARM指令。
- ENTRY伪指令:用于指定汇编程序的入口。
- END伪指令:已经到了源程序的结尾。
- EQU伪指令:用于为程序中的常量、标号等定义一个等效的字符名称,类似于#define。
- EXPORT(GLOBAL)伪指令:用于声明一个全局的标号。
- IMPORT伪指令:用于通知编译器要使用的标号在其他源文件中有定义,但当前源文件需要引用。会被加入到当前文件的符号表中。类似extern。
- EXTERN伪指令:用于通知编译器要使用的标号在其他源文件中有定义,但当前源文件需要引用。只有当前文件引用了该标号,才会被加入到当前文件的符号表中。类似extern。
- GET(INCLUDE)指令:用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。
- INCBIN伪指令:用于将一个源文件包含到当前的源文件中,被包含的文件不作改动的放到当前文件中,并在当前位置继续进行汇编处理。
- RN伪指令:给一个寄存器取个别名。
- ROUT伪指令:给一个局部变量定义作用范围。通常是两个ROUT搭配使用。
13. NOR Flash和NAND Flash的区别(P73)
- Nand器件执行擦除操作比较简单,而Nor则要求在进行写入前先将目标块内所有的位都写为0。
- Nor的读速度比Nand稍快一些。
- Nand的写速度比Nor快很多。Nand需要4ms擦除,而Nor需要5s擦除。
- Nand的单元尺寸几乎是Nor器件的一半,因此Nand的生产过程更简单,价格更低。
- Nand每个块的最大擦除次数是一百万次,而Nor的擦写次数是十万次。
- Nor具有XIP(芯片内执行)特性,应用程序可直接在Nor Flash内执行,不必把代码读到系统RAM中,而且传输效率很高。Nand结构可以提供极高的密度单元,可以达到高存储密度。
- Nor Flash带有SRAM接口,Nand器件使用复杂的I/O接口来串行存取数据。
14. S3C2410的UART的操作模式和功能(P79)
UART可通过UCONn控制寄存器来设置模式:回送模式(用于测试)、发送模式(确定是否发送数据到发送缓冲器)、接收模式(确定是否从接收缓冲器中接收数据)。
15. 与S3C2410的UART相关的寄存器有哪些?串口的初始化函数、驱动函数(考注释)?
与UART相关的寄存器有:ULCON、UCON、UERSTAT、UTRSTAT、UTXH、URXH、UBRDIV。
- ULCON(线控制寄存器):主要用来选择每帧数据位数、停止位数、奇偶校验模式及是否使用红外模式。
- UCON(控制寄存器):主要用来选择时钟,接收和发送中断类型(即电平还是脉冲触发类型),接收超时使能,接收错误状态中断使能等。
- UERSTAT(错误状态寄存器):寄存器的相关位用来表明是否有帧错误或溢出错误发生。读取该寄存器后自动清零。
- UTSTAT(接收/发送寄存器):如名字所示。
- UTXH(发送缓冲寄存器):如名字所示。
- URXH(接收缓冲寄存器):如名字所示。
- UBRDIV(波特率因子寄存器):如名字所示。
串口的初始化函数:
/* 选择要操作的串口。(UART0--0,UART1--1)
选择串口后,必需调用一次UART_Init()进行初始化(只需要一次)。*/
int UART_Select(uint8 no)
{
int ret;
ret = g_uart_sel;
g_uart_sel = no;
return(ret);
}
/* 初始化串口。设置为8位数据位,1位停止位,无奇偶校验,波特率为UART_BPS */
void UART_Init(void)
{
int i;
if(g_uart_sel) // 判断是否为串口1
{
// I/O口设置 (GPH5,GPH4)
rGPHUP = rGPHUP | (0x03<<4);
rGPHCON = (rGPHCON & (~0x00000F00)) | (0x00000A00);
// 串口模式设置
rUFCON1 = 0x00; // 禁止FIFO功能
rUMCON1 = 0x00; // AFC(流控制)禁能
rULCON1 = 0x03; // 禁止IRDA,无奇偶校验,1位停止位,8位数据位
rUCON1 = 0x245; // 使用PCLK来生成波特率,发送中断为电平触发模式,接收中断为边沿触发模式,
// 禁止接收超时中断,使能接收错误中断,正常工作模式,中断或查询方式(非DMA)
// 串口波特率设置
rUBRDIV1=(int)(PCLK/16.0/UART_BPS + 0.5) -1;
}
else
{
// I/O口设置 (GPH3,GPH2)
rGPHUP = rGPHUP | (0x03<<2);
rGPHCON = (rGPHCON & (~0x000000F0)) | (0x000000A0);
// 串口模式设置
rUFCON0 = 0x00; // 禁止FIFO功能
rUMCON0 = 0x00; // AFC(流控制)禁能
rULCON0 = 0x03; // 禁止IRDA,无奇偶校验,1位停止位,8位数据位
rUCON0 = 0x245; // 使用PCLK来生成波特率,发送中断为电平触发模式,接收中断为边沿触发模式,
// 禁止接收超时中断,使能接收错误中断,正常工作模式,中断或查询方式(非DMA)
// 串口波特率设置
rUBRDIV0=(int)(PCLK/16.0/UART_BPS + 0.5) -1;
}
for(i=0;i<100;i++);
}
驱动函数:
/* 向串口发送字节数据,并等待发送完毕。*/
void UART_SendByte(uint8 data)
{
int i;
if(g_uart_sel)
{
while(!(rUTRSTAT1 & 0x02)); // 等待发送器为空
for(i=0; i<10; i++);
rUTXH1 = data; // 发送数据
}
else
{
while(!(rUTRSTAT0 & 0x02)); // 等待发送器为空
for(i=0; i<10; i++);
rUTXH0 = data; // 发送数据
}
}
/*向串口发送一字符串。
对于'\n'字符,发送时会加入'\r'字符。*/
void UART_SendStr(char const *str)
{
while(*str != '\0')
{
if(*str == '\n') UART_SendByte('\r');
UART_SendByte(*str++); // 发送数据
}
}
/* 从UART口读取一字节按键数据。
会一直等待,直到接收到1字节数据。*/
int UART_GetKey(void)
{
int i;
if(g_uart_sel)
{
while(!(rUTRSTAT1 & 0x1));
for(i=0; i<10; i++);
return(rURXH1);
}
else
{
while(!(rUTRSTAT0 & 0x1));
for(i=0; i<10; i++);
return(rURXH0);
}
}
16. 总线宽度和等待寄存器BWSCON、Bank控制寄存器BANKCONn的初始化程序,中断向量表、堆栈的初始化(考注释)?
用来设置总线宽和等待状态。例如,只要通过配置相应寄存器的值,可以使CPU时钟频率改变。
总线宽度和等待控制寄存器BWSCON和BANKCON控制寄存器的初始化程序:
// config.h
/* 总线宽度控制定义(0表示8位,1表示16位,2表示32位) */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
/* Bank时序控制(位域)定义 */
#define MT 15 /* 存储类型选择,仅对Bank6和Bank7有效 (2bit) */
#define Trcd 2 /* RAS到CAS延迟,仅对SDRAM有效 (2bit) */
#define SCAN 0 /* 列地址位数,仅对SDRAM有效 (2bit) */
#define Tacs 13 /* 在nGCSn有效之前,地址信号的建立时间 (2bit) */
#define Tcos 11 /* 在nOE有效之前,片选的建立时间 (2bit) */
#define Tacc 8 /* 访问周期 (3bit) */
#define Tcoh 6 /* nOE结束之后,片选信号的保持时间 (2bit) */
#define Tcah 4 /* nGCSn结束之后,地址信号的保持时间 (2bit) */
#define Tacp 2 /* Page模式的访问周期 (2bit) */
#define PMC 0 /* Page模式配置 (2bit) */
/**** 外部总线配置,用户可根据实际需要修改 ****/
#define B7_BWCON (DW16|WAIT|UBLB)
#define B6_BWCON (DW32|UBLB) /* SDRAM所用的Bank,不要修改 */
#define B5_BWCON (DW16|WAIT|UBLB)
#define B4_BWCON (DW16|WAIT|UBLB)
#define B3_BWCON (DW16|WAIT|UBLB)
#define B2_BWCON (DW16|WAIT|UBLB)
#define B1_BWCON (DW16|WAIT|UBLB)
#define B7_BANKCON ((0<<MT)|(1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B6_BANKCON ((3<<MT)|(1<<Trcd)|(1<<SCAN)) /* SDRAM所用的Bank,不要修改 */
#define B5_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B4_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B3_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B2_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B1_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define B0_BANKCON ((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
// s3c2410.h
// BWSCON寄存器基地址定义
#define BWSCON_ADDR 0x48000000
// Memory control
#define rBWSCON (*(volatile unsigned *)0x48000000) //Bus width & wait status
#define rBANKCON0 (*(volatile unsigned *)0x48000004) //Boot ROM control
#define rBANKCON1 (*(volatile unsigned *)0x48000008) //BANK1 control
#define rBANKCON2 (*(volatile unsigned *)0x4800000c) //BANK2 cControl
#define rBANKCON3 (*(volatile unsigned *)0x48000010) //BANK3 control
#define rBANKCON4 (*(volatile unsigned *)0x48000014) //BANK4 control
#define rBANKCON5 (*(volatile unsigned *)0x48000018) //BANK5 control
#define rBANKCON6 (*(volatile unsigned *)0x4800001c) //BANK6 control
#define rBANKCON7 (*(volatile unsigned *)0x48000020) //BANK7 control
#define rREFRESH (*(volatile unsigned *)0x48000024) //DRAM/SDRAM refresh
#define rBANKSIZE (*(volatile unsigned *)0x48000028) //Flexible Bank Size
#define rMRSRB6 (*(volatile unsigned *)0x4800002c) //Mode register set for SDRAM
#define rMRSRB7 (*(volatile unsigned *)0x48000030) //Mode register set for SDRAM
// target.c
// 总线配置数据表 (用户可以在config.h文件中配置总线)
const uint32 __BUS_INIT[] =
{
(B7_BWCON<<28)|(B6_BWCON<<24)|(B5_BWCON<<20)|(B4_BWCON<<16)|(B3_BWCON<<12)|(B2_BWCON<<8)|(B1_BWCON<<4), // BWSCON寄存器
B0_BANKCON, // BANKCON0寄存器
B1_BANKCON, // BANKCON1寄存器
B2_BANKCON, // BANKCON2寄存器
B3_BANKCON, // BANKCON3寄存器
B4_BANKCON, // BANKCON4寄存器
B5_BANKCON, // BANKCON5寄存器
B6_BANKCON, // BANKCON6寄存器 (SDRAM)
B7_BANKCON, // BANKCON7寄存器 (SRAM)
(1<<23)|(0<<22)|(0<<20)|(3<<18)|(1113), // REFRESH寄存器(SDRAM) 例如:period=15.6us, HCLK=60Mhz, (2048+1-15.6*60)
(1<<7)|(1<<5)|(1<<4)|(2<<0), // BANKSIZE寄存器,128MB
(3<<4), // MRSRB6寄存器
(3<<4) // MRSRB7寄存器
};
// target.c
/*********************************************************************************************************
** Function name: TargetBusInit
** Descriptions: 针对目标板的总线系统初始化,包括Bank的宽度、SDRAM控制器等等。
** 不要在此函数中加入任何用户代码。
** Input: 无
** Output: 无
********************************************************************************************************/
void TargetBusInit(void)
{
#ifdef __Release
int i;
volatile uint32 *cp1;
// 总线设置,初始化SDRAM控制器
cp1 = (void *)BWSCON_ADDR;
for(i=0; i<13; i++)
{
*cp1++ = __BUS_INIT[i];
}
#endif
}
中断向量表初始化:
;定义堆栈的大小
USR_STACK_LEGTH EQU 64
SVC_STACK_LEGTH EQU 0
FIQ_STACK_LEGTH EQU 16
IRQ_STACK_LEGTH EQU 64
ABT_STACK_LEGTH EQU 0
UND_STACK_LEGTH EQU 0
AREA Example5,CODE,READONLY ; 声明代码段Example5
ENTRY ; 标识程序入口
CODE32 ; 声明32位ARM指令
START MOV R0,#0
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
MOV R6,#6
MOV R7,#7
MOV R8,#8
MOV R9,#9
MOV R10,#10
MOV R11,#11
MOV R12,#12
BL InitStack ; 初始化各模式下的堆栈指针
; 打开IRQ中断 (将CPSR寄存器的I位清零)
MRS R0,CPSR ; R0 <= CPSR
BIC R0,R0,#0x80
MSR CPSR_cxsf,R0 ; CPSR <= R0
; 切换到用户模式
MSR CPSR_c, #0xd0
MRS R0,CPSR
; 切换到管理模式
MSR CPSR_c, #0xdf
MRS R0,CPSR
HALT B HALT
; 名称:InitStack
; 功能:堆栈初始化,即初始化各模式下的堆栈指针。
; 入口参数:无
; 出口参数:无
; 说明:在特权模式下调用此子程序,比如复位后的管理模式
InitStack
MOV R0, LR ; R0 <= LR,因为各种模式下R0是相同的
;设置管理模式堆栈
MSR CPSR_c, #0xd3
LDR SP, StackSvc
;设置中断模式堆栈
MSR CPSR_c, #0xd2
LDR SP, StackIrq
;设置快速中断模式堆栈
MSR CPSR_c, #0xd1
LDR SP, StackFiq
;设置中止模式堆栈
MSR CPSR_c, #0xd7
LDR SP, StackAbt
;设置未定义模式堆栈
MSR CPSR_c, #0xdb
LDR SP, StackUnd
;设置系统模式堆栈
MSR CPSR_c, #0xdf
LDR SP, StackUsr
MOV PC, R0
StackUsr DCD UsrStackSpace + (USR_STACK_LEGTH - 1)*4
StackSvc DCD SvcStackSpace + (SVC_STACK_LEGTH - 1)*4
StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)*4
StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)*4
StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)*4
StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)*4
; 分配堆栈空间
AREA MyStacks, DATA, NOINIT, ALIGN=2
UsrStackSpace SPACE USR_STACK_LEGTH * 4 ; 用户(系统)模式堆栈空间
SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ; 管理模式堆栈空间
IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ; 中断模式堆栈空间
FiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ; 快速中断模式堆栈空间
AbtStackSpace SPACE ABT_STACK_LEGTH * 4 ; 中止义模式堆栈空间
UndtStackSpace SPACE UND_STACK_LEGTH * 4 ; 未定义模式堆栈
END
堆栈初始化:
/*********************************************************************************************************
** 函数名称: OSTaskStkInit
** 功能描述: 任务堆栈初始化代码,本函数调用失败会使系统崩溃
** 输 入: task : 任务开始执行的地址
** pdata :传递给任务的参数
** ptos :任务的堆栈开始位置
** opt :附加参数,当前版本对于本函数无用,具体意义参见OSTaskCreateExt()的opt参数
** 输 出: 栈顶指针位置
** 全局变量:
** 调用模块:
********************************************************************************************************/
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
OS_STK *stk;
opt = opt; /* 'opt' 没有使用。作用是避免编译器警告 */
stk = ptos; /* 获取堆栈指针 */
/* 建立任务环境,ADS1.2使用满递减堆栈 */
*stk = (OS_STK) task; /* pc */
*--stk = (OS_STK) task; /* lr */
*--stk = 0; /* r12 */
*--stk = 0; /* r11 */
*--stk = 0; /* r10 */
*--stk = 0; /* r9 */
*--stk = 0; /* r8 */
*--stk = 0; /* r7 */
*--stk = 0; /* r6 */
*--stk = 0; /* r5 */
*--stk = 0; /* r4 */
*--stk = 0; /* r3 */
*--stk = 0; /* r2 */
*--stk = 0; /* r1 */
*--stk = (unsigned int) pdata; /* r0,第一个参数使用R0传递 */
*--stk = (USER_USING_MODE|0x00); /* spsr,允许 IRQ, FIQ 中断 */
*--stk = 0; /* 关中断计数器OsEnterSum; */
return (stk);
}