我是从网上看到的这篇应用笔记,感觉还可以,分享给大家。我粗略翻译了一点,加了一点自己理解的注释。后面的就不再翻译了,大家想继续看的话到菲利普网站上下吧。 使用LPC2106的Timer 1 进行的简单的中断处理。示例代码中Timer1分为FIQ和IRQ,用户可以从Flash或者SRAM中运行这些代码。 示例展示了ARM构架中中断是如何操作的。提供的代码表示了向量IRQ(中断请求)和FIQ(快速中断)两种情况。中断向量位于FLASH地址中的 0x00-0x1C。如果需要从SRAM中运行,则中断向量需要被remapped to 0x40000000-0x4000000C。这可以通过Memory Map register来做到。这些代码用ADS1.2开发,从FLASH中运行。提供了从SRAM中运行代码的不同之处。中断服务程序(ISR)使用C语言编写IRQ,用汇编来编写FIQ。 示例使用下面的样式排列: 1. TIMER1 被配置为触发IRQ中断,代码从FLASH中运行; 2. 代码从SRAM中运行所需要的改变和增加; 3. TIMER1被配置为触发FIQ中断,代码从FLASH中运行; 4. 代码从SRAM中运行所需要的改变和增加。 TIMER1 被配置为触发一个IRQ中断,代码从FLASH中运行 这个示例包含下述文件: 1. 中断向量表(ivt.s) 2. 启动用的汇编代码(init.s) 3. 主C文件
只包含了相关的文件。在不同的交叉编译环境下,C文件不用改变太多,而汇编文件需要改变。 中断向量表 这些代码应该被连接到0x0。 ;*********************************************************** ; 汇编指令 ;************************************************************* AREA IVT,CODE ;新的代码段 CODE32 ;ARM 代码 IMPORT start ;导入外部函数。Start标志不应该在这个段内定义 ENTRY ;定义程序入口 ;********************************************************************* LDR PC,=START LDR PC,Underfined_Addr LDR PC,SWI_Addr LDR PC,Prefetch_Addr LDR PC,abort_Addr 在 0x14用户应当插入一个标识(checksum),这个标识允许bootloader决定是否允许在FLASH中存放用户代码。当前大多数FLASH编程工具(debuggers and isp utility)有这个内在性能,所以用户不用担心。如果工具没有提供这个功能,这个值需要自己计算,而且应当被插入到0x14。在 LPC2104/5/6的用户手册中的FLASH编程的章节中可以找到checksum相关计算的细节。 DCD ……….. LDR PC,[PC,#=0Xff0] LDR PC,FIQ_Addr Undefined_Addr DCD Undefined_Handler SWI_Addr DCD SWI_Handler Prefetch_Addr DCD Prefetch_Handler Abort_Addr DCD Abort_Handler FIQ_Addr DCD FIQ_Handler ;******************************************************************** ; 意外处理 ;******************************************************************* 下面虚拟的操作在本例子中不做任何有用的操作。这里写下来仅仅是为了完整性 Undefined_Handler B Undefined_Handler SWI_Handler B SWI_Handler Prefetch_Handler B Pretetch_Handler Abort_Handler B Abort_Handler FIQ_Handler B FIQ_Handler END 复位时,本例子执行的第一条指令是: LDR PC,=start 将转移到汇编启动代码,允许中断,建立IRQ的堆栈指针核管理员模式。 中断向量的假肢就是IRQ中断 LDR PC,[PC,#=0Xff0] 这条指令加载到PC,PC地址将从VIC向量地址寄存器(0Xffff f030)转到ISR,并在这里执行转移。其余的向量都是虚拟的中断操作。 启动汇编代码 ;********************************************************************* ; 汇编指令 ;****************************************************************** AREA asm_code,CODE ;新的代码段 CODE32 ;ARM模式 IMPORT _main ;main 不要在此段中定义 EXPORT start ;全局标志,参考ivt.s ;******************************************************************** start ; Enable interrupts MSR cpsr_c,#0x13 为管理模式设置SP。由应用程序所需要的堆栈空间来决定这个值。 LDR SP,=0x4…….. 设置IRQ模式的SP。在设置SP_irq前转换模式到IRQ,然后再返回管理模式。 MRS R0,CPSR BIC R1,R0,#0x1F ORR R1,R1,#0x12 MSR cpsr_c,R1 LDR SP,=0x4…….. MSR cpsr_c,R0 跳转到C代码 LDR lr,=_main MOV pc,lr END 这段代码在第一条指令链接到ivt.s。如果建立堆栈指针失败,将导致数据取消,因此堆栈的建立应当在跳转到C main()前建立。 C 代码 这样的话,TIMER1中相关的寄存器就被建立起来了,当寄存器匹配的时候,TIMER将会中断CPU的核。TIMER1 将会以60M Hz的速度运行。这段代码已经在实验板上测试过。实验板使用10 M Hz的晶振,同样地设置PLL。有关定时器的操作请参考LPC2106、5、4用户手册相关的章节。ISR的寄存器将为空,然后根据需要由后面的用户来设置。_irq编译关键字被用来定义IRQHandler()函数,作为一个IRQ ISR。 执行下面的指令,将会执行 init.s 中的C main LDR lr,=_main MOV pc,lr 下面是C代码: /********************************************************************* 函数功能说明 ************************************************************************/ _irq void IRQHandler(void); void feed(void); void Initialize(void); /***************************************************************** 头文件 *************************************************************/ #include “LPC210x.h” /************************************************************* MAIN ***********************************************************/ int main() { /*建立系统*/ Initialize(); /*启动定时器*/ T1_TCR=0x1; while(1) { } } /******************************************************************* 初始化 *******************************************************************/ void Initialize() { /*初始化PLL(使用10MHz晶振配置),使CPU时钟达到60MHz*/ /*设置驱动和应用*/ PLLCFG=0x25; Feed(); /*开PLL*/ PLLCON=0x1; Feed(); /*等待PLL设置频率并锁定*/ while(!PLLSTAT & PLOCK)){} /*连接PLL作为时钟源*/ PLLCON=0x3; Feed(); 开启MAM,设置时钟数来取得FLASH MEMORY。 MAMCR=0x2; MAMTIM=0x4; 设置设备的时钟(pclk)到系统时钟(cclk) VPBDIV=0X1; 初始化GPIO IODIR = 0Xffff; IOSET = 0Xffff; 初始化TIMER1 T1_TCR = 0x0; T1_TC = 0x0; T1_PR = 0x0; T1_PC = 0x0; 后面的用户来填充相关的值 T1_MR0 = 0x……; 复位,进入相关的中断 T1_MCR = 0x3; 初始化VIC VICINTSEL = 0x0; /*TIMER1选择为IRQ*/ VICINTEN = 0x20; //TIMER1 中断允许 VICCNTL0 = 0x25; ISR 的地址 VICVADDR0 = (unsigned long)IRQHandler; } /******************************************************************** TIMER1 ISR ******************************************************************/ _irq void IRQHandler() { /*这里是中断服务子程序。这个中断需要在TIMER1中清除,然后写入一个合适的值到VIC向量地址寄存器来更新VIC硬件优先级。*/ T1_IR = 0x1; VICVADDR = 0Xff; } /************************************************************** PLL的反馈频率 *************************************************************/ void feed() { PLLFEED = 0Xaa; PLLFEED = 0x55; } 在SRAM中运行上述代码所需要进行的改变和增加 链接需要按照如下方法配置:中断向量表(ivt.s)需要链接到SRAM的底部(0x40000000)。确定相关的中断向量位于0x40000000-0x4000003F。其他的文件链接到代码内部,可以存放在SRAM中。 而且,中断向量需要被remapped to SRAM。使用MEMAP寄存器,配置它为用户RAM模式可以实现。 Int main() { …………………. 初始化 MEMAP MEMAP = 0x2; ……………………….. } TIMER1配置为触发一个FIQ中断,代码从FLASH中运行 例子包含下面的文件: 1. 中断向量表(ivt.s) 2. 启动汇编代码(init.s) 3. 主C文件 本应用笔记只提到了相关的文件。如果使用其他的交叉编译环境,C文件可以保存大部分不动,汇编文件需要更改。 中断向量表 这些代码应当被链接到0x0。这样中断向量和FIQ ISR就被提供给了ARM核。 ;******************************************************************* 汇编指令 ******************************************************************** AREA IVT,CODE ;新的代码段 CODE32 IMPORT start T1_IR EQU 0Xe0008000 ENTRY ;******************************************************************* LDR PC,=start LDR PC,Undefined_Addr LDR PC,SWI_Addr LDR PC,Prefetch_Addr LDR PC,Abort_Addr DCD ;标识 LDR PC,IRQ_Addr ;******************************************************************* FIQ ISR已经自己存放在了 0x1C,取代了放置在这里的LDR 指令 ****************************************************************** ;清 TIMER1 中断 MOV R8,#0x1 LDR R9,=T1_IR STR R8,[R9] 后面的用户应当增加更多的代码在这里。 ;返回到C main SUBS PC,R14,#0x04 ;************************************************************************* Undefined_Addr DCD Undefined_Handler SWI_Addr DCD SWI_Handler Pregetch_Addr DCD Pregetch_Handler Abort_Addr DCD Abort_Handler IRQ_Addr DCD IRQ_Handler 原文连接:http://www.semiconductors.philips.com/acrobat_download/applicationnotes/AN10254_1.pdf(21ic aMonster)
|