ARM 的中断机制有两种-----向量中断、非向量中断
向量中断:
当中断发生后程序会跳转到事先规定好的相应的中断服务程序的入口地址
非向量中断:
当中断产生后程序会跳到统一的入口,再由软件判断是哪个中断源产生的中断
这里使用6410的向量中断做介绍
6410有两个中断向量控制器 VIC0 VIC1,一共支持64个向量中断其中27个外部中断被分为了四个向量中断源
6410还支持可编程的中断优先级,软件中断,硬件屏蔽低于用户设置中断优先级的中断功能等具体功能看手册
6410中断编程流程:
当中断源产生中断时中断控制器会过滤不需要的中断然后自动查找中断向量表,将对应中断向量号IRQStatus[31:0]的中断向量表中的中断服务函数的地址赋值给VICADDR然后执行VICADDR指向的函数
一般中断配置的流程为 (1)设置上升或下降沿触发--->(2)取消屏蔽外部中断--->(3)使能相应中断--->(4)给中断向量地址装载中断服务函数--->(5)打开总中断 在6410中前两步只有27个外部中断需要配置,其他的中断如ADC,DMA,IIC等等中断还需要在它们的控制寄存器中(如 IICCON的第五位) 使能中断
这里以外部中断为例
void init_irq()
{
EXT_INT_0_CON &= ~(0xfff); /* 配置为下降沿触发 */
EXT_INT_1_CON &= ~(0xfff);
EXT_INT_0_CON |= ((0b010<<8)|(0b010<<4) |(0b010<<0));
EXT_INT_1_CON |= ((0b010<<8)|(0b010<<4) |(0b010<<0)); /* 配置为下降沿触发 */
EXT_INT_0_MASK &= ~(0x3f); /* 取消屏蔽外部中断 */
<span style="white-space:pre"> </span>//使能需要的中断
VIC0INTENABLE |= ((0x3) | (1<<23) |(1<<18) |(1<<17) |(1<<2) |(1<<6)); //enable key1 2 3 4 & TIMER0 & RTC_Tic & DMA0 & DMA1
VIC1INTENABLE |= ((0x0f) |(1<<31) | (1<<30) | (1<<28) |(1<<18) |(1<<10) |(1<<9)); // enable adc & touch & security & RTC_Alram and I2C0
//给相应的中断向量地址填中断服务函数
EINT0_VECTADDR = (long)key_handle;
EINT2_VECTADDR = (long)RTC_ISR;
EINT60_VECTADDR = (long)RTC_Alarm;
EINT63_VECTADDR = (long)ADC_ISR;
EINT23_VECTADDR = (long)pwm_isr;
EINT17_VECTADDR = (long)SDMA0_IRQ;
EINT18_VECTADDR = (long)SDMA1_IRQ;
EINT50_VECTADDR = (long)IIC_IRQ;
EINT41_VECTADDR = (long)DMA0_IRQ;
EINT42_VECTADDR = (long)dma1_irq;
//之前在启动代码中关闭了总中断现在需要打开
__asm__(
"mov r0, #0x53\n"
"msr CPSR_cxsf, r0\n"
:
:
);
}
void do_irq() //统一的中断入口但是服务函数从中断向量中取
{
void (*the_isr)(void); //void 类型函数指针
the_isr = VIC0ADDRESS; //指向VIC0 的中断服务函数
if(the_isr == 0) //如果VIC0没有产生中断
the_isr = VIC1ADDRESS; //指向VIC1 的中断服务函数
the_isr(); //执行中断服务函数
//以下全是清除中断标志位
TINT_CSTAT |= (0x1 << 5); //定时器计数中断清除
EXT_INT_0_PEND |= 0xff; //外部中断 0 组清除
RTCINTP |= 0x3; //clear RTC interrupt pend
ADCUPDN = 0x0; //ADC
ADCCLRINT = 1;
ADCCLRINTPNDNUP = 1;
IICCON0 &= ~(1<<4); //IIC0 Clear pending bit to resume
//装载中断服务函数的寄存器清零
VIC0ADDRESS = 0;
VIC1ADDRESS = 0;
}
其中有个需要注意的是如果上面打开总中断的汇编代码改成下面的话会出现中断无法退出的错误,具体原因还没搞懂
__asm__(
//使能向量中断
"mrc p15,0,r0,c1,c0,0\n"
"orr r0,r0,#(1<<24)\n"
"mcr p15,0,r0,c1,c0,0\n"
"mrs r0,cpsr\n"
"bic r0, r0, #0x53\n"
"msr cpsr_c, r0\n"
:
:
);