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

发布者:星际穿越最新更新时间:2018-12-18 来源: eefocus关键字:S3C6410  ARM11  核心初始化  中断向量表 手机看文章 扫描二维码
随时随地手机看文章

前面将流程搞清楚后,下面就开始进行按照顺序来编写程序了。


           第一步就是进行中断向量表的设置。在ARM11中,中断向量表叫做异常向量表。


           ARM11共有10种异常,这个在ARM11的datasheet中有。


           clip_image002


这里说明一下:


异常

说明

详细说明

Reset

复位异常

当系统刚上电,或者按下复位键时候,触发这个异常,这个时候,程序跳转到这个地址处执行程序

undefined_instruction

未定义指令异常

当程序执行发现有一条指令是未定义的指令,会触发这个异常,这个时候,程序跳转到这个地址处执行程序

software_interrupt

软中断异常

当软件设置软中断时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序

prefetch_abort

取指异常

当CPU取指令发生问题时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序

data_abort

数据异常

这个就包括内部取数据和外部取数据,当取数据发生问题时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序

irq

中断异常

当有中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执行程序

fiq

快中断异常

当快中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执行程序


 最后一个目前不知道是什么意思。现在也用不上,先就不管了。

 

异常,也都写得比较清楚,都知道这些异常大致是干什么的。这里,要注意,异常发生的时候,是跳转到异常地址去执行程序的,但是每个异常地址的大小是4个字节,4个字节大小肯定是放不下程序的。所以,肯定会有第二级跳转。所以这个异常地址的指令,就是一个跳转指令,跳转到对应的程序去执行。


 这些异常,现在不用清楚这些异常怎么用,用的时候再来学习就可以了。只要知道有这么些异常就可以了。


 这些异常的地址是固定的,这个和STM32是不一样的。所以,我们设置中断向量表的时候,要将这些异常写在固定的地址上。这样,程序才能正常访问这些异常。


异常

地址

Reset

0x0000_0000

undefined_instruction

0x0000_0004

software_interrupt

0x0000_0008

prefetch_abort

0x0000_000c

data_abort

0x0000_0010

irq

0x0000_0018

fiq

0x0000_001c


从表中,会发现,数据异常和中断异常之间怎么相隔了8个字节大小,其他都是相隔的4个字节大小。这里是保留了一个异常,但是目前没有定义这个异常是什么,所以把地址给空出来了。所以,我们写程序的时候,要注意把这个地址给空出来。


下面就是我们的程序:


.text.global _start_start:    b reset    ldr  pc, _undefined_instructions    ldr  pc, _software_interrupt    ldr  pc, _prefetch_abort    ldr  pc, _data_abort    ldr  pc, _no_use    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_use:    .word no_use_irq:    .word irq_fiq:    .word fiq   undefined_instructions:    nopsoftware_interrupt:    nopprefetch_abort:    nop data_abort:    nopno_use:    nop irq:    nop fiq:    nopreset:


简单说明下


.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指令。因为目前没有用到这些异常,所以这里,除了Reset异常我们是编写代码外,其他的异常我们都是写的nop。


 其他异常的分析,和以上的分析是一样的。只是要注意,我们中间定义了一个_no_use异常。可是这个异常是ARM异常里面没有的。这里定义这个异常,就是为了占一个字节大小,这样的话,irq的地址才会是0x0000_0018,否则的话就是0x0000_0014,这样就不对了。

 

这里有个问题,只有Reset的跳转指令是b指令,其他的指令都是ldr指令。这个是为什么了?


b指令是相对跳转指令,ldr是绝对跳转指令。在上电或者复位的时候,程序在内部的stepping stone中执行,地址从0x0000_0000开始。但是我们在编译代码的时候,用的链接脚本的链接地址是0x5000_0000,如果使用ldr决定跳转指令的话,就会跳到内存去执行程序了,这个时候,我们还没有把程序拷贝到内存中,所以执行就会出错了,所以这里使用b指令。复位结束后,我们已经把代码拷贝到内存中去了,所以这个时候,就要用ldr绝对跳转指令了。


以上,就将我们的异常向量表就设置好了,接下来,我们就对Reset函数编写代码就好了。因为这里写的代码,就是上电执行的代码。


对比一下STM32的中断向量表的建立:


这个应该很多学STM32的人,都很少去分析这个了,我以前也没有分析,现在是学习比较的时候,才去分析了一下这个东西,发现了很多好玩的东西。


STM32不像ARM一样,分为几个异常,而是将各个异常都分开成独立的中断(在STM32中将异常称为中断了)。在ARM11中,只有一个irq异常,这样的话,不管是什么中断发生,都会跳转到irq的代码去执行。但是STM32就不是了,他将各个中断给独立开,比如外部有外部中断,串口有串口中断。。。当外部中断产生时,就执行外部中断的代码,不会执行串口中断的代码。所以STM32的中断向量表就相对比较大。

          

下面是中断向量表的一部分截图


clip_image004


前面几个是系统的一些中断,后面是外设的一些中断。我们发现第一个Reset中断的地址竟然不是0x0000_0000,而是0x0000_0004。这里先记下来,后面分析。


