基于S3C6410的ARM11学习(三)核心初始化之设置中断向量表

更新时间:2023-05-23 10:48:30 阅读: 评论:0

基于S3C6410的ARM11学习(三)核⼼初始化之设置中断向
量表
前⾯将流程搞清楚后,下⾯就开始进⾏按照顺序来编写程序了。
deposition第⼀步就是进⾏中断向量表的设置。在ARM11中,中断向量表叫做异常向量表。
ARM11共有10种异常,这个在ARM11的datasheet中有。
这⾥说明⼀下:
异常说明详细说明
Ret复位异常当系统刚上电,或者按下复位键时候,触发这个异常,这个时候,程序跳转到这个地址处执⾏程序
undefined_instruction 未定义指令
len异常
当程序执⾏发现有⼀条指令是未定义的指令,会触发这个异常,这个时候,程序跳转到这个地址
处执⾏程序
software_interrupt软中断异常当软件设置软中断时,会触发这个异常,这个时候,程序跳转到这个地址处执⾏程序prefetch_abort取指异常当CPU取指令发⽣问题时,会触发这个异常,这个时候,程序跳转到这个地址处执⾏程序
data_abort数据异常这个就包括内部取数据和外部取数据,当取数据发⽣问题时,会触发这个异常,这个时候,程序跳转到这个地址处执⾏程序
irq中断异常当有中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执⾏程序
fiq快中断异常当快中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执⾏程序
ebuddy最后⼀个⽬前不知道是什么意思。现在也⽤不上,先就不管了。
异常,也都写得⽐较清楚,都知道这些异常⼤致是⼲什么的。这⾥,要注意,异常发⽣的时候,是跳转到异常地址去执⾏程序的,但是每个异常地址的⼤⼩是4个字节,4个字节⼤⼩肯定是放不下程序的。所以,肯定会有第⼆级跳转。所以这个异常地址的指令,就是⼀个跳转指令,跳转到对应的程序去执⾏。
这些异常,现在不⽤清楚这些异常怎么⽤,⽤的时候再来学习就可以了。只要知道有这么些异常就可以了。
这些异常的地址是固定的,这个和STM32是不⼀样的。所以,我们设置中断向量表的时候,要将这些异常写在固定的地址上。这样,程序才能正常访问这些异常。
异常地址
Ret0x0000_0000
undefined_instruction0x0000_0004
software_interrupt0x0000_0008
prefetch_abort0x0000_000c
data_abort0x0000_0010
irq0x0000_0018
fiq0x0000_001c
从表中,会发现,数据异常和中断异常之间怎么相隔了8个字节⼤⼩,其他都是相隔的4个字节⼤⼩。这⾥是保留了⼀个异常,但是⽬前没有定义这个异常是什么,所以把地址给空出来了。所以,我们写程序的时候,要注意把这个地址给空出来。
下⾯就是我们的程序:
.text.global _start_start:    b ret    ldr  pc, _undefined_instructions    ldr  pc, _software_interrupt    ldr  pc, _prefetch_abort    ldr  pc, _data_abort    ldr  pc, _no_u    ldr  pc, _irq    ldr  pc, _fiq_undefined_instructions:    .word undefined_instructions_software_interrupt:    .word
software_interrupt_prefetch_abort:    .word prefetch_abort_data_abort:    .word data_abort_no_u:    .word no_u_irq:    .word irq_fiq:    .word fiq  undefined_instructions:    nopsoftware_interrupt:    nopprefetch_abort:    nop data_abort:    nopno_u:    nop irq:    nop fiq:    nopret:
简单说明下
.text :  表⽰是代码段,说明下⾯的程序是代码
.global _start : 定义全局标号_start
萌发>感动在身边
_start的代码,就是设置中断向量表了。可以看出,其实都是跳转指令。不同的异常,跳转到不同的地⽅去执⾏程序,这样就实现了异常的处理。
这⾥
ldr  pc, _undefined_instructions    1
_undefined_instructions:
.word undefined_instructions
undefined_instructions:
nop
1的指令,就是将标号_undefined_instructions地址处的值赋值给pc,这样pc的值就是undefined_instructions的值,所以就跳转
到undefined_instructions程序地⽅去执⾏。这⾥,undefined_instructions程序就只有⼀个nop指令。因为⽬前没有⽤到这些异常,所以这⾥,除了Ret异常我们是编写代码外,其他的异常我们都是写的nop。
其他异常的分析,和以上的分析是⼀样的。只是要注意,我们中间定义了⼀个_no_u异常。可是这个异常是ARM异常⾥⾯没有的。这⾥定义这个异常,就是为了占⼀个字节⼤⼩,这样的话,irq的地址才会是0x0000_0018,否则的话就是0x0000_0014,这样就不对了。
这⾥有个问题,只有Ret的跳转指令是b指令,其他的指令都是ldr指令。这个是为什么了?
b指令是相对跳转指令,ldr是绝对跳转指令。在上电或者复位的时候,程序在内部的stepping stone中执⾏,地址从0x0000_0000开始。但是我们在编译代码的时候,⽤的链接脚本的链接地址是0x5000_0000,如果使⽤ldr决定跳转指令的话,就会跳到内存去执⾏程序了,这个时候,我们还没有把程序拷贝到内存中,所以执⾏就会出错了,所以这⾥使⽤b指令。复位结束后,我们已经把代码拷贝到内存中去了,所以这个时候,就要⽤ldr绝对跳转指令了。erasmus
以上,就将我们的异常向量表就设置好了,接下来,我们就对Ret函数编写代码就好了。因为这⾥写的代码,就是上电执⾏的代码。
对⽐⼀下STM32的中断向量表的建⽴:
这个应该很多学STM32的⼈,都很少去分析这个了,我以前也没有分析,现在是学习⽐较的时候,才去分析了⼀下这个东西,发现了很多好玩的东西。
STM32不像ARM⼀样,分为⼏个异常,⽽是将各个异常都分开成独⽴的中断(在STM32中将异常称为中断了)。在ARM11中,只有⼀个irq异常,这样的话,不管是什么中断发⽣,都会跳转到irq的代码去执⾏。但是STM32就不是了,他将各个中断给独⽴开,⽐如外部有外部中断,串⼝有串⼝中断。。。当外部中断产⽣时,就执⾏外部中断的代码,不会执⾏串⼝中断的代码。所以STM32的中断向量表就相对⽐较⼤。stud
下⾯是中断向量表的⼀部分截图
前⾯⼏个是系统的⼀些中断,后⾯是外设的⼀些中断。我们发现第⼀个Ret中断的地址竟然不是0x0000_0000,⽽是
0x0000_0004。这⾥先记下来,后⾯分析。
上⾯就是外设的⼀些中断,可以看出,不同的外设对应不同的中断,⽽不同的中断有不同的地址。
这⾥,要说明⼀下,STM32的中断向量表和ARM11的中断向量表有什么区别,最⼤的区别就是
STM32的中断向量表的内容保存的是中断的⼊⼝地址,即当中断发⽣时,PC需要跳转的地址
ARM11的中断向量表的内容是异常发⽣时需执⾏的指令,即当异常发⽣时,PC应该执⾏什么指令。
所以,从上⾯两个区别可以得出:
ARM11的中断向量表的位置是绝对唯⼀的,即每个异常的地址是固定的,Ret就是0x0000_0000, irq就是0x0000_0018。
研磨粉STM32的中断向量表的位置不是唯⼀的。即每个中断的地址是可以随意放置的。因为他存的是中断的⼊⼝地址,⽽不是存的指令。
还有⼀个区别,STM32的Ret的地址是0x0000_0004,⽽不是0x0000_0000。那是因为,STM32规定中断向量表的第⼀项内容,存的是栈的地址。这个和ARM11也不⼀样,ARM11的中断向量表的第⼀项内容就是Ret的指令。
从STM32的启动⽂件分析,在代码的前⾯,就定义了这样⼀个向量表,这个就是中断向量表,⾥⾯保存的每个中断的⼊⼝地址。第⼀项内容就是栈的地址。依次是定义各个中断的⼊⼝地址。使⽤DCD    0是定义⼀个数据,⽤来占位的。
中断向量表定义之后,就是定义各个中断函数了。
march是什么意思第⼀个定义的是复位中断,也是就系统上电或者复位有效的时候,执⾏的程序。后⾯的依次定义各个中断函数。每个函数的后⾯都带有[WEAK]属性,表⽰这⾥定义的函数是弱函数,外部程序是可以改写freak out
这个中断函数的。
到这⾥,我们就可以知道,因为这⾥定义了中断函数,所以,当你要使⽤某个外设的中断的时候,中断函数名字可是不能随便取的,⽽是要和这⾥取的名字要⼀样。不然的话,就跳转不到正确的中断地址去了。
在复位中断函数中,会跳转到SystemInit去执⾏,这个函数是对时钟和中断向量表进⾏设置。我们这⾥就看中断向量表的设置。
这⾥将设置中断向量表的代码和代码中宏定义定义的值给截图出来。
⾸先是判断是否定义了VECR_TAB_SRAM这个宏定义,
定义的话,那么中断向量表的基地址就为SRAM_BASE | VECT_TAB_OFFSET
否则的话,中断向量表的基地址就为FLASH_BASE | VECT_TAB_OFFSET
要理解这个代码,就得要说说STM32的启动⽅式。之前知道ARM11的启动⽅式有多种,从NANDFLASH启动,从SD卡启动。。。。不管怎么启动,ARM11都是从外部的存储器设备启动的。但是我们的STM32可不是这样的噢。
⾸先贴上STM32的内部存储器的图。
这个图,没有画出内部闪存FLASH的区域。可以看到内部是有SRAM的,地址从0x2000—_0000到0x3FFFF_FFFF。⽽且空间还挺⼤的,有0.5G空间,但是不是所有的STM32都使⽤了这0.5G空间,像我⽤的STM32F103ZET6,只有64KB的SRAM,不过已经很⼤了。不像ARM11,只有8K⼤⼩。所以⼀般STM32是不需要外加SRAM的。还有⼀个闪存区,图上没有画,从0x0800_0000开始,⾄于结束地址由芯⽚的FLASH⼤⼩决定的。我⽤的是STM32F103ZET6系列,FLASH⼤⼩是512K。看出来,这⼤⼩也不算特别⼤,但是⼀般的程序还是够了,毕竟,我们都是⽤STM32写裸机程序的。
所以说,程序是可以从内部FLASH启动,或者是从SRAM启动的。
这个就是由芯⽚的两个管脚来决定的。
我⽤过是主闪存和内置SRAM模式,这两个⽐较常见。内置SRAM模式启动⼀般是调试的时候⽤的。因为FLASH的擦除次数是有限的,调试的话会⼀直擦除FLASH。会影响FLASH寿命。
有了上⾯的知识后,理解设置中断向量表的程序就不难了。
定义了VECT_TAB_SRAM这个宏定义,就说明程序是从SRAM启动了,所以就要将中断向量表的基地址给映射到SRAM的起始地址中。SRAM的起始地址是0x2000_0000。
如果没有定义这个宏的话,就说明程序从FLASH启动,所以就要将中断向量表的基地址给映射到FLASH的起始地址中。FLASH的起始地址是0x0800_0000。
因为之前说过,STM32的中断向量表的位置是可以随意放的,可以就可以映射到内存或者是FLASH中。但是ARM11可就不⾏了,就必须得是0x0000_0000处。
以上,就分析了核⼼初始化的第⼀步,设置中断向量表,接着,就是进⾏设置处理器的模式了。

本文发布于:2023-05-23 10:48:30,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/78/744130.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:中断   程序   地址   中断向量   跳转
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图