cortexm3权威指南Word文档下载推荐.docx
《cortexm3权威指南Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《cortexm3权威指南Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
![cortexm3权威指南Word文档下载推荐.docx](https://file1.bdocx.com/fileroot1/2022-11/26/1544b941-0ff3-4fd0-ab62-ae4ce92164e6/1544b941-0ff3-4fd0-ab62-ae4ce92164e61.gif)
绝大多数16位Thumb指令只能访问R0-R7,而32位Thumb-2指令可以访问所有存放器。
●BankedR13:
两个堆栈指针
CM3拥有两个堆栈指针,然而是banked(应该是堆积、组合的意思),因此任意时刻只能使用其中的一个。
①主堆栈指针〔MSP〕:
复位后默认使用的堆栈指针,用于操作系统内核以及异常处理例程〔包括中断效劳例程〕。
②进程堆栈指针〔PSP〕:
由用户的应用程序代码使用。
堆栈指针的最低两位永远是0,这意味着堆栈总是4字节对齐的。
在ARM编程领域中,但凡打断程序顺序执行的事件,都被称为异常〔exception〕,如外部中断、或者当有指令执行了“非法操作〞、或者访问被禁的内存空间,因各种错误产生的fault、或者不可屏蔽的中断。
在不严格的上下文中,异常与中断也可以混用。
另外,程序代码也可以主动请求进入异常状态〔常用于系统调用〕。
●R14:
连接存放器(LR)
●R15:
程序计数器(PC)
●特殊功能存放器
CM3在内核水平上搭载了假设干特殊功能存放器,包括:
①程序状态字存放器组〔PSR〕
②中断屏蔽存放器组〔PRIMASK,FAULTMASK,BASEPRI〕
③控制存放器〔CONTROL〕
1.3操作模式和特权级别
Cortex-M3处理器支持两种处理器的操作模式,还支持两级特权操作。
两种操作模式分别为处理者模式〔handlermode〕和线程模式〔threadmode〕。
引入两种模式的本意,是用于区别普通应用程序的代码和异常效劳例程的代码-包括中断效劳例程的代码。
两级特权操作分别为特权级和用户级。
这可以提供存储器访问的保护机制,使得普通用户的程序代码不能意外地,甚至是恶意地执行涉及要害的操作。
处理器支持两种特权级,这也是一个根本的平安模型。
特权级用户级
异常handler的代码
主应用程序的代码
Cortex-M3下的操作模式和特权级别
在CM3运行主应用程序时〔线程模式〕,既可以使用特权级,也可以使用用户级;
但是异常效劳例程必须在特权级下执行。
复位后,处理器默认进入线程模式,特权级访问。
在特权级下,程序可以访问所有范围的存储器〔如果有MPU,还要在MPU规定的禁地之外〕,并且可以执行所有指令。
在特权级下的程序可以为所欲为,但也可能把子集给玩进去——切换到用户级。
一旦进入用户级,再想回来就得走“法律程序〞了——用户级的程序不能简单地试图改写CONTROL存放器就回到特权级,而必须先“申诉〞:
执行一条系统调用指令〔SVC〕,这回触发SVC异常,然后由异常效劳例程〔通常是操作系统的一局部〕接管,如果批准了进入,那么异常效劳例程修改CONTROL存放器,才能在用户级的线程模式下重新进入特权级。
其实,从用户级到特权级的唯一途径就是异常:
如果在程序执行过程中触发了一个异常,处理器总是先切换入特权级,并且在异常效劳例程执行完毕退出时,返回先前的状态。
合法的操作模式转换图
通过引入特权级和用户级,就能够在硬件水平上限制某些不受信任的或者还没有调试好的程序,不让它们随便地配置涉及要害的存放器,因而系统的可靠性得到了提高。
进一步地,如果配了MPU,它还可以作为特权机制的补充——保护关键的存储区域不被破坏,这些区域通常是操作系统的区域。
举例来说,操作系统的内核通常都在特权级下执行,所有没有被MPU禁掉的存储器都可以访问。
在操作系统开启了一个用户程序后,通常都会让它在用户级下执行,从而使系统不会因某个程序的崩溃或恶意破坏而受损。
1.4内建的嵌套向量中断控制器
CM3在内核水平上搭载了一颗中断控制器——嵌套向量中断控制器NVIC(NestedVectoredInterruptController)。
它与内核有很深的“亲密接触〞——与内核是紧耦合的。
NVIC提供如下的功能:
●可嵌套中断支持
●向量中断支持
●动态优先级调整支持
●中断延迟大大缩短
●中断可屏蔽
下面来详细解释下:
可嵌套中断支持的作用范围很广,覆盖了所有的外部中断和绝大多数系统异常。
外在表现是这些异常都可以被赋予不同的优先级。
当前优先级被存储在xPSR的专用字段中。
当一个异常发生时,硬件会自动比较该异常的优先级是否比当前的异常优先级更高。
如果发现来了更高优先级的异常,处理器就会中断当前的中断效劳例程〔或者是普通程序〕,而效劳新来的异常——即立即抢占。
当开始响应一个中断后,CM3会自动定位一张向量表,并且根据中断号从表中找出ISR的入口地址,然后跳转过去执行,不需要像以前的ARM那样,由软件来分辨到底是哪个中断发生了,也无需半导体厂商提供私有的中断控制器来完成这种工作。
这么一来,中断延迟时间大为缩短。
软件可以在运行时期更改中断的优先级。
如果在某ISR中修改了自己所对应中断的优先级,而且这个中断又有新的实例处于挂起中(pending),也不会自己打断自己,从而没有重入风险。
CM3为了缩短中断;
延迟,引入了好几个新特性,包括自动的现场保护和恢复,以及其它的措施,用于缩短中断嵌套时的ISR间延迟。
详情见后面关于“咬尾中断〞和“晚到中断〞的讲述。
既可以屏蔽优先级低于某个阈值的中断/异常〔设置BASEPRI存放器〕,也可以全体封杀〔设置PRIMASK和FAULTMASK存放器〕。
这是为了让时间关键〔time-critical〕的任务能在最后期限〔deadline〕到来前完成,而不被干扰。
注:
鉴于〔外部〕中断的常见性,以后稳重如果没有特殊说明,异常指除了外部中断外的异常,中断表示所有外部中断。
1.5存储器映射
总体来说,CM3支持4GB存储空间,被划分成假设干区域。
不像其它ARM架构的存储器映射由半导体厂家说了算,CM3预先定义好了“粗线条〞的存储器映射。
通过把片上外设的存放器映射到外设区,就可以简单地以访问内存的方式来访问这些外设的存放器,从而控制外设的工作。
结果片上外设可以使用C语言来操作。
这种预定义的映射关系,也使得对访问速度可以做高度的优化,而且对于片上系统的设计而言更易集成〔还有一个重要原因,不用每学一种不同的单片机就要熟悉一种新的存储器映射〕。
CM3的内部拥有一个总线根底设施,专用于优化对这种存储器结构的使用。
在此之上,CM3甚至还允许这些区域之间“越权使用〞。
比方说,数据存储器也可以被放到代码区,而且代码也能够在外部RAM区中执行。
处于最高地址的系统级存储区,是CM3用于藏“私房钱〞的——包括中断控制器、MPU以及各种调试组件。
所有这些设备均使用固定的地址〔下面有专门的章节讨论存储器系统〕。
通过把根底设施的地址锁死,就至少在内核水平上,为应用程序的移植扫清了障碍。
1.6总线接口
CM3内部有假设干个总线接口,使CM3能同时取指和访问〔访问内存〕,它们是:
●指令存储区总线〔两条〕:
负责对代码存储区的访问,分别是I-Code总线和D-Code总线。
前者用于取指,后者用于查表等操作,它们按最正确执行速度进行优化。
●系统总线:
用于访问内存和外设,覆盖的区域包括SRAM、片上外设、片外RAM、片外扩展设备,以及系统级存储区的局部空间。
●私有外设总线:
负责一局部私有外设的访问,主要是访问调试组件。
它们也在系统级存储区。
1.7存储器保护单元〔MPU〕
CM3有一个可选的MPU,配上它以后,就可以对特权级访问和用户级访问分别施加不同的访问限制。
当检测到犯规〔violated〕时,MPU会产生一个fault异常,可以由fault异常的效劳例程来分析该错误,并且在可能时改正它。
MPU有很多玩法,最常见的就是由操作系统使用MPU,以使特权级代码的数据〔包括操作系统本身的数据〕不被其它用户程序弄坏。
MPU在保护内存时是按区管理的,它可以把某些内存region设置成只读,从而防止了那里的内容被意外更改;
还可以再多任务系统中把不同任务之间的数据区隔离。
一句话,它会使嵌入式系统变得更加健壮,更加可靠〔很多行业标准,尤其是航空的,就规定了必须使用MPU来行使保护只能〕。
1.8指令集
CM3只使用了Thumb-2指令集,这是个了不起的突破,因为它允许32位指令和16位指令水乳交融,代码密度与处理性能两手抓,两手都硬。
而且虽然它很强大,却依然易于使用。
CM3比传统的ARM处理器先进表达在以下几个方面:
●消灭了状态切换的额外开销,节省了执行时间和指令空间。
●不再需要把源代码文件分成按ARM编译的和按Thumb编译的,软件开发的管理大大减负。
●无需再反复地求证和测试:
究竟该在何时何地切换到何种状态下,程序才最有效率。
开发软件容易多了。
1.9中断和异常
第二章Cortex-M3根底
触类旁通
2.1存放器组
●R0-R7
也称为低组存放器,所有指令都能访问它们。
字长32位。
复位后初始值不可预料。
●R8-R12
也称为高组存放器,因为只有很少的16位Thumb指令能访问它们,32位的Thumb-2指令那么不受限制。
字长32位,复位后初始值不可预料。
●堆栈指针R13(SP)
CM3微控制器内核中共有两个堆栈指针,于是也就支持两个堆栈。
当引用R13(SP)时,引用的是当前正在使用的那一个,另一个必须用特殊的指令来访问〔MRS和MSR〕。
两个堆栈指针分别是:
①主堆栈指针(MSP):
或写作SP_main,这是默认的堆栈指针,它由OS内核、异常效劳例程以及所有需要特权访问的应用程序代码来使用。
②进程堆栈指针(PSP):
或写作SP_process。
用于常规的应用程序代码。
要注意的是,并不是每个程序都要用齐两个堆栈指针才算圆满,简单的应用程序只使用MSP就够了。
堆栈指针当然是用来访问堆栈的,并且PUSH指令和POP指令默认使用SP。
PUSH和POP汇编语法如下所示:
PUSH{R0}
POP{R0}
也可以一次操作多个存放器:
PUSH{R0-R7,R12,R14}
POP{R0-R7,R12,R14}
注意:
在存放器列表中,不管存放器的序号是以什么顺序给出的,汇编器都将把它们升序排序。
然后先PUSH序号大的存放器,所以也就先POP序号小的存放器。
在程序中为了突出重点,可以把R13写作SP。
在程序代码中,MSP和PSP都被称为R13/SP。
不过,也可以通过MRS/MSR指令来指名道姓地访问具体的堆栈指针。
存放器的PUSH和POP操作永远都是4字节对齐的——也就是说它们的地址必须是0x4、0x8、0xc......。
事实上,R13的最低两位被硬线连接到0,并且总是读出0。
●连接存放器R14〔LR〕
因为其它有些ARM处理器支持ARM和Thumb状态并存,为了方便汇编程序移植,CM3需要允许LSB〔最低有效位〕可读可写。
●程序计数器R15〔PC〕
在分支时,无论是直接写PC的值还是使用分支指令,都必须保证加载到PC的数值是奇数〔即:
LSB=1〕,用以说明这是在Thumb状态下执行。
倘假设写了0,那么视为企图转入ARM模式,CM3将产生一个fault异常。
2.2特殊功能存放器
CM3中的特殊功能存放器包括:
●程序状态存放器组〔PSRs或曰xPSR〕
●中断屏蔽存放器组〔PRIMASK、FAULTMASK、BASEPRI〕
●控制存放器〔CONTROL〕
它们只能被专用的MSR/MRS指令访问,而且它们也没有与之相关联的访问地址。
MRS<
gp_reg>
<
special_reg>
;
读特殊功能存放器的值到通用存放器
MSR<
写通用存放器的值到特殊功能存放器
gp=generalprogram通用程序
2.2.1程序状态存放器〔PSRs或曰xPSR〕
程序状态存放器在其内部又被分为3个子状态存放器:
●APSR:
应用程序PSR
●IPSR:
中断号PSR
●EPSR:
执行PSR
通过MRS/MSR指令,这3个PSR既可以单独访问,也可以组合访问〔2个组合、3个组合都可以〕。
当使用三合一的方式访问时,应使用名字“xPSR〞或者“PSR〞
2.2.2中断屏蔽存放器组
这三个存放器用于控制异常的使能和除能,如下表:
名字
功能描述
PRIMASK
只有单一bit的存放器,被置1后,就关掉所有可屏蔽的异常,只剩下NMI和硬fault可以响应。
默认值为0,表示没有关掉中断
FAULTMASK
只有单一bit的存放器,被置1后,只有NMI才能响应,所有其它的异常,甚至是硬fault,也通通闭嘴。
默认值0,表示没有关异常。
BASEPRI
这个存放器最多有9位〔由表达式优先级的位数决定〕。
它定义了被屏蔽优先级的阈值。
当它被设置成某个值后,所有优先级号大于等于此值的中断都被关〔优先级号越大,优先级越低〕。
但假设被设成0,那么不关闭任何中断,0也是默认值。
NMI:
NonMaskableInterrupt不可屏蔽中断
对于时间-关键任务而言,恰如其分地使用PRIMASK和BASEPRI来暂时关闭一些中断是非常必要的,而FAULTMASK那么可以被OS用于暂时关闭fault处理器能,这种处理在某个任务崩溃时可能需要,因为在任务崩溃时,常常伴随着一大堆fault,总之,FAULTMASK就是专门留给OS用的。
要访问PRIMASK、FAULTMASK、BASEPRI同样需要使用MRS/MSR指令,如:
MRSR0,PRIMASK;
读取PRIMASK到R0中
MRSR0,FAULTMASK;
读取FAULTMASK到R0中
MRSR0,BASEPRI;
读取BASEPRI到R0中
MSRPRIMASK,R0;
写R0到PRIMASK中
MSRFAULTMASK,R0;
写R0到FAULTMASK中
MSRBASEPRI,R0;
写R0到BASEPRI中
只有在特权级下,才允许访问这3个存放器。
补充:
其实,为了快速地开关中断,CM3还专门设置了一条CPS指令,有4种用法:
CPSIDI;
PRIMASK=1;
关中断
CPSIEI;
PRIMASK=0;
开中断
CPSIDF;
FAULTMASK=1;
关异常
FAULTMASK=0;
开异常
2.2.3控制存放器〔CONTROL〕
控制存放器有两个用途:
●用于定义特权级别
●用于选择当前使用哪个堆栈指针
位
功能
CONTROL[0]
0-特权级的线程模式
1=用户级的线程模式
handler模式永远都是特权级的
CONTROL[1]
堆栈指针选择
0=选择主堆栈指针MSP〔复位后的缺省值〕
1=选择进程堆栈指针PSP
在线程或根底级〔没有在响应异常〕,可以使用PSP。
在handler模式下,只允许使用MSP,所以此时不得往该位写1
CONTROL[0]仅在特权级下,此位才可写。
CONTROL[1]仅在特权级的线程模式下,此位才可写,其它场合下禁止写此位。
当然,CONTROL存放器也是通过MRS和MSR指令来操作的:
MRSR0,CONTROL
MSRCONTROL,R0
2.3操作模式
在用户级线程模式下,对系统控制空间〔SCS〕的访问将被阻止——该空间包含了配置存放器组以及调试组建的存放器组。
除此之外,还禁止使用MRS/MSR访问除APSR之外的特殊功能存放器。
如果访问了除APSR之外的特殊功能存放器,那么操作被忽略;
而如果访问SCS空间的,将产生fault。
原文的意思是越权访问一律产生fault。
2.4异常与中断
CM3支持大量异常,包括16-4-1=11个系统异常和最多240个外部中断——简称IRQ(InterruptRequest,中断请求)。
具体使用这240个中断源中的多少个,那么由芯片制造商决定。
由外设产生的中断信号除了SysTick的之外,全都连接到NVIC的中断输入信号线。
典型情况下,处理器一般支持16-32个中断,当然也有在此之外的。
作为中断功能的强化,NVIC还有一条NMI输入信号线。
NMI究竟被拿去做什么,还要视处理器的设计而定。
在多数情况下,NMI会被连接到一个看门狗定时器,有时也会是电压件事功能块,以便在电压掉至危险级别后警告处理器。
NMI可以在任何时间被激活,甚至是在处理器刚刚复位之后。
2.5向量表
当CM3内核响应了一个发生的异常后,对应的异常效劳例程〔ESR〕就会执行。
为了决定ESR的入口地址,CM3使用了“向量表查表机制〞。
这里使用一张向量表,向量表其实是一个WORD〔32位整数〕数组,每个下标对应一种异常,该下标元素的值那么是该ESR的入口地址。
向量表在地址空间中的位置是可以设置的,通过NVIC中的一个重定位存放器来之处向量表的地址。
复位后,该存放器的值为0.因此,在地址0处必须包含一张向量表,用于初始时的异常分配。
异常类型
表项地址偏移量
异常向量
0x00
MSP的初始值
1
0x04
复位
2
0x08
NMI
3
0x0c
硬fault
4
0x10
MemManagefault
5
0x14
总线fault
...
18-255
0x48-0x3FF
IRQ#2-#239
举个例子,如果发生了异常2(NMI),那么NVIC会计算出偏移量是2*4=0x08,然后从那里取出效劳例程的入口地址并跳入。
要注意的是这里有两个另类:
0号类型并不是什么入口地址,而是给出了复位后的MSP的初值。
2.6栈内存操作
2.7Cortex-M3的堆栈实现
2.8复位序列
在离开复位状态后,CM3做的第一件事就是读取以下两个32位整数的值:
●从地址0x00000000处取出MSP的初始值
●从地址0x00000004处取出PC的初始值——这个值是复位向量,LSB必须是1。