clip_image005

    

上面就是外设的一些中断,可以看出,不同的外设对应不同的中断,而不同的中断有不同的地址。

     

这里,要说明一下,STM32的中断向量表和ARM11的中断向量表有什么区别,最大的区别就是


STM32的中断向量表的内容保存的是中断的入口地址,即当中断发生时,PC需要跳转的地址


ARM11的中断向量表的内容是异常发生时需执行的指令,即当异常发生时,PC应该执行什么指令。


所以,从上面两个区别可以得出:

 

ARM11的中断向量表的位置是绝对唯一的,即每个异常的地址是固定的,Reset就是0x0000_0000, irq就是0x0000_0018。

 

STM32的中断向量表的位置不是唯一的。即每个中断的地址是可以随意放置的。因为他存的是中断的入口地址,而不是存的指令。


还有一个区别,STM32的Reset的地址是0x0000_0004,而不是0x0000_0000。那是因为,STM32规定中断向量表的第一项内容,存的是栈的地址。这个和ARM11也不一样,ARM11的中断向量表的第一项内容就是Reset的指令。


clip_image007


从STM32的启动文件分析,在代码的前面,就定义了这样一个向量表,这个就是中断向量表,里面保存的每个中断的入口地址。第一项内容就是栈的地址。依次是定义各个中断的入口地址。使用DCD    0是定义一个数据,用来占位的。


      中断向量表定义之后,就是定义各个中断函数了。


clip_image009

 

 第一个定义的是复位中断,也是就系统上电或者复位有效的时候,执行的程序。后面的依次定义各个中断函数。每个函数的后面都带有[WEAK]属性,表示这里定义的函数是弱函数,外部程序是可以改写这个中断函数的。

 到这里,我们就可以知道,因为这里定义了中断函数,所以,当你要使用某个外设的中断的时候,中断函数名字可是不能随便取的,而是要和这里取的名字要一样。不然的话,就跳转不到正确的中断地址去了。


 在复位中断函数中,会跳转到SystemInit去执行,这个函数是对时钟和中断向量表进行设置。我们这里就看中断向量表的设置。


clip_image011

clip_image013

clip_image015


这里将设置中断向量表的代码和代码中宏定义定义的值给截图出来。


   首先是判断是否定义了VECR_TAB_SRAM这个宏定义,


定义的话,那么中断向量表的基地址就为SRAM_BASE | VECT_TAB_OFFSET


否则的话,中断向量表的基地址就为FLASH_BASE | VECT_TAB_OFFSET


要理解这个代码,就得要说说STM32的启动方式。之前知道ARM11的启动方式有多种,从NANDFLASH启动,从SD卡启动。。。。不管怎么启动,ARM11都是从外部的存储器设备启动的。但是我们的STM32可不是这样的噢。


首先贴上STM32的内部存储器的图。


clip_image017

   

这个图,没有画出内部闪存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启动的。


   这个就是由芯片的两个管脚来决定的。


clip_image019

  

我用过是主闪存和内置SRAM模式,这两个比较常见。内置SRAM模式启动一般是调试的时候用的。因为FLASH的擦除次数是有限的,调试的话会一直擦除FLASH。会影响FLASH寿命。


  有了上面的知识后,理解设置中断向量表的程序就不难了。


  定义了VECT_TAB_SRAM这个宏定义,就说明程序是从SRAM启动了,所以就要将中断向量表的基地址给映射到SRAM的起始地址中。SRAM的起始地址是0x2000_0000。


  如果没有定义这个宏的话,就说明程序从FLASH启动,所以就要将中断向量表的基地址给映射到FLASH的起始地址中。FLASH的起始地址是0x0800_0000。


  因为之前说过,STM32的中断向量表的位置是可以随意放的,可以就可以映射到内存或者是FLASH中。但是ARM11可就不行了,就必须得是0x0000_0000处。


  以上,就分析了核心初始化的第一步,设置中断向量表,接着,就是进行设置处理器的模式了。


关键字:S3C6410  ARM11  核心初始化  中断向量表 引用地址:基于S3C6410的ARM11学习(三) 核心初始化之设置中断向量表

上一篇:基于S3C6410的ARM11学习(一) 基础知识
下一篇:基于S3C6410的ARM11学习(七) 核心初始化之关闭MMU和CACHE

推荐阅读最新更新时间:2024-03-16 16:20

