type
status
slug
date
summary
tags
category
password
icon
第四章4.1伪指令概述1、什么是伪指令2、伪指令具有的两个特征3、伪指令的作用4.2 通用伪指令伪指令类型4.2.1 为变量定义或赋值的伪指令4.2.2 数据定义伪指令4.2.4其它伪指令4.3.1 宏1、MACRO 和 MEND2、MEXIT4.3.2 宏指令1、小范围的地址读取宏指令2、中等范围的地址读取宏指令ADRL3、大范围的地址读取宏指令LDR4、NOP程序举例示例1示例24.4.1 汇编语言的语句格式4.4.2 汇编语言程序中常用的符号4.4.3 汇编语言的表达式和运算符1、运算次序2、数字表达式及运算符3、逻辑表达式及运算符4、字符串表达式及运算符5、其他运算符8、程序中的变量替换小练习4.5 ARM工程4.6 ARM程序框架4.6.1 初始化程序部分4.6.2 初始化部分与主应用程序部分的衔接4.6.3 ARM开发环境提供的程序框架4.7.1 段4.7.2分支程序设计1、普通分支程序设计2、多分支(散转)程序设计3、带ARM/Thumb状态切换的分支程序设计4.7.3循环程序设计4.7.4子程序及其返回1、子程序的调用与返回2、子程序中堆栈的使用4.8.1 汇编程序访问全局C变量4.8.2 C与汇编之间的函数调用4.8.2.1 ATPCS简介4.8.1.2 C程序可调用汇编函数实例4.8.1.3 汇编程序调用C函数实例4.8.2 C/C++语言和汇编语言的混合编程4.8.2.1 内联汇编4.8.2.2 嵌入式汇编4.8.2.3 内联汇编代码与嵌入式汇编代码之间的差异内联汇编程序与嵌入式汇编程序的主要差异对应实验代码c部分汇编部分第五章5.2.1 S3C2440存储控制器特性5.2.2 S3C2440存储控制器功能(1)BANK0总线宽度(2)存储器(SROM/SDRAM)地址引脚的连接5.2.3 S3C2440存储控制器寄存器(1) 总线宽度/等待控制寄存器 (BWSCON)(2)总线控制寄存器(BANKCONn:nGCS0~nGCS5)(3)BANK控制寄存器(BANKCONn:nGCS6~nGCS7)(4)SDRAM刷新控制寄存器(5)BANKSIZE寄存器(6)SDRAM模式寄存器集寄存器(MRSR)5.3 NAND FLASH控制器5.4 时钟和功率管理(1)正常模式(2)低速模式(3)空闲模式(4)掉电模式5.4.1 时钟和功率管理功能描述(1) 时钟发生器(2) 时钟源选择(3) 锁相环PLL频率计算公式(4)时钟控制逻辑(5)USB模块控制(6)FCLK、HCLK 和 PCLK(7)功率管理①正常模式②空闲模式③低速模式④掉电模式5.5DMA(1)DMA的服务对象5.5.2 DMA工作原理(3)外部DMA请求/响应协议5.6中断控制器5.6.1 中断控制器的操作(1)当前程序状态寄存器(CPSR)的 F位 和 I位(2)中断模式(3)中断挂起寄存器(4)中断屏蔽寄存器(INTMSK)5.6.2 S3C2440中断源(1)中断优先级仲裁器及工作原理(2)中断优先级5.6.3 中断控制器的特殊功能寄存器(1)源挂起寄存器(2)中断模式寄存器(3)中断屏蔽寄存器(4)优先级控制寄存器(5)中断挂起寄存器(6)INTOFFSET寄存器(7)次级源挂起寄存器(8)中断次级屏蔽寄存器各中断相关寄存器中,相关中断顺序表CPSR SRCPND和INTPNDINTOFFSETSUBSRCPNDINTSUBMSKINTMSKINTMODPRIORITY中断源中断优先级仲裁器及其工作原理外部中断EINTPENDnEXTINTn关于引脚复用中断:5.8 PWM定时器5.8.1 PWM概念5.8.2 PWM 定时器结构5.8.3 PWM 定时器操作5.9人机交互设备2、独立按键键盘3、矩阵式键盘示例代码
第四章
4.1伪指令概述
1、什么是伪指令
人们设计了一些专门用于指导汇编器进行汇编工作的指令,由于这些指令不形成机器码指令,它们只是在汇编器进行汇编工作的过程中起作用,所以被叫做伪指令。
2、伪指令具有的两个特征
(1)伪指令是一条指令;
(2)伪指令没有指令代码。
3、伪指令的作用
(1)程序定位的作用;
(2)为非指令代码进行定义;
(3)为程序完整性做标注;
(4)有条件的引导程序段。
4.2 通用伪指令
伪指令类型
在 ARM 汇编程序语言中,有如下几种伪指令:
符号定义(Symbol Definition)伪指令
数据定义(Data Definition)伪指令
汇编控制(Assembly Control)伪指令
其它(Miscellaneous)伪指令
4.2.1 为变量定义或赋值的伪指令
符号的命名由编程者决定,但必须遵循以下约定:
- 符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号;
- 符号在其作用范围内必须唯一;
- 自定义的符号不能与系统保留字相同;
- 符号不应与指令或伪指令同名。
一、声明全局变量伪指令GBLA、GBLL和GBLS
GBLA、GBLL 和 GBLS 伪指令用于定义一个ARM 程序中的全局变量,并将其初始化。
指令格式:
GBLA(GBLL和GBLS) <variable>
variable
为变量名称;- GBLA 定义一个 全局数字变量,其默认初值为 0 ;
- GBLL 定义一个 全局逻辑变量 ,其默认初值为 FALSE(假);
- GBLS 定义一个 全局字符串变量,其默认初值为 空 ;
例:
GBLA Test1 ;定义一个全局数字变量,变量名为 Test1
GBLL Test2 ;定义一个全局逻辑变量,变量名为 Test2
GBLS Test3 ;定义一个全局字符串变量,变量名为 Test3
全局变量 的变量名在整个程序范围内必须具有 唯一性。
二、声明局部变量伪指令LCLA、LCLL和LCLS
Local Constant Longword Allocation
LCLA、LCLL和LCLS伪指令用于定义一个ARM程序中的局部变量,并将其初始化。
格式:
LCLA(LCLL和LCLS) <variable>
variable
为变量名称;- LCLA 定义一个局部数字变量,其默认初值为 0;
- LCLL 定义一个局部逻辑变量,其默认初值为 FALSE(假);
- LCLS 定义一个局部字符串变量,其默认初值为 空。
例:
LCLA Test4 ;定义一个局部数字变量,变量名为 Test4
LCLL Test5 ;定义一个局部逻辑变量,变量名为 Test5
LCLS Test6 ;定义一个局部字符串变量,变量名为 Test6
局部变量 的变量名在变量作用范围内必须具有唯一性。
在默认情况下,局部变量只在定义该变量的程序段内有效。
三、变量赋值伪指令 SETA、SETL和SETS
伪指令SETA、SETL和SETS 用于给一个已经定义的全局变量或局部变量进行赋值。 注:要顶格写
指令格式:
变量名 SETA(SETL或SETS) 表达式
SETA伪指令用于给一个数字变量赋值;
SETL伪指令用于给一个逻辑变量赋值;
SETS伪指令用于给一个字符串变量赋值;例:
Test1 SETA 0xAA ;将Test1变量赋值为0xAA。
Test2 SETL {TRUE} ;将Test2 变量赋值为真;
;假是{FALSE}。
Test3 SETS “Testing” ;将Test3变量赋值为“Testing” 。
四、定义寄存器列表伪指令
指令 LDM/STM 需要使用一个比较长的寄存器列表,使用伪指令 RLIST 可对一个列表定义一个统一的名称。
格式:
<name> RLIST <{list}>
例如:
LoReg RLIST {R0-R7} ;定义寄存器列表{R0-R7}
;的名称为LoReg
STMFD SP!, LoReg ;堆栈操作使用寄存器列表
RegList RLIST {R0-R5,R8,R10} ;将寄存器列表名称定义
;为RegList,可在ARM指令LDM/STM中
;通过该名称访问寄存器列表4.2.2 数据定义伪指令
1、 LTORG
用于声明一个数据缓冲池(文字池)的开始。
语法格式:
LTORG
伪指令 LTORG 用来说明某个存储区域为一个用来暂存数据的数据缓冲区,也叫文字池或数据缓冲池。大的代码段也可以使用多个数据缓冲池。例:
下图为 LTORG 的作用。
其目的是,防止在程序中使用LDR之类的指令访问时,可能产生的越界。
通常把数据缓冲池放在代码段的最后面,或放在无条件转移指令或子程序返回指令之后,这样处理器就不会错误地将数据缓冲池中的数据当作指令来执行。
2、MAP和FIELD
在应用程序中经常使用一种如下图所示的表:
MAP 用于定义一个结构化的内存表的首地址。MAP 可以用“^” 代替。
语法格式:
MAP <expr> {,<base_register>}
expr
是数字表达式或程序中的标号。当指令中没有base_register时,expr即为结构化内存表的首地址,可以为 标号 或 数字表达式;
base_register
为基址寄存器(可选项)。当指令中包含这一项时,结构化内存表的首地址为expr与base_register寄存器值的和;
例子:
MAP fun ; fun就是内存表的首地址
MAP 0x100,R9 ;内存表的首地址为R9+0X100
MAP 通常和 FIELD 伪指令相配合来定义一个结构化的内存表。
FIELD 伪指令用于定义一个结构化内存表中的数据域。
指令格式:
{label} FIELD expr
Label
为域标号,要顶格写;
Expr
表示本数据域在内存表中所占用的字节数;
功能:FIELD用于定义一个结构化内存表中的数据域,“#”与FIELD同义。
MAP 0X100 ;定义结构化内存表首地址为 0X100
A FIELD 16 ;定义A的长度为16字节,位置为 0X100
B FIELD 32 ;定义B的长度为32字节,位置为 0X110
S FIELD 256 ;定义S的长度为256字节,位置为 0X130
注意:MAP 和 FIELD 伪指令仅用于定义数据结构,并不实际分配存储单元。
FIELD 也可用“#” 代替。
3、SPACE
SPACE伪指令用于分配一片连续的存储区域并初始化为 0。
指令格式:
{label} SPACE expr
label
为内存块起始地址标号;
Expr
为所要分配的内存字节数; SPACE 也可用“%” 代替。
例子:
4、DCB
分配内存单元并初始化
指令格式:
{label} DCB expr{,expr }{,expr }…
label
是存块起始地址标号;
expr
可以为0至255的数值或字符串,内存分配的字节数由expr个数决定;
功能:DCB用于分配一段字节内存单元,并用伪指令中的expr初始化,一般可用来定义数据表格,或文字符串,“=”与DCB同义。
例如:
使用示例:
5、DCD和DCDU分配存储单元并初始化
指令格式:
{label} DCD expr{,expr }{,expr }…
{label} DCDU expr{,expr }{,expr }…
label
是内存块起始地址标号
expr
为常数表达式或程序中标号,内存分配字节数由expr个数决定
功能:
DCD
用于分配一段字内存单元,并用伪指令中的expr初始化,字对齐,可定义数据表格或其它常数。“&”与DCD同义。
DCDU
用于分配一段字内存单元,并用伪指令中的expr初始化。DCDU伪指令分配的内存不需要字对齐,可定义数据表格或其它常数 。
该例说明了:MAP和FIELD伪指令不分配存储空间,只是给相关存储单元取个名称(标号)。便于程序以结构的方式访问对应的内存单元。
4.2.4其它伪指令
1、定义对齐方式伪指令 ALIGN
指令格式:
ALIGN {表达式,{偏移量}}
ALIGN是边界对齐伪指令,它可以通过添加填充字节的方式,使当前位置满足一定的对齐方式。其中表达式用于指定对齐方式在不同场合有不同的定义。对于在代码中单独使用的ALIGN伪指令,表达式的值,就是对齐方式的值,且该值必须是2的幂次方(2、4、8….)。
例
ALIGN 4 ;4字节字对齐,ALIGN后面不能有等号。
又比如
还比如:
2、段定义伪指令AREA
AREA用于定义一个代码段或数据段。
指令格式:
AREA sectionname {,attr} {,attr}…
- sectionname是定义的代码段或数据段的名称。若该名称是以数字开头的,则该名称必须用“|”括起来,如|2_datasec|。还有一些代码段的名称是专有名称。
- Attr表示代码或数据段的属性,多个属性用短号分隔,常用的属性如下:
属性 | 含义 | 备注 |
CODE | 代码段 | 默认读/写属性为READONLY |
DATA | 数据段 | 默认读/写属性为READWRITE |
NOINIT | 数据段 | 指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元。 |
READONLY | 本段为只读 | ㅤ |
READWRITE | 本段为可读可写 | ㅤ |
ALIGN表达式 | ㅤ | ELF 的代码段和数据段为字对齐 |
COMMON | 多源文件共享段 | ㅤ |
例如
该伪指令定义了一个代码段,段名为 Init ,属性为 只读。
一个汇编语言程序 至少 要有一个段。
3、CODE16 和 CODE32
CODE16告诉汇编编译器后面的指令序列为16位的Thumb指令。
CODE32告诉汇编编译器后面的指令序列为32位的ARM指令。
语法格式:
CODE16
CODE32
注意:CODE16和CODE32只是告诉编译器后面指令的类型,该伪操作本身不进行程序状态的切换。
例:
4、定义程序入口伪指令 ENTRY
指定程序的入口点。
语法格式:
ENTRY
注意:一个程序(可包含多个源文件)中至少要有一个ENTRY(可以有多个ENTRY,当有多个ENTRY入口时,程序的真正入口点由链接器指定),但一个源文件中最多只能有一个ENTRY(可以没有ENTRY)例子
5、汇编结束伪指令
END 伪指令用于通知编译器汇编工作到此结束,不再往下汇编了。
语法格式:
END
例子
注意:每一个汇编源程序都必须包含END伪操作,以表明本源程序的结束。
6、外部可引用符合声明伪指令 EXPORT(或GLOBAL)
声明一个源文件中的符号,使此符号可以被其他源文件引用。
语法格式:
EXPORT/GLOBAL symbol {[weak]}
- symbol:声明的符号的名称。(区分大小写)
- [weak]:声明其他同名符号优先于本符号被引用。
例子:
7、IMPORT
当在一个源文件中需要使用另外一个源文件的外部可引用符号时,在被引用的符号前面,必须使用伪指令 IMPORT 对其进行声明:声明一个符号是在其他源文件中定义的。
语法格式:
IMPORT symbol{[weak]}
如果源文件声明了一个引用符号,则无论当前源文件中程序是否真正地使用了该符号,该符号均会被加入到当前源文件的符号表中。
- symbol:声明的符号的名称
- [weak]: 当没有指定此项时,如果symbol在所有的源文件中都没有被定义,则连接器会报告错误。 当指定此项时,如果symbol在所有的源文件中都没有被定义,则连接器不会报告错误,而是进行下面的操作:
- 如果该符号被B或者BL指令引用,则该符号被设置成下一条指令的地址,该B或BL指令相当于一条NOP指令。
- 其他情况下此符号被设置成0。
例子:
8、EXTERN
EXTERN 伪指令与 IMPORT 伪指令的功能基本相同,但如果当前源文件中的程序实际并未使用该符号,则该符号不会加入到当前源文件的符号表中。
其它与 IMPORT 相同。
9、等效伪指令 EQU
EQU 伪指令用于为程序中的常量、标号等定义一个等效的字符名字,其作用类似于 C语言 中的 #define。
语法格式:
name EQU expr{,type}
name
:为expr定义的字符名称。
expr
:基于寄存器的地址值、程序中的标号、32位的地址常量或者32位的常量。表达式,为常量。
type
:当expr为32位常量时,可以使用type指示expr的数据的类型。取值为: CODE32 CODE16 DATA
例:
10、GET(或INCLUDE)
GET 伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编。
语法格式:
GET 文件名
可以使用 INCLUDE 代替 GET。
GET 伪指令只能用于包含源文件,包含目标文件则需要使用 INCBIN 伪指令。例子:
4.3.1 宏
1、MACRO 和 MEND
MACRO 和 MEND 伪指令可以为一个程序段定义一个名称。这样,在汇编语言应用程序中,就可以通过这个名称来使用它所代表的程序段,即当程序做汇编时,该名称将被替换为其所代表的程序段。
MACRO
$标号 宏名 $参数1, $参数2,…..
程序段(宏定义体)
MEND
- $标号:为主标号,宏内的所有其它标号必须由主标号组成;
- 宏名:宏名称,为宏在程序中的引用名;
- $参数1,$参数2:宏中可以使用的参数。 宏中的所有标号必须在前面冠以符号“$”。 MACRO、 MEND伪指令可以嵌套使用。
例子:
主程序中调用该宏:
Lab1 MAXNUM 0x01, 0x02
2、MEXIT
MEXIT 用于从宏定义中跳转出去。
语法格式:MEXIT
例:
该宏是用于中断服务程序的一个宏定义,除reset中断外的其余6种中断,都可以使用该宏定义的程序段进入。
在程序中调用该宏
例如:HandlerFIQ HANDLER HandleFIQ展开后为:
4.3.2 宏指令
在ARM中,还有一种汇编器内置的无参数和标号的宏——宏指令。
在汇编时,这些宏指令被替换成一条或两条真正的ARM或 Thumb 指令。ARM宏指令有四条,分别是:
ADR
:小范围的地址读取宏指令;
ADRL
:中等范围的地址读取宏指令;
LDR
:大范围的地址读取宏指令;
NOP
:空操作宏指令。
1、小范围的地址读取宏指令
ADR 指令用于将一个 近地址值 传递到一个寄存器中。
指令格式:
ADR{cond} <reg>, <expr>
- reg 为目标寄存器名称;
- expr 为表达式。该表达式通常是程序中一个表示存储位置的 地址标号。
该宏指令的功能是把标号所表示的地址传递到目标寄存器中。
汇编器在汇编时,将把ADR宏指令替换成一条真正的ADD或SUB指令,以当前的PC值减去或加上expr与PC之间的偏移量得到标号的地址,并将其传递到目标寄存器。若不能用一条指令实现,则产生错误,编译失败。
例:
由于指令ADD或SUB中对立即数的限制,因此标号地址就不能距离当前指令的地址(PC)过远。对于非字对齐地址来说,其距离必须在 255 字节以内;而对于字对齐地址来说,距离必须在 1020 字节以内。所以ADR也叫做近地址读取指令。
例2:查表
2、中等范围的地址读取宏指令ADRL
类似于ADR,但可以把更远的地址赋给目标寄存器。
指令格式:
ADRL{cond} <reg>, <expr>
reg
为目标寄存器名称;
Expr
为表达式,必须是64KB以内非字对齐地址,或256KB以内的字对齐地址。
该指令只能在ARM状态下使用,在Thumb状态下不能使用。汇编时,ADRL宏指令由汇编器替换成两条合适的指令。
例如:
其中 ADRL 将被替换为如下两条指令:
如果汇编器找不到合适的两条指令,将会报错。
例:
3、大范围的地址读取宏指令LDR
指令格式:
LDR{cond} reg,={expr | label - expr}
- reg:目标寄存器名称;
- expr:32位常数;
- label – expr:为地址表达式。
程序经常用这条指令把一个地址传递到寄存器reg中。汇编器在对这种指令进行汇编时,会根据指令中expr的值的大小来把这条指令替换为合适的指令。
与ARM指令的LDR的区别:伪指令LDR的参数有“=”号。
当 expr 的值未超过 MOV 或 MVN 指令所限定的取值范围时,汇编器用 ARM 的 MOV 或 MVN 指令来取代宏指令 LDR;
当 expr 的值超过 MOV 或 MVN 指令所限定的取值范围时,汇编器将常数 expr 放在由 LTORG 定义的文字缓冲池,同时用一条 ARM 的装载指令 LDR 来取代宏指令 LDR ,而这条装载 LDR 指令则用 PC 加偏移量的方法到文字缓冲池中把该常数读取到指令指定的寄存器。
由于这种指令可以传递一个 32 位地址,因此也被叫做全范围地址读取指令。
例如:(包含其编译后对应代码)
使用LDR将程序标号Delay所表示的地址存入R1。
例:
4、NOP
汇编器对NOP指令进行汇编时,会将其转换为:
MOV R0,R0
指令格式:
NOP
例:延时子程序
程序举例
示例1
示例2
4.4.1 汇编语言的语句格式
ARM(Thumb)汇编语言的语句格式为:
{<标号>} <指令或伪指令> {;注释}
在汇编语言程序设计中,每一条指令的助记符可以全部用大写或全部用小写 ,但不允许在一条指令中大小写混用 。标号要顶格。
如果一条语句太长,则可将该长语句分成若干行来书写,每行的末尾用“\”来表示下一行与本行为同一条语句。但是注意:在”\”之后不能再有其他字符,包括空格和制表符.
4.4.2 汇编语言程序中常用的符号
在ARM汇编语言中,符号可以代表地址、变量和数字常量。
符号命名规则如下:
- 符号由大小写字母、数字以及下画线组成;
- 除局部标号以数字开头,其他的符号都不能以数字开头;
- 符号是区分大小写的;
- 符号在其作用范围内必须唯一;
- 程序中的符号不能与指令助记符、伪指令、宏指令同名。
这些规则主要涉及程序中的变量和常量。
4.4.3 汇编语言的表达式和运算符
1、运算次序
(1)优先级相同的双目运算符运算顺序为从左到右;
(2)相邻的单目运算符的运算顺序为从右到左,且单目运算符 的优先级高于其他运算符;
(3)括号运算符的优先级最高。
2、数字表达式及运算符
(1)+、-、*、/及MOD算术运算符
X + Y 表示 X 与 Y 的和;
X - Y 表示X与Y的差;
X * Y 表示X与Y的乘积;
X / Y 表示X除以Y的商;
X :MOD: Y 表示X除以Y的余数。
(2)ROL、ROR、SHL及SHR移位运算符
X :ROL: Y 表示将X循环左移Y位;
X :ROR: Y 表示将X循环右移Y位;
X :SHL: Y 表示将X左移Y位;
X :SHR: Y 表示将X右移Y位。
(3)AND、OR、NOT及EOR按位逻辑运算符
X :AND: Y 表示将X和Y按位做逻辑“与”的操作。
X :OR: Y 表示将X和Y按位做逻辑“或”的操作;
:NOT: Y 表示将Y按位做逻辑“非”的操作;
X :EOR: Y 表示将X和Y按位做逻辑“异或”的操作。
3、逻辑表达式及运算符
(1)=、>、<、>=、<=、/=、<>运算符
X = Y 表示X等于Y;
X > Y 表示X大于Y;
X < Y 表示X小于Y;
X >= Y 表示X大于或等于Y;
X <= Y 表示X小于或等于Y;
X /= Y 表示X不等于Y;
X <> Y 表示X不等于Y。
(2)LAND、LOR、LNOT及LEOR运算符
X :LAND: Y 表示将X和Y做逻辑“与”的操作;
X :LOR: Y 表示将X和Y做逻辑“或”的操作;
:LNOT: Y 表示将Y做逻辑“非”的操作;
X :LEOR: Y 表示将X和Y做逻辑“异或”的操作。
4、字符串表达式及运算符
编译器所支持的字符串最大长度为512 字节。
(1)LEN 运算符
LEN 运算符返回字符串的长度(字符数),以 X 表示字符串表达式。
:LEN: X
示例:
(2)CHR 运算符
CHR 运算符将 0~255 之间的整数转换为一个字符,以 M 表示一个整数,其格式如下:
:CHR: M
在内存单元中,其值还是没有变。只是经过这种处理后,可以把它当做一个字符,用于字符串处理函数中。
(3)STR 运算符
STR 运算符将一个数字表达式或逻辑表达式转换为一个字符串。
对于 数字表达式,STR 运算符将其转换为一个以 十六进制 组成的字符串(用于表示32位数值如:0000000F);对于 逻辑表达式,STR 运算符将其转换为 字符串"T"或"F" 。
:STR: X ;X为数字表达式或逻辑表达式
例子:
例子:
该程序执行后,R1的值为0x34333231(十六进制), 0x34是4对应的ASCII码,0x31是1对应的ASCII码。
(4)LEFT 运算符
LEFT 运算符返回某个字符串 左端 的一个 子集。
X :LEFT: Y
X 为源字符串,Y 为一个整数,表示要返回的字符个数。
举例:
(5)RIGHT 运算符
RIGHT 运算符返回某个字符串 右端 的一个 子集。
X :RIGHT: Y
X 为源字符串,Y 为一个整数,表示要返回的字符个数。
举例:
(6)CC 运算符
CC 运算符用于将两个字符串连接成一个字符串。
X :CC: Y
X为源字符串1,Y为源字符串2,CC运算符将Y连接到X的后面。
举例:
再举例:
GS2=“TA”
:STR:LL1 = “T”
:CHR:65= “A”
5、其他运算符
了解,略。
8、程序中的变量替换
程序中的变量可通过代换操作取得一个常量。代换操作符为“$”。
如果在数字变量前面有一个代换操作符 “$” ,则编译器会将该数字变量的值转换为十六进制的字符串,并将该十六进制的字符串代换 “$” 后的数字变量。
如果在逻辑变量前面有一个代换操作符 “$” ,则编译器会将该逻辑变量代换为它的取值(真或假)。
如果在字符串变量前面有一个代换操作符 “$” ,则编译器会将该字符串变量的值代换 “$” 后的字符串变量。
例子:
字符串变量S2的值为“This is a Test !”
还例如:
StrMem存放的内容为字符串:“1234500000066TF”对应的ASCII码
小练习
1、
R3=1,R4=3,R5=2,R6=4
2、
该段程序执行完成后,假如R0的值为0x10001000,
R1=0x10001003
R4=0x03000001
3、
该段程段中Str3和Str4对应的字符串分别为:
Str3=”AAAABCDF”
Str4=”AAAF”
4.5 ARM工程
由于C语言便于理解,有大量的支持库,所以它是当前 ARM 程序设计所使用的主要编程语言。
对硬件系统的初始化、CPU状态设定、中断使能、主频设定以及RAM控制参数初始化等C程序力所不能及的底层操作,还是要由汇编语言程序来完成。
用汇编语言或C/C++语言编写的程序叫做源程序,对应的文件叫做源文件。
一个ARM工程应由多个文件组成,其中包括扩展名为 .S 的汇编语言源文件、扩展名为 .C的C语言源文件,扩展名为 .CPP的C++源文件、扩展名为.H的头文件等。
ARM工程的各种源文件之间的关系,以及最后形成可执行文件的过程如下:
各种源文件先由编译器和汇编器将它们分别编译或汇编成汇编语言文件及目标文件。
连接器负责将所有目标文件连接成一个文件并确定各指令的确定地址,从而形成最终可执行文件。
连接器有 三个 功能:
- 根据程序员所指定的选项,为程序分配地址空间;
- 生成与地址相关的代码,把所有文件连接成一个可执行文件;
- 给出连接信息,以说明连接过程和连接结果。
4.6 ARM程序框架
在应用系统的程序设计中,若所有的编程任务均用汇编语言来完成,其工作量是可想而知的,这样做也不利于 系统升级或应用软件移植。
通常汇编语言部分完成系统硬件的初始化;高级语言部分完成用户的应用。
执行时,首先执行初始化部分,然后再跳转到 C/C++ 部分。整个程序结构显得清晰明了,容易理解。程序的基本结构如下:
4.6.1 初始化程序部分
由于在用于完成初始化任务的汇编语言程序中需要在 特权模式 下做一些诸如修改 CPSR 等特权操作,所以不能过早地进入用户模式。(上电复位后进入SVC模式,除用户模式外,其它模式中能任意切换工作模式)
4.6.2 初始化部分与主应用程序部分的衔接
当所有的系统初始化工作完成之后,就需要把程序流程转入主应用程序。
最简单的方法是,在汇编语言程序末尾使用跳转指令 B 或 BL 直接从启动代码转移到 C/C++ 程序入口。
B main ;跳转到C/C++程序
同时在汇编文件中有如下代码:
IMPORT main
完整的汇编语言程序大致如下:
C程序如下:
4.6.3 ARM开发环境提供的程序框架
为方便工程开发,ARM 公司的开发环境ARM ADS 为用户提供了一个可以选用的应用程序框架。该框架把为用户程序做准备工作的程序分成了: 启动代码和应用程序初始化两部分。
用于硬件初始化的汇编语言部分叫做启动代码;用于应用程序初始化的C部分叫做初始化部分。整个程序如下所示:
4.7.1 段
汇编语言编写的程序叫做汇编语言源程序,包含源程序的文件叫做汇编语言程序文件。
一个工程可以有多个源文件,汇编源文件的扩展名为 .S。
在ARM(Thumb)汇编语言程序中,通常以段为单位来组织代码。段是具有特定名称且功能相对独立的指令或数据序列。
根据段的内容,分为代码段和数据段。
一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段。
以下是一个汇编语言程序段的基本结构:
4.7.2分支程序设计
具有两个或两个以上可选执行路径的程序叫做分支程序。
1、普通分支程序设计
使用 带有条件码的指令可以很容易地实现分支程序。
例1:编写一个分支程序段,如果寄存器 R5 中的数据等于 10,就把 R5 中的数据存入寄存器 R1;否则把 R5 中的数据分别存入寄存器 R0 和 R1。
(1)用 条件指令 实现的分支程序段
(2)用 条件转移指令 来实现分支程序段
例2:编写一个程序段,当寄存器R1中的数据大于R2中数据时,将R2中的数据加10存入寄存器 R1;否则将R2中数据加 5 存入寄存器 R1。
(1)HI:无符号数大于,LS:无符号数小于或等于;
(2)GT:带符号数大于,LE:带符号数小于或等于。
2、多分支(散转)程序设计
程序分支点上有多于两个以上的执行路径的程序叫做 多分支程序。利用条件测试指令或跳转表可以实现多分支程序。
例1:编写一个程序段,判断寄存器R1中数据是否为10、15、12、22。如果是,则将R0中的数据加1;否则将R0设置为 0XF。
当多分支程序的每个分支所对应的是一个程序段时,常常把各个分支程序段的首地址依次存放在一个叫做跳转地址表的存储区域,然后在程序的分支点处使用一个可以将 跳转表中的目标地址传送到PC的指令来实现分支。
一个具有 3 个分支的跳转地址表示意图如下:
3、带ARM/Thumb状态切换的分支程序设计
在ARM程序中经常需要在程序跳转的同时还要进行处理器状态的转移,即从ARM指令程序段跳转到Thumb指令程序段(或相反)。为了实现这个功能,系统提供了一条专用的、可以实现4GB空间范围内的绝对跳转交换指令BX。
下面是一段从 ARM 指令程序段跳转到 Thumb 指令程序的状态切换例程。
下面是一段从Thumb 指令程序段跳转到ARM指令程序的状态切换例程。
4.7.3循环程序设计
当条件满足时,需要重复执行同一个程序段做同样工作的程序叫做循环程序。
被重复执行的程序段叫做循环体,需要满足的条件叫做循环条件。
循环程序有两种结构:DO-WHILE结构 和 DO-UNTIL 结构。
在汇编语言程序设计中,常用的是DO-UNTIL 结构循环程序。
例1:编写一个程序,把首地址为DATA_SRC的80个字的数据复制到首地址为DATA_DST的目标数据块中。
4.7.4子程序及其返回
1、子程序的调用与返回
人们把可以多次反复调用的、能完成指定功能的程序段称为“子程序”。把调用子程序的程序称为“主程序”。
为进行识别,子程序的第1条指令之前必须赋予一个标号,以便其他程序可以用这个标号调用子程序。
在ARM汇编语言程序中,主程序一般通过BL指令来调用子程序。
为使子程序执行完毕能返回主程序的调用处,子程序末尾处应有MOV、B、BX、LDMFD等指令,并在指令中将返回地址重新复制到 PC 中。
例1:一个使用 MOV 指令实现返回的子程序
使用 B 指令实现返回的子程序。
2、子程序中堆栈的使用
4.8.1 汇编程序访问全局C变量
一般来说,汇编语言程序与C语言程序不在同一个文件上,所以实质上这是一个引用不同文件定义的变量问题。解决这个问题的办法就是使用关键字IMPORT和EXPORT。
在C程序中声明的全局变量可以被汇编程序通过地址间接访问,具体访问方法如下。
- 使用 IMPORT 伪指令声明该全局变量;
- 使用LDR宏指令读取该全局变量的内存地址,通常该全局变量的内存地址值存放在程序的数据缓冲池中;
- 根据该数据的类型,使用相应的LDR指令读取该全局变量的值;使用相应的STR 指令修改该全局变量的值。
各数据类型及其对应的 LDR/STR 指令如下。
对于无符号的char类型的变量通过指令LDRB/STRB来读写;
对于无符号的short类型的变量通过指令LDRH/STRH 来读写;
对于 int 类型的变量通过指令LDR/STR 来读写;
对于有符号的char类型的变量通过指令LDRSB 来读取;
对于有符号的char 类型的变量通过指令 STRB 来写入;
对于有符号的short类型的变量通过指令 LDRSH 来读取;
对于有符号的short类型的变量通过指令 STRH 来写入;
对于小于8个字的结构型变量,可以通过一条 LDM/STM 指令来读/写整个变量;
对于结构型变量的数据成员,可以使用相应的 LDR/STR 指令来访问,这时必须知道该数据成员相对于结构型变量开始地址的偏移量。
例、下面是一个汇编代码的函数,它引用了一个在其他文件中定义的全局变量globvar,将其加 2 后写回 globvar 。
4.8.2 C与汇编之间的函数调用
在ARM工程中,C程序调用汇编函数和汇编程序调用C 函数是经常发生的事情。为此人们制定了ARM-Thumb过程调用标准ATPCS(ARM-Thumb Procedure Call Standard)。
4.8.2.1 ATPCS简介
为了使单独编译的C语言程序和汇编语言程序之间能够相互调用,必须为子程序间的调用设置一定的规则。具体包括:
(1)在子程序编写时必须遵守相应的ATPCS规则。
(2)数据栈的使用要遵守相应的ATPCS规则。
(3)在汇编编译器中使用选项。
一、堆栈与寄存器在函数调用中的作用
函数是通过寄存器和堆栈来传递参数和返回值的。
下面是C语言程序调用C函数的情况以及在C程序中,主函数 main() 调用该函数的方法:
ARM编译器使用的函数调用规则就是ATPCS标准。ATPCS标准既是ARM编译器的规则,也是设计可被C程序调用的汇编函数的编写规则。
二、ATPCS 关于堆栈和寄存器的使用规则
ATPCS规定,ARM的数据堆栈为FD型堆栈,即递减满堆栈。
ATPCS 标准规定,对于参数个数不多于4的函数,编译器必须按参数在列表中的顺序,自左向右为它们分配寄存器R0~R3。其中函数返回时,R0还被用来存放函数的返回值。
编译器为函数AddInt()的参数分配寄存器的示意图如下:
如果函数的参数多于4个,那么多余的参数则按自右向左的顺序压入数据堆栈,即参数入栈顺序与参数顺序相反。
函数参数使用寄存器和数据栈的示意图如下:
4.8.1.2 C程序可调用汇编函数实例
下面是一个用汇编语言编写的函数,该函数把R1指向的数据块复制到R0指向的存储块。
根据ATPCS的C语言程序调用汇编函数的规则,参数由左向右依次传递给寄存器R0~R3,可知汇编函数strcopy 在 C 程序中原型应该为:
void strcopy(char d,const char s);
在 C 语言文件中,调用 strcopy 函数的方法如下:
1、常量指针
表示指针所指向的地址的内容是不可修改的,但指针自身可变。
const 类型* 指针名
2、指针常量
表示指针自身不可变,但其指向的地址的内容是可以修改的。
类型* const 指针名
4.8.1.3 汇编程序调用C函数实例
现有 C 函数 g() 如下:
汇编函数f中调用C函数g(),以实现下面的功能:
int f(int i) {return –g(i, 2*i, 3*i, 4*i,5*i)}
整个汇编函数 f 的代码如下:
4.8.2 C/C++语言和汇编语言的混合编程
除了上面介绍的函数调用方法之外,ARM编译器 armcc 中含有的内嵌汇编器还允许在C程序中内联或嵌入式汇编代码,以提高程序的效率。
4.8.2.1 内联汇编
1、定义内联汇编程序
所谓内联汇编程序,就是在C程序中直接编写汇编程序段而形成一个语句块,这个语句块可以使用除了 BX 和 BLX之外的全部ARM指令来编写,从而可以使程序实现一些不能从C获得的底层功能。
其格式为:
例子:
内联式汇编伪指令不能使用!
汇编语句块中,如果有两条指令占据了同一行,那么必须用分号“ ;”将它们分隔。如果一条指令需要占用多行,那么必须用反斜线符号“ \”作为续行符。
可以在内联汇编语言块内的任意位置使用 C/C++ 格式的注释。
内联汇编代码中定义的标号可被用作跳转或C/C++ goto 语句的目标,同样,在C/C++代码中定义的标号,也可被用作内联汇编代码跳转指令的目标。
2、内联汇编的限制
内联汇编与真实汇编之间有很大区别,会受到很多限制。
- 它不支持 Thumb 指令;除了程序状态寄存器 CPSR 之外,不能直接访问其他任何物理寄存器等;
- 如果在内联汇编程序指令中出现了以某个寄存器名称命名的操作数,那么它被叫做虚拟寄存器,而不是实际的物理寄存器。编译器在生成和优化代码的过程中,会给每个虚拟寄存器分配实际的物理寄存器,但这个物理寄存器可能与在指令中指定的不同。唯一的一个例外就是状态寄存器PSR ,任何对PSR的引用总是执行指向物理 PSR;
例子
- 在内联汇编代码中不能使用寄存器 PC(R15)、LR(R14)和SP(R13),任何试图使用这些寄存器的操作都会导致出现错误消息;
- 鉴于上述情况,在内联汇编语句块中最好使用C或C++ 变量作为操作数;
- 虽然内联汇编代码可以更改处理器模式,但更改处理器模式会禁止使用C操作数或对已编译C代码的调用,直到将处理器模式恢复为原设置之后。
4.8.2.2 嵌入式汇编
嵌入式汇编程序是一个编写在C程序外的单独汇编程序,该程序段可以像函数那样被C程序调用。
与内联汇编不同,嵌入式汇编具有真实汇编的所有特性,数据交换符合 ATPCS 标准,同时支持 ARM 和Thumb,所以它可以对目标处理器进行不受限制的低级访问。但是不能直接引用 C/C++ 的变量。
用 _ _asm声明的嵌入式汇编程序像C函数那样可以有参数和返回值。定义一个嵌入式汇编函数的语法格式为:
- return–type:函数返回值类型,C语言中的数据类型;
- function–name:函数名;
- parameter-list:函数参数列表。
注:ADS环境中不能使用嵌入式汇编。
嵌入式汇编在形式上看起来就像使用关键字 _ _asm进行了声明的函数,如下所示:
参数名只允许使用在参数列表中,不能用在嵌入式汇编函数体内。
如下面定义的嵌入式汇编程序是错误的。
按 ATPCS 规定,应该使用寄存器 R0 来代替 i。
在C程序中调用嵌入式汇编程序的方法与调用C函数的方法相同。
灵活地使用内联汇编和嵌入式汇编,有助于提高程序效率。
4.8.2.3 内联汇编代码与嵌入式汇编代码之间的差异
- 内联汇编代码使用高级处理器抽象,并在代码生成过程中与 C 和 C++代码集成。因此编译程序将 C 和 C++代码与汇编代码一起进行优化;
- 与内联汇编代码不同,嵌入式汇编代码从 C 和 C++ 代码中分离出来单独进行汇编,产生与 C 和 C++ 源代码编译对象相结合的编译对象;
- 可通过编译程序来内联汇编代码,但无论是显示还是隐式,都无法内联嵌入式汇编代码。
内联汇编程序与嵌入式汇编程序的主要差异
项目 | 内联汇编 | 嵌入式汇编 |
指令集 | 仅限于ARM | ARM和Thumb |
ARM汇编程序命令 | 不支持 | 支持 |
C表达式 | 支持 | 仅支持常量表达式 |
优化代码 | 支持 | 不支持 |
内联 | 可能 | 从不 |
寄存器访问 | 不使用物理寄存器 | 使用物理寄存器 |
返回指令 | 自动生成 | 显示编写 |
对应实验代码
c部分
汇编部分
第五章
5.2.1 S3C2440存储控制器特性
S3C2440的存储控制器有以下特性:
(1)小/大端(通过软件选择);
(2)地址空间:每BANK有128MB(共有1GB/8BANKS);
(3)除BANK0(只能是16/32位宽)之外,其他BANK都具有可编程的访问大小(8/16/32位);
(4)总共8个存储器BANK,6个是ROM、SRAM等类型存储器BANK,剩下的2个可以为ROM、SRAM、SDRAM等存储器BANK;
(5)7个固定的存储器BANK的起止地址;
(6)最后一个BANK的起始地址是可调整的;
(7)最后2个BANK的大小是可编程的;
(8)所有存储器BANK的访问周期都是可编程的;
(9)总线访问周期可以通过插入外部等待(nWAIT)来延长;
(10)支持SDRAM的自刷新和掉电模式。
下图为S3C2440复位后的存储图
注:底部是 0000的位置
这里的 SROM 是指 ROM 和 SRAM 类型存储器 。
当 OM=00时,是采用的NAND flash。当OM=01 10是从ROM,或NOR 类型的flash启动。
在分析 启动 流程 之前 我们 首先 要 清楚 不论是 arm的 何种 处理器,其 都是 从 0x0000 0000 地址处 开始 执行 程序的。
然后,我们 再看看 不同 类型的 flash的 区别:
NOR flash 适合 存放 代码 而 NAND适合 存放 数据,由 他们的 性质 所 决定的,NAND的操作对象是页,也就是 你 读写 都 针对 整个 页面,而 NOR 可以 按字节 进行 读操作,读取的 速度快,所以 NOR 更 适合 代码。
从 上图 我们 可以 清楚的 看到 左边的 是 从Nor Flash 启动的 地址布局,右边是 从NAND 启动的 地址布局,因为Nor Flash内 可以 运行程序,所以 我们在 放bootloader的 时候 放在 0地址处 即可,所以 我们 重点 分析 从 NAND 启动。
我们 从 地址 布局图 中 可以 看到,当 我们 从 NAND 启动的 时候 0地址处 是BootSRAM(又叫做stepping stone垫脚石),当 我们上 电时 其 会做 以下 事情。
- 上电后 处理器 自动将 nandflash 前 4KB的 内容 复制到 boot sram,这个 由 硬件 完成 ,然后,从 boot sram 开始执行。
- 通过 bootsram,也就是 刚才 复制 进来的 4k代码,来初始化 相关 硬件 和 寄存器 从而 访问 nandflash,接下来 把 剩余的 bootloader 复制 到 内存(SDRAM/DRAM)中,当boot sram 里面的 4KB 代码 执行 完 以后 跳转到 内存 继续 执行,完成 系统 的 启动。
当不使用NAND时,ARM芯片内部的集成的RAM的单元地址为0x4000 0000开始的
5.2.2 S3C2440存储控制器功能
(1)BANK0总线宽度
BANK0 的数据总线(nGCS0)必须首先设置成 16位或32位的,因为 BANK0 通常作为 引导ROM区(映射到地址0X00000000)。在复位时,系统将检测 OM[1:0] 上的逻辑电平,并依据这个电平来决定 BANK0 区存储器的总线宽度,具体如下表所示:
数据宽度选择
OM1(操作模式1) | OM0(操作模式0) | 导入ROM数据宽度 |
0 | 0 | Nand Flash Mode |
0 | 1 | 16位 |
1 | 0 | 32位 |
1 | 1 | 测试模式 |
(2)存储器(SROM/SDRAM)地址引脚的连接
存储器(SROM/SDRAM)地址引脚的连接方式由于数据宽度的设置不同而有所区别。
存储器地址连接
存储器地址引脚 | S3C2440地址/8位数据总线(8位芯片) | S3C2440地址/16位数据总线(16位芯片) | S3C2440地址/32位数据总线(32位芯片) |
A0 | A0 | A1 | A2 |
A1 | A1 | A2 | A3 |
5.2.3 S3C2440存储控制器寄存器
(1) 总线宽度/等待控制寄存器 (BWSCON)
总线宽度/等待控制寄存器(BWSCON)的地址描述如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
BWSCON | 0X48000000 | R/W | 总线宽度和等待状态控制器 | 0X00000000 |
总线宽度/等待控制寄存器各位描述
BWSCON | 位 | 描述 | 初始状态 |
ST7 | [31] | 决定SRAM映射在BANK7时是否使用UB/LB;0:不使用UB/LB(引脚对应nWBE[3:0]);
1:使用UB/LB(引脚对应nBE[3:0]); | 0 |
WS7 | [30] | 决定BANK7中的SRAM存储器的等待状态,0:等待禁止;1:等待使能 | 0 |
DW7 | [29:28] | 决定BANK7数据总线宽度;00:8位;01:16位;10:32位;11:保留 | 0 |
BWSCON | 位 | 描述 | 初始状态 |
ST6 | [27] | 决定SRAM映射在BANK6时是否使用UB/LB;
0:不使用UB/LB(引脚对应nWBE[3:0]);
1:使用UB/LB(引脚对应nBE[3:0]); | 0 |
WS6 | [26] | 决定BANK6中的SRAM存储器的等待状态;
0:等待禁止;1:等待使能 | 0 |
DW6 | [25:24] | 决定BANK6数据总线宽度;
00:8位;01:16位;10:32位;11:保留 | 0 |
ST5 | [23] | 决定SRAM映射在BANK5时是否使用UB/LB;
0:不使用UB/LB(引脚对应nWBE[3:0]);
1:使用UB/LB(引脚对应nBE[3:0]); | 0 |
WS5 | [22] | 决定BANK5中的SRAM存储器的等待状态,
0:等待禁止;1:等待使能 | 0 |
DW5 | [21:20] | 决定BANK5数据总线宽度;
00:8位;01:16位;10:32位;11:保留 | 0 |
4-1都是和上面的形式一样的,不列了,但是0不一样
BWSCON | 位 | 描述 | 初始状态 |
DW0 | [2:1] | 显示BANK0的数据总线宽度(只读) | - |
Reserved | [0] | 不使用 | - |
在这个存储控制器里,所有类型的主时钟都对应着总线时钟。例如:SRAM的HCLK就是总线时钟,SDRAM的SCLK也和总线时钟相同;
(2)总线控制寄存器(BANKCONn:nGCS0~nGCS5)
总线控制寄存器 BANKCON0~BANKCON5 的地址信息如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
BANKCON0 | 0X48000004 | R/W | BANKCON0控制寄存器 | 0X0700 |
BANKCON1 | 0X48000008 | R/W | BANKCON1控制寄存器 | 0X0700 |
BANKCON2 | 0X4800000C | R/W | BANKCON2控制寄存器 | 0X0700 |
BANKCON3 | 0X48000010 | R/W | BANKCON3控制寄存器 | 0X0700 |
BANKCON4 | 0X48000014 | R/W | BANKCON4控制寄存器 | 0X0700 |
BANKCON5 | 0X48000018 | R/W | BANKCON5控制寄存器 | 0X0700 |
0X0700 0000 0111 0000 0000 Tacc [10:8]=111
总线控制寄存器 BANKCON0~BANKCON5的各位描述如下:
BANKCONn | 位 | 描述 | 初始值 |
Tacs | [14:13] | 在nGCSn起效前,地址信号的建立时间。
00:0 clock;01:1 clock;
10:2 clocks;11:4 clocks | 00 |
Tcos | [12:11] | 在nOE起效之前,片选的建立时间。
00:0 clock;01:1clock;
10:2 clocks;11:4 clocks | 00 |
Tacc | [10:8] | 访问周期
000:1 clock;001:2 clocks;
010:3 clocks;011:4 clocks
100:6 clock;101:8 clocks;
110:10 clocks;111:14 clocks | 111 |
Tcoh | [7:6] | nOE之后,片选的保持时间。
00:0 clock;01:1clock;
10:2 clocks;11:4 clocks | 00 |
BANKCONn | 位 | 描述 | 初始值 |
Tcah | [5:4] | nGCSn之后,地址信号的保持时间。
00:0 clock;01:1 clock;
10:2 clocks;11:4 clocks | 00 |
Tacp | [3:2] | Page模式的访问周期(在Page模式下)。00:2 clocks;01:3 clocks;
10:4 clocks;11:6 clocks | 00 |
PMC | [1:0] | Page模式配置。
00:正常(1 data);01:4 data;
10:8 data;11:16 data | 00 |
- Tacs:片选信号nGCSn起效前,地址信号建立时间
- Tcos:在nOE (或nWE)起效前,片选信号建立时间
- Tacc:访问周期
- Tcoh:nOE结束后(即电平升高),片选保持时间
- Tcah:nGCSn结束后(即电平升高),地址信号保持时间
- Tacp:Page模式的访问周期
- Tacs:片选信号nGCSn起效前,地址信号建立时间
- Tcos:在nOE(或nWE)起效前,片选信号建立时间
- Tacc:访问周期
- Tcoh:nWE结束后(即电平升高),片选保持时间
- Tcah:nGCSn结束后(即电平升高),地址信号保持时间
- Tacp:Page模式的访问周期
(3)BANK控制寄存器(BANKCONn:nGCS6~nGCS7)
BANK 控制寄存器 BANKCON6~BANKCON7的地址信息如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
BANKCON6 | 0X4800001C | R/W | BANK6控制寄存器 | 0X18008 |
BANKCON7 | 0X48000020 | R/W | BANK7控制寄存器 | 0X18008 |
各个位的具体描述如下:
BANKCONn | 位 | 描述 | 起始状态 |
MT | [16:15] | 决定BANK6和BANK7的存储器类型。
00:ROM或SRAM;01:保留
10:保留;11:Sync.DRAM | 11 |
存储器类型=ROM或SRAM[MT=00](15位)
BANKCONn | 位 | 描述 | 起始状态 |
Tacs | [14:13] | nGCSn起效之前,地址信号的建立时间
00:0 clock; 01:1 clock
10:2 clocks; 11:4 clocks | 00 |
Tcos | [12:11] | nOE起效之前,地址信号的建立时间
00:0 clock; 01:1 clock
10:2 clocks; 11:4 clocks | 00 |
Tacc | [10:8] | 访问时间
000:1 clock; 001:2 clocks;
010:3 clocks; 011:4 clocks
100:6 clocks; 101:8 clocks | 111 |
Tcoh | [7:6] | nOE之后,片选的保持时间
00:0 clock; 01:1 clock
10:2 clocks; 11:4 clocks | 00 |
Tcah | [5:4] | nGCSn之后,地址信号保持时间
00:0 clock; 01:1 clock
10:2 clocks; 11:4 clocks | 00 |
存储器类型=ROM或SRAM[MT=00](15位)
BANKCONn | 位 | 描述 | 起始状态 |
Tacp | [3:2] | Page模式下的访问周期
00:2 clocks; 01:3 clocks
10:4 clocks; 11:6 clocks | 00 |
PMC | [1:0] | Page模式配置
00:正常(1 data); 01:4数据连续访问
10:8数据连续访问; 11:16数据连续访问 | 00 |
存储器类型=SDRAM[MT=11](4位)
BANKCONn | 位 | 描述 | 起始状态 |
Trcd | [3:2] | RAS到CAS延迟
00:2 clocks; 01:3 clocks;10:4 clocks | 10 |
SCAN | [1:0] | 列地址位数
00:8位; 01:9位;10:10位 | 00 |
(4)SDRAM刷新控制寄存器
刷新控制寄存器的地址信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
刷新 | 0X48000024 | R/W | SDRAM刷新控制寄存器 | 0XAC0000 |
它的设置决定了 SDRAM的刷新 是否允许、刷新模式、RAS预充电的时间、RAS和CAS最短时间、CAS保持时间 以及 刷新计数值,各位的描述如下所示:
刷新 | 位 | 描述 | 起始状态 |
REFEN | [23] | SDRAM刷新使能,0:停止;1:使能 | 1 |
TREFMD | [22] | SDRAM刷新模式
0:自动刷新;1:自我刷新(在自我刷新模式下),SDRAM控制信号被置于适当的电平 | 0 |
Trp | [21:20] | SDRAM RAS预充电时间,00:2 clocks;01:3 clocks;10:4 clocks;11:不支持 | 10 |
Tsrc | [19:18] | SDRAM半行周期时间。
00:4 clocks;01:5 clocks;10:6 clocks;11:7 clocks;
SDRAM运行周期时间(Trc)=Tsrc+Trp,如果Trp=3 clocks和Tsrc=7 clocks,Trc=10 clocks | 11 |
Reserved | [17:16] | 不使用 | 00 |
Reserved | [15:11] | 不使用 | 0000 |
Refresh Counter | [10:0] | SDRAM刷新计数器值,刷新时间=(211-刷新计数值+1)/HCLK。如果刷新时间是15.6us,HCLK是60MHZ,刷新计数器值计算如下:
刷新计数值 = 211 - 60*15.6 + 1 | 0 |
自动刷新(Auto Refresh,简称 AR)与自我刷新(Self Refresh,简称 SR),对应 DRAM的 两种 工作状态,自动刷新,用于 正常 工作的 状态,处理器 芯片 自动产生 行地址,用于刷新。
自我刷新,SR 则 主要 用于 休眠模式 低功耗 状态下 的 数据 保存,此时 不再 依靠 系统时钟 工作,而是 根据 内部的 时钟 进行 刷新 操作。在 SR 期间 除了 CKE 之外 的 所有 外部信号 都是 无效的,该状态下,无需 外部 提供 刷新 指令,只有 重新 使 CKE 有效 ,才能 退出 自刷新模式 并 进入 正常 操作 状态。 自刷新 时 CKE为 低, 自动刷新 时 CKE 为高。
(5)BANKSIZE寄存器
BANKSIZE 寄存器是控制 BANK 大小的寄存器,主要是决定 BANK6/7 的存储区域的空间大小。BANKSIZE 寄存器的地址信息如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
BANKSIZE | 0X48000028 | R/W | 可灵活设置的BANK尺寸寄存器 | 0X0 |
BANKSIZE | 位 | 描述 | 起始状态 |
BURST_EN | [7] | ARM内核猝发操作使能
0:禁止;1:使能 | 0 |
Reserved | [6] | 不使用 | 0 |
SCKE_EN | [5] | SCKE使能控制(是否进入省电模式)
0:SDRAM SCKE禁止;1:SDRAM SCKE使能 | 0 |
SCLK_EN | [4] | 只有在SDRAM访问周期期间,SCLK才使能,这样做是可以减少功耗。当SDRAM不被访问时,SCLK变成低电平。
0:SCLK总是激活;
1:SCLK只有在访问期间(推荐的)激活,推荐设置为1 | 0 |
Reserved | [3] | 不使用 | 0 |
BK76MAP | [2:0] | BANK6/7的存储空间分布,
010:128MB/128MB;001:64MB/64MB;
000:32MB32MB;111:16MB/16MB;110:8MB/8MB;101:4MB/4MB;100:2MB/2MB | 010 |
猝[cù]
4、猝发读 允许 DRMA中的 一行 被 激活后,连续 读出 若干 个 数据。第一个 数据 在 经过 指定的 CAS延时 节拍 后 呈现 在 数据线 上,以后 每个 时钟 节拍 都会 读出 一个 新的 数据。
5、猝发写 与 猝发读 类似,允许 DRMA中的 一行 被 激活后,连续 写入 若干 个 数据。第一个 写数据 与 猝发写 命令 同时在 数据线上 给出,以后 每个 时钟节拍 给出 一个 新的 数据。
SCKE_EN[5]:SDRAM 片内 时钟 允许 信号(就是 前面说的 CKE 信号),0 =不使用 SCKE信号, 1 =使用 SCKE 信号,使得 SDRAM 进入 省电模式。(书上的有错)
SCLK_EN[4]: 0 =时刻发出SCLK信号, 1 =仅在访问SDRAM期间发出SCLK信号;
(6)SDRAM模式寄存器集寄存器(MRSR)
SDRAM模式寄存器集寄存器的地址信息描述如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
MRSRB6 | 0X4800002C | R/W | 模式寄存器集BANK6寄存器 | X |
MRSRB7 | 0X48000030 | R/W | 模式寄存器集BANK7寄存器 | X |
MRSR | 位 | 描述 | 起始状态 |
Reserved | [11:10] | 不使用 | - |
WBL | [9] | 猝发写的长度
0:猝发(固定的)
1:保留 | X |
TM | [8:7] | 测试模式
00:模式寄存器集(固定的)
01、10、11:保留 | X |
CL | [6:4] | CAS(列地址通选)反应时间
000:1 clock;010:2 clocks
011:3 clocks;其他:保留 | X |
BT | [3] | 猝发类型
0:连续的(固定)
1:保留 | X |
BL | [2:0] | 猝发时间
000:1(固定的)
其他:保留 | X |
CAS信号(Column Address Strobe,列地址信号) CAS反应时间: 列地址信号激活,需要的时间。
这个寄存器的 个段 基本都是固定值,没得选,除了 CL字段
注意:当代码在 SDRAM 中运行时,绝不能够重新配置 MRSR 寄存器。
重要说明:在掉电模式下, SDRAM 必须进入 SDRAM 的自我刷新模式。
这么一大堆寄存器,有什么用?对这些寄存器的操作,在什么时候做?
这 一堆 寄存器,有 很大 一部分,是在 系统 初始化的 时候,需要 进行 设置和 控制的,比如 BANK 控制寄存器 ,这个 设置 各个 控制信号 间的 时序 关系:这类 寄存器,在 系统 工作 期间,是没有必要更改的。当然针对不同的存储芯片,这些设置的值,可能不同。
- Tacs:片选信号nGCSn起效前,地址信号建立时间
- Tcos:在nOE起效前,片选信号建立时间
- Tacc:访问周期
- Tcoh:nOE结束后(即电平升高),片选保持时间
- Tcah:nGCSn结束后(即电平升高),地址信号保持时间
- Tacp:Page模式的访问周期
5.3 NAND FLASH控制器
由于 NOR Flash 价格较高,而 SDRAM 和 NAND Flash 存储器相对经济,这样促使一些用户在 NAND Flash 上存储启动代码,在 SDRAM 上执行主程序。
在 NAND Flash 上存储启动代码,在 SDRAM 上执行主程序。 这个就类似我们的电脑,程序是存放在硬盘中,运行时,才调入内容中执行。
注:代码不能直接在NAND Flash 中执行。 SDRAM一般从 0x30000000开始!
“Steppingstone” 垫脚石。 就是 前面 讲 的bootram
S3C2440A 的驱动代码可以在执行在存储在外部的NAND Flash 存储器上的代码。为了支持NAND Flash 的 boot loader,S3C2440A 配备了一个内部的 SRAM 缓冲器名为 “Steppingstone”(bootram)。
启动时,NAND Flash 上的前 4KByte 字节 将被装载到 Steppingstone 中,并且装载到 Steppingstone 上的启动代码会被执行。
一般情况下,启动代码会拷贝 NAND Flash 上的内容到 SDRAM 中,在引导代码执行完毕后就跳转到 SDRAM 执行。使用硬件的 ECC(纠错码)对 NAND Flash 的数据进行有效性检查。在完成拷贝的基础上,主程序将在 SDRAM 上被执行。
自动启动:启动代码在重启时被传输到 4kbytes 的 Steppingstone 上。传输后代码会在 Steppingstone 上被执行;
5.4 时钟和功率管理
时钟和功率管理模块由 三部分 组成:时钟控制、USB控制 和 功率控制。
S3C2440 的时钟控制逻辑能够产生系统所需要的时钟,包括:CPU的FCLK、AHB总线接口的HCLK 和 APB总线接口的PCLK。
S3C2440 有两个PLL(锁相环),一个用于FCLK、HCLK、PCLK;另一个用于USB模块(48MHZ)。时钟控制逻辑能够由软件控制不将 PLL 连接到各接口模块以降低处理器时钟频率,从而降低功耗。
S3C2440 有各种针对不同任务提供的最佳功率管理策略,功率管理模块能够使系统工作在如下四种模式:正常模式、低速模式、空闲模式 和 掉电模式。
(1)正常模式
功率管理模块向 CPU 和 所有外部设备提供时钟。这种模式下,当所有外设都开启时,系统功率将达到 最大。用户可以通过 软件 控制各种外设的开关。
(2)低速模式
没有PLL的模式。与正常模式不同,低速模式 直接使用外部时钟(XTIpll或者EXTCLK)作为FCLK,这种模式下,功率仅由外部时钟决定。
(3)空闲模式
功率管理模块 仅关掉FCLK,而继续提供时钟给其他外设。空闲模式可以 减少由于CPU核心产生的功耗。任何中断请求都可以将CPU从中断模式唤醒。
(4)掉电模式
功率管理模块断开内部电源,因此 CPU 和 除唤醒逻辑单元以外的外设 都不会产生功耗。要执行掉电模式需要有两个独立的电源,其中一个给唤醒逻辑单元供电,另一个给包括CPU在内的其他模块供电。在掉电模式下,第二个电源将被关掉。掉电模式可以由外设中断EINT[15:0]或RTC唤醒。
5.4.1 时钟和功率管理功能描述
(1) 时钟发生器
时钟发生器功能框图如下:
(2) 时钟源选择
控制引脚(OM3和OM2)的组合模式与 S3C2440 时钟源选择关系如下表所示。引脚 OM[3:2] 的状态在 nRESET 上升沿通过控制引脚 OM3 和 OM2 被锁定。
模式OM[3:2] | MPLL状态 | UPLL状态 | 主时钟源 | USB时钟源 |
00 | on | on | 晶振 | 晶振 |
01 | on | on | 晶振 | 外部时钟 |
10 | on | on | 外部时钟 | 晶振 |
11 | on | on | 外部时钟 | 外部时钟 |
OM[3:2]=00 使用晶振,没有用 外部时钟。 主时钟 和 USB 时钟 都 使用 晶振。 这个 情况 下 使用 XTIpll 和 XTOpll 引脚 连接 晶振,产生时钟 频率。外部时钟 引脚 接 VDD
OM[3:2]=11 没有 使用 晶振 ,主时钟 和 USB 时钟 都 使用 外部时钟。XTIpll 和 XTOpll 一个 接 VDD , 输出 引脚 不接,悬空。
(3) 锁相环PLL
S3C2440上的 时钟源 是 12MHz,如果 想让 CPU 工作在 更高 频率 上,就 需要 通过 PLL(锁相环)来 提高 主频。S3C2440 上的 PLL 有 两个 锁相环,一个 是 MPLL(主PLL),它是 用来 产生 FCLK、HCLK、PCLK 的 高频 工作 时钟;还有 一种 是 UPLL,用来 为 USB 提供 工作 频率。
晶振 由于 其 频率的 稳定性,一般 作为 系统的 外部 时钟源。晶振的 频率 虽然 稳定,但是,由于 成本 与 工艺 限制,频率 无法 做到 很高,因此 芯片中 高频时钟 就 需要 一种 叫做 压控振荡器 的 器件 生成了,顾名思义,VCO 就是 根据 电压 来 调整 输出 频率。可 压控振荡器 也有 问题,其 频率 不够 稳定,因此,为了 将 频率 锁定在 一个 固定的 期望值,使用 了 锁相环 。
- 相位 频率 探测器(鉴相鉴频器PFD):对输入的 基准信号(来自 频率 稳定的 晶振)和反馈 回路的 信号 进行 频率的 比较,输出 一个 代表 两者 差异的 电压 信号。
- 充电泵:把相鉴频器PFD 输出的 电压信号 进行 等比例的 转换,也 就是 根据 需要 对其 按比例 进行 放大 或 缩小。
- 回环 滤波器(低通 滤波器 LPF)(Low-Pass Filter):将PFD 中 生成的 差异 信号的 高频 成分 滤除,保留 直流 部分
- 压控振荡器VCO(Voltage Controlled Oscillator):根据 输入 电压,输出 对应 频率的 周期 信号。
- 反馈回路FL(Feedback Loop):通常 由一个 分频器 实现。将 VCO的 输出 降低到 与 基准 信号 相同级别的 频率 才能在 PFD中 比较
PLL工作的基本原理就是将压控振荡器的输出经过分频后与基准信号输入PFD,PFD通过比较这两个信号的频率差,输出一个代表两者差异的信号,再经过低通滤波器转变成一个直流脉冲电压去控制VCO使它的频率改变。这样经过一个很短的时间,VCO的输出就会稳定下来。所以:
- PLL并不是直接对晶振进行倍频,而是将频率稳定的晶振作为基准信号,与PLL内部振荡电路生成的信号分频后进行比较,使PLL输出的信号频率稳定
最后,根据原理,理解一下锁相环(Phase Locked Loop)的名称
- 为了对基准信号与反馈信号进行频率比较,二者的相位必须相同且锁住,任何时间都不能改变,这样才能方便的比较频率,所以叫锁相(Phase Locked)
- 为了快速稳定输出系统,整个系统加入反馈成为闭环,所以叫环(Loop)
以下部分描述了PLL的运行,包括鉴相器、电荷泵、环路滤波器和压控振荡器(VCO)。
(1)鉴相器
鉴相器(PFD)检测Fref和Fvco之间的相位差,并在检测到相位差时产生一个控制信号(跟踪信号)。 Fref意思为参考频率,如图所示。
(2)电荷泵
电荷泵(PUMP)将PFD控制信号转换为一个按比例变化的电压并通过外部滤波器来驱动VCO。
(3)环路滤波器
PFD产生用于电荷泵的控制信号,在每次Fvco与Fref比较时可能产生很大的偏差(纹波)。为了避免VCO过载,使用低通滤波器采样并且滤除控制信号的高频分量。环路滤波器是一个典型由一个电阻和一个电容组成的单极性RC滤波器。
(4)压控振荡器
VCO工作原理是从环路滤波器的输出电压驱动VCO,引起其振荡频率线性增大或减小,如同均匀变化电压的功能。当Fvco与Fref频率和相位都在限期内相匹配时, PFD停止发送控制信号给电荷泵,并转变为稳定输入电压给环路滤波器。 VCO频率保持恒定, PLL则保持固定为系统时钟。
频率计算公式
Mpll = (2 * m * Fin)/(p * )
m = M(分频器M的分频值) + 8
p = P(分频器P的分频值) + 2
S3C2440上的 时钟源 是 12MHz,开发板上常用的设置为 m=75(0x4B),p=3,s=1
则 Mpll =(27512)/(3*21) =300M
(4)时钟控制逻辑
时钟控制逻辑决定使用 哪个 时钟源,例如是 PLL时钟 还是直接的 外部时钟(XTIpll或者EXTCLK)。当 PLL 被配置为 一个新的频率值时,时钟控制逻辑在 PLL输出稳定之前 禁止 FCLK ,直到 PLL锁定系统时钟后 取消禁止。时钟控制逻辑同时在 开电源重启时 和 从掉电模式唤醒时起作用。
①加电重启
上电重启的次序图如下:
从 时序图 中,我们 可以 看到,上电 之后,如果 什么 都 不设置,FCLK 和 晶振的 频率 相等,也就是 它 直接 使用的 是 外部晶振 的 时钟,没有 经过 PLL 做 倍频 处理,这个时候VCO是没有工作的,其波形前端 是 直线。当设置PLL后,CPU并不是马上就使用设置好的高频时钟,而是有一段锁定时间,在这段时间里,CPU停止运行,等12MHz变成高频时钟稳定以后,整个系统再重新运行。
latch[lætʃ]用插销插上;用碰锁锁上
②在普通操作模式下改变 PLL 设置
通过设置 P、M、S 的值改变低速时钟时序图如下:
在 Normal 模式下的 s3c2440 操作中,用户可以改变频率通过写 P M S 三个分频器的值,在 PLL 锁存时间会被自动的插入。在锁定时间,时钟没有被提供给 s3c2440A 的内部时
钟。图 7-5 所示的时序图。 这个示例,是把一个高速时钟的频率降低,变为低速时钟,以节约功耗。
(5)USB模块控制
USB主接口 和 USB驱动接口 需要 48MHZ 的时钟。在 S3C2440 中,UPLL(USB dedicated PLL) 为 USB 产生 48MHZ 的时钟。在 UPLL 没有被设置之前 UCLK 不产生。对应于不同条件下的 UCLK 和 UPLL 状态如下表所示:
条件 | UCLK状态 | UPLL状态 |
重启之后 | XTIpll或者EXTCLK | On |
UPLL配置之后 | 低电平:PLL锁定时间
48MHZ:PLL锁定时间之后 | On |
CLKSLOW寄存器关掉UPLL | XTIpll或者EXTCLK | Off |
CLKSLOW寄存器打开UPLL | 48MHZ | 0n |
USB主接口 和 USB驱动接口 需要 48MHZ 的时钟。在 S3C2440 中,UPLL(USB dedicated PLL USB专用PLL) 为 USB 产生 48MHZ 的时钟。在 UPLL 没有 被设置 之前 UCLK 不产生(也就是,系统 启动后,如果 不对 UPLL 进行 设置, UPLL 是 不会 工作的 )。对应于 不同 条件下的 UCLK 和 UPLL 状态 如下表 所示:
UPLL(USB PLL),用来为 USB 提供 工作频率, UCLK,就是 USB 所需的 48MHz的 时钟 信号。
重启之后:UCLK 没有 产生 48MHz的 信号,直接 使用的 是 XTIpll(外部晶振)或者 EXTCLK(外部时钟),但是 其 状态位 是on,是 打开的。
UPLL配置之后,则UPLL处于锁定期,这期间,UCLK没有时钟信号输出,一直处于低电平状体。
CLKSLOW:低速时钟控制寄存器 其中 包含 相关的 控制位( UCLK_ON),可以 控制 UPLL 是打开 还是 关闭的。
(6)FCLK、HCLK 和 PCLK
①FCLK信号是ARM920T内核使用的时钟信号;
②HCLK信号是AHB总线的时钟信号,在ARM920T内核、存储控制器、中断控制器、LCD控制器、DMA和USB主模块使用;
③PCLK信号是APB总线的时钟信号,在外部设备中使用,如WDT、IIS、C、PWM定时器、MMC接口、ADC、UART、GPIO、RTC和SPI。
S3C2440 在 FCLK、HCLK 和 PCLK之间可以选择划分比率。比率由
CLKDIVN
控制寄存器的 HDIVN 和 PDIVN 决定,具体如下表所示:HDIVN
[2:1] | PDIVN
[0] | HCLK3_HALF/HCLK4_HALF | FCLK | HCLK | PCLK | 划分比率 |
0 | 0 | - | FCLK | FCLK | FCLK | 1:1:1(缺省) |
0 | 1 | - | FCLK | FCLK | FCLK/2 | 1:1:2 |
1 | 0 | - | FCLK | FCLK/2 | FCLK/2 | 1:2:2 |
1 | 1 | - | FCLK | FCLK/2 | FCLK/4 | 1:2:4 |
3 | 0 | 0/0 | FCLK | FCLK/3 | FCLK/3 | 1:3:3 |
3 | 1 | 0/0 | FCLK | FCLK/3 | FCLK/6 | 1:3:6 |
3 | 0 | 1/0 | FCLK | FCLK/6 | FCLK/6 | 1:6:6 |
3 | 1 | 1/0 | FCLK | FCLK/6 | FCLK/12 | 1:6:12 |
2 | 0 | 0/0 | FCLK | FCLK/4 | FCLK/4 | 1:4:4 |
2 | 1 | 0/0 | FCLK | FCLK/4 | FCLK/8 | 1:4:8 |
2 | 0 | 0/1 | FCLK | FCLK/8 | FCLK/8 | 1:8:8 |
2 | 1 | 0/1 | FCLK | FCLK/8 | FCLK/16 | 1:8:16 |
这张 表 就表示 FCLK、HCLK 和 PCLK之间 可以 选择的 频率 划分 比率。 HDIVN|[2:1] 共2位 PDIVN[0]只有一位
这两个是 时钟除数控制寄存器(CLKDIVN)中的两位。
division[dɪˈvɪʒn]分开;分隔;
CAMDIVN(CAMERA CLOCK DIVIDER REGISTER)摄像头时钟分频器寄存器,HCLK4_HALF,HCLK3_HALF这这个寄存器的2位
HCLK3_HALF,在CLKDIVN[2:1]=3的时候起作用, HCLK3_HALF,在CLKDIVN[2:1]=2的时候起作用,
通过这张表,大家也可以看出:HCLK和PCLK主要是通过对FCLK分频得到。也就是MPLL(主锁相环)输出的时钟,经过分频后就可以得到不同的时钟,正常情况下,FCLK的频率就是=MPLL的输出频率。
HCLK4_HALF [9] HDIVN分频比率改变位,当CLKDIVN[2:1]=10b. 0: HCLK = FCLK/4 1: HCLK= FCLK/8
HCLK4_HALF[8] HDIVN分频比率改变位,当CLKDIVN[2:1]=11b. 0: HCLK = FCLK/3 1: HCLK= FCLK/6
在设定 P、M、S 的值之后,需要设定 CLKDIVN 寄存器的值,其会在 PLL 锁定的时间后有效,当然在重启和改变电源管理模式之后也可以使用。
注释:
设定 PMS 就是 设置 好 PLL的 三个 分频器 的值。 也就是 确定 了 PLL 输出 的 频率。然后,还需要 设定 CLKDIVN 时钟分频控制寄存器 ,确定 FCLK、HCLK、PCLK 的 频率比,当然,如果 不设置,则 缺省 为1:1:1
(7)功率管理
功率管理模块通过软件来控制系统模式,以降低 S3C2440 的功耗。这些方案 与 PLL、时钟控制逻辑 和 唤醒信号有关。
S3C2440 有 4种 电源模式,在模式之间的切换 不是没有限制地允许的,有效的模式切换如下图所示:
不同电源模式下的时钟电源管理:
模式 | ARM920T | AHB 模块/WDT | 电源管理 | GPIO | 32.768KHZ RTC时钟 | APB 模块&
USBH/LCD/NAND |
NORMAL | ○ | ○ | ○ | SEL | ○ | SEL |
IDLE | ╳ | ○ | ○ | SEL | ○ | SEL |
SLOW | ○ | ○ | ○ | SEL | ○ | SEL |
POWER_OFF | OFF | OFF | 等待唤醒事件 | 原状态 | ○ | SEL |
SEL:○或╳; ○:使能; ╳:禁止;OFF:电源关断。
①正常模式
在正常模式下,所有的外设 和 基本模块,包括:电源管理模块、CPU核、总线控制器、寄存器控制器、中断控制器和DMA,都能完全正常工作。但是,除基本模块外,可以通过软件设置对每一个外设时钟进行选择性的停止,以降低功耗。
②空闲模式
在空闲模式下,仅停止 为 CPU 提供时钟信号,只对:总线控制器、存储器控制器 和 电源管理模式等外设提供时钟。如果要退出空闲模式,则 EINT[23:0] 或者 RTC 告警中断,或者其他的中断必须处于活动状态(如果想使用 EINT ,则 GPIO 模块在启动前必须是开启的)。
注:因为用于唤醒的外部中断引脚和GPIO引脚是复用的,可以通过配置设置为:输入、输出或 外中断模式。 因此,如果使用 EINT ,则在开启空闲模式前,必须设置为 EINT,外中断模式。
③低速模式
低速模式是 非PLL模式。与正常模式不同的是:低速模式没有通过 PLL电路 。而是直接使用了 一个外部时钟(ETIpll或者EXTCLK)作为 FCLK 信号。在此模式中,电源的功耗仅取决于外部时钟的频率,将 PLL 自身的耗电排除在外。
前面,说过,FCLK在 Nomal(正常模式)下,FCLK就=MPLL(主锁相环)的 输出 时钟。在 低速模式 下,FCLK 就是 输入 时钟信号(input clock)除以 分频值,得到。
在低速模式,可以通过 一个低速模式 和把 PLL 自身的耗电量 排除在外来降低电源损耗。FCLK 是没有 PLL 时,将 FinN 等分后的频率。分割的比率是由 CLKSLOW 和 CLKDIVN 控制寄存器中的 SLOW_VAL 决定的。下表列出了 SLOW模式下 CLKSLOW 和 CLKDIVN 控制寄存器的设置。
FinN,就是 输入 时钟源,该 时钟源,也 作为 PPL 的基准 时钟信号。
CLKSLOW 和 CLKDIVN
低速时钟控制寄存器(CLKSLOW)
CLKDIVN 时钟分频控制寄存器
SLOW_VAL | FCLK | HCLK | ㅤ | PCLK | ㅤ | UCLK |
ㅤ | ㅤ | 1/1 Option
(HDIVN=00) | 1/2 Option
(HDIVN=01) | 1/1 Option
(PDIVN=0) | 1/2 Option
(PDIVN=1) | ㅤ |
000 | EXTCLK或
XTIpll/1 | EXTCLK或
XTIpll/1 | EXTCLK或
XTIpll/2 | HCLK | HCLK/2 | 48MHZ |
001 | EXTCLK或
XTIpll/2 | EXTCLK或
XTIpll/2 | EXTCLK或
XTIpll/4 | HCLK | HCLK/2 | 48MHZ |
010 | EXTCLK或
XTIpll/4 | EXTCLK或
XTIpll/4 | EXTCLK或
XTIpll/8 | HCLK | HCLK/2 | 48MHZ |
011 | EXTCLK或
XTIpll/6 | EXTCLK或
XTIpll/6 | EXTCLK或
XTIpll/12 | HCLK | HCLK/2 | 48MHZ |
100 | EXTCLK或
XTIpll/8 | EXTCLK或
XTIpll/8 | EXTCLK或
XTIpll/16 | HCLK | HCLK/2 | 48MHZ |
这张表,表示的 是,通过 设置,我们 可以 按 EXTCLK 或 XTIpll 时钟 的 什么 比例 进行 分频。
SLOW_VAL [2:0] 当 SLOW_BIT 位 开启,即 开启 低速模式 时,这几位 表示 低速 时钟的 分频值 FCLK 是 外部时钟源 的 分频
时钟分频器控制寄存器 CLOCK DIVIDER CONTROL REGISTER (CLKDIVN)
PDIVN [0] 0: PCLK 是和HCLK/1 相同的时钟。 1: PCLK 是和HCLK/2 相同的时钟。 这个是PCLK 对 HCLK的分频关系
HDIVN [2:1] 00: HCLK = FCLK/1. 01: HCLK = FCLK/2. 这个是 HCLK 对 FCLK 的分频关系
10: HCLK = FCLK/4,当 CAMDIVN[9] = 0.
HCLK = FCLK/8,当 CAMDIVN[9] = 1.
11: HCLK = FCLK/3,当 CAMDIVN[8] = 0.
HCLK = FCLK/6,当 CAMDIVN[8] = 1.
④掉电模式
断开内部电源,所以 CPU 和 内部逻辑 没有电源消耗,除了在此模式下唤醒的逻辑。激活掉电模式需要 两个独立的电源,一个为唤醒逻辑供电,另一个为其它的内部逻辑包括CPU供电,并且可以被电源开关控制。在掉电模式下,为 CPU 和 内部逻辑供电的第二个电源将被关掉。退出掉电模式,可以通过 EINT[15:0] 或者 RTC 告警中断发出。
5.5DMA
S3C2440 拥有 4个通道 的 DMA 控制器,相连于 系统总线 和 外围总线。DMA控制器 的每一个通道可以在:系统总线上的存储器与外围总线之间、系统总线上的设备之间,以及外围总线设备之间操作数据传输而不被限制。
DMA (直接 存储器 访问),DMA方式 直接 依靠 硬件 控制 主存与 I/O设备 之间的 数据 传送,传送期间 不需要 CPU干预。主要 用于 主存与 高速外设 之间的 数据 传输;比如 实时音频、视频 采集 等、S3C2440 拥有 4个通道 的 DMA 控制器,相连于 系统总线 和 外围总线。DMA控制器 的每一个通道可以在:系统总线上的存储器与外围总线之间、系统总线上的设备之间,以及外围总线之间操作数据传输而不被限制。
S3C2440 的 DMA 在以下 四种情况 可运行:
(1)源设备和目标都在系统总线AHB上;
(2)源设备和目标都在外围总线APB上;
(3)源设备在系统总线,而目标设备位于外围总线;
(4)源设备在外围总线,而目标设备位于系统总线。
DMA的主要优点是:可以不通过 CPU 的中断来实现数据的传输,DMA 的运行可以通过软件或者通过外围设备的中断和请求来初始化。
上面的方框中,是920T,内部包含ARM9TDMICoprocessor[ˈkoʊˈprɑsɛsər] 协处理器 Coproc是协处理器简写。 Extenal Copoc Interface是扩展协处理器接口。CP15为CACHE和MMU功能提供的系统控制协处理器回写存储单元(Write Back PA TAG RAM)ICE(In Circuit Emulator)在线仿真器的缩写。在基于IP”复用的”SoC设计中,片上总线”的设计”是最关键”的问题。为此,业界”出现了”很多”片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。 AMBA已不仅是一种总线,更是一种带有接口模块的互连体系。AMBA 2.0规范包括四个部分:AHB、ASB、APB和Test Methodology [ˌmeθəˈdɑːlədʒi]测试方法!
(1)DMA的服务对象
每个 DMA通道 都有 多个DMA请求源 ,通过设置,可以从中挑选一个服务。每个通道的 DMA 请求源如下表所示:
这里 nXDREQ0 和 nXDREQ1 表示两个外部源(外部设备),I2SSDO 和 I2SSDI 分别表示 IIS 传输和接收。
(2)DMA的工作过程
①外设向DMA发出请求
②DMA通过HOLD向CPU发出总线请求
③CPU响应释放三总线,并且发应答HLDA
④DMA向外设发DMA应答
⑤DMA发出地址、控制信号,为外设传送数据
5.5.2 DMA工作原理
传送完规定的数据后,DMA 撤销 HOLD 信号,CPU 也撤销 HLDA 信号,并且恢复对三条总线的控制。
S3C2440 的 DMA 工作过程可以分为以下 三个状态:
①状态1——等待状态
DMA 等待一个 DMA请求。如果有请求到来,将转移到 状态2。在这个状态下,DMA ACK 和 INT REQ 为 0。
②状态2——准备状态
DMA ACK 变为 1,计数器(CURR_TC)从 DCON[19:0] 寄存器装载计数值。注意:DMA ACK保持为 1 直到它被清除。
③状态3——传输状态
DMA 控制器从 源地址 读入数据并将它写到 目的地址,每传输 一次,CURR_TC 计数器减1,并且可能做以下操作:
A.重复传输:在全服务模式下,将重复传输,直到计数器 CURR_TC变为0;在单服务模式下,仅传输一次;
B.设置中断请求信号:当 CURR_TC 变为 0 时,而且 DCON[29] 即中断使能设定位被设为 1 ,则DMAC(DMA控制器) 发出 INT REQ 信号;
C.清除 DMA ACK 信号:
全服务模式 CURR_TC 变为 0。
对单服务模式,执行完该次传输操作。
注意:在单服务模式下,DMAC 的三个状态(等待、准备和传输)被执行一遍,然后停止,等待下一个 DMA REQ 的到来。如果 DMA REQ 到来,则这些状态被重复操作,直到 CURR_TC 减为 0。
不管服务模式如何,一旦计数器(CURR_TC)变成 0,中断请求信号 INT REQ 发出。
在 单服务模式 下,DMAC 的 三个 状态 被 执行 一遍,然后 停止,等待 下一个 DMA REQ (请求)的到来。如果 DMA REQ 到来,则 这些 状态 被重复 操作,直到 CURR_TC 减为 0。因此,单次传输 过程(有些资料 也称为 原子过程,即表示 是 不可 分割的 一个 过程)中 DMA ACK 总是 先 有效 再 无效。相反,在 全服务模式 中,主状态机 一直在状态 3 (也就是 传输 状态)等待,直到 计数器(CURR_TC)变成 0。所以 DMA ACK 在 这个 传输过程 中 有效,然后 当计数器(CURR_TC)为 0 时 ,才 无效。
(3)外部DMA请求/响应协议
DMA有 三种类型 的 外部DMA请求/响应 规则:
①single service demand,单服务请求(对应于需求模式);
②single service handshake,单服务握手(握手模式);
③whole service handshake,全服务握手(全服务模式)。
每种类型都定义了像DMA请求和DMA响应这些信号怎样与这些规则相联系。
请求/握手(demand与handshake)模式的比较如下:
在一次传输结束时,DMA检查xnxDREQ(DMA请求)信号的状态。
A.在需求模式下:如果DMA请求(xnxDREQ)信号仍然有效,则传输马上再次开始,否则等待;
B.在握手模式下:如果 DMA 请求信号无效,DMA 在2个时钟周期后将 DMA 响应(xnxDACK)信号变得无效,否则 DMA 等待直到 DMA 请求信号变得无效,每请求一次传输一次。
在 握手模式 下:如果 DMA 请求信号 无效,DMA 在 2个 时钟周期 后 将 DMA 响应信号(xnxDACK)变得 无效。但是,如果 一次 传送 结束,DMA的 请求信号 还是 有效的,那 DMA控制器,不会 进行 下一次 传送,而是 要 等待,直到 DMA 请求信号 变得 无效,然后,再把 DMA 响应信号 变为 无效。只有等 DMA 响应信号 变为 无效后,DMA请求源,才能 发出 下一次 请求。每请求 一次 传输 一次,也就是 每次 请求 和 响应 对,只能 进行 一次 传送。该次 请求、响应 信号 都无效 后,才能 根据 下一次的 请求 和 响应,进行 下一次 传送,因此 每次 请求,只能 传送 一次。不像 需求模式 下,只要 请求信号 存在,就可以 一直 传送。
5.6中断控制器
S3C2440X 中断控制器有 56个 中断源,对外提供 24个 外中断输入引脚,内部所有设备都有中断请求信号,例如:DMA控制器、UART、IIC等。
S3C2440X 的 ARM920T 内核有两个中断:IRQ中断 和 快速中断FIQ。
中断仲裁:当中断控制器接收到 多个中断请求时,其内的优先级仲裁器裁决后向 CPU 发出优先级最高的中断请求信号或快速中断请求信号。
5.6.1 中断控制器的操作
(1)当前程序状态寄存器(CPSR)的 F位 和 I位
CPSR 指 ARM920T 处理器的程序状态寄存器。如果 CPSR 的 F位 被设置为 1 ,处理器将不接受来自中断控制器的FIQ(快速中断请求);如果 PSR 的 I位 被设置为 1 ,处理器将不接受来自中断控制器的IRQ(中断请求)。因此,为了使能 FIQ 和 IRQ ,PSR 的 F位 或 I位 必须被 清零,同时中断屏蔽寄存器 INTMASK 的相应位也必须被 清0 。
I位 相当于 总开关,对于每个具体的 中断而言,还有相关的 屏蔽位 来 控制其 是否响应。
(2)中断模式
ARM920T 有两种类型的中断模式(INTMOD),即:FIQ(快速中断请求)和IRQ(普通中断模式)。所有的中断源在中断请求时都要确定使用哪一种中断模式。
(3)中断挂起寄存器
S3C2440 有两个中断挂起寄存器:源挂起寄存器(SRCPND) 和 中断挂起寄存器(INTPND)。这些挂起寄存器指示了一个中断请求是否被挂起。
当中断源请求中断服务时,SRCPND 相应位被置 1 。
并且同时在仲裁后 INTPND 寄存器 仅有1位被置1。
如果中断被屏蔽,那么 SRCPND 相应位被 置1,但并不能引起 INTPND 改变。
当 INTPND 的挂起位被设置时,只要相应的 标志位I 或 标志位F 被清0,相应的中断服务程序都被执行。SRCPND 和 INTPND 可以被读写。
在 允许 中断的 情况下,所执行的 操作。如果 相关中断 被 屏蔽了,则 该 中断源 提出 中断请求 后,SRCPND 相应 位 被 置1,但 由于 该中断 被屏蔽了 则 不会 引起 INTPND 改变。
SRCPND 和 INTPND 可以 被 读写,在 中断服务 程序 里,可以 通过 读取 INTPND 寄存器 来 判断 是 哪个 中断源 提出了 中断请求。所以 中断服务程序 中 必须 加入 对 SRCPND 相应位 清0 的 代码,以便 清除 对应 标志位 的 挂起 状态
(4)中断屏蔽寄存器(INTMSK)
如果该寄存器的某一个位被 置1 ,则该位对应的中断响应被 禁止 了;
如果某个中断在 INTMSK 寄存器的对应位 为0 ,则这个中断发生时将会正常被响应。
如果某个中断在 INTMSK 的寄存器中的对应位 为1,但是这个中断发生了,它的源挂起寄存器(SRCPND)对应位还是会 置1。而对应中断挂起寄存器(INTPND)标志位,不会被置1 。
5.6.2 S3C2440中断源
中断控制器提供 60 个 中断源,所以中断优先级非常重要。
(1)中断优先级仲裁器及工作原理
中断系统有 6个 分仲裁器 和 1个 总仲裁器,每一个仲裁器可以处理 6路 中断,优先级产生模块图如下:
如图,所示,系统 右边,是 6个 分 仲裁器,这 6个 分仲裁器,连接到左边的那个 总 仲裁器 上,因此 是 通过两级 仲裁 的方式,来 最终 确定 多个 中断源 的优先级。每个仲裁器,可以处理6路中断信号。但是大家看图,右边,最上面的 仲裁器 和 最下面 的仲裁器 都只 接入 了 4路信号。因此ARM 处理器 这种 仲裁方式,只对 32 路信号 进行了 优先级 仲裁。但是,我们刚才,提到 中断控制器提供 60个 中断源 的 管理。这个是如何 实现的?
原理 也很 简单,就是 S3C2440将 中断源 分为 两级: 中断源 和 子中断源, 中断源 就是 这32 个 中断源。而 这 32个中断源 中 包含 单一 中断源 和 复合中断源, 复合中断源 是 子中断源 的 复合 信号。如 实时 时钟 中断, 该硬件 只会 产生 一种 中断, 没有 子中断源, 它是 单一中 断源。而 复合中断源,则 包含 子中断源, 以 UART 串口 为例 ,S3C2440 可以 支持 3个 UART 串口,每个 串口 对应 一个 复合中断源 信号 INT_UARTn, 而 每个 串口 可以 产生 三种 中断, 也 就是 三个 子中断: 接收数据 中断、发送数据 中断、数据错误 中断,这 三个 子中断 信号 在 中断 源寄存器 复合 为 一个 中断 信号,三种 中断 任何 一个 产生 都会 将 中断 信号 传递给 对应 的 中断源INT_UARTn, 然后 通过 中断信号线 传递 给 ARM内核。这种 设计,使得 S3C2440 中断控制器 支持 60 个 中断源,
中断控制器提供60个中断源的管理。是如何实现的?
S3C2440将中断源分为两级: 中断源和子中断源(次级中断源):
- 中断源就是上图32个中断源。而这32个中断源中包含单一中断源和复合中断源。
- 复合中断源是子中断源(次级中断源)的复合信号。比如:INT_UARTn。
这种设计,使得S3C2440中断控制器支持60个中断源。
(2)中断优先级
每一个仲裁器可以控制 6个 中断请求,其基于由仲裁模式控制的 1位(ARB_MODE) 和 选择控制信号的2位(ARB_SEL)。
①如果ARB_SEL位为:00b,优先级次序为REQ0、REQ1、REQ2、REQ3、REQ4和REQ5;
②如果ARB_SEL位为:01b,优先级次序为REQ0、REQ2、REQ3、REQ4、REQ1和REQ5;
③如果ARB_SEL位为:10b,优先级次序为REQ0、REQ3、REQ4、REQ1、REQ2和REQ5;
④如果ARB_SEL位为:11b,优先级次序为REQ0、REQ4、REQ1、REQ2、REQ3和REQ5。
注意:仲裁器的 REQ0 为最高优先级,REQ5 为最低优先级;通过改变 ARB_SEL 位的值,可以设定 REQ1~REQ4 优先级。
- 这里,如果 ARB_MODE位 设置为 0 , ARB_SEL 位不会自动改变,仲裁器会在固定的优先级模式中操作(即使在这个模式中,也可以通过手动改变 ARB_SEL 位配置优先级)。
- 另一方面,如果 ARB_MODE 位设置为 1,ARB_SEL 位轮流改变。例如,如果 REQ1 被执行,为了把 REQ1 放在最低优先级,ARB_SEL 位会被自动改为 01b。 ARB_SEL 变化的详细规则如下:
①如果REQ0或者REQ5被执行,ARB_SEL不改变;
②如果REQ1被执行,ARB_SEL位改变为01b;
③如果REQ2被执行,ARB_SEL位改变为10b;
④如果REQ3被执行,ARB_SEL位改变为11b;
⑤如果REQ4被执行,ARB_SEL位改变为00b。
5.6.3 中断控制器的特殊功能寄存器
中断控制器中包括 5个 控制寄存器:源挂起寄存器、中断挂起寄存器、屏蔽寄存器、中断模式寄存器、优先级寄存器。
来自中断的中断请求首先寄存在 源挂起寄存器。它们基于中断模式寄存器分为 两组:FIQ中断请求 和 IRQ中断请求。对多重IRQ请求的仲裁过程使用优先级寄存器。
(1)源挂起寄存器
源挂起寄存器由 32位 组成,每一个比特位均与一个中断源相连。当中断源产生中断请求并且等待中断服务程序的执行时,其相应的比特位设置为 1 。
还有,源挂起寄存器指示此时哪一个中断源正在等待执行中断请求。注意: SRCPND 寄存器的各比特位均为 中断源自动设置,与屏蔽寄存器的相应位设置无关。
另外,SRCPND 寄存器不受中断控制寄存器的优先级逻辑的影响。
当中断服务被执行时,SRCPND 寄存器的相应位应该 及时清0,以便正确地接收相应中断源的中断请求。如果没有清除源挂起位,当中断服务返回时,中断控制寄存器会将之作为来自相同中断源的中断请求 第二次执行。也就是说,如果 SRCPND 寄存器的某位为 1,系统一般会当作一个有效的等待执行的中断请求。
清除相应位的时间依赖于用户的需求。如果要接收来自相同源的另一个有效中断请求,那么应该清除相应挂起位并且使能中断。
可以通过写入一个数据到此寄存器来清除SRCPND寄存器的指定位,这时只清除那些数据中被设置为1的相应位置的SRCPND位。那些数据中被设置为0的相应位置的位保持不变。
源挂起寄存器 SRCPND 的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
SRCPND | 0X4A000000 | R/W | 指示中断请求状态:
0:没有中断请求;
1:产生中断请求。 | 0 |
SRCPND 寄存器中各比特位的描述如下所示:
SRCPND | 位 | 描述 | 初始值 |
INT_ADC | [31] | 0:无请求;1:请求 | 0 |
INT_RTC | [30] | 0:无请求;1:请求 | 0 |
INT_SPI1 | [29] | 0:无请求;1:请求 | 0 |
INT_UART0 | [28] | 0:无请求;1:请求 | 0 |
INT_IIC | [27] | 0:无请求;1:请求 | 0 |
INT_USBH | [26] | 0:无请求;1:请求 | 0 |
INT_USBD | [25] | 0:无请求;1:请求 | 0 |
INT_NFCON | [24] | 0:无请求;1:请求 | 0 |
SRCPND | 位 | 描述 | 初始值 |
INT_UART1 | [23] | 0:无请求;1:请求 | 0 |
INT_SPI0 | [22] | 0:无请求;1:请求 | 0 |
INT_SDI | [21] | 0:无请求;1:请求 | 0 |
INT_DMA3 | [20] | 0:无请求;1:请求 | 0 |
INT_DMA2 | [19] | 0:无请求;1:请求 | 0 |
INT_DMA1 | [18] | 0:无请求;1:请求 | 0 |
INT_DMA0 | [17] | 0:无请求;1:请求 | 0 |
INT_LCD | [16] | 0:无请求;1:请求 | 0 |
INT_UART2 | [15] | 0:无请求;1:请求 | 0 |
INT_TIMER4 | [14] | 0:无请求;1:请求 | 0 |
INT_TIMER3 | [13] | 0:无请求;1:请求 | 0 |
INT_TIMER2 | [12] | 0:无请求;1:请求 | 0 |
INT_TIMER1 | [11] | 0:无请求;1:请求 | 0 |
INT_TIMER0 | [10] | 0:无请求;1:请求 | 0 |
INT_WDT | [9] | 0:无请求;1:请求 | 0 |
SRCPND | 位 | 描述 | 初始值 |
INT_TICK | [8] | 0:无请求;1:请求 | 0 |
nBATT_FLT | [7] | 0:无请求;1:请求 | 0 |
INT_CAM | [6] | 0:无请求;1:请求 | 0 |
EINT8_23 | [5] | 0:无请求;1:请求 | 0 |
EINT4_7 | [4] | 0:无请求;1:请求 | 0 |
EINT3 | [3] | 0:无请求;1:请求 | 0 |
EINT2 | [2] | 0:无请求;1:请求 | 0 |
EINT1 | [1] | 0:无请求;1:请求 | 0 |
EINT0 | [0] | 0:无请求;1:请求 | 0 |
(2)中断模式寄存器
中断模式寄存器 INTMOD 的 32个 比特位分别与一个中断源相对应。如果某位被设置为 1 ,则相应的中断会以 FIQ 的模式来处理。相反,以 IRQ 的模式来处理。
注意:中断控制器中 仅有一个中断源 可以由 FIQ 模式来处理(只紧急中断使用FIQ中断),所以 INTMOD 中只有一个比特位可以被设置为 1 。
中断模式寄存器 INTMOD 的 32个 比特位分别与一个中断源相对应。如果某位被设置为 1 ,则相应的中断会以 FIQ 的模式来处理。相反,以 IRQ 的模式来处理。 注意:中断控制器中 仅有一个中断源 可以由 FIQ 模式来处理(只紧急中断使用FIQ中断),所以 INTMOD 中只有一个比特位可以被设置为 1 。为很么 快中断只能有一个中断源?(学生讨论!) 快中断,之所以 快,我们 前面 讲过,有 2 个处理 措施 。其中 最 主要 的一点,就是 有 更多的 寄存器,避免了 数据 出栈 和 入栈 的 开销,如果,有 2 个 以上 的快 中断 产生,也就是 如果 一个快 中断 在 执行 时候,来 了 一个优先级 更高 的 快 中断 需要 执行,则 将 形成 中断 嵌套。而 第二个 快 中断,使用的 寄存器 和 第一个 快中断,使用的 寄存器 是 一套,则 所有 的 寄存器 都 必须 进行 压栈 处理,那 快中断 快 的优势 就 没有了。所以 仅支持 一个 快中断。
中断模式寄存器 INTMOD 的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
INTMOD | 0X4A000004 | R/W | 中断模式寄存器:
0:IRQ模式;
1:FIQ模式。 | 0 |
INTMOD 寄存器中各比特位的描述如下所示:
INTMOD | 位 | 描述 | 初始值 |
INT_ADC | [31] | 0:IRQ;1:FIQ | 0 |
INT_RTC | [30] | 0:IRQ;1:FIQ | 0 |
INT_SPI1 | [29] | 0:IRQ;1:FIQ | 0 |
INT_UART0 | [28] | 0:IRQ;1:FIQ | 0 |
INT_IIC | [27] | 0:IRQ;1:FIQ | 0 |
INT_USBH | [26] | 0:IRQ;1:FIQ | 0 |
INT_USBD | [25] | 0:IRQ;1:FIQ | 0 |
INT_NFCON | [24] | 0:IRQ;1:FIQ | 0 |
INT_UART1 | [23] | 0:IRQ;1:FIQ | 0 |
INT_SPI0 | [22] | 0:IRQ;1:FIQ | 0 |
INT_SDI | [21] | 0:IRQ;1:FIQ | 0 |
INT_DMA3 | [20] | 0:IRQ;1:FIQ | 0 |
INT_DMA2 | [19] | 0:IRQ;1:FIQ | 0 |
INT_DMA1 | [18] | 0:IRQ;1:FIQ | 0 |
INT_DMA0 | [17] | 0:IRQ;1:FIQ | 0 |
INTMOD | 位 | 描述 | 初始值 |
INT_LCD | [16] | 0:IRQ;1:FIQ | 0 |
INT_UART2 | [15] | 0:IRQ;1:FIQ | 0 |
INT_TIMER4 | [14] | 0:IRQ;1:FIQ | 0 |
INT_TIMER3 | [13] | 0:IRQ;1:FIQ | 0 |
INT_TIMER2 | [12] | 0:IRQ;1:FIQ | 0 |
INT_TIMER1 | [11] | 0:IRQ;1:FIQ | 0 |
INT_TIMER0 | [10] | 0:IRQ;1:FIQ | 0 |
INT_WDT | [9] | 0:IRQ;1:FIQ | 0 |
INT_TICK | [8] | 0:IRQ;1:FIQ | 0 |
nBATT_FLT | [7] | 0:IRQ;1:FIQ | 0 |
INT_CAM | [6] | 0:IRQ;1:FIQ | 0 |
EINT8_23 | [5] | 0:IRQ;1:FIQ | 0 |
EINT4_7 | [4] | 0:IRQ;1:FIQ | 0 |
EINT3 | [3] | 0:IRQ;1:FIQ | 0 |
EINT2 | [2] | 0:IRQ;1:FIQ | 0 |
INTMOD | 位 | 描述 | 初始值 |
EINT1 | [1] | 0:IRQ;1:FIQ | 0 |
EINT0 | [0] | 0:IRQ;1:FIQ | 0 |
注意:如果 INTMOD 寄存器中某中断模式设置为 FIQ ,那么 FIQ 中断将不会影响 INTPND 和 INTOFFSET 寄存器,两者只对 IRQ 模式的中断源有效。
(3)中断屏蔽寄存器
中断屏蔽寄存器 INTMSK 也包括了32位,每一个比特位均与相应的一个中断源相对应。如果某位被设置为1,那么CPU不会执行相应中断源提出的中断请求(即使源挂起寄存器的相应位被设置为1)。如果屏蔽位为0,那么中断请求会被正常执行。
中断屏蔽寄存器 INTMSK 的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
INTMSK | 0X4A000008 | R/W | 决定屏蔽的中断源,屏蔽的中断源将不会执行。
0:中断服务有效;
1:中断服务屏蔽。 | 0 |
INTMSK 寄存器中各个比特位的描述如下所示:
INTMSK | 位 | 描述 | 初始值 |
INT_ADC | [31] | 0:有效;1:屏蔽 | 1 |
INT_RTC | [30] | 0:有效;1:屏蔽 | 1 |
INT_SPI1 | [29] | 0:有效;1:屏蔽 | 1 |
INT_UART0 | [28] | 0:有效;1:屏蔽 | 1 |
INT_IIC | [27] | 0:有效;1:屏蔽 | 1 |
INT_USBH | [26] | 0:有效;1:屏蔽 | 1 |
INT_USBD | [25] | 0:有效;1:屏蔽 | 1 |
INT_NFCON | [24] | 0:有效;1:屏蔽 | 1 |
INT_UART1 | [23] | 0:有效;1:屏蔽 | 1 |
INT_SPI0 | [22] | 0:有效;1:屏蔽 | 1 |
INTMSK | 位 | 描述 | 初始值 |
INT_SDI | [21] | 0:有效;1:屏蔽 | 1 |
INT_DMA3 | [20] | 0:有效;1:屏蔽 | 1 |
INT_DMA2 | [19] | 0:有效;1:屏蔽 | 1 |
INT_DMA1 | [18] | 0:有效;1:屏蔽 | 1 |
INT_DMA0 | [17] | 0:有效;1:屏蔽 | 1 |
INT_LCD | [16] | 0:有效;1:屏蔽 | 1 |
INT_UART2 | [15] | 0:有效;1:屏蔽 | 1 |
INT_TIMER4 | [14] | 0:有效;1:屏蔽 | 1 |
INT_TIMER3 | [13] | 0:有效;1:屏蔽 | 1 |
INT_TIMER2 | [12] | 0:有效;1:屏蔽 | 1 |
INT_TIMER1 | [11] | 0:有效;1:屏蔽 | 1 |
INT_TIMER0 | [10] | 0:有效;1:屏蔽 | 1 |
INT_WDT | [9] | 0:有效;1:屏蔽 | 1 |
INT_TICK | [8] | 0:有效;1:屏蔽 | 1 |
INTMSK | 位 | 描述 | 初始值 |
nBATT_FLT | [7] | 0:有效;1:屏蔽 | 1 |
INT_CAM | [6] | 0:有效;1:屏蔽 | 1 |
EINT8_23 | [5] | 0:有效;1:屏蔽 | 1 |
EINT4_7 | [4] | 0:有效;1:屏蔽 | 1 |
EINT3 | [3] | 0:有效;1:屏蔽 | 1 |
EINT2 | [2] | 0:有效;1:屏蔽 | 1 |
EINT1 | [1] | 0:有效;1:屏蔽 | 1 |
EINT0 | [0] | 0:有效;1:屏蔽 | 1 |
(4)优先级控制寄存器
优先级控制寄存器 PRIORITY 的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
PRIORITY | 0X4A00000C | R/W | IRQ优先级控制寄存器 | 0X7F |
PRIORITY 寄存器中各个比特位的描述如下所示:
PRIORITY | 位 | 描述 | 初始值 |
ARB_SEL6 | [20:19] | Arbiter6优先级顺序设置:
00:REQ 0-1-2-3-4-5;01:REQ 0-2-3-4-1-5;10:REQ 0-3-4-1-2-5;11:REQ 0-4-1-2-3-5 | 0 |
ARB_SEL5 | [18:17] | Arbiter5优先级顺序设置:
00:REQ 1-2-3-4;01:REQ 2-3-4-1;10:REQ 3-4-1-2;11:REQ 4-1-2-3 | 0 |
ARB_SEL4 | [16:15] | Arbiter4优先级顺序设置:
00:REQ 0-1-2-3-4-5;01:REQ 0-2-3-4-1-5;10:REQ 0-3-4-1-2-5;11:REQ 0-4-1-2-3-5 | 0 |
ARB_SEL3 | [14:13] | Arbiter3优先级顺序设置:
00:REQ 0-1-2-3-4-5;01:REQ 0-2-3-4-1-5;10:REQ 0-3-4-1-2-5;11:REQ 0-4-1-2-3-5 | 0 |
PRIORITY | 位 | 描述 | 初始值 |
ARB_SEL2 | [12:11] | Arbiter2优先级顺序设置:
00:REQ 0-1-2-3-4-5;01:REQ 0-2-3-4-1-5;10:REQ 0-3-4-1-2-5;11:REQ 0-4-1-2-3-5 | 0 |
ARB_SEL1 | [10:9] | Arbiter1优先级顺序设置:
00:REQ 0-1-2-3-4-5;01:REQ 0-2-3-4-1-5;10:REQ 0-3-4-1-2-5;11:REQ 0-4-1-2-3-5 | 0 |
ARB_SEL0 | [8:7] | Arbiter0优先级顺序设置:
00:REQ 1-2-3-4;01:REQ 2-3-4-1;10:REQ 3-4-1-2;11:REQ 4-1-2-3 | 0 |
ARB_MODE6 | [6] | Arbiter6优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
ARB_MODE5 | [5] | Arbiter5优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
PRIORITY | 位 | 描述 | 初始值 |
ARB_MODE4 | [4] | Arbiter4优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
ARB_MODE3 | [3] | Arbiter3优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
ARB_MODE2 | [2] | Arbiter2优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
ARB_MODE1 | [1] | Arbiter1优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
ARB_MODE0 | [0] | Arbiter0优先级转换使能:
0:优先级不自动转换;1:优先级自动转换 | 1 |
(5)中断挂起寄存器
中断挂起寄存器INTPND的32位,显示具有最高优先级,且未被屏蔽的中断请求,在等待中断服务。因为INTPND寄存器位于优先级逻辑之后,仅 1 位可以被置 1。该中断请求将生成对CPU的IRQ。在对于IRQ的中断服务程序中,我们可以读取该寄存器,来查看哪个中断源被服务。
同 SRCPND 一样,INTPND 也需要在中断服务程序中加入 清0 操作,位于 SRCPND 寄存器 清0 操作之后。
可以通过向 INTPND 寄存器写入一个数据对相应位 清0 。仅将1对应位清除,其余保持原值不变。
中断挂起寄存器 INTPND 的地址等信息如下表所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
INTPND | 0X4A000010 | R/W | 指示中断请求状态:
0:无中断请求
1:产生中断请求 | 0X0 |
INTPND 寄存器中各个比特位的描述如下所示:
INTPND | 位 | 描述 | 初始值 |
INT_ADC | [31] | 0:无请求;1:请求 | 0 |
INT_RTC | [30] | 0:无请求;1:请求 | 0 |
INT_SPI1 | [29] | 0:无请求;1:请求 | 0 |
INT_UART0 | [28] | 0:无请求;1:请求 | 0 |
INT_IIC | [27] | 0:无请求;1:请求 | 0 |
INT_USBH | [26] | 0:无请求;1:请求 | 0 |
INT_USBD | [25] | 0:无请求;1:请求 | 0 |
INT_NFCON | [24] | 0:无请求;1:请求 | 0 |
INT_UART1 | [23] | 0:无请求;1:请求 | 0 |
INT_SPI0 | [22] | 0:无请求;1:请求 | 0 |
INTPND | 位 | 描述 | 初始值 |
INT_SDI | [21] | 0:无请求;1:请求 | 0 |
INT_DMA3 | [20] | 0:无请求;1:请求 | 0 |
INT_DMA2 | [19] | 0:无请求;1:请求 | 0 |
INT_DMA1 | [18] | 0:无请求;1:请求 | 0 |
INT_DMA0 | [17] | 0:无请求;1:请求 | 0 |
INT_LCD | [16] | 0:无请求;1:请求 | 0 |
INT_UART2 | [15] | 0:无请求;1:请求 | 0 |
INT_TIMER4 | [14] | 0:无请求;1:请求 | 0 |
INT_TIMER3 | [13] | 0:无请求;1:请求 | 0 |
INT_TIMER2 | [12] | 0:无请求;1:请求 | 0 |
INT_TIMER1 | [11] | 0:无请求;1:请求 | 0 |
INT_TIMER0 | [10] | 0:无请求;1:请求 | 0 |
INT_WDT | [9] | 0:无请求;1:请求 | 0 |
INTPND | 位 | 描述 | 初始值 |
INT_TICK | [8] | 0:无请求;1:请求 | 0 |
nBATT_FLT | [7] | 0:无请求;1:请求 | 0 |
INT_CAM | [6] | 0:无请求;1:请求 | 0 |
EINT8_23 | [5] | 0:无请求;1:请求 | 0 |
EINT4_7 | [4] | 0:无请求;1:请求 | 0 |
EINT3 | [3] | 0:无请求;1:请求 | 0 |
EINT2 | [2] | 0:无请求;1:请求 | 0 |
EINT1 | [1] | 0:无请求;1:请求 | 0 |
EINT0 | [0] | 0:无请求;1:请求 | 0 |
⚠️注意:!!!
如果 FIQ 模式中断发生,那么在 INTPND 寄存器相应位将不被改变,因为 INTPND 寄存器仅设置为 IRQ 模式中断有效。
(6)INTOFFSET寄存器
INTOFFSET 寄存器的值说明了 INTPND 寄存器中哪一个 IRQ 模式的中断请求有效。这个比特位可以通过清除 SRCPND 和 INTPND 寄存器来自动清除。
INTOFFSET 寄存器的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
INTOFFSET | 0X4A000014 | R/W | 指示IRQ中断请求源 | 0X0 |
INTOFFSET 寄存器中各个比特位的描述如下所示:
中断源 | OFFSET值 | 中断源 | OFFSET值 |
INT_ADC | 31 | INT_UART1 | 23 |
INT_RTC | 30 | INT_SPI0 | 22 |
INT_SPI1 | 29 | INT_SDI | 21 |
INT_UART0 | 28 | INT_DMA3 | 20 |
INT_IIC | 27 | INT_DMA2 | 19 |
INT_USBH | 26 | INT_DMA1 | 18 |
INT_USBD | 25 | INT_DMA0 | 17 |
INT_NFCON | 24 | INT_LCD | 16 |
中断源 | OFFSET值 | 中断源 | OFFSET值 |
INT_UART2 | 15 | nBATT_FLT | 7 |
INT_TIMER4 | 14 | INT_CAM | 6 |
INT_TIMER3 | 13 | EINT8_23 | 5 |
INT_TIMER2 | 12 | EINT4_7 | 4 |
INT_TIMER1 | 11 | EINT3 | 3 |
INT_TIMER0 | 10 | EINT2 | 2 |
INT_WDT | 9 | EINT1 | 1 |
INT_TICK | 8 | EINT0 | 0 |
注意:FIQ 模式中断不影响 INTOFFSET 寄存器,因为 INTOFFSET 寄存器仅对 IRQ 模式中断有效。
(7)次级源挂起寄存器
可以通过向 SUBSRCPND 寄存器某一位写入1来清除该位。此数据仅清除数据对应的比特位,其它的比特位不变。次级源挂起寄存器 SUBSRCPND 的地址等信息如下所示:
寄存器 | 地址 | R/W | 描述 | 复位值 |
SUBSRCPND | 0X4A000018 | R/W | 指示中断请求的状态:
0:无中断发生;
1:有中断发生。 | 0X0 |
SUBSRCPND 寄存器中各个比特位的描述如下所示:
(8)中断次级屏蔽寄存器
中断次级屏蔽寄存器 INTSUBMSK 中的 11位 和响应的中断源有联系,如果某一比特位设置为 1 ,那么来自相应中断源的中断请求便不会被 CPU 执行(注意此种情况下,SUBSRCPND 寄存器相应位会被设置为 1)。如果屏蔽位为 0 ,那么中断请求将会被执行。
中断次级屏蔽寄存器 INTSUBMSK 的地址等信息如下:
寄存器 | 地址 | R/W | 描述 | 复位值 |
INTSUBMSK | 0X4A00001C | R/W | 决定哪一个中断源被屏蔽,被屏蔽的中断源将不会执行。
0:中断服务有效;
1:中断服务屏蔽。 | 0X7FF |
INTSUBMSK 寄存器中各个比特位的描述如下所示:
各中断相关寄存器中,相关中断顺序表
CPSR
中断仲裁:当中断控制器接收到 多个中断请求时,其内的优先级仲裁器裁决后向 CPU 发出优先级最高的中断请求信号或快速中断请求信号。
CPSR 指 ARM920T 处理器的程序状态寄存器。如果 CPSR 的 F位 被设置为 1 ,处理器将不接受来自中断控制器的FIQ(快速中断请求);如果 PSR 的 I位 被设置为 1 ,处理器将不接受来自中断控制器的IRQ(中断请求)。因此,为了使能 FIQ 和 IRQ ,PSR 的 F位 或 I位 必须被 清零,同时中断屏蔽寄存器 INTMASK 的相应位也必须被 清0 。
SRCPND和INTPND
S3C2440 有两个中断挂起寄存器:源挂起寄存器(SRCPND) 和 中断挂起寄存器(INTPND)。这些挂起寄存器指示了一个中断请求是否被挂起。
当中断源请求中断服务时,SRCPND 相应位被置 1 。
并且同时在仲裁后 INTPND 寄存器 仅有1位被置1。
如果中断被屏蔽,那么 SRCPND 相应位被 置1,但并不能引起 INTPND 改变。
当 INTPND 的挂起位被设置时,只要相应的 标志位I 或 标志位F 被清0,相应的中断服务程序都被执行。SRCPND 和 INTPND 可以被读写。
来自中断的中断请求首先寄存在 源挂起寄存器。它们基于中断模式寄存器分为 两组:FIQ中断请求 和 IRQ中断请求。对多重IRQ请求的仲裁过程使用优先级寄存器。
源挂起寄存器
源挂起寄存器由 32位 组成,每一个比特位均与一个中断源相连。当中断源产生中断请求并且等待中断服务程序的执行时,其相应的比特位设置为 1 。
还有,源挂起寄存器指示此时哪一个中断源正在等待执行中断请求。注意: SRCPND 寄存器的各比特位均为 中断源自动设置,与屏蔽寄存器的相应位设置无关。
另外,SRCPND 寄存器不受中断控制寄存器的优先级逻辑的影响。
当中断服务被执行时,SRCPND 寄存器的相应位应该 及时清0,以便正确地接收相应中断源的中断请求。如果没有清除源挂起位,当中断服务返回时,中断控制寄存器会将之作为来自相同中断源的中断请求 第二次执行。也就是说,如果 SRCPND 寄存器的某位为 1,系统一般会当作一个有效的等待执行的中断请求。
清除相应位的时间依赖于用户的需求。如果要接收来自相同源的另一个有效中断请求,那么应该清除相应挂起位并且使能中断。
可以通过写入一个数据到此寄存器来清除SRCPND寄存器的指定位,这时只清除那些数据中被设置为1的相应位置的SRCPND位。那些数据中被设置为0的相应位置的位保持不变。
SRCPND 寄存器中各比特位的描述如下所示(没截完):
中断挂起寄存器
中断挂起寄存器INTPND的32位,显示具有最高优先级,且未被屏蔽的中断请求,在等待中断服务。因为INTPND寄存器位于优先级逻辑之后,仅 1 位可以被置 1。该中断请求将生成对CPU的IRQ。在对于IRQ的中断服务程序中,我们可以读取该寄存器,来查看哪个中断源被服务。
同 SRCPND 一样,INTPND 也需要在中断服务程序中加入 清0 操作,位于 SRCPND 寄存器 清0 操作之后。
可以通过向 INTPND 寄存器写入一个数据对相应位 清0 。仅将1对应位清除,其余保持原值不变。
INTPND 寄存器中各个比特位的描述如下所示(部分):
⚠️注意!!!
如果 FIQ 模式中断发生,那么在 INTPND 寄存器相应位将不被改变,因为 INTPND 寄存器仅设置为 IRQ 模式中断有效。
INTOFFSET
INTOFFSET 寄存器的值说明了 INTPND 寄存器中哪一个 IRQ 模式的中断请求有效。这个比特位可以通过清除 SRCPND 和 INTPND 寄存器来自动清除。
INTOFFSET 寄存器中各个比特位的描述如下(部分):
⚠️注意!!!
注意:FIQ 模式中断不影响 INTOFFSET 寄存器,因为 INTOFFSET 寄存器仅对 IRQ 模式中断有效。
SUBSRCPND
次级源挂起寄存器
可以通过向 SUBSRCPND 寄存器某一位写入1来清除该位。此数据仅清除数据对应的比特位,其它的比特位不变。次级源挂起寄存器 SUBSRCPND 的地址等信息如下所示:
INTSUBMSK
中断次级屏蔽寄存器 INTSUBMSK 中的 11位 和响应的中断源有联系,如果某一比特位设置为 1 ,那么来自相应中断源的中断请求便不会被 CPU 执行(注意此种情况下,SUBSRCPND 寄存器相应位会被设置为 1)。如果屏蔽位为 0 ,那么中断请求将会被执行。
INTSUBMSK 寄存器中各个比特位的描述如下所示:
INTMSK
如果该寄存器的某一个位被 置1 ,则该位对应的中断响应被 禁止 了;
如果某个中断在 INTMSK 寄存器的对应位 为0 ,则这个中断发生时将会正常被响应。
如果某个中断在 INTMSK 的寄存器中的对应位 为1,但是这个中断发生了,它的源挂起寄存器(SRCPND)对应位还是会 置1。而对应中断挂起寄存器(INTPND)标志位,不会被置1 。
中断屏蔽寄存器 INTMSK 也包括了32位,每一个比特位均与相应的一个中断源相对应。如果某位被设置为1,那么CPU不会执行相应中断源提出的中断请求(即使源挂起寄存器(
SRCPND
)的相应位被设置为1)。如果屏蔽位为0,那么中断请求会被正常执行。中断屏蔽寄存器 INTMSK 的地址等信息如下所示(只截图了一部分):
INTMOD
中断模式寄存器 INTMOD 的 32个 比特位分别与一个中断源相对应。如果某位被设置为 1 ,则相应的中断会以 FIQ 的模式来处理。相反,以 IRQ 的模式来处理。
注意:中断控制器中 仅有一个中断源 可以由 FIQ 模式来处理(只紧急中断使用FIQ中断),所以 INTMOD 中只有一个比特位可以被设置为 1 。
INTMOD寄存器中各比特位的描述(不完整):
注意:如果 INTMOD 寄存器中某中断模式设置为 FIQ ,那么 FIQ 中断将不会影响 INTPND 和 INTOFFSET 寄存器,两者只对 IRQ 模式的中断源有效。
PRIORITY
优先级控制寄存器 PRIORITY 的地址等信息如下所示:
6个地方裁决:
中断源
中断控制器提供 60 个 中断源,所以中断优先级非常重要。
中断优先级仲裁器及其工作原理
中断系统有 6个 分仲裁器 和 1个 总仲裁器,每一个仲裁器可以处理 6路 中断,优先级产生模块图如下:
中断控制器提供60个中断源的管理。是如何实现的?
S3C2440将中断源分为两级: 中断源和子中断源(次级中断源):
- 中断源就是上图32个中断源。而这32个中断源中包含单一中断源和复合中断源。
- 复合中断源是子中断源(次级中断源)的复合信号。比如:INT_UARTn。
这种设计,使得S3C2440中断控制器支持60个中断源。
外部中断
EINTPENDn
外部中断挂起寄存器 EINTPENDn 是针对 20个 外部中断(EINT[23:4])的,可以通过向此 EINTPEND 寄存器相应位 写1来清除比特位。
外部中断挂起寄存器各位说明如下(部分):
EXTINTn
外部中断控制寄存器:
24个外部中断 可以有不同的信号方式请求。EXTINTn 为外部中断请求,配置信号的方式为:电平触发 或者 边沿触发,也可以配置信号极性。
关于引脚复用中断:
5.8 PWM定时器
S3C2440 定时器的主要特性如下:
(1)5个16 位定时器;
(2)2个8位预分频器 和 2个4位分频器
(时钟除法器);
(3)输出波形的占空比可编程控制(PWM);
(4)自动加载模式 或 单触发脉冲模式;
(5)死区产生器。
S3C2440 具有 5个16位定时器,定时器0、1、2、和3 具有PWM功能(脉宽调制),定时器4 是一个内部定时器,不具有对外输出口线。定时器0 具有死区发生器,通常用于大电流设备应用。
定时器0和1 公用 一个8位预分频器,定时器2、3和4 公用 另一个8位预分频器。每一个定时器通过除法器可以得到5种不同的信号(1/2、1/4、1/8、1/16和TCLK ) 。
除法器 也是 一种 分频器,只是 这里 的 分频器 只使用 4个 除数因子 进行 分频,而不 支持 其他 的 任意值。 也 就是 每个 定时器,所使用 的 时钟信号 是 把 PCLK 先 经过 预分频器 分频后,再 经过 除法器 分频,所 得到 的。通过 这种 方式,我们 可以 设置 时钟 信号 的周期。
每一个时钟模块 从其时钟除法器中 接收时钟信号,时钟除法器 从其相应的 8位预分频器 中接收时钟信号。8位预分频器 是可编程的,并根据存储在 TCFG0 和 TCFG1 的值来对 PCLK信号 进行分频。
首先,PWM 的模块 使用的 PCLK时钟信号(也就是APB总线使用的时钟信号),5:1MUX,5选1 多路选择器,也就是 从 4位 时钟分频器 输出的 5路信号 中,选择1路 作为 定时器 的时钟信号。定时器计数缓冲寄存器(TCNTBn)定时器比较缓冲器(TCMPBn)定时器输出引脚,是TOUTn,TOUT[3:0]引脚(对应 GPB[3:0],和GPB[3:0]复用)和TIMER[3:0]输出对应。
5.8.1 PWM概念
PWM 概念(脉宽调制)就是只对 一方波序列信号的占空比 按要求进行调制,而不是 改变方波信号的其它参数,即不改变 幅度和周期,因此脉宽调制信号的产生和传输,都是数字式的。
占空比 是 什么?占空比 是指 在 一个 脉冲 信号(也就是 时钟 信号) 的周期 内,高电平 相对于 总时间 所占 的 比例。(。。可以画波形。),周期 不变,高电平 时间 多一点,则 低电平 的时间 就 少一点。那 脉宽调制技术,到底 有 什么用?为什么,脉冲信号 的 周期,不变的 情况下,我们要 改变它 的 占空比?改变后,会产生 什么 效果?
用脉宽调制技术 可以 实现模拟信号:如果调制信号的 频率远远大于 信号接受者的分辨率,则接受者获得的是信号平均效果,不能感知数字信号的 0和1 ,其信号大小的平均值与信号的占空比有关,信号的占空比越大,平均信号越强,其平均值与占空比成正比。只要带宽足够(频率足够高或周期足够短),任何模拟信号都可以使用 PWM 来实现。
通过对一系列脉冲的宽度进行调制,等效出所需要的波形(含形状和幅值) ) 。
刚才,那么 一大段话,其实 概括起来,PWM 的 用途:通过对一系列脉冲的宽度进行调制,等效出所需要的波形(含形状和幅值) ,用它来产生任意波形。
其 理论 基础 就是 这个:面积 等效 原理 —— 冲量 相等 而 形状 不同的 窄脉冲 加在 具有 惯性的 环节 上时,其 效果 基本 相同。冲量 就是 窄脉冲的 面积。效果 基本相同 是 指 环节的 输出响应 波形 基本 相同
基本 思想,比如 这 正弦波 ,把 这个 正弦波 按 时间 间隔 等分,如图,就是 得到 不同 颜色的 色块,如果 右边 图形 的 每个 脉冲的 幅度 不变,但 宽度 变化了,也就是 每个 脉冲的 面积,和左边 相同 色块 的面积 一样大。 则 在 输出 环节,得到 的波形,和 左边的 等效,
PWM 技术的应用:借助于微处理器,使用脉宽调制方法实现模拟信号是一种非常有效的技术,广泛应用在:从测量、通信到功率控制与变换的许多领域中。
5.8.2 PWM 定时器结构
- 定时器计数缓冲寄存器(TCNTBn)的值 是当定时器使能时装载到减法计数器的 初值; (周期)
- 定时器比较缓冲器(TCMPBn)的值 将被装载到比较寄存器并与减法计数器的值进行比较; (占空比)
- TCNTBn 和 TCMPBn 双重缓冲器的特性使 定时器频率 和 占空比改变时,确保产生稳定的输出。
定时器 计数 缓冲 寄存器(TCNTBn)的 值 是 当 定时器 使能 时 装载到 减法计数器 的 初值。也就是,减法 计数器,将 这个 寄存器中 存放的 值 做为 初值,进行 减法 计数。从 这个 初值 装入 减法计数器,到 该值 被减到 0 的 时间,就是 一个 脉冲的 周期。定时器 比较 缓冲器(TCMPBn)的值 将被 装载 到 比较寄存器 并与 减法计数器 的 值进 行 比较。这个 寄存器 存放的 值,用于 调节 输出 脉冲信号的 占空比。减法计数器 的 值 从 初始值 开始,在输入 时钟脉冲 的 作用下,不断的 进行 减1 操作,每个 时种周期 都 减1,当减法计数器 中的值 被减到 和 比较寄存器 中的值 相等 的时候,就 将 改变 输出信号的 极性。使之 从高电平 转到 低电平,或 从 低电平 转到 高电平。因此,通过 调整 定时器比较缓冲器(TCMPBn) 的 值,可以 改变 输出脉冲信号的 占空比。TCNTBn 和 TCMPBn 双重 缓冲器的 特性 使 定时器 频率 和 占空比 改变时,确保 产生 稳定的 输出。这句话,什么意思?所谓的 缓冲,是指 减法计数器 在进行 减法 计数操作的 时候,并没有 直接 对这 两个 寄存器 进行 操作。只是 把这 两个 寄存器的 值,分别装入 减法计数器 和 比较寄存器 中,在做 减法计数 时,实际 使用的 是 那两个 寄存器的 值。这样做 的 好处 就是,你可以在 一次 减法计数操作的 过程中,随时 修改 定时器计数缓冲寄存器(TCNTBn)和 定时器比较缓冲器(TCMPBn)的 值,而 不会 对 当前 的计数 操作 有 任何 影响,只有 当一次 计数操作 完成,也就是 减法计数器 中的 值,被 减到 了0 以后,计数器 会重新 装载 初值 和 比较值,这个时候,新的值 才起作用。这样 可以 避免在 减法计数的 时候,直接修改 初值 和 比较值 而 导致的 混乱,因此说 确保 产生 稳定的 输出。
每个计数器都有自己的 16位减法器,由定时器时钟驱动。当定时器计数器值 达到0时,定时器发出中断请求,通知 CPU 定时工作已经完成,相应的 TCNTBn 将自动装入计数器,以继续下一个操作。但是,如果,定时器控制寄存器TCONn中的自动重装载开/关被清除, 则 TCNTBn 中的值将不会被装载到计数器。
TCMPBn 的值用于脉宽调节,当该计数器值与定时器控制逻辑中的比较寄存器值相等时,定时控制逻辑改变输出电平。因此,比较寄存器决定 PWM 输出的高电平时间(或低电平时间)。
5.8.3 PWM 定时器操作
(1)预分频器 和 分频器(时钟除法器)
一个 8位 的预分频器和一个 4位 分频器(除法器)作用下的输出频率如下所示:
4位分频器的设置 | 最小分辨率
(预分频器=0) | 最大分辨率
(预分频器=255) | 最大间隔时间
(TCNTBn=65535) |
1/2(PCLK=66.5MHZ) | 0.0300us(33.2500MHZ) | 7.6992us(129.8828kHZ) | 0.5045s |
1/4(PCLK=66.5MHZ) | 0.06001us(16.6250MHZ) | 15.3984us(64.9414kHZ) | 1.0091s |
1/8(PCLK=66.5MHZ) | 0.1203us(8.3125MHZ) | 30.7968(32.4707kHZ) | 2.0182s |
1/16(PCLK=66.5MHZ) | 0.2406us(4.1562MHZ) | 61.5936us(16.2353kHZ) | 4.0365s |
假如 PCLK输入的 时钟频率为 66.6Mhz 4位分频器选择 对预分频器 输出信号 做2分频,即1/2这选项,则最小 分辨率,也就是从 4位 分频器输出的 最小的时钟周期为 0.03us。这个时候预分频器 的值 为 0,也就是不对PCLK做分频处理。
最大分辨率,就是 能从 4位 分频器输出的 最大的时钟周期为 7.6992us,这个时候预分频器 的值 为 255+1=256,也就是先对PCLK做256分频处理后,再送给 4位分频器。此时,是信号的 周期最长,为 7.6992us
因此,最大 间隔 时间为 减法 计数器 最大值 65536(0-65535) * 最大 时钟周期(7.6992)= 0.5045s
(2)定时器基本操作
一个定时器(定时器4除外)包含:TCNTBn、TCNTn、TCMPBn和TCMPn几个寄存器(TCNTn和TCMPn是减法计数器内部寄存器的名称,TCNTn的值可以通过读TCNTOn得到)。当定时器达到 0时 ,TCNTBn 和 TCMPBn的值将 自动加载 到 TCNTn 和 TCMPn 中。当 TCNTn到0且中断使能时,定时器将 产生一个中断请求。
一个定时器(定时器4除外)包含:TCNTBn(定时器比较缓冲器)、TCNTn(减法计数器 )、TCMPBn(定时器计数缓冲寄存器)和TCMPn(减法计数器 )几个寄存器(TCNTn和TCMPn是内部寄存器的名称,TCNTn的值可以通过读TCNTOn得到)。当定时器达到 0时 ,TCNTBn 和 TCMPBn的值将 自动加载 到 TCNTn 和 TCMPn 中。当 TCNTn到0且中断使能时,定时器将 产生一个中断请求。
(3)自动加载 和 双缓冲模式
脉宽调制定时器 有一个 双缓冲功能,在这种情况下,改变下次加载值的同时 不影响 当前定时周期。因此,尽管设置一个 新的定时器值,当前定时器的操作将会继续完成而不受影响。双缓冲功能时序图如下所示:
定时器的值可以写入定时器计数值缓冲寄存器(TCNTBn)中,而当前计数器的值可以通过读定时器计数值观测寄存器(TCNTOn)得到。
当 TCNTn 的值到 0时,自动加载操作复制 TCNTBn 的值到 TCNTn 中。但是如果 自动加载模式 没有使能, TCNTn 将不进行任何操作。
(4)用手动更新位和反相器位对定时器进行初始化
当递减计数器的值 到0时,自动加载操作才能进行。所以,用户必须预先对 TCNTn 定时一个起始值。因此,起始值必须由手动更新位载入。以下步骤描述了怎么起始一个定时器。
①将初始值写入到 TCNTBn 和 TCMPBn中;
②设置相应定时器的手动更新位。推荐同时配置反相器位开关位(不管反相器用与否);
③设置相应定时器的起始位,从而启动一个定时器(同时清除手动更新位)。
如果定时器被迫停止,TCNTn将保留计数器的值且不重载TCNTBn。如果用户需要设置一个新值,必须执行手动更新。
如果 定时器 被迫 停止,TCNTn 将 保留 计数器的 值 且不 重载 TCNTBn。也就是,如果 不是 计数器 减为0 ,是不会 自动 更新 其 初始值的。如果 用户 需要 设置 一个 新值,必须 执行 手动 更新。就是 通过 把 手动更新位 置1 ,使得 计数器 重新 加载 定时器计数 缓冲 寄存器TCNTBn 和 定时器比较缓冲器 TCMPBn 的 值。
(5)定时器操作步骤举例
①使能自动加载功能
设置 TCNTBn 为 160,TCMPBn 为 110。设置手动更新位并配置反相器位(关)。手动更新位设置 TCNTn 和 TCMPn 的值与 TCNTBn 和 TCMPBn 相同。手动更新位清0。然后设置 TCNTBn 和 TCMPBn的 值分别为 80 和 40,确定下一个周期的值;
设置 TCNTBn 为 160,TCMPBn 为 110。设置 手动更新位 并 配置 反相器位(关)。手动更新位 设置 TCNTn 和 TCMPn 的 值 与 TCNTBn 和 TCMPBn 相同,也就是,手动更新位 被置1 后,计数器,将从 定时器计数缓冲寄存器 TCNTBn 和 定时器比较缓冲器 TCMPBn 中 加载 初值。加载 后,他们 的 值 就是 缓冲器 的 值,所以说 相等。手动更新位 清0。然后 设置 TCNTBn 和 TCMPBn的 值 分别为 80 和 40,确定 下一个 周期的 值;因为 手动更新位 是0,这两个 新设置 的值,这里 不会 立即生效,会在 下一个 计数周期 生效,所以说,是 确定 下一个 周期 的值;
②自动加载 开,设置起始位,在定时器的延迟时间后定时器开始递减计数;
③当 TCNTn 的值和 TCMPn 相等时,则 TOUTn 的逻辑电平将发生改变,由低到高;
④当 TCNTn 的值 到0时,产生一个中断并且将 TCNTBn 的值加载到一个临时寄存器。在下一个时钟周期,TCNTBn 由临时寄存器加载到 TCNTn 中;
⑤在中断服务程序中,TCNTBn 和 TCMPBn 分别设置成 80 和 60;
⑥当 TCNTn 的值和 TCMPn(40) 相等时,则 TOUTn 的逻辑电平发生改变,由低到高;
⑦当 TCNTn到0时,TCNTn 自动重新加载,并发出一个中断请求;
⑧在中断服务子程序中,自动加载和中断请求都被禁止,从而将停止定时器;
⑨当 TCNTn的值和TCMPn相等时,则 TOUTn 的逻辑电平将发生改变,由低到高;
⑩当 TCNTn的值为0时,TCNTn 将不再重新加载新的值,从而定时器停止;
⑪由于中断请求被禁止,不再产生中断请求。
(6)脉宽调制
脉宽调制功能可以通过改变 TCMPBn 的值实现。PWM 的频率由 TCNTBn 决定。下图显示一个通过改变 TCMPBn 的值实现 PWM 的例子:
我们可以看出,TCMPB 的值 越大,输出 波形的 高电平 部分 越多,占空比越大。
如果想得到一个 高的PWM值 ,则要 增加TCMPBn的值。相反,如果想要得到一个 低的PWM值 ,则要 减少TCMPBn的值。如果反相器使能,则情况正好相反。
由于定时器具有双缓冲功能,则在当前周期的任何时间都可以通过 ISR 和其它程序改变 TCMPBn 的值。
(7)输出电平控制
以下步骤描述了如何在反相器关闭的情况下,控制 TOUT 的值的高或低。
①关闭自动加载位。然后,TOUT 变高且在 TCNTn 为 0 后定时器停止运行;
②通过定时器开始位清零来停止定时器运行。如果 TCNTn≤TCMPn,则输出高;如果 TCNTn>TCMPn,输出为低;
⇒以下 步骤 描述 了 如何 在 反相器 关闭的 情况下,控制 TOUT 的值 的 高或低。 注意,该方法 是 指 通过 手动控制 的 方式,控制 定时器 输出引脚 TOUT 的 值。使其 为 高电平 或 低电平。⇒①关闭 自动加载位。因为 你要 进行 手动控制,所以 把 自动加载位 关闭。然后,TOUT 变高 且在 TCNTn 为 0 后 定时器 停止 运行,关闭 自动加载位 后,当前 计时周期 不会 立即 停止,会 继续 执行 完 当前的 计时 周期,当然,执行 完 当前的 计时周期 后,由于 取消了 自动加载 功能,定时器 停止 运行。这个 时候 TOUT 输出 是 高电平(可以问学生); 这个 是 一种 方法,使用 这种 方法,最终,TOUT,输出的 是 高电平。⇒②第二种 方法:通过 定时器开始位 清零 来 停止 定时器 运行。通过 这种 方法,让 定时器 停止 运行 后,定时器 TOUT 输出 电平,就是 停止 时,该 引脚 所 对应的 电平。如果 TCNTn≤TCMPn,则 输出高;如果 TCNTn>TCMPn,输出为低;
③通过改变 TCON 中的反相器开关位来使 TOUTn 为高或低。
下图为反相器 开与关 时的输出:
反相器,其实 就是 一个 非门 的 作用。它把 0变1 把 1变0。 注意:反相器 使能后,是 立即 生效,不管 是否 在一个 计数周期 都 立即 生效,把 输出波形 变反。
(8)死区发生器
死区是为了功率器件中的 PWM控制。这一功能 使能 在一个关键器件关闭和另一个开关器件开启的 间隔时间。这一时间间隔 禁止 了两个开关器件同时处于开启状态,即使是一段非常短的时间内。
TOUT0 是一个 PWM输出。nTOUT0 是 TOUT0 的反向。如果死区使能,则 TOUT0 和 nTOUT0 的输出波形将是 TOUT0_DZ 和 nTOUT0_DZ 。nTOUT0_DZ 由 TOUT1 脚输出。
大家注意,在 死区 功能 被 使能 启动 的时候,TOUT0_DZ 和 nTOUT0_DZ 将 分别 经 TOUT0引脚 和 TOUT1引脚 同时 输出。这样,就 可以 控制 一个 器件 关闭的 同时,另外 一个 器件 开启。因为 这两个 波形是 反相的,一个 变为 低 电平,另外 一个则 变为 高电平。所以 一个 器件关,另外 一个 器件 就开。当然,这种 两个 器件 的 开 和关,不能 完全 同时 发生,或者在 极短 的时间 内 连续 发生。因此 死区 发生器,将 使得 两个波形 的 变化,间隔 一定 的 时间,以 避免 这种 情况 的 发生。
在死区间隔,TOUT0_DZ 和 nTOUT0_DZ 将不会同时开启。下图为死区使能后的输出波形:
(9)DMA请求模式
PWM 定时器能在每个特定时间间隔产生 一个DMA请求。定时器保持 DMA请求信号(nDMA_REQ)为低 直到 定时器接收到ACK信号。当定时器接收到 ACK信号时,定时器将使请求信号无效。产生DMA请求的 定时器由设置 DMA模式位(TCFG1)决定。如果一个定时器配置成 DMA请求模式,则此定时器将不能产生中断请求,而其他定时器将正常产生中断请求。
PWM 定时器 能在每个 特定 时间 间隔 产生 一个 DMA请求,也就是 说, 通过 定时器,一个 固定 周期 的 DMA请求 信号,用于 实现 两个 模块 的定期 DMA 传输。定时器 保持 DMA 请求信号(nDMA_REQ)为低 直到 定时器 接收到 ACK信号。当 定时器 接收到 ACK信号 时,定时器 将使 请求信号 无效。产生 DMA 请求的 定时器 由 设置 DMA 模式位(TCFG1)决定。如果 一个 定时器 配置成 DMA 请求 模式,则 此 定时器将 不能 产生 中断 请求,而 其他 定时器 将 正常 产生 中断请求。
注|:这里 定时器 只 起到 DMA 请求源 的 作用,它 既不是 数据源 也 不是 目的地,比如 通过 定时器 产生 一个 固定 时间间隔 的 DMA 请求,但是 ,这个 DMA 传输 可能 是 内存 到 LCD 显存 的DMA 传输,也可能 是 内存 到 DA转换 的 数据 传输。
PWM可以工作在 中断 和 DMA 方式。是否可以用于查询方式? 是可以的。
DMA模式 配置如下所示:
DMA模式 | DMA请求 | Timer0 INT | Timer1
INT | Timer2 INT | Timer3 INT | Timer4 INT |
0000 | No select | ON | ON | ON | ON | ON |
0001 | Timer 0 | OFF | ON | ON | ON | ON |
0010 | Timer 1 | ON | OFF | ON | ON | ON |
0011 | Timer 2 | ON | ON | OFF | ON | ON |
0100 | Timer 3 | ON | ON | ON | OFF | ON |
0101 | Timer 4 | ON | ON | ON | ON | OFF |
0110 | No select | ON | ON | ON | ON | ON |
DMA 模式 控制位,是 定时器 配置寄存器1 TCFG1 的 [23:20]位,用于 设置 哪个 定时器 用于 DMA模式,通过 该 表 可以 看出,同一 时刻,只能 有一个 定时器,可以 配置为 DMA 传输模式。就是 INT 为 OFF的 所 对应的 那个 定时器,因为 开启 DMA模式 后,INT 是被 禁止 的。 DMA 模式 为 0000 或0110 的 时候,所有 定时器,都不 使用 DMA模式。
定时器4 的DMA模式操作如下图所示:
注意:这个图,是一个 示意图: INCLK,是 经过 预分频 和 4位 分频器 以后,进入 定时器4 的 时钟 信号。
INT4tmp:这里,有一个 tmp,表示 的是 它不是 一个 实际 的 信号线,这里 只是 为了 说明, 而 放在 这里,用于 表明,一次 计数周期 结束,如果 是 使用 中断 模式,则 这里 将会 发生 一个 中断。但 实际 的 中断 INT4 没有 发生,因为 它 配置 成 了 DMA 模式。
DMAreq_en,就是 定时器 配置寄存器1 TCFG1 的 DMA 模式 配置位:为0101. 定时器4 配置 为 DMA模式。
当 定时器4 的 当前 计数器 递减 到0 的时候,在 原本 应该 产生 中断 的地方(INT4tmp所示),由于 被 配置为 DMA模式,因此,没有 产生 中断,而是 产生 了 DMA 请求。对应的 DMA 请求线 被拉低,直到 收到 DMA 应答信号 DMA ACK。再把 请求信号 清除。
这个是硬件自动产生,如果你自己设计硬件,需要满足相关时序的要求。
5.9人机交互设备
1、输入设备
键盘、鼠标、手写板、触摸屏等。
2、输出设备
显示器、打印机、绘图仪等。
解决抖动问题的办法有 两种:
(1)一种是使用 硬件 消抖电路(如RC电路、专用芯片)滤掉抖动波形;
(2)另一种是当发现键盘输出电平 有变化时 ,通过 延时 的方法躲过按键的抖动,待电路状态稳定之后再来检测按键的输出电平,从而达到正确确定按键信息的目的。
2、独立按键键盘
独立按键式键盘也叫做 单线键盘,其 特点 是每一个键都占用 一条 接口线,所以这种键盘简单可靠,但在键数目较多时,占用接口线也 较多。
3、矩阵式键盘
当键盘的按键数目较大时,为了减少键盘接口线的数目,人们常常采用 矩阵式键盘。
由于按键的一端没有接地,因此需要4条行输出端口输出低电平。如果有按键按下,则4个输入端口一定有一个变为0,通过这个可以检查是否有按键按下,如果有,再进一步检查是哪个按键按下。这个时候就每次只输出一行低电平,依次检查后,就知道是哪一行的按键按下了,再和列相对应,就知道是哪个按键按下了。