完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1、入口函数的确认
/* * linker script for STM32F767IG with GNU ld */ /* Program Entry, set to mark it as "used" and avoid gc */ MEMORY { ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 1024K flash */ RAM (rw) : ORIGIN = 0x20020000, LENGTH = 384k /* 384K sram */ } ENTRY(Reset_Handler) _system_stack_size = 0x400; 2、执行函数流程 一图流,如图2.2.1 图2.2.1 3、关键函数功能详解 功能功能介绍增加到了代码注释中。 3.1 Reset_Handler 主板上电复位后从Reset_Handler开始执行,在进入SystemInit函数前,主要有以下情况: 3.1.1 设置 SP 栈路径; 3.1.2 数据段数据从闪存移动到 SRAM; 3.1.3 bss段清零,然后跳转至 SystemInit; 注意:相关地址信息均由链接。 lds 链接文件在编译时确定。 .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: ldr sp, =_estack /* set stack pointer initialize, the '_estack' definition in the link file*/ /** * Data segment: Data stored at compile time (not at runtime) that can be read and written. * This is also known as static storage, * where initialized global variables and initialized static variables are stored, * and where constants are stored */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 /* save 0 to R1 */ b LoopCopyDataInit CopyDataInit: /* .data data copy */ ldr r3, =_sidata /* R3 = The .data is at the starting address of Flash */ ldr r3, [r3, r1] /* load the value of the [R3 + R1] address into R3 */ str r3, [r0, r1] /* save the value of R3 to the address of [R0 + R1] */ adds r1, r1, #4 /* R1 = R1 + 4 */ LoopCopyDataInit: ldr r0, =_sdata /* assign the .data start address into R0 */ ldr r3, =_edata /* assign the .data end address into R3 */ adds r2, r0, r1 /* r2 = r0 + r1, */ cmp r2, r3 /* compare R2 and R3 value */ bcc CopyDataInit /* if R2 and R3 value not equality, jump */ ldr r2, =_***ss /* load the .bss satrt address into R2 */ b LoopFillZerobss /* jump to LoopFillZerobss */ /** * BSS section: * Global and static variables defined without initial values are placed in this section */ /* Zero fill the bss segment. */ FillZerobss: movs r3, #0 /* save 0 to R3 */ str r3, [r2], #4 /* save the value of R3 to the address of [R2], and R2 = R2 + 4 */ LoopFillZerobss: ldr r3, = _ebss /* load the .bss end address into R2 */ cmp r2, r3 /* compare R2 and R3 value */ bcc FillZerobss /* if R2 and R3 value not equality, jump */ /* Call the clock system initialization function.*/ bl SystemInit /* jump to SystemInit */ /* Call static constructors */ /* bl __libc_init_array */ /* Call the application's entry point.*/ bl entry /* jump to entry */ bx lr /* */ .size Reset_Handler, .-Reset_Handler 3.2 SystemInit() 该函数由ST官方提供,进行了FPU设置,Clock初始化,中断表偏移地址设置。 void SystemInit(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Reset the RCC clock configuration to the default reset state ------------*/ /* Set HSION bit */ RCC->CR |= (uint32_t)0x00000001; /* Reset CFGR register */ RCC->CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */ RCC->CR &= (uint32_t)0xFEF6FFFF; /* Reset PLLCFGR register */ RCC->PLLCFGR = 0x24003010; /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ RCC->CIR = 0x00000000; /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = RAMDTCM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ #endif } 3.3 entry() 调用rtthread_startup(),进入RT-Thread启动阶段。 int entry(void) { rtthread_startup(); return 0; } 3.4 rtthread_startup 内部进行函数调用,包括硬件初始化和OS内核启动两两。 int rtthread_startup(void) { rt_hw_interrupt_disable(); /* board level initialization * NOTE: please initialize heap inside board initialization. */ rt_hw_board_init(); /* show RT-Thread version */ rt_show_version(); /* timer system initialization */ rt_system_timer_init(); /* scheduler system initialization */ rt_system_scheduler_init(); #ifdef RT_USING_SIGNALS /* signal system initialization */ rt_system_signal_init(); #endif /* create init_thread */ rt_application_init(); /* timer thread initialization */ rt_system_timer_thread_init(); /* idle thread initialization */ rt_thread_idle_init(); #ifdef RT_USING_SMP rt_hw_spin_lock(&_cpus_lock); #endif /*RT_USING_SMP*/ /* start scheduler */ rt_system_scheduler_start(); /* never reach here */ return 0; } |
|
|
|
3.4 rt_hw_interrupt_disable
硬件初始化前关闭中断,防止初始化失败,只有语言实现,该函数操作了某个地方的中断屏蔽屏蔽PRIMASK。 /* * rt_base_t rt_hw_interrupt_disable(); * interrupt mask register * This register has only one bit, and when set to 1, it will turn off all interrupt-masking exceptions, * leaving only NMI and hard fault. The default value is 0 * * operating instructions: * MRS R0, PRIMASK ; R0=PRIMASK * MSR PRIMASK, R0 ; PRIMASK=R0 * CPSID I ; PRIMASK=1 * CPSIE I ; PRIMASK=0 */ .global rt_hw_interrupt_disable .type rt_hw_interrupt_disable, %function rt_hw_interrupt_disable: MRS r0, PRIMASK CPSID I BX LR /* * void rt_hw_interrupt_enable(rt_base_t level); */ .global rt_hw_interrupt_enable .type rt_hw_interrupt_enable, %function rt_hw_interrupt_enable: MSR PRIMASK, r0 BX LR 3.4 rt_hw_board_init 该函数中的堆初始化函数涉及到内存管理,具体实现复杂的复杂性,这里不展开,讲解,算法的请自行学习 RT_WEAK void rt_hw_board_init() { extern void hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq); /* Heap initialization */ #if defined(RT_USING_HEAP) rt_system_heap_init((void *) HEAP_BEGIN, (void *) HEAP_END); #endif hw_board_init(BSP_CLOCK_SOURCE, BSP_CLOCK_SOURCE_FREQ_MHZ, BSP_CLOCK_SYSTEM_FREQ_MHZ); /* Set the shell console output device */ #if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif /* Board underlying hardware initialization */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif } 3.5 hw_board_init 板级驱动初始化,包括设备初始化,系统定时器Systick初始化,PuP设备初始化,USART_串口初始化。其中设备初始化了设备驱动框架,会在开发阶段展开讲解。 void hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq) { extern void rt_hw_systick_init(void); extern void clk_init(char *clk_source, int source_freq, int target_freq); #ifdef SCB_EnableICache /* Enable I-Cache---------------------------------------------------------*/ SCB_EnableICache(); #endif #ifdef SCB_EnableDCache /* Enable D-Cache---------------------------------------------------------*/ SCB_EnableDCache(); #endif /* HAL_Init() function is called at the beginning of the program */ HAL_Init(); /* enable interrupt */ __set_PRIMASK(0); /* System clock initialization */ clk_init(clock_src, clock_src_freq, clock_target_freq); /* di***ale interrupt */ __set_PRIMASK(1); rt_hw_systick_init(); /* Pin driver initialization is open by default */ #ifdef RT_USING_PIN extern int rt_hw_pin_init(void); rt_hw_pin_init(); #endif /* USART driver initialization is open by default */ #ifdef RT_USING_SERIAL extern int rt_hw_usart_init(void); rt_hw_usart_init(); #endif } 3.6 rt_console_set_device 设备绑定,这里在创建工程的时候指定为UART1(PA9、PA10),也涉及到了设备驱动框架,通过rt_device_t rt_device_find(const char *name) 找到命名的设备,然后函数设备的设备描述结构体赋值给一个变量_console_device,然后在调用void rt_kprintf(const char *fmt, ...)等输出函数时,通过设备初始化时的编写函数进行具体的输出行为。 rt_device_t rt_console_set_device(const char *name) { rt_device_t new_device, old_device; /* save old device */ old_device = _console_device; /* find new console device */ new_device = rt_device_find(name); if (new_device != RT_NULL) { if (_console_device != RT_NULL) { /* close old console device */ rt_device_close(_console_device); } /* set new console device */ rt_device_open(new_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); _console_device = new_device; } return old_device; } rt_kprintf部分源码,着重理解rt_device_write()函数调用,指定了输出设备的具体行为。 void rt_kprintf(const char *fmt, ...) { va_list args; rt_size_t length; static char rt_log_buf[RT_CONSOLEBUF_SIZE]; va_start(args, fmt); /* the return value of vsnprintf is the number of bytes that would be * written to buffer had if the size of the buffer been sufficiently * large excluding the terminating null byte. If the output string * would be larger than the rt_log_buf, we have to adjust the output * length. */ length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args); if (length > RT_CONSOLEBUF_SIZE - 1) length = RT_CONSOLEBUF_SIZE - 1; #ifdef RT_USING_DEVICE if (_console_device == RT_NULL) { rt_hw_console_output(rt_log_buf); } else { rt_uint16_t old_flag = _console_device->open_flag; _console_device->open_flag |= RT_DEVICE_FLAG_STREAM; /* by rt_console_set_device() function bound output device */ rt_device_write(_console_device, 0, rt_log_buf, length); _console_device->open_flag = old_flag; } #else rt_hw_console_output(rt_log_buf); #endif va_end(args); } 3.7 rt_components_board_init 该函数用于执行通过INIT_BOARD_EXPORT(fn)宏把fn函数的地址.rti_fn.1段,该宏展开步骤如下: 第一步:INIT_EXPORT(fn, "1")以drv_clk.c中的INIT_BOARD_EXPORT(clock_information)宏举例,展开后形式如下: __attribute__((used)) const init_fn_t __rt_init_clock_information __attribute__((section(".rti_fn." "1"))) = clock_information 翻译过来就是clock_information的习惯为__rt_init_clock_information并把函数地址引导.rti_fn.1 section段中 void rt_components_board_init(void) { const init_fn_t *fn_ptr; for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++) { (*fn_ptr)(); } #endif } 该函数的需要结合.map文件,可以查看该函数共执行了两个函数,int rti_board_start(void) 和 int clock_information(void)。 *(SORT(.rti_fn*)) .rti_fn.0 0x0800d0d8 0x4 ./rt-thread/src/components.o 0x0800d0d8 __rt_init_rti_start .rti_fn.0.end 0x0800d0dc 0x4 ./rt-thread/src/components.o 0x0800d0dc __rt_init_rti_board_start .rti_fn.1 0x0800d0e0 0x4 ./drivers/drv_clk.o 0x0800d0e0 __rt_init_clock_information .rti_fn.1.end 0x0800d0e4 0x4 ./rt-thread/src/components.o 0x0800d0e4 __rt_init_rti_board_end .rti_fn.6 0x0800d0e8 0x4 ./rt-thread/components/finsh/shell.o 0x0800d0e8 __rt_init_finsh_system_init .rti_fn.6.end 0x0800d0ec 0x4 ./rt-thread/src/components.o 0x0800d0ec __rt_init_rti_end 0x0800d0f0 __rt_init_end = . 0x0800d0f0 . = ALIGN (0x4) 3.8 rt_show_version 该函数打印输出OS系统版本,编译日期等信息 void rt_show_version(void) { rt_kprintf("n \ | /n"); rt_kprintf("- RT - Thread Operating Systemn"); rt_kprintf(" / | \ %d.%d.%d build %sn", RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__); rt_kprintf(" 2006 - 2019 Copyright by rt-thread teamn"); } 下一步OS内核启动。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1763 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1617 浏览 1 评论
1059 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
723 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1670 浏览 2 评论
1932浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
725浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
564浏览 3评论
591浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
549浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 03:51 , Processed in 0.800231 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号