S3C6410裸机SD卡驱动(SDIO模式)
花了几天写了SD卡裸机驱动,现在还不完善,只支持4G以内的卡,以后再加上;现在经过修改可以写入数据了,亲测没问题. S3C6410_SDIO.C #include s3c6410_system.h #include s3c6410_sdio.h /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //配置 //块大小寄存器(0通道)BLKSIZE0 #define BLKSIZE0_BLKSIZE
[单片机]
在ubuntu下开发ARM裸机程序--S3C6410—LED
很多人都是在ads或者rvds或keil中开发ARM裸机程序,使用此类的开发工具虽然简单但是却不能使开发者很好的掌握更多程序原理,要想更好的掌握更多程序细节,感觉还是最好使用arm-linux-进行开发。 转载请注明出处,谢谢,张同浩:http://blog.csdn.net/muge0913/article/details/15016959 邮箱:muge0913@sina.com 下面是一个简单的点亮led灯的程序,在tiny6410上运行。其中set_peri_port函数是必须要添加的,这样才能访问到s3c6410的外设空间。 @ @ File:led_on.S @ 功能:LED点灯程序,点亮LED1 @
[单片机]
S3C6410核心初始化
一:异常向量表 异常定义:因为内部或者外部一些事件,导致处理器停下正在处理的工作,转而去处理这些发生的事件。当一种异常发生的时候,ARM处理器会跳转到对应该异常的固定地址去执行异常处理程序,而这个固定的地址,就称之为异常向量。以下为七个异常向量及处理函数跳转关系组成的表。 在Data Abort和IRQ之间有一段地址没有用上,在初始化的时候需要补上一段_not_used ,不然的话会报错,在发生异常的时候,程序会跳转到undefined_instruction: nop这段去执行,由于现在还不需要操作这些异常向量,所以在后面只加上nop。具体以后还会进一步学到 .text .global _start _st
[单片机]
<font color='red'>S3C6410</font><font color='red'>核心</font><font color='red'>初始化</font>
ARM11——点亮LED灯
首先你得有三星公司提供的startup.s文件,用来初始化并通过跳转进入main()函数 使用软件:ADS1.2 使用JLINK调试 //使用加入头文件, //以下头文件中包含了6410的寄存器的定义 #include s3c6410_addr.h //#include utils.h //用来使用Uart_Printf函数 //配置LED灯亮暗的数据 //这里你得知道你的LED灯所在的具体引脚位置,例:GPK4-GPK7 //输出低电平点亮LED #define LED1_ON ~(1 4) #define LED2_ON ~(1 5) #define LED3_ON
[单片机]
s3c6410串口裸机开发串口波特率计算
假设时钟选择为PCLK(S3C6410为66Mhz) 由以下两个公式可以帮助我们通过设置相关寄存器来决定串口波特率 公式1: 公式2: 我们可以先通过公式2算出DIV_VAL的值,然后将接近DIV_VAL的值赋给寄存器UBRDIVn,然后在根据公式1算出num of 1's in UDIVSLOTn。其中UDIVSLOTn的赋值可以根据下表来设置: 通过上述配置,就将UBRDIVn和UDIVSLOTn的值确定下来,从而得到我们想要的波特率bps 将此公式和表格列出,方便以后再做开发使用。 参考: S3C6410 datasheet
[单片机]
<font color='red'>s3c6410</font>串口裸机开发串口波特率计算
基于ARM11的无线视频监控系统
  1 引言   随着无线网络的普及,ARM 处理器运算的能力不断地增强以及计算机处理图像的技术不断地提高,基于ARM 的视频监控正越来越广泛的应用于学校,社区,酒店,网吧,医疗等各种各样地领域。传统的视频监控系统布线复杂,设备庞大,智能化低,以及软硬件资源得不到充分的发挥。而ARM 嵌入式系统的小型化、占用空间小、成本低廉、结构紧凑、支持无线网络等特点,使得利用S3C6410 的ARM11+linux系统构成各种各样的无线网络数字监控系统具有广泛的应用价值。   2 系统整体设计   2.1 硬件总体设计   本系统采用韩国三星公司ARM11 内核的S3C6410 作为微处理器,该款处理器体积小,尺寸仅相当于一个48mm
[单片机]
基于<font color='red'>ARM11</font>的无线视频监控系统
ARM Linux (S3C6410架构/2.6.35内核)的内存映射(四)
set_pte_ext()的作用是根据Linux给出的Linux版本页表项来填充Arm硬件版本的页表项。 对于s3c6410,set_pte_ext()函数由汇编宏armv6_set_pte_ext来实现,定义在proc-macros.S文件中。 进入函数时,参数分别为: r0: pte的地址,这里的pte是二级页表Linux版本中对应的页表项。 r1: Linux版二级页表项的内容。 r2: 0。 .macro armv6_set_pte_ext pfx str r1, , #-2048 @ linux version bic r3, r1, #0x000003fc bic r3, r3, #PTE_TYPE_
[单片机]
支持S3C6410处理器SD卡启动模式的U-Boot-2011.06移植修改方案
通用Bootloader(Universal Bootloader,U-Boot)是系统上电后执行的第一段代码,其作用主要包括初始化硬件环境以及加载执行操作系统内核。在进行系统安装时,U-Boot通常需要使用专用工具烧写到FLASH中,内核及文件系统则通过U-Boot命令进行烧写,该过程操作繁琐,并且容易出错,不适宜系统的大量安装。 S3C6410是三星公司生产的一款基于ARM11架构的通用嵌入式处理器,其启动方式除了传统的Flash启动模式外,还支持从SD 卡中启动系统。本文基于S3C6410处理器,分析了从SD卡启动系统的原理,并对U-Boot源码进行修改以支持该启动方式,在此基础上进一步扩展了U-Boot的功能,使其支持
[单片机]
支持<font color='red'>S3C6410</font>处理器SD卡启动模式的U-Boot-2011.06移植修改方案
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved