[ZLG-ARM] AT91RM9200 AIC总结(中断在灵活使用)

[复制链接]
 楼主| armqt 发表于 2009-7-9 13:38 | 显示全部楼层 |阅读模式
当ARM处理器上电或者Reset之后,处理器从0x0取指。因此,必须保证系统上电时,0x0处有指令可以执行。所以,上电的时候,0x0地址处必定是ROM或者Flash(NOR)。<br /><br />Remap<br />1.什么是Remap?<br />在ROM从0x0用几句指令引导系统之后,把RAM映射到0x0就是Remap。比如AT91RM9200,系统资源:片内128K的rom,片内16K的SRAM。复位后片内的ROM可以通过0x0和0x0010_0000来访问,片内SRAM通过0x0020_0000来访问。系统启动后,通过Remap命令可以把片内SRAM映射到0x0处,即remap后,只能通过0x0010_0000访问片内rom,通过地址0x0和0x0020_0000访问片内SRAM。<br />&nbsp;&nbsp;Remap前后,不同之处就是片内RAM的位置变了。<br />2.Remap的作用,为何要进行remap呢?有什么好处?<br />为了加快启动的速度,也方便可以更改异常向量表,加快中断响应速度,往往把异常向量表映射到更快、更宽的RAM中。但是异常向量表的开始地址是由ARM架构决定的,必须位于0x0处,因此,必须把RAM映射到0x0处。<br />所以9200如果要执行带中断的程序,必须Remap。<br />3.Remap的实现<br />&nbsp;&nbsp;&nbsp;Remap的实现和ARM处理器的实现相关。<br />&nbsp;&nbsp;&nbsp;1)如果处理器有专门的寄存器可以完成Remap。那么Remap是通过Remap寄存器的相应bit置1完成的。如Atmel&nbsp;AT91RM9200的MC_RCR寄存器中RCB位,注意该命令位是切换的,如果已经remap了,执行后将取消remap。<br />&nbsp;&nbsp;&nbsp;2)如果处理器没有专门的寄存器,但是memory的bank控制寄存器可以用来配置bank的起始地址,那么只要把RAM的起始地址编程为0x0,也可以完成remap。如samsung&nbsp;s3c4510<br />&nbsp;&nbsp;&nbsp;3)如果上面两种机制都没有,那么Remap就不要做了。因为处理器实现决定了SDRAM对应的bank地址是不能改变的。如Samsung&nbsp;S3c2410.<br />&nbsp;&nbsp;&nbsp;4)如果象2410那样不能Remap的话怎么办?2410不是不能Remap吗?为了加快启动速度,可以这样做:<br />&nbsp;&nbsp;&nbsp;A.使用它的NAND&nbsp;boot模式。为什么NAND&nbsp;boot会比较快,那是因为2410里面有块小石头——“SteppingStone”,一块4KB&nbsp;SRAM,它是映射在0x0的。启动程序会自动被copy到这个石头里面。自然异常向量的入口放到这个地方,一样可以达到比NOR&nbsp;boot快的启动、异常响应速度。<br />&nbsp;&nbsp;&nbsp;B.如果你对NOR&nbsp;Boot情有独衷,那么你只好把你的异常向量的入口copy到SDRAM里面,实现所谓的High&nbsp;Vector.<br /><br /><br />&nbsp;<br /> &nbsp;&nbsp;<br />Initboot.c<br />一般在LowlevelInit()部分设置向量表:<br />//&nbsp;Init&nbsp;Interrupt&nbsp;Controller<br />AT91F_AIC_Open(<br />&nbsp;&nbsp;AT91C_BASE_AIC,&nbsp;//&nbsp;pointer&nbsp;to&nbsp;the&nbsp;AIC&nbsp;registers<br />&nbsp;&nbsp;AT91C_AIC_BRANCH_OPCODE,&nbsp;//&nbsp;IRQ&nbsp;exception&nbsp;vector<br />&nbsp;&nbsp;AT91F_UndefHandler,&nbsp;//&nbsp;FIQ&nbsp;exception&nbsp;vector<br />&nbsp;&nbsp;AT91F_UndefHandler,&nbsp;//&nbsp;AIC&nbsp;default&nbsp;handler<br />&nbsp;&nbsp;AT91F_SpuriousHandler,&nbsp;//&nbsp;AIC&nbsp;spurious&nbsp;handler<br />&nbsp;&nbsp;0);&nbsp;//&nbsp;Protect&nbsp;mode,当需要单步跟踪AIC寄存器值时,设置为1,即工作在保护模式下<br /><br /><br />//&nbsp;Perform&nbsp;8&nbsp;End&nbsp;Of&nbsp;Interrupt&nbsp;Command&nbsp;to&nbsp;make&nbsp;sure&nbsp;AIC&nbsp;will&nbsp;not&nbsp;Lock&nbsp;out&nbsp;nIRQ&nbsp;<br />//因为AIC有八级优先级,最多的情况是中断嵌套了8次,所以执行8次中断结束命令<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br />AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);<br /><br />AT91F_AIC_SetExceptionVector((unsigned&nbsp;int&nbsp;*)0x0C,&nbsp;AT91F_FetchAbort);<br />AT91F_AIC_SetExceptionVector((unsigned&nbsp;int&nbsp;*)0x10,&nbsp;AT91F_DataAbort);<br />AT91F_AIC_SetExceptionVector((unsigned&nbsp;int&nbsp;*)0x4,&nbsp;AT91F_Undef);<br />&nbsp;<br /> &nbsp;&nbsp;<br />程序主体部分:main.c<br />#include&nbsp;'AT91RM9200.h'<br />#include&nbsp;'lib_AT91RM9200.h'<br />#include&nbsp;<br />extern&nbsp;void&nbsp;AT91F_IRQ0_ASM_HANDLER(void);<br />char&nbsp;receive[10000];<br />int&nbsp;i=0;<br />void&nbsp;AT91F_IRQ0_HANDLER(void)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;//串口中断<br />&nbsp;&nbsp;&nbsp;int&nbsp;temp;<br />&nbsp;&nbsp;&nbsp;temp=AT91C_BASE_US1-&gtUS_RHR;<br />&nbsp;&nbsp;&nbsp;//receive[i++]=temp;<br />&nbsp;&nbsp;&nbsp;while(!(AT91C_BASE_US1-&gtUS_CSR&AT91C_US_TXRDY));<br />&nbsp;&nbsp;&nbsp;AT91C_BASE_US1-&gtUS_THR=temp;&nbsp;<br />}<br /><br />void&nbsp;AICUS1Init()<br />{<br />&nbsp;&nbsp;AT91F_AIC_ConfigureIt&nbsp;(<br />&nbsp;&nbsp;AT91C_BASE_AIC,&nbsp;//&nbsp;AIC&nbsp;base&nbsp;address<br />&nbsp;&nbsp;AT91C_ID_US1,&nbsp;//&nbsp;System&nbsp;peripheral&nbsp;ID<br />&nbsp;&nbsp;AT91C_AIC_PRIOR_HIGHEST,&nbsp;//&nbsp;Max&nbsp;priority<br />&nbsp;&nbsp;AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED,<br />&nbsp;&nbsp;AT91F_IRQ0_ASM_HANDLER&nbsp;);<br />&nbsp;&nbsp;&nbsp;<br />//&nbsp;Enable&nbsp;IRQ0&nbsp;interrupt<br />AT91F_AIC_EnableIt(AT91C_BASE_AIC,&nbsp;AT91C_ID_US1);<br />}<br /><br />void&nbsp;UART1Init()<br />{<br />&nbsp;&nbsp;//Configure&nbsp;PIO&nbsp;controllers&nbsp;to&nbsp;drive&nbsp;US1&nbsp;signals<br />AT91F_US1_CfgPIO();<br />//Enable&nbsp;Peripheral&nbsp;clock&nbsp;in&nbsp;PMC&nbsp;for&nbsp;US1<br />AT91F_US1_CfgPMC();<br />//外设时钟在PMC初始化时设为60MHz,现在把串口配置为8数据位,没有校验位,1个停止位,波特率为115200,时间保障为0<br />AT91F_US_Configure&nbsp;(<br />&nbsp;&nbsp;(AT91PS_USART)&nbsp;AT91C_BASE_US1,&nbsp;//&nbsp;US1&nbsp;base&nbsp;address<br />&nbsp;&nbsp;60000000,&nbsp;//60&nbsp;MHz<br />&nbsp;&nbsp;AT91C_US_ASYNC_MODE,&nbsp;//&nbsp;mode&nbsp;Register&nbsp;to&nbsp;be&nbsp;programmed<br />&nbsp;&nbsp;115200&nbsp;,&nbsp;//&nbsp;baudrate&nbsp;to&nbsp;be&nbsp;programmed<br />&nbsp;&nbsp;0);&nbsp;//&nbsp;timeguard&nbsp;to&nbsp;be&nbsp;programmed<br /><br />&nbsp;&nbsp;*AT91C_US1_IDR=0xf3fff;//屏蔽所有中断<br />&nbsp;&nbsp;AT91F_US_EnableTx((AT91PS_USART)AT91C_BASE_US1);<br />&nbsp;&nbsp;AT91F_US_EnableRx((AT91PS_USART)AT91C_BASE_US1);<br />&nbsp;&nbsp;*AT91C_US1_IER=AT91C_US_RXRDY;//仅允许RXRDY中断,只要串口收到数据,RXRDY置位后,就产生中断,进入中断处理函数<br />}<br /><br />int&nbsp;main()<br />{<br />&nbsp;&nbsp;&nbsp;UART1Init();&nbsp;//串口配置<br />&nbsp;&nbsp;&nbsp;AICUS1Init();&nbsp;//配置中断<br />}<br />&nbsp;<br /> &nbsp;&nbsp;<br />Asm_isr.s部分:<br />这部分汇编代码主要是为了能够实现中断嵌套做得一些现场保护,如果整个处理器只有一个中断源使能了,这部分代码可以只保留跳到C的那部分。<br />;----------------------------------------------------------------------------<br />AREA&nbsp;itHandler,&nbsp;CODE,&nbsp;READONLY<br />;----------------------------------------------------------------------------<br />&nbsp;&nbsp;&nbsp;&nbsp;INCLUDE&nbsp;AT91RM9200.inc<br />ARM_MODE_USER&nbsp;EQU&nbsp;0x10<br />ARM_MODE_FIQ&nbsp;EQU&nbsp;0x11<br />ARM_MODE_IRQ&nbsp;EQU&nbsp;0x12<br />ARM_MODE_SVC&nbsp;EQU&nbsp;0x13<br />ARM_MODE_ABORT&nbsp;EQU&nbsp;0x17<br />ARM_MODE_UNDEF&nbsp;EQU&nbsp;0x1B<br />ARM_MODE_SYS&nbsp;EQU&nbsp;0x1F<br />I_BIT&nbsp;EQU&nbsp;0x80<br />F_BIT&nbsp;EQU&nbsp;0x40<br />T_BIT&nbsp;EQU&nbsp;0x20<br />;----------------------------------------------------------------------------<br />;-&nbsp;IRQ&nbsp;Entry<br />;----------------------------------------------------------------------------<br />MACRO<br />IRQ_ENTRY&nbsp;$reg<br /><br />;-&nbsp;Adjust&nbsp;and&nbsp;save&nbsp;LR_irq&nbsp;in&nbsp;IRQ&nbsp;stack<br />&nbsp;&nbsp;sub&nbsp;r14,&nbsp;r14,&nbsp;#4<br />stmfd&nbsp;{r14}<br /><br />;-&nbsp;Write&nbsp;in&nbsp;the&nbsp;IVR&nbsp;to&nbsp;support&nbsp;Protect&nbsp;Mode<br />;-&nbsp;No&nbsp;effect&nbsp;in&nbsp;Normal&nbsp;Mode<br />;-&nbsp;De-assert&nbsp;the&nbsp;NIRQ&nbsp;and&nbsp;clear&nbsp;the&nbsp;source&nbsp;in&nbsp;Protect&nbsp;Mode<br />ldr&nbsp;r14,&nbsp;=AT91C_BASE_AIC<br />str&nbsp;r14,&nbsp;[r14,&nbsp;#AIC_IVR]<br /><br />;-&nbsp;Save&nbsp;SPSR&nbsp;and&nbsp;r0&nbsp;in&nbsp;IRQ&nbsp;stack<br />mrs&nbsp;r14,&nbsp;SPSR<br />stmfd&nbsp;{r0,&nbsp;r14}<br /><br />;-&nbsp;Enable&nbsp;Interrupt&nbsp;and&nbsp;Switch&nbsp;in&nbsp;SYS&nbsp;Mode<br />mrs&nbsp;r0,&nbsp;CPSR<br />bic&nbsp;r0,&nbsp;r0,&nbsp;#I_BIT<br />orr&nbsp;r0,&nbsp;r0,&nbsp;#ARM_MODE_SYS<br />msr&nbsp;CPSR_c,&nbsp;r0<br /><br />;-&nbsp;Save&nbsp;scratch/used&nbsp;registers&nbsp;and&nbsp;LR&nbsp;in&nbsp;User&nbsp;Stack<br />IF&nbsp;'$reg'&nbsp;=&nbsp;''<br />stmfd&nbsp;{&nbsp;r1-r3,&nbsp;r12,&nbsp;r14}<br />ELSE<br />stmfd&nbsp;{&nbsp;r1-r3,&nbsp;$reg,&nbsp;r12,&nbsp;r14}<br />ENDIF<br /><br />MEND<br />;----------------------------------------------------------------------------<br />;-&nbsp;IRQ&nbsp;Exit<br />;----------------------------------------------------------------------------<br />&nbsp;&nbsp;MACRO<br />IRQ_EXIT&nbsp;$reg<br />&nbsp;&nbsp;&nbsp;<br />;-&nbsp;Restore&nbsp;scratch/used&nbsp;registers&nbsp;and&nbsp;LR&nbsp;from&nbsp;User&nbsp;Stack<br />&nbsp;&nbsp;IF&nbsp;'$reg'&nbsp;=&nbsp;''<br />ldmia&nbsp;{&nbsp;r1-r3,&nbsp;r12,&nbsp;r14}<br />ELSE<br />ldmia&nbsp;{&nbsp;r1-r3,&nbsp;$reg,&nbsp;r12,&nbsp;r14}<br />ENDIF<br /><br />;-&nbsp;Disable&nbsp;Interrupt&nbsp;and&nbsp;switch&nbsp;back&nbsp;in&nbsp;IRQ&nbsp;mode<br />mrs&nbsp;r0,&nbsp;CPSR<br />bic&nbsp;r0,&nbsp;r0,&nbsp;#ARM_MODE_SYS<br />orr&nbsp;r0,&nbsp;r0,&nbsp;#I_BIT:OR:ARM_MODE_IRQ<br />msr&nbsp;CPSR_c,&nbsp;r0<br /><br />;-&nbsp;Mark&nbsp;the&nbsp;End&nbsp;of&nbsp;Interrupt&nbsp;on&nbsp;the&nbsp;AIC<br />ldr&nbsp;r0,&nbsp;=AT91C_BASE_AIC<br />str&nbsp;r0,&nbsp;[r0,&nbsp;#AIC_EOICR]<br /><br />;-&nbsp;Restore&nbsp;SPSR_irq&nbsp;and&nbsp;r0&nbsp;from&nbsp;IRQ&nbsp;stack<br />ldmia&nbsp;{r0,&nbsp;r14}<br />msr&nbsp;SPSR_cxsf,&nbsp;r14<br /><br />;-&nbsp;Restore&nbsp;adjusted&nbsp;LR_irq&nbsp;from&nbsp;IRQ&nbsp;stack&nbsp;directly&nbsp;in&nbsp;the&nbsp;PC<br />ldmia&nbsp;{pc}^<br /><br />MEND<br />;----------------------------------------------------------------------------<br />;&nbsp;AT91F_IRQ_ASM_HANDLER<br />;&nbsp;Handler&nbsp;called&nbsp;by&nbsp;the&nbsp;AIC<br />;&nbsp;Save&nbsp;context<br />;&nbsp;Call&nbsp;C&nbsp;handler<br />;&nbsp;Restore&nbsp;context<br />;----------------------------------------------------------------------------<br />EXPORT&nbsp;AT91F_IRQ0_ASM_HANDLER<br />IMPORT&nbsp;AT91F_IRQ0_HANDLER<br /><br />AT91F_IRQ0_ASM_HANDLER<br />IRQ_ENTRY<br />ldr&nbsp;r1,&nbsp;=AT91F_IRQ0_HANDLER<br />mov&nbsp;r14,&nbsp;pc<br />bx&nbsp;r1<br />IRQ_EXIT<br />END<br />&nbsp;<br /> &nbsp;&nbsp;<br />上面程序把串口和中断配置好后,就可以用axd+jtag+目标板调试了,我的RO=0x20&nbsp;0000,放在片内sram中运行。<br />打开PC机调试助手,发送一个字符,9200串口收到调试助手发送的数据后,RXRDY置位,产生中断,在中断处理函数中,把串口中的RHR数据取走,然后再写到THR中,发给PC。这样通过观察调试助手发送的数据和接收到的数据是否一致,就可以判断中断是否正常工作了。<br />为了理解AIC的工作过程,最好跟踪一下寄存器的值是如何变化的。所以把AIC配置在保护模式下。<br />0xfffff09C&nbsp;SVR[AT91C_ID_US1]&nbsp;<br />0xfffff100&nbsp;IVR<br />0xfffff108&nbsp;ISR<br />0xfffff10c&nbsp;IPR<br />0xfffff110&nbsp;IMR<br />0xfffff114&nbsp;CISR<br />
lpc2410 发表于 2009-7-9 14:09 | 显示全部楼层

领教了

  
tmake 发表于 2009-7-11 14:11 | 显示全部楼层

很详细

  
JunZe 发表于 2009-9-27 22:40 | 显示全部楼层
谢谢.
稳定分析 发表于 2009-10-25 13:12 | 显示全部楼层
领教啦
稳定分析 发表于 2009-10-25 13:12 | 显示全部楼层
你写得很详细,我看了,觉得你写的很好
稳定分析 发表于 2009-10-25 13:13 | 显示全部楼层
不过不知道是不是自己写的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

150

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

31

主题

150

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部