andrewpei 发布于 2007-10-17 16:14:00
最近对比研究了三个大厂的ARM7单片机,发现它们在中断控制器的设计上有两种不同的作法:
一种是ST半导体和ATMEL的作法,它们没有采用ARM公司的中断控制器IP设计(编号是PL190),好象是都用了另外同一种设计。STR71x系列的EIC与SAM7上的AIC非常相似,都用了所谓的硬件堆栈来实现中断嵌套,以减少单片机在中断嵌套中的软件开销,只是嵌套的次层不同。
另一种是NXP的LPC2000系列。它采用了ARM公司的标准IP设计,名为VIC,ARM公司的设计IP文档号为PL190。这种设计没有实现什么硬件栈结构。
我对采用硬件栈的这种设计持保留态度,认为它在中断嵌套的实际应用中,没有太多的实用意义,是个“鸡肋”。原因在于:
1、对于中断嵌套,最重要的是保留在前次中断处理程序中,被新中断所打断的原PC值和处理器当时的状态。而EIC的和AIC的这个硬件栈却是在硬件栈中保存无关痛痒的上一个中断优先级值和中断源编号。这种堆栈根本不会减少CPU核在中断嵌套中的用来将LR值和SPSR压栈的软件开销。
2、纵观几大厂的ARM7单片机,我发现:作为ARM7核在MCU中的设计使用,ST半导体STR71xF系列的EIC和ATMEL公司SAM7系列实现了硬件栈,但是作为面市时间较晚的LPC2000,NXP并没有再去实现什么硬件堆栈。 这是不对我上述判断的一个佐证呢?
由于没有用ATMEL或ST半导体的ARM单片机做过实际项目,以上只是个人的一点分析。提请熟悉ATMEL公司或ST半导体公司产品的达人们评论!
谢谢
平常人 发布于 2007-10-17 22:57:00 但是有个问题想请LZ一并考虑,当允许中断嵌套以后,如何解决低优先级的事件不会中断高优先级的事件(中断)处理,同时允许高优先级的事件中断低优先级事件的处理程序。
zusen 发布于 2007-10-18 8:50:00 进入低优先级后,置自己为最高优先级,退出前还原,嘿嘿
andrewpei 发布于 2007-10-18 9:15:00 ARM公司的专家曾经出版过一本经典的ARM编程书,中文的译版叫做《ARM嵌入式系统开发-软件设计与优化》,由北航出版,其中第9章是专门讨论异常与中断编程的专题,可供讨论参考。
楼上兄台提到的问题,我想可以简单地回答如下:中断控制器(interrupt controller)的作用,就是分担CPU核对中断管理的软件开销工作:如,确定中断源,对产生的中断源进行分析,按优先级排序,等等。
以下我们分三种情况讨论:
1、当有多个中断同时产生时,中断控制器会对这多个中断源进行优先级序,并将其中优先级最高的中断ISR的地址提交给CPU核,提交的方式是将该中断ISR地址存储在控制器单元中的Interrupt Vector Address寄存器内,供CPU读取。这样,低优先级的任务决不会在中断源的仲裁中胜出。
2、如果CPU正在响应一个高优先级中断,那么在完成中断服务后,它需要以写操作中断控制器中的某一个寄存器的方式来通知中断控制器它已经完成了ISR服务,中断控制器这时才会再次对悬挂在它管理范围内的低优先级中断源重新排序仲裁,提交新的高优先级中断给CPU。假如CPU核没有完成中断服务,中断控制器就得不到CPU的这个ISR完成通知信号,也就不会仲裁未处理的那些低优先级中断源。这样的话,低优先级的中断就不会打断高优先级中断服务了。
3、如果CPU正在响应一个优先级别较低的中断时,这时来了一个优先级别较高的中断源信号进入中断控制器,中断控制器这时会将nIRQ信号再次拉低激活,通知CPU需要立即中止当前正在处理的低优先级中断,进行高优先级的中断响应。而未处理完的低优先级中断服务的程序状态和处理器状态都需要保存,以便将来返回时继续完成处理工作,这些都需要CPU来执行并保存到内存中去,这就是所谓中断嵌套的软件开销。
这就是中断控制器的作用: 1、对CPU核的外部中断源进行排序促裁,决定何时,提交哪一个中断源给CPU; 2、提交对应中断源的ISR地址提供给CPU,让CPU进行相应的中断服务。
最后我们可以讨论硬件堆栈了:通常意义上来讲,硬件堆栈的作用就是由硬件完成对被打断中断服务的状态保存。由于硬件资源非常有限,所以硬件堆栈的深度一般都是很少的,ATMEL的SAM7是8级深度,ST半导体的STR71xF是16级深度。但是令人奇怪的是:这两种MCU的硬件堆栈并不具备保存程序状态的功能,而是去保存对编程用户没有什么用处的中断源编号和中断优先级数。如果我们对比一下TI的C2000系列DSP控制器,就会发现C2000系列的硬件堆栈确确实实是在保存被中止ISR程序的返回地址,是可以减少DSP内核在中断嵌套中的软件开销的,这就可以看出来这两种硬件堆栈功能上的差别了,就会发现我指的ATMEL和ST半导体的MCU中那种令人无法理解的硬件堆栈设计。
谢谢!打字真累!
* - 本贴最后修改时间:2007-10-18 9:20:07 修改者:andrewpei HWM 发布于 2007-10-18 9:41:00 特殊情况除外。
dld2 发布于 2007-10-18 10:02:00 系统里有嵌套的中断,想想就头大。 要求ISR尽可能短,基本就满足应用要求了吧。
平常人 发布于 2007-10-19 18:50:00 先简单地说一下5楼的方法,你的方法适用于没有嵌套,“进入低优先级后,置自己为最高优先级”,那么比它优先级高的中断不就进不来了,还谈什么嵌套?
LZ的问题关键是为什么中断控制器不保存中断服务的返回地址和CPU的状态,其实这个问题的答案很简单:LZ有没有注意到ARM公司没有把中断控制器集成在核心中,中断控制器是各个半导体公司自己加上去的,ARM7的核心只提供两条信号线允许核心外部的中断申请,即IRQ和FIQ;中断服务的返回地址和CPU的状态都在核心内部,各家半导体公司谁也不能修改ARM7的核心,自然在中断控制器中不能访问到这些信息了,不能得到这些信息又如何能够在中断控制器中保存它们呢?
再多说一句,ARM7核心本身并不支持中断嵌套,因为对于ARM7核心只有两个中断源,自然不用谈嵌套了。
wishcom 发布于 2007-10-19 23:22:00 参考“ARM体系结构与编程”
avr32 发布于 2007-10-20 0:02:00 ATMEL精妙的IRQ中断处理过程——牛X
从栈地址开始,栈顶为AT91SAM7S64的16K片内RAM尽头0x00204000 IRQ_STACK_SIZE = 3*8*4 FIQ_STACK_SIZE = 0x004 ABT_STACK_SIZE = 0x004 UND_STACK_SIZE = 0x004 SVC_STACK_SIZE = 0x800 SYS_STACK_SIZE = 0x400
irq栈为什么用3*8*4=96B呢?因为irq最多8级嵌套,ARM字长4B,而3,是由于每次进栈均破坏了3个寄存器r0、spsr、lr,所以需要压栈保存的也就是3。计算十分精准,没有一个字浪费,这是AT第一牛X的地方。
当irq发生时,下列操作处理器自动完成: 1。r14(irq)=返回地址 2。spsr(irq)=cpsr(中断发生前的模式) 3。改cpsr,成模式为irq,禁止irq中断。 4。设pc,跳转到0x00000018去
下面看中断0x00000018指向的irq_handle代码:
;因为要继续调用函数,lr会被冲掉,所以压irq栈 sub lr,lr,#4 stmfd sp!,{lr}
;将r0和spsr压irq栈,因为下面用到r0,spsr mrs r14,spsr stmfd sp!,{r0,r14}
;写IVR,支持保护模式,普通模式无效 ;释放NIRQ,清除保护模式下中断源 ldr r14,=AT91C_BASE_AIC ldr r0,[r14,#AIC_IVR] str r14,[r14, #AIC_IVR]
;允许中断嵌套,由irq模式切换入svc模式 msr cpsr_c, #ARM_MODE_SVC
;保存scratch和被使用到的寄存器、lr入svc堆栈 stmfd sp!, {r1-r3, r12, r14}
;跳转到AIC_IVR指向的中断服务程序地址 mov r14,pc bx r0
;恢复scratch、被用到的寄存器、lr ldmia sp!,{r1-r3, r12, r14}
;禁止irq中断嵌套,由svc切换到irq模式。 msr cpsr_c,#I_BIT | ARM_MODE_IRQ
;写AIC_EOICR ldr r14,=AT91C_BASE_AIC str r14,[r14, #AIC_EOICR]
;恢复spsr、r0 ldmia sp!,{r0, r14} msr spsr_cxsf, r14
;中断返回 ldmia sp!, {pc}^
以上就是全部,让我惊叹的是如上做法支持了中断嵌套,想了想,自己以前搞的东西还真是全部回避回去了,也就是说,以前各个中断并没有优先级区分,进了中断就关门i->I。中断服务程序执行完了再打开,优点是简单明了,缺点是中断服务程序必须迅速处理完.
* - 本贴最后修改时间:2007-10-20 0:04:28 修改者:avr32 原文
linminjun 发布于 2007-10-22 19:11:00 九楼的高见,学习了
hpy013 发布于 2007-10-23 12:59:00 不错,学习了。
ayb_ice 发布于 2007-10-24 16:49:00 我也买了一本。。。 ARM要是能象51那样直接中断嵌套就好了。。。
netjob 发布于 2007-10-24 22:54:00 偶一直用 void _irq interrupt_handle(){...}
但看了ATMEL的程序,就蒙了! 那位高人在说一下啊!
;------------------------------------------------------------------------------ ;- IRQ Entry ;----------- ;------------------------------------------------------------------------------ MACRO IRQ_ENTRY $reg
;- Adjust and save LR_irq in IRQ stack sub r14, r14, #4 stmfd sp!, {r14}
;- Write in the IVR to support Protect Mode ;- No effect in Normal Mode ;- De-assert the NIRQ and clear the source in Protect Mode ldr r14, =AT91C_BASE_AIC str r14, [r14, #AIC_IVR]
;- Save SPSR and r0 in IRQ stack mrs r14, SPSR stmfd sp!, {r0, r14}
;- Enable Interrupt and Switch in SYS Mode mrs r0, CPSR bic r0, r0, #I_BIT orr r0, r0, #ARM_MODE_SYS msr CPSR_c, r0
;- Save scratch/used registers and LR in User Stack IF "$reg" = "" stmfd sp!, { r1-r3, r12, r14} ELSE stmfd sp!, { r1-r3, $reg, r12, r14} ENDIF
MEND
;------------------------------------------------------------------------------ ;- IRQ Exit ; --------- ;------------------------------------------------------------------------------ MACRO IRQ_EXIT $reg ;- Restore scratch/used registers and LR from User Stack IF "$reg" = "" ldmia sp!, { r1-r3, r12, r14} ELSE ldmia sp!, { r1-r3, $reg, r12, r14} ENDIF
;- Disable Interrupt and switch back in IRQ mode mrs r0, CPSR bic r0, r0, #ARM_MODE_SYS orr r0, r0, #I_BIT:OR:ARM_MODE_IRQ msr CPSR_c, r0
;- Mark the End of Interrupt on the AIC ldr r0, =AT91C_BASE_AIC str r0, [r0, #AIC_EOICR]
;- Restore SPSR_irq and r0 from IRQ stack ldmia sp!, {r0, r14} msr SPSR_cxsf, r14
;- Restore adjusted LR_irq from IRQ stack directly in the PC ldmia sp!, {pc}^
MEND
;------------------------------------------------------------------------------ ; AT91F_ASM_UDP_Handler ; --------------------- ; Handler called by the AIC ; ; Save context ; Call C handler ; Restore context ;------------------------------------------------------------------------------ EXPORT AT91F_ASM_UDP_Handler IMPORT AT91F_UDP_Handler AT91F_ASM_UDP_Handler IRQ_ENTRY
ldr r1, =AT91F_UDP_Handler mov r14, pc bx r1
IRQ_EXIT ;------------------------------------------------------------------------------
END
gumanzhou 发布于 2007-10-28 22:23:00 建议你看一下 easy2131 开发板的中断嵌套,再看这个就简单多了…… 那里有实验,应该有相关的文档
或者2200也有好像
andrewpei 发布于 2007-10-17 16:14:00
最近对比研究了三个大厂的ARM7单片机,发现它们在中断控制器的设计上有两种不同的作法:
一种是ST半导体和ATMEL的作法,它们没有采用ARM公司的中断控制器IP设计(编号是PL190),好象是都用了另外同一种设计。STR71x系列的EIC与SAM7上的AIC非常相似,都用了所谓的硬件堆栈来实现中断嵌套,以减少单片机在中断嵌套中的软件开销,只是嵌套的次层不同。
另一种是NXP的LPC2000系列。它采用了ARM公司的标准IP设计,名为VIC,ARM公司的设计IP文档号为PL190。这种设计没有实现什么硬件栈结构。
我对采用硬件栈的这种设计持保留态度,认为它在中断嵌套的实际应用中,没有太多的实用意义,是个“鸡肋”。原因在于:
1、对于中断嵌套,最重要的是保留在前次中断处理程序中,被新中断所打断的原PC值和处理器当时的状态。而EIC的和AIC的这个硬件栈却是在硬件栈中保存无关痛痒的上一个中断优先级值和中断源编号。这种堆栈根本不会减少CPU核在中断嵌套中的用来将LR值和SPSR压栈的软件开销。
2、纵观几大厂的ARM7单片机,我发现:作为ARM7核在MCU中的设计使用,ST半导体STR71xF系列的EIC和ATMEL公司SAM7系列实现了硬件栈,但是作为面市时间较晚的LPC2000,NXP并没有再去实现什么硬件堆栈。 这是不对我上述判断的一个佐证呢?
由于没有用ATMEL或ST半导体的ARM单片机做过实际项目,以上只是个人的一点分析。提请熟悉ATMEL公司或ST半导体公司产品的达人们评论!
谢谢
平常人 发布于 2007-10-17 22:57:00 但是有个问题想请LZ一并考虑,当允许中断嵌套以后,如何解决低优先级的事件不会中断高优先级的事件(中断)处理,同时允许高优先级的事件中断低优先级事件的处理程序。
zusen 发布于 2007-10-18 8:50:00 进入低优先级后,置自己为最高优先级,退出前还原,嘿嘿
andrewpei 发布于 2007-10-18 9:15:00 ARM公司的专家曾经出版过一本经典的ARM编程书,中文的译版叫做《ARM嵌入式系统开发-软件设计与优化》,由北航出版,其中第9章是专门讨论异常与中断编程的专题,可供讨论参考。
楼上兄台提到的问题,我想可以简单地回答如下:中断控制器(interrupt controller)的作用,就是分担CPU核对中断管理的软件开销工作:如,确定中断源,对产生的中断源进行分析,按优先级排序,等等。
以下我们分三种情况讨论:
1、当有多个中断同时产生时,中断控制器会对这多个中断源进行优先级序,并将其中优先级最高的中断ISR的地址提交给CPU核,提交的方式是将该中断ISR地址存储在控制器单元中的Interrupt Vector Address寄存器内,供CPU读取。这样,低优先级的任务决不会在中断源的仲裁中胜出。
2、如果CPU正在响应一个高优先级中断,那么在完成中断服务后,它需要以写操作中断控制器中的某一个寄存器的方式来通知中断控制器它已经完成了ISR服务,中断控制器这时才会再次对悬挂在它管理范围内的低优先级中断源重新排序仲裁,提交新的高优先级中断给CPU。假如CPU核没有完成中断服务,中断控制器就得不到CPU的这个ISR完成通知信号,也就不会仲裁未处理的那些低优先级中断源。这样的话,低优先级的中断就不会打断高优先级中断服务了。
3、如果CPU正在响应一个优先级别较低的中断时,这时来了一个优先级别较高的中断源信号进入中断控制器,中断控制器这时会将nIRQ信号再次拉低激活,通知CPU需要立即中止当前正在处理的低优先级中断,进行高优先级的中断响应。而未处理完的低优先级中断服务的程序状态和处理器状态都需要保存,以便将来返回时继续完成处理工作,这些都需要CPU来执行并保存到内存中去,这就是所谓中断嵌套的软件开销。
这就是中断控制器的作用: 1、对CPU核的外部中断源进行排序促裁,决定何时,提交哪一个中断源给CPU; 2、提交对应中断源的ISR地址提供给CPU,让CPU进行相应的中断服务。
最后我们可以讨论硬件堆栈了:通常意义上来讲,硬件堆栈的作用就是由硬件完成对被打断中断服务的状态保存。由于硬件资源非常有限,所以硬件堆栈的深度一般都是很少的,ATMEL的SAM7是8级深度,ST半导体的STR71xF是16级深度。但是令人奇怪的是:这两种MCU的硬件堆栈并不具备保存程序状态的功能,而是去保存对编程用户没有什么用处的中断源编号和中断优先级数。如果我们对比一下TI的C2000系列DSP控制器,就会发现C2000系列的硬件堆栈确确实实是在保存被中止ISR程序的返回地址,是可以减少DSP内核在中断嵌套中的软件开销的,这就可以看出来这两种硬件堆栈功能上的差别了,就会发现我指的ATMEL和ST半导体的MCU中那种令人无法理解的硬件堆栈设计。
谢谢!打字真累!
* - 本贴最后修改时间:2007-10-18 9:20:07 修改者:andrewpei HWM 发布于 2007-10-18 9:41:00 特殊情况除外。
dld2 发布于 2007-10-18 10:02:00 系统里有嵌套的中断,想想就头大。 要求ISR尽可能短,基本就满足应用要求了吧。
平常人 发布于 2007-10-19 18:50:00 先简单地说一下5楼的方法,你的方法适用于没有嵌套,“进入低优先级后,置自己为最高优先级”,那么比它优先级高的中断不就进不来了,还谈什么嵌套?
LZ的问题关键是为什么中断控制器不保存中断服务的返回地址和CPU的状态,其实这个问题的答案很简单:LZ有没有注意到ARM公司没有把中断控制器集成在核心中,中断控制器是各个半导体公司自己加上去的,ARM7的核心只提供两条信号线允许核心外部的中断申请,即IRQ和FIQ;中断服务的返回地址和CPU的状态都在核心内部,各家半导体公司谁也不能修改ARM7的核心,自然在中断控制器中不能访问到这些信息了,不能得到这些信息又如何能够在中断控制器中保存它们呢?
再多说一句,ARM7核心本身并不支持中断嵌套,因为对于ARM7核心只有两个中断源,自然不用谈嵌套了。
wishcom 发布于 2007-10-19 23:22:00 参考“ARM体系结构与编程”
avr32 发布于 2007-10-20 0:02:00 ATMEL精妙的IRQ中断处理过程——牛X
从栈地址开始,栈顶为AT91SAM7S64的16K片内RAM尽头0x00204000 IRQ_STACK_SIZE = 3*8*4 FIQ_STACK_SIZE = 0x004 ABT_STACK_SIZE = 0x004 UND_STACK_SIZE = 0x004 SVC_STACK_SIZE = 0x800 SYS_STACK_SIZE = 0x400
irq栈为什么用3*8*4=96B呢?因为irq最多8级嵌套,ARM字长4B,而3,是由于每次进栈均破坏了3个寄存器r0、spsr、lr,所以需要压栈保存的也就是3。计算十分精准,没有一个字浪费,这是AT第一牛X的地方。
当irq发生时,下列操作处理器自动完成: 1。r14(irq)=返回地址 2。spsr(irq)=cpsr(中断发生前的模式) 3。改cpsr,成模式为irq,禁止irq中断。 4。设pc,跳转到0x00000018去
下面看中断0x00000018指向的irq_handle代码:
;因为要继续调用函数,lr会被冲掉,所以压irq栈 sub lr,lr,#4 stmfd sp!,{lr}
;将r0和spsr压irq栈,因为下面用到r0,spsr mrs r14,spsr stmfd sp!,{r0,r14}
;写IVR,支持保护模式,普通模式无效 ;释放NIRQ,清除保护模式下中断源 ldr r14,=AT91C_BASE_AIC ldr r0,[r14,#AIC_IVR] str r14,[r14, #AIC_IVR]
;允许中断嵌套,由irq模式切换入svc模式 msr cpsr_c, #ARM_MODE_SVC
;保存scratch和被使用到的寄存器、lr入svc堆栈 stmfd sp!, {r1-r3, r12, r14}
;跳转到AIC_IVR指向的中断服务程序地址 mov r14,pc bx r0
;恢复scratch、被用到的寄存器、lr ldmia sp!,{r1-r3, r12, r14}
;禁止irq中断嵌套,由svc切换到irq模式。 msr cpsr_c,#I_BIT | ARM_MODE_IRQ
;写AIC_EOICR ldr r14,=AT91C_BASE_AIC str r14,[r14, #AIC_EOICR]
;恢复spsr、r0 ldmia sp!,{r0, r14} msr spsr_cxsf, r14
;中断返回 ldmia sp!, {pc}^
以上就是全部,让我惊叹的是如上做法支持了中断嵌套,想了想,自己以前搞的东西还真是全部回避回去了,也就是说,以前各个中断并没有优先级区分,进了中断就关门i->I。中断服务程序执行完了再打开,优点是简单明了,缺点是中断服务程序必须迅速处理完.
* - 本贴最后修改时间:2007-10-20 0:04:28 修改者:avr32 原文
linminjun 发布于 2007-10-22 19:11:00 九楼的高见,学习了
hpy013 发布于 2007-10-23 12:59:00 不错,学习了。
ayb_ice 发布于 2007-10-24 16:49:00 我也买了一本。。。 ARM要是能象51那样直接中断嵌套就好了。。。
netjob 发布于 2007-10-24 22:54:00 偶一直用 void _irq interrupt_handle(){...}
但看了ATMEL的程序,就蒙了! 那位高人在说一下啊!
;------------------------------------------------------------------------------ ;- IRQ Entry ;----------- ;------------------------------------------------------------------------------ MACRO IRQ_ENTRY $reg
;- Adjust and save LR_irq in IRQ stack sub r14, r14, #4 stmfd sp!, {r14}
;- Write in the IVR to support Protect Mode ;- No effect in Normal Mode ;- De-assert the NIRQ and clear the source in Protect Mode ldr r14, =AT91C_BASE_AIC str r14, [r14, #AIC_IVR]
;- Save SPSR and r0 in IRQ stack mrs r14, SPSR stmfd sp!, {r0, r14}
;- Enable Interrupt and Switch in SYS Mode mrs r0, CPSR bic r0, r0, #I_BIT orr r0, r0, #ARM_MODE_SYS msr CPSR_c, r0
;- Save scratch/used registers and LR in User Stack IF "$reg" = "" stmfd sp!, { r1-r3, r12, r14} ELSE stmfd sp!, { r1-r3, $reg, r12, r14} ENDIF
MEND
;------------------------------------------------------------------------------ ;- IRQ Exit ; --------- ;------------------------------------------------------------------------------ MACRO IRQ_EXIT $reg ;- Restore scratch/used registers and LR from User Stack IF "$reg" = "" ldmia sp!, { r1-r3, r12, r14} ELSE ldmia sp!, { r1-r3, $reg, r12, r14} ENDIF
;- Disable Interrupt and switch back in IRQ mode mrs r0, CPSR bic r0, r0, #ARM_MODE_SYS orr r0, r0, #I_BIT:OR:ARM_MODE_IRQ msr CPSR_c, r0
;- Mark the End of Interrupt on the AIC ldr r0, =AT91C_BASE_AIC str r0, [r0, #AIC_EOICR]
;- Restore SPSR_irq and r0 from IRQ stack ldmia sp!, {r0, r14} msr SPSR_cxsf, r14
;- Restore adjusted LR_irq from IRQ stack directly in the PC ldmia sp!, {pc}^
MEND
;------------------------------------------------------------------------------ ; AT91F_ASM_UDP_Handler ; --------------------- ; Handler called by the AIC ; ; Save context ; Call C handler ; Restore context ;------------------------------------------------------------------------------ EXPORT AT91F_ASM_UDP_Handler IMPORT AT91F_UDP_Handler AT91F_ASM_UDP_Handler IRQ_ENTRY
ldr r1, =AT91F_UDP_Handler mov r14, pc bx r1
IRQ_EXIT ;------------------------------------------------------------------------------
END
gumanzhou 发布于 2007-10-28 22:23:00 建议你看一下 easy2131 开发板的中断嵌套,再看这个就简单多了…… 那里有实验,应该有相关的文档
或者2200也有好像
|