ARM7 学习笔记
1.MEMMAP
MEMMAP = 0x00时为Boot模式,异常向量表从Boot Block重新映射
MEMMAP = 0x01时为片内Flash模式,异常向量表不重新映射
MEMMAP = 0x10时为片内RAM模式,异常向量表从静态RAM重新映射
MEMMAP = 0x11时为片外存储器模式,异常向量表从外部存储器重新映射(only for LPC22xx)
所谓映射,就是一种对应关系,所以“重映射”就是重新对应的意思
逻辑地址 | MEMMAP | 对应物理地址 |
---|---|---|
0x00000000~0x0000003F | 00 | 0x7FFFE000~0x7FFFE03F (Boot Block地址) |
(同上) | 01 | 0x00000000~0x0000003F (片内Flash地址) |
(同上) | 10 | 0x40000000~0x4000003F (片内RAM地址) |
(同上) | 11 | 0x80000000~0x8000003F (片外存储器地址) |
0x00000040~0xFFFFFFFF | 任意 | 对应不变 |
2.P0 & P1
LPC2148有两个32位的通用I/O口:PORT0的32个可用引脚中P0.31为输出引脚,P0.24未用,其余30个为输入/输出引脚;PORT1中P1.16-P1.31引脚可用作GPIO功能。
PINSEL0、PINSEL1用于选择PORT0,每2bit对应一个引脚(2bit有4种组合,对应4种引脚功能)
PINSEL0 [31:0]对应P0.15~P0.0
PINSEL1 [31:0]对应P0.31~P0.16
PINSEL2直接控制P1.31~P1.0
IO0SET、IO1SET [31:0]:对应P0.31~P0.0和P1.31~P1.0,往 [n]写1即将Px.n置1,写0无效
IO0CLR、IO1CLR [31:0]:对应P0.31~P0.0和P1.31~P1.0,往 [n]写1即将Px.n置0,写0无效
IO0DIR、IO1DIR [31:0]:对应P0.31~P0.0和P1.31~P1.0,往 [n]写1即将Px.n设为output,写0则设为input
IO0PIN、IO1PIN [31:0]:存储P0.31~P0.0和P1.31~P1.0的当前值(for read)
3.F & PLL
Fosc:晶振频率,在软件中设置时应与实际晶振频率相同,是计算其他频率的基础
Fcclk:system clock,= M * Fosc,int M∈ [1, 32],但Fcclk≤60MHz
Fcco:CCO工作频率,= 2 * P * Fcclk = 2 * P * M * Fosc,int p=1/2/4/8,须满足Fcco∈ [156, 320]MHz
Fpclk:外设工作频率
PLLCON:PLL Control
PLLCON [0]:enable PLL when 1
PLLCON [1]:connect PLL when 1
PLLCON [1:0]:00/10->disabled and not connected; 01->enabled but not connected; 11->enabled and connected
PLLCFG:PLL Config
PLLCFG [4:0]:将(M-1)的值写入这5位即设置M值
PLLCFG [6:5]:写入00/01/10/11即设置P值为1/2/4/8
PLLFEED:设置好PLLCON和PLLCFG后,向PLLFEED先后写入0xAA、0x55才能使设置生效(像点击“确定”一样)
PLLSTAT:存储PLL的当前状态(for read)
PLLSTAT [4:0]:当前的PLLCFG [4:0]值
PLLSTAT [6:5]:当前的PLLCFG [6:5]值
PLLSTAT [8]:当前的PLLCON [0]值
PLLSTAT [9]:当前的PLLCON [1]值
PLLSTAT [10]:PLOCK值,为1时表示PLL已被锁定到设置的频率上。PLOCK在0xAA、0x55 写入PLLFEED后由系统自动设置。必须等待PLOCK为1时才能connect PLL
4.PR, PC, TCR, MR, MCR & IR
T0PR、T1PR:用来存储Prescale值
T0PC、T1PC:Prescale Counter,频率为Fpclk,从0开始,递增到Prescale值时,PC置0,TC加1
T0TC、T1TC:Timer Counter,由PC可知,TC的频率为Fpclk/(Prescale+1),是整个Timer的中断源
T0TCR、T1TCR:Timer Control Register
T0TCR、T1TCR [0]:enable TC and PC when 1
T0TCR、T1TCR [1]:reset TC and PC when 1
MR0、MR1、MR2、MR3:设置Match值,当TC递增到Match值时产生动作(产生中断、复位TC或是停止TC和PC,这个动作由MCR控制)
MCR:Match Control Register,控制TC递增到Match值时的动作
MCR [0]:为1时,TC递增到MR0中的Match值时产生中断
MCR [1]:为1时,TC递增到MR0中的Match值时复位TC
MCR [2]:为1时,TC递增到MR0中的Match值时停止TC和PC
MCR [5:3]:对应MR1,顺序同上
MCR [8:6]:对应MR2,顺序同上
MCR [11:9]:对应MR3,顺序同上
T0IR、T1IR:Interrupt Register,有中断时,对应位置1;往某位写入1则将该位置0 (即复位中断),写入0无效
T0IR、T1IR [3:0]:对应timer自身产生的MR3/MR2/MR1/MR0中断
T0IR、T1IR [7:4]:对应捕获到的外部输入中断,即CR3/CR2/CR1/CR0中断
5.向量地址
所谓“向量”,就是引导、跳转的意思,“向量地址”实际就是跳转地址 (another example of why I hate translation)
-> ARM7: 8种异常的向量地址 <-
异常 | 向量地址 | 优先级 |
---|---|---|
Reset 复位 | 0x0000 0000 | 1 (highest) |
Undefined Instruction 未定义指令 | 0x0000 0004 | 6 |
Software Interrupt (SWI) 软件中断 | 0x0000 0008 | 7 (lowest) |
Prefetch Abort (instruction fetch memory fault) 预取指中止 | 0x0000 000C | 5 |
Data Abort (data access memory fault) 数据中止 | 0x0000 0010 | 2 |
Reserved (used by the Boot Loader as the Valid User Program key) 保留 | 0x0000 0014 | N/A |
IRQ | 0x0000 0018 | 4 |
6.FIQ
发生中断时,ARM只负责(把PC)跳转到向量地址(FIQ to 0x1C, IRQ to 0x18),后面的工作需要我们自己完成。
FIQ的ISR可以直接写到0x1C,也可以像IRQ一样,用一个一级ISR取到VICVectAddr中的地址(即是二级ISR的地址),再运行二级ISR。当然,也可以直接在0x18写IRQ的ISR,不过 ARM 既然提供了这么多类似VICVectAddr的寄存器,不用白不用。
接下来的问题是:如何把一个函数地址准确地放在0x18/0x1C?
Yeah, we have #pragma
!
In Programming Languages, Principles and Practice (Boston, PWS-Kent Publishing Co, 1993), Kenneth C. Louden writes
“Finally, a translator needs to provide the user options for debugging, for interfacing with the operating system, and perhaps with a software development environment. These options, such as specifying files for inclusion, disabling optimizations or turning on tracing or debugging information, are the pragmatics of a programming language translator. Occasionally, facilities for pragmatic directives (实用性指示), or pragmas, are part of the language definition”
#pragma vector = address
该命令为其后声明的一个中断函数指定地址,即把中断函数和地址绑定
#pragma type_attribute = keyword
该命令影响其后声明的一个函数,keyword包括:
__arm:使函数以ARM模式运行
__thumb:使函数以thumb模式运行
__interwork:使函数既可以以ARM模式运行,也可以以thumb模式运行
__fiq:声明函数为FIQ函数(ISR)
__irq:声明函数为IRQ函数(ISR)
ISR must be compiled in ARM mode. ISR does not accept parameters and does not have a return value.
__swi:声明函数为软件中断函数(ISR)
__monitor:声明函数为监视函数
这些keyword也可以在函数声明时直接使用,如:
__irq __arm interrupt_handler() {
...
}
7.中断引脚
LPC2148有32个中断源(部分保留未用),每个中断源对应一个固定的VIC Channel (VIC Channel #可以看作中断源的编号) (可以理解为每一个中断源有一根固定的信号线连到内核,一有中断就通过这根信号线通知内核)。一些片内中断源已经固定,额外添加的中断源要经过外部中断引脚(EINT),此时要用到PINSEL,一般使用P0.15和P0.16,因为P0.15对应S4(也就是说S4可以控制P0.15的值,也一点并不只是在P0.15用作GPIO时才成立),P0.16对应S5,而它们又分别对应EINT2和EINT0 (关于YL所做的内部连接是个让人头痛的问题)
EXTMODE:设置EXTINT的捕捉模式
EXTMODE [0]:对应EINT0,置1表示即EXTINT捕捉EINT0引脚上的边沿,0表示EXTINT捕捉EINT0引脚上的电平
EXTMODE [1]:对应EINT1,同上
EXTMODE [2]:对应EINT2,同上
EXTMODE [3]:对应EINT3,同上
EXTPOLAR:设置EXTINT的捕捉极性
EXTPOLAR [0]:对应EINT0,置1表示EXTINT捕捉EINT0引脚上的高电平或是上升沿,0表示EXTINT捕捉EINT0引脚上的低电平或是下降沿
EXTPOLAR [1]:对应EINT1,同上
EXTPOLAR [2]:对应EINT2,同上
EXTPOLAR [3]:对应EINT3,同上
EXTINT:External Interrupt Flag register (where dose the ‘F’ go?)
EXTINT [0]:对应EINT0,若捕捉到EINT0上的敏感信号(电平或是边沿),则该位置1,否则为0,写入1则将该位置0
EXTINT [1]:对应EINT1,同上
EXTINT [2]:对应EINT2,同上
EXTINT [3]:对应EINT3,同上
8.中断源
32个中断源可以设置为FIQ和IRQ两种模式,有关FIQ和IRQ的处理方式,参见第6点。
VICIntEnable:使能中断源
VICIntEnable [x]:置1表示使能第x号中断源(即是VIC Channel #为x的中断源),写0无效
VICIntEnClr:禁止中断源
VICIntEnClr [x]:写入1即将VICIntEnable [x]置0,写0无效
VICIntSelect:设置中断源
VICIntSelect [x]:写1表示把第x号中断源设置为FIQ,写0则设置为IRQ
VICFIQStatus:FIQ Status
VICFIQStatus [x]:为1表示第x号中断源产生FIQ中断请求
VICIRQStatus:IRQ Status
VICIRQStatus [x]:为1表示第x号中断源产生IRQ中断请求
LPC2148有16个优先级(对应16个slot,0到15优先级从高到低)供IRQ使用,使用slot的IRQ即是向量IRQ,没有使用slot的IRQ即是非向量IRQ
VICVectAddr0~VICVectAddr15、VICDefVectAddr、VICVectAddr:
当ISR读取VICVectAddr时,VICVectAddr会先去查找发送过来的最高优先级的VICVectAddrx (若有向量IRQ发生,VIC会把对应的VICVectAddrx发送到VICVectAddr),若没有VICVectAddrx发送过来 (即没有向量IRQ发生),则VICVectAddr返回VICDefVectAddr (Def: default)中的地址值
所以一般把非向量IRQ的地址放在VICDefVectAddr (第6点中提到处理FIQ也可以在一级ISR里读取VICVectAddr,所以FIQ的ISR一般也是写在VICDefVectAddr里的),如果有多个非向量IRQ或是FIQ中断源,则在ISR里要先用if-else或是swith-case来判断中断源,再做相应的处理。若是非向量IRQ倒也无所谓,反正非向量IRQ不要求处理速度;若是FIQ则会严重影响FIQ的处理速度,所以一般只设置1个FIQ中断源(总之是越少越好)
“VICVectAddr查找发送过来的最高优先级的VICVectAddrx”实际是通过一个硬件的排序器来实现的,在ISR末尾应向VICVectAddr写入(一般是0x00)来清除硬件排序器中的中断标志
Comments