本帖最后由 yuanlai2010 于 2014-7-26 20:16 编辑
裸机第十弹——S3C2416中断控制器+定时器中断实践
参与Helper2416开发板助学计划心得
看了下S3C2416的中断控制器的配置还是比较简单的,对比之前AM335X的中段控制器,感觉S3C2416的中断用起来不是很灵活,至少这个优先级机制感觉很死板,也不能实现抢占优先级,不知道怎么实现高优先级中断打断低优先级中断而执行。不过也可能是我还没能领悟其中的奥妙之处吧!参考下图,基本就知道该怎么使用该中断控制器了
实践目的:
学习怎么使用S3C2416的中断机制,练习汇编及C程序编程。
关键代码解释:
1:start.S / 异常向量表 (实现中断所必须的,位于代码最前端,链接地址为0x00,直接用YL-boot加载到SDRAM中执行(已把0x00重映射到SDRAM起始地址0x30000000))
- @******************************************************************************
- @
- @ The fist thing is to set exception vecter
- @
- Entry:
- LDR pc, Reset_Addr
- LDR pc, Undefined_Addr
- LDR pc, SWI_Addr
- LDR pc, Prefetch_Abor_Addr
- LDR pc, Data_Abort_Addr
- LDR pc, Nouse_Addr
- LDR pc, IRQ_Addr
- LDR pc, FIQ_Addr
- Reset_Addr:
- .word ResetHandler
-
- Undefined_Addr:
- .word UndefInstHandler
-
- SWI_Addr:
- .word SVC_Handler
-
- Prefetch_Abor_Addr:
- .word AbortHandler
-
- Data_Abort_Addr:
- .word AbortHandler
-
- Nouse_Addr:
-
- IRQ_Addr:
- .word IRQHandler
-
- FIQ_Addr:
- .word FIQHandler
-
- @******************************************************************************
复制代码
2:exceptionhandler.S / IRQ_Handler (完成上下文保护及恢复的工作,同时负责跳转到相应的中断服务函数)
- IRQHandler:
- SUB r14, r14, #4 @ Apply lr correction
- STMFD r13!, {r0-r3, r12, r14} @ Save context
- MRS r12, spsr @ Copy spsr
- STMFD r13!, {r12} @ Save spsr
- LDR r0, =INTOFFSET1 @ Get the Offset
- LDR r1, [r0, #0]
- LDR r0, =INTOFFSET2 @ Get the Offset
- LDR r2, [r0, #0]
- ADD r3, r1, r2 @ Get the IRQ Offset
-
- LDR r0, =interrupt_routine @ Get the IRQ Bass Address
- ADD r14, pc, #0 @ Save return address in LR
- LDR pc, [r0, r3, lsl #2] @ Jump to the ISR
-
- LDMFD r13!, {r12} @ Get spsr
- MSR spsr, r12 @ Restore spsr
- LDMFD r13!, {r0-r3, r12, pc}^ @ Restore the context and return
复制代码这里通过以函数指针数组名为基址,以
(INTOFFSET1 + INTOFFSET2)*4作为偏移地址寻找各中断服务函数的入口地址,我们只需要把中断服务函数的入口地址(函数名)放到函数指针数组里面就行了,方便中断服务函数的管理。
3:interruptcontrol.c / int_register (注册中断服务函数到函数指针数组里(只包含group1的所有和group2的前7个,之后的全是reserve!),同时完成相关配置)
- /*************************** global ****************************/
- void (*interrupt_routine[39])(void);
- char int_register(unsigned char group, unsigned char number,
- void (*_isr)(void))
- {
- if((group > 2) || (group < 1) ||(number > 31))
- {
- return 1; //参数错误 则返回1
- }
- if(1 == group)
- {
- SRCPND1 = (1<<number);
- INTMSK1 &= ~(1<<number);
- interrupt_routine[number] = _isr;
- }
- else
- {
- SRCPND2 = (1<<number);
- INTMSK2 &= ~(1<<number);
- interrupt_routine[number + 32] = _isr;
- }
- }
复制代码使用这种中断服务函数注册的方式显得比较方便与高效。
运行效果:
最后,我的工程完成的工作就是在主循环中让蜂鸣器发出嘀嘀响声,在Timer0的中断服务函数中改变LED的亮灭状态,周期为1S。
主函数:
- void main()
- {
- LED_init(); //初始化LED
- BEEP_init(); //初始化蜂鸣器
- int_initialize(); //初始化中断控制器并开启中断
- int_register(1, 10, timer0_handler); //注册Timer0中断函数
- timer_init(); //初始化Timer0并开始计数
- while(1)
- {
- BEEP(1);
- delay(40000);
- BEEP(0);
- delay(500000);
- }
- }
复制代码
这里就只贴这么几段了,感兴趣的可以下载源码包阅读,如果对中断的处理有什么见解,希望能与大家分享,谢谢!
话说,最近论坛这个板块确实不是很活跃了啊!大家都去研究深奥的东西去了?有什么收获记得回来分享哦!
源码附上:
YL-boot请移步:https://bbs.eeworld.com.cn/thread-442801-1-1.html
论坛ID:yuanlai2010
发表时间:2014-07-25