目录结构
1、入口函数
2、详细启动流程
3、关键函数功能详解
3.1 Reset_Handler
3.2 SystemInit()
3.3 csi_coret_config()
3.4 mm_heap_initialize()
3.5 csi_vic_enable_irq
3.6 board_init()
3.7 main
1、入口函数的确认
编译工具链为csky-elfabiv2,根据链接文件gcc_csky.ld中的关键字ENTRY可以确认程序的入口地址是Reset_Handler。
/* 指定了I-SRAM、D-SRAM、O-SRAM与SRAM的起始地址,以及大小 */
MEMORY
{
I-SRAM : ORIGIN = 0x0 , LENGTH = 0x80000 /* I-SRAM 512KB */
D-SRAM : ORIGIN = 0x20000000 , LENGTH = 0x80000 /* D-SRAM 512KB */
O-SRAM : ORIGIN = 0x50000000 , LENGTH = 0x800000 /* off-chip SRAM 8MB */
SRAM : ORIGIN = 0x60000000 , LENGTH = 0x20000 /* on-chip SRAM 128KB */
}
__min_heap_size = 0x200;
PROVIDE (__ram_end = 0x20080000);
PROVIDE (__heap_end = __ram_end);
REGION_ALIAS("REGION_TEXT", I-SRAM);
REGION_ALIAS("REGION_RODATA", I-SRAM);
REGION_ALIAS("REGION_DATA", D-SRAM);
REGION_ALIAS("REGION_BSS", D-SRAM);
/* 程序的入口地址 */
ENTRY(Reset_Handler)
2、详细启动流程
详细启动流程图
3、关键函数功能详解
函数功能讲解增加到了代码注释中。
3.1 Reset_Handler
主板上电复位后从Reset_Handler开始执行,在进入SystemInit函数前,主要做了如下事情:
3.1.1 设置SP栈指针;
3.1.2 data段数据从flash搬运到SRAM;
3.1.3 bss段清零,然后跳转至SystemInit; 注意:地址相关信息均由gcc_csky.ld链接文件在编译时确定。
000000d4 <Reset_Handler>:
.text
.align 2
.globl Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
lrw r0, 0x80000200
d4: 1012 lrw r0, 0x80000200 // 11c <__exit+0x2>
mtcr r0, psr
d6: c0006420 mtcr r0, cr<0, 0>
lrw r0, g_top_irqstack
da: 1012 lrw r0, 0x20001078 // 120 <__exit+0x6>
mov sp, r0
dc: 6f83 mov r14, r0
* __data_start__: VMA of start of the section to copy to
* __data_end__: VMA of end of the section to copy to
*
* All addresses must be aligned to 4 bytes boundary.
*/
lrw r1, __erodata
de: 1032 lrw r1, 0x45a4 // 124 <__exit+0xa>
lrw r2, __data_start__
e0: 1052 lrw r2, 0x20000000 // 128 <__exit+0xe>
lrw r3, __data_end__
e2: 1073 lrw r3, 0x20000078 // 12c <__exit+0x12>
subu r3, r2
e4: 60ca subu r3, r2
cmpnei r3, 0
e6: 3b40 cmpnei r3, 0
bf .L_loop0_done
e8: 0c08 bf 0xf8 // f8 <Reset_Handler+0x24>
.L_loop0:
ldw r0, (r1, 0)
ea: 9100 ld.w r0, (r1, 0x0)
stw r0, (r2, 0)
ec: b200 st.w r0, (r2, 0x0)
addi r1, 4
ee: 2103 addi r1, 4
addi r2, 4
f0: 2203 addi r2, 4
subi r3, 4
f2: 2b03 subi r3, 4
cmpnei r3, 0
f4: 3b40 cmpnei r3, 0
bt .L_loop0
f6: 0bfa bt 0xea // ea <Reset_Handler+0x16>
* __bss_start__: start of the BSS section.
* __bss_end__: end of the BSS section.
*
* Both addresses must be aligned to 4 bytes boundary.
*/
lrw r1, __bss_start__
f8: 102e lrw r1, 0x20000078 // 130 <__exit+0x16>
lrw r2, __bss_end__
fa: 104f lrw r2, 0x2000167c // 134 <__exit+0x1a>
movi r0, 0
fc: 3000 movi r0, 0
subu r2, r1
fe: 6086 subu r2, r1
cmpnei r2, 0
100: 3a40 cmpnei r2, 0
bf .L_loop1_done
102: 0c06 bf 0x10e // 10e <Reset_Handler+0x3a>
.L_loop1:
stw r0, (r1, 0)
104: b100 st.w r0, (r1, 0x0)
addi r1, 4
106: 2103 addi r1, 4
subi r2, 4
108: 2a03 subi r2, 4
cmpnei r2, 0
10a: 3a40 cmpnei r2, 0
bt .L_loop1
10c: 0bfc bt 0x104 // 104 <Reset_Handler+0x30>
.L_loop1_done:
#ifndef __NO_SYSTEM_INIT
jbsr SystemInit
10e: e00014fd bsr 0x2b08 // 2b08 <SystemInit>
#endif
#ifndef __NO_BOARD_INIT
jbsr board_init
112: e0001099 bsr 0x2244 // 2244 <board_init>
#endif
jbsr main
116: e0001a11 bsr 0x3538 // 3538 <main>
0000011a <__exit>:
.size Reset_Handler, . - Reset_Handler
__exit:
br __exit
11a: 0400 br 0x11a // 11a <__exit>
11c: 80000200 .long 0x80000200
120: 20001078 .long 0x20001078
124: 000045a4 .long 0x000045a4
128: 20000000 .long 0x20000000
12c: 20000078 .long 0x20000078
130: 20000078 .long 0x20000078
134: 2000167c .long 0x2000167c
3.2 SystemInit()
该函数由平头哥半导体官方提供,进行psr和vbr的初始化,中断向量表偏移地址设置。
/**
* @brief initialize the system
* Initialize the psr and vbr.
* @param None
* @return None
*/
void SystemInit(void)
{
__set_VBR((uint32_t) & (__Vectors));
#if defined(CONFIG_SEPARATE_IRQ_SP) && !defined(CONFIG_KERNEL_NONE)
/* 801 not supported */
__set_Int_SP((uint32_t)&g_top_irqstack);
__set_CHR(__get_CHR() | CHR_ISE_Msk);
VIC->TSPR = 0xFF;
#endif
/* Clear active and pending IRQ */
VIC->IABR[0] = 0x0;
VIC->ICPR[0] = 0xFFFFFFFF;
#ifdef CONFIG_KERNEL_NONE
__enable_excp_irq();
#endif
csi_coret_config(drv_get_sys_freq() / CONFIG_SYSTICK_HZ, CORET_IRQn); //10ms
#ifndef CONFIG_KERNEL_NONE
csi_vic_enable_irq(CORET_IRQn);
#endif
#ifndef CONFIG_KERNEL_RHINO
#ifndef CONFIG_NUTTXMM_NONE
extern void mm_heap_initialize(void);
mm_heap_initialize();
#endif
#endif
}
3.3 csi_coret_config()
初始化系统定时器和中断,开启Systick定时器。
__STATIC_INLINE uint32_t csi_coret_config(uint32_t ticks, int32_t IRQn)
{
if ((ticks - 1UL) > CORET_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
CORET->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
CORET->VAL = 0UL; /* Load the CORET Counter Value */
CORET->CTRL = CORET_CTRL_CLKSOURCE_Msk |
CORET_CTRL_TICKINT_Msk |
CORET_CTRL_ENABLE_Msk; /* Enable CORET IRQ and CORET Timer */
return (0UL); /* Function successful */
}
3.4 mm_heap_initialize
系统堆初始化,malloc函数可使用。
void mm_heap_initialize(void)
{
mm_initialize(&g_mmheap, &__heap_start,
(uint32_t)(&__heap_end) - (uint32_t)(&__heap_start))
}
3.5 csi_vic_enable_irq
使能外部中断
__STATIC_INLINE void csi_vic_enable_irq(int32_t IRQn)
{
IRQn &= 0x7FUL;
VIC->ISER[_IR_IDX(IRQn)] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn % 32));
#ifdef CONFIG_SYSTEM_SECURE
VIC->ISSR[_IR_IDX(IRQn)] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn % 32));
#endif
}
3.6 board_init
板级驱动,初始化console,配置串口。
void board_init(void)
{
int32_t ret = 0;
/* init the console*/
console_handle = csi_usart_initialize(CONSOLE_IDX, NULL);
/* config the UART */
ret = csi_usart_config(console_handle, 115200, USART_MODE_ASYNCHRONOUS,
USART_PARITY_NONE, USART_STOP_BITS_1, USART_DATA_BITS_8);
if (ret < 0) {
return;
}
}
3.7 main
main函数。