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