|
程序执行过程介绍 启动过程 工程中配置分散加载文件如下图:
![]()
sp
uvoton
k-980iotlinking_scripts
uc980.sct下 ER_IROM1 0x00000000 0x800000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) }
可以看出RESET段代码放在了ER_IROM1的区域,
搜索RESET,可以找到libcpuarmarm926start_rvds.S 查看内容如下:
AREA RESET, CODE, READONLY ARM Entry_Point LDR PC, vector_reset LDR PC, vector_undef LDR PC, vector_swi LDR PC, vector_pabt LDR PC, vector_dabt LDR PC, vector_resv LDR PC, vector_irq LDR PC, vector_fiq vector_reset DCD Reset_Handler
也就是RESET段的第一条指令就是, LDR PC, vector_reset
即跳入Reset_Handler执行。
芯片硬件决定,复位后会从地址0x00000000处执行,而分散加载文件将RESET段的代码放在了0x00000000处,且第一条代码是LDR PC,vector_reset。
所以芯片复位后第一条执行的语句就是LDR PC,vector_reset,而vector_reset标签处的值是Reset_Handler,所以就跳转到Reset_Handler执行。
再看Reset_Handler处的代码,前面有设置各栈模式的指针等,先不管。
后面看到
; Enter the C code LDR R0, =__main BLX R0
即跳到__main处执行,__main是编译器符号,编译器会提供运行环境初始化的代码比如初始化data段等,入口是__main。__main执行完后会跳转到我们熟悉的main函数执行。 实际上这里对main进行了”重载”
在
t-threadsrccomponents.c中
extern int $Super$$main(void); /* re-define main function */ int $Sub$$main(void) { rtthread_startup(); return 0; }
$Sub$$main是编译器符号如果有该符号则__main函数中会跳入到$Sub$$main执行而不是用户的main。
查看rtthread_startup的实现,进行了系统运行环境的初始化,
其中rt_application_init创建了任务rt_application_init,
在rt_system_scheduler_start系统调度开始后,会执行任务rt_application_init,
在这里最终调用$Super$$main
extern int $Super$$main(void); $Super$$main(); /* for ARMCC. */
$Super$$main即用户的main函数。 $Super$$main和$Sub$$main可以通过菜单栏[Help]->[uVision Help]打开帮助文档,搜索查看相关说明。
![]()
中断处理 libcpuarmarm926start_rvds.S IRQ_Handler PROC STMFD SP!, {R0-R12,LR} BL rt_interrupt_enter BL rt_hw_trap_irq BL rt_interrupt_leave ; If rt_thread_switch_interrupt_flag set, ; jump to rt_hw_context_switch_interrupt_do and don't return LDR R0, =rt_thread_switch_interrupt_flag LDR R1, [R0] CMP R1, #1 BEQ rt_hw_context_switch_interrupt_do LDMFD SP!, {R0-R12,LR} SUBS PC, LR, #4 ENDP
前后有一些保护上下文等处理先不管,
进入rt_hw_trap_irq(libcpuarmarm926 rap.c)
调用rt_interrupt_dispatch(sp
uvotonlibraries
uc980
tt_portdrv_sys.c)
根据irq = rt_hw_interrupt_get_active(fiq_irq);查找REG_AIC_FIQNUM或REG_AIC_IRQNUM寄存器,看当前触发的是哪个中断,
再根据中断号查表执行中断服务函数isr_func(irq, param); 最后rt_hw_interrupt_ack设置REG_AIC_EOIS或REG_AIC_EOFS
对应的中断注册rt_hw_interrupt_install(sp
uvotonlibraries
uc980
tt_portdrv_sys.c)
就是设置中断服务函数表。 注册中断服务函数调用以下两个API既可
rt_hw_interrupt_install(i, rt_hw_interrupt_dummy_handler, RT_NULL, (char *)"dummy");
rt_hw_interrupt_mask(i);
|