十.ARM裸机学习之中断系统1(S5PV210的中断系统详解)
程序员文章站
2024-02-25 21:13:51
...
一.轮询方式处理按键
参考 E:\Linux\8.key_open
//按键的初始化
void key_init(void)
{
// GPH0CON的bit8~15全部设置为0,即为输入模式
rGPH0CON &=~(0xff<<8);
// GPH2CON的bit0~15全部设置为0,即为输入模式
rGPH2CON &= ~(0xFFFF<<0);
}
void key_polling(void)//轮询方式
{
// 依次,挨个去读出每个GPIO的值,判断其值为1还是0.如果为1则按键按下,为0则弹起
// 轮询的意思就是反复循环判断有无按键,隔很短时间
// 对应开发板上标着LEFT的那个按键
while(1)
{
if (rGPH0DAT & (1<<2))
{
// 为1,说明没有按键
led_off();
printf("key left.\n");
}
else
{
// 添加消抖
// 第一步,延时
delay20ms();
// 第二步,再次检验按键状态
if (!(rGPH0DAT & (1<<2)))
{
// 为0,说明有按键
led1();
printf("key down.\n");
}
}
// 对应开发板上标着DOWN的那个按键
if(rGPH0DAT &(1<<3)) // 为1,说明没有按键
{
led_off();
printf("key down.\n");
}
else // 为0,说明有按键
{
// 添加消抖
// 第一步,延时
delay20ms();
// 第二步,再次检验按键状态
if (!(rGPH0DAT & (1<<3)))
{
// 为0,说明有按键
led1();
printf("key down.\n");
}
}
// 对应开发板上标着UP的那个按键
if (rGPH2DAT & (1<<0))
{
// 为1,说明没有按键
led_off();
printf("key down.\n");
}
else
{
// 添加消抖
// 第一步,延时
delay20ms();
// 第二步,再次检验按键状态
if (!(rGPH2DAT & (1<<0)))
{
// 为0,说明有按键
led3();
printf("key down.\n");
}
}
}
}
二.中断系统 2017/11/21 23:30
1.异常向量表分析:
(1)、复位(RESET)
a、当处理器复位引脚有效时,系统产生复位异常中断,程序跳转到复位异常中断处理程序处执行,包括系统加电和系统复位。
b、通过设置PC跳转到复位中断向量处执行称为软复位。
(2)、未定义的指令
当ARM处理器或者是系统中的协处理器认为当前指令未定义时,产生未定义的指令异常中断,可以通过改异常中断机制仿真浮点向量运算。
(3)、软件中断
这是一个由用户定义的中断指令(SWI)。该异常由执行SWI指令产生,可用于用户模式下的程序调用特权操作指令。在实时操作系统中可以通过该机制实现系统功能调用。
(4)、指令与取终止(Prefech Abort)
如果处理器预取的指令的地址不存在,或者该地址不允许当前指令访问,当被预取的指令执行时,处理器产生指令预取终止异常中断。
(5)、数据访问终止(DATAABORT)
如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问终止异常中断。
(6)、外部中断请求(IRQ)
当处理器的外部中断请求引脚有效,而且CPSR的寄存器的I控制位被清除时,处理器产生外部中断请求异常中断。系统中个外设通过该异常中断请求处理服务。
(7)、快速中断请求(FIQ)
当处理器的外部快速中断请求引脚有效,而且CPSR的F控制位被清除时,处理器产生外部中断请求异常中断。
一.CPU自动处理的过程包括如下:
1、 拷贝CPSR到SPSR_
2、 设置适当的CPSR位: 改变处理器状态进入ARM状态;改变处理器模式进入相应的异常模式;设置中断禁止位禁止相应中断。
3、 更新LR_,这个寄存器中保存的是异常返回时的链接地址
4、 设置PC到相应的异常向量
异常中断处理返回
二. 异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回:
(1)、将所有修改过的用户寄存器从处理程序的保护栈中恢复。
(2)、将SPSR复制回CPSR中,将连接寄存器LR的值减去相应的偏移量后送到PC中。
(3)、若在进入异常处理时设置了中断禁止位,要在此清除。
复位异常处理程序不需要返回。
当异常发生时,内核会跳转到向量表的相应位置,并执行当中的指令。对于每一种异常,保存的返回地址都是不一样的,一般都需要我们手动的跳转,当然调整的时机也需要我们选择,是在进入处理前跳转还是返回时调整都是需要我们程序员控制的。
三.中断处理的第一阶段(异常向量表阶段)处理。 2017/11/23 22:35
第一个阶段的主要任务是从异常发生到响应异常并且保存/恢复现场、跳转到真正的异常处理程序处。
1.查210的iROM application ,iRAM中的异常向量表起始地址为0xD0037400
各个异常对应的入口就等于异常向量表的起始地址+上图中入口的偏移地址:如下图
2.中断处理保存现场,包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12,
1)中断处理要注意保护现场(中断从SVC模式来,则保存SVC模式下的必要寄存器的值)和恢复现场(中断处理完成后,准备返回SVC模式前,要将保存的SVC模式下的必要寄存器的值恢复回去,不然到了SVC模式后寄存器的值乱了,SVC模式下原来正在进行的常规任务就被你搞坏了)
(2)保存现场包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12
(3)为什么要保存LR寄存器?要考虑中断返回的问题。中断ISR执行完后如何返回SVC模式下去接着执行原来的代码。中断返回其实取决于我们进入中断时如何保存现场。中断返回时关键的2个寄存器就是PC和CPSR。所以我们在进入IRQ模式时,应该将SVC模式下的下一句指令的地址(中断返回地址)和CPSR保存起来,将来恢复时才可以将中断返回地址给PC,将保存的CPSR给CPSR。
(4)中断返回地址就保存在LR中,而CPSR(自动)保存在(IRQ模式下的)SPSR中
四、中断处理的第二阶段处理过程
第二个阶段就是进入了真正的异常处理程序irq_handler之后,目的是识别多个中断源中究竟哪一个发生了中断,然后调用相应的中断处理程序来处理这个中断。
1.第一阶段:找到具体是哪个中断:S5PV210中因为支持的中断源很多,所以直接设计了4个中断寄存器,每个32位,每位对应一个中断源。(理论上210最多支持128个中断,实际支持不足128个,有些位是空的);210没有子中断寄存器,每个中断源都是并列的。当中断发生时,在irq_handler中依次去查询4个中断源寄存器,看哪一个的哪一位被置1,则这个位对应的寄存器就发生了中断,即找到了中断编号。
2.第二阶段,找到对应的中断服务处理isr:2210开拓了一种全新的寻找isr的机制。210提供了很多寄存器来解决每个中断源对应isr的寻找问题,实现的效果是当发生相应中断时,硬件会自动的将相应isr推入一定的寄存器中,程序员在设置中断的时候,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器即可。
S5PV210中断处理的主要寄存器:
VIC0INTENABLE:中断使能
VIC0INTENCLEAR:中断禁止
VIC0INTSELECT:中断选择,IRQ/FIQ
VIC0IRQSTATUS:IRQ中断状态寄存器,软件在处理中断第二阶段的第一阶段,就是靠查询这个寄存器来得到中断编号的
VIC0FIQSTATUS:FIQ中断状态寄存器
VIC0VECTADDR:中断源对应的ISR地址,中断发生第二阶段如何获取isr地址由这个寄存器自动完成,只需要拿出ISR地址,调用即可
VICnVECTPRIORITY31:中断优先级设置寄存器
VIC0ADDRESS:向量地址寄存器,当有中断发生时,硬件上会将当前中断的中断服务例程ISR地址从寄存器VICVECTADDR自动拷贝到寄存器VICDDR中
总结:S5PV210的中断体系采用如下的ISR确定策略
(1)、将128个中断源分为4组,每组的ISR组成一个数组,以中断号为数组索引。
(2)、4组ISR数组的首地址分别存放在VICVECTADDR0~VICVECTADDR3中。
绑定ISR时,只需将用户自己编写的ISR地址放入ISR数组中以中断号为索引的位置即可
S5PV210中断处理流程:
1、中断处理前的准备工作
A、初始化中断控制器。
外部中断的中断控制器的初始化包括:绑定第一阶段异常向量表;外设相应GPIO引脚设置为外部中断模式、外部中断控制寄存器的初始化、中断向量控制寄存器的初始化。
内部中断的中断控制器的初始化包括:中断向量控制寄存器的初始化,
B、绑定中断源的ISR到向量中断控制器的VICnVECTADDR。
C、使能中断源中断。
问题1:如何绑定自己实现的isr到VICnVECTADDR
(1)搞清楚2个寄存器的区别:VICnVECTADDR和VICnADDR(寄存器在上面已经解释)
(1)VICVECTADDR寄存器一共有4×32个,每个中断源都有一个VECTADDR寄存器,我们应该将自己为这个中断源写的isr地址丢到这个中断源对应的VECTADDR寄存器中即可。
问题二:真正的中断处理程序如何获取isr?
(1)当发生中断时,硬件会自动把相应中断源的isr地址从VICnVECTADDR寄存器中推入VICnADDR寄存器中,所以我们第二阶段的第二阶段isr_handler中,只需要到相应的VICnADDR中去拿出isr地址,调用执行即可。
思考问题:中断处理程序与中断服务ISR的区别:?(截取的网上的资料)
中断处理程序和中断服务例程ISR是两个非常容易混淆的概念,但两者是两个不同的概念。内核中的中断处理程序与中断服务例程的关系如下图:
每一个触发中断的中断源对应一个中断处理程序,每一个中断处理程序对应多个中断服务例程。对中断服务例程进行注册后中断服务例程就会挂在中断请求队列中。中断处理程序是中断向量的处理程序,如果多个设备共享一个中断源,中断处理程序必须要调用每个设备的中断服务例程ISR。
在裸机中,由于每个中断源(终端编号)只有一个对应的中断向量地址寄存器VICVECTADDR,所以每一个中断处理程序只有一个中断服务例程。
2、中断处理流程
A、异常向量表跳转到IRQ入口
CPU处理常规任务时收到中断的通知,于是S5PV210根据iROM固化代码跳转到iRAM的异常向量表的IRQ异常向量地址。一般将负责保护现场、处理中断、恢复现场的汇编代码段的起始地址赋值给IRQ异常向量地址,作为处理中断的入口。
B、保护中断现场(在start.S中),然后跳入isr_handler
处理中断之前先要保护总线 现场,主要工作是:设置IRQ模式下的栈,将R0-R12,LR压栈保存(由于流水线的原因,LR一般为当前执行的指令地址加8,LR减去4就是下一条要运行指令的地址)。
C、执行中断处理程序
在isr_handler中先去搞清楚是哪个VIC中断了。查看VICnADDR寄存器是否有ISR函数地址,如果有,执行ISR。一般在中断发生之前已经绑定好ISR到VICnVECTADDR。
D、恢复现场
执行ISR后,将栈中的R0-R12,LR分别出栈R0-R12,PC,程序将根据PC的值自动跳转会到常规任务执行。
// 在这个汇编函数中,用来做中断模式下的现场保护和恢复,并且调用真正的中断处理程序
IRQ_handle:
// 设置IRQ模式下的栈
ldr sp, =IRQ_STACK
// 保存LR
// 因为ARM有流水线,所以PC的值会比真正执行的代码+8,
sub lr, lr, #4
// 保存r0-r12和lr到irq模式下的栈上面
stmfd sp!, {r0-r12, lr}
// 在此调用真正的isr来处理中断
bl irq_handler
// 处理完成开始恢复现场,其实就是做中断返回,关键是将r0-r12,pc,cpsr一起回复
ldmfd sp!, {r0-r12, pc}^