完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
怎样去使用基于LiteOS一站式开发工具LiteOS Studio呢?使用LiteOS Studio调测的技巧有哪些?LiteOS的启动流程是怎样的? |
|
相关推荐
1个回答
|
|
了解LiteOS系统,我们可以先从它的启动流程开始。不同的芯片和编译工具,其启动流程可能会有一些差异,本文基于码云 LiteOS开源站点 master分支12月的代码,以STM32F769IDISCOVERY(ARM Cortex M7)开发板和GCC编译工具为例,使用LiteOS Studio的单步调试,动态分析LiteOS的启动流程。 LiteOS Studio环境准备 在开始前,需要准备好LiteOS Studio环境,包含LiteOS Studio安装、新建工程、编译、烧录,掌握LiteOS Studio如何调测等等,可以参考官网文档站点
注意,如果开发板使用的是板载ST-LINK仿真器,需要刷为JLINK。请参考 st-link仿真器单步调测。 另外,执行单步调测,默认停止在main()函数。LiteOS操作系统的启动是从main函数开始的。而ARM Cortex-M芯片从上电到执行main函数,中间经过了Reset_Handler等函数。LiteOS系统重启、复位等都是从Reset_Handler函数开始执行的。在LiteOS Studio工程找到文件.vscodelaunch.json,把其中的postLaunchCommands属性下面的"b main"改为"b Reset_Handler"。如下图: 重新开始调测,系统会暂停在Reset_Handler函数处。如下图: los_startup_gcc.S启动引导文件介绍 当对STM32F769IDISCOVERY开发板进行上电操作或者复位操作时,该开发板会从异常向量表中获取Reset_Handler函数的地址并执行该函数。汇编文件targetsSTM32F769IDISCOVERYlos_startup_gcc.S定义了该函数。 los_startup_gcc.S是启动引导文件,从Reset_Handler开始到执行main函数,主要工作就是准备C代码的运行环境,具体包括:
Reset_Handler: cpsid i ldr sp, =_estack /* set stack pointer *//* Copy the vector_ram segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyVectorInitCopyVectorInit: ldr r3, =_si_liteos_vector_data ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4LoopCopyVectorInit: ldr r0, =_s_liteos_vector ldr r3, =_e_liteos_vector adds r2, r0, r1 cmp r2, r3 bcc CopyVectorInit/* Copy the data segment initializers from flash to SRAM */ movs r1, #0 b LoopCopyDataInitCopyDataInit: ldr r3, =_sidata ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4LoopCopyDataInit: ldr r0, =_sdata ldr r3, =_edata adds r2, r0, r1 cmp r2, r3 bcc CopyDataInit ldr r2, =_***ss b LoopFillZerobss/* Zero fill the bss segment. */FillZerobss: movs r3, #0 str r3, [r2], #4LoopFillZerobss: ldr r3, = _ebss cmp r2, r3 bcc FillZerobss/* Call the clock system initialization function.*/ bl SystemInit/* Call static constructors *//* bl __libc_init_array *//* Call the application's entry point.*/ bl main bx lr Data段存放的是已经初始化的全局变量,需要从Flash中获取这些数据到RAM中。而bss段存放的是没有初始化的全局变量,因此Flash中并没有bss段的变量值,所以启动引导文件只是对RAM中的.bss段进行清零操作。 los_startup_gcc.S启动引导文件中使用的_estack 、_si_liteos_vector_data、_s_liteos_vector、_e_liteos_vector、_sidata、_sdata 、_edata、_***ss、_ebss,这些符号都定义在targetsSTM32F769IDISCOVERYliteos.ld链接脚本中。 链接脚本根据应用需要,设置堆栈大小和栈地址,并控制每个段的存放位置。对于中断向量和data段,既要放到Flash中,也需要放到RAM中,并通过链接脚本的AT关键字把Flash的地址设定为load地址。 注:链接脚本中的相关代码可以访问 los_startup_gcc.S启动引导文件中除了定义Reset_Handler函数,还定义了其他中断异常处理函数Default_Handler,并为Default_Handler的每个异常处理程序提供弱别名。所谓弱别名,即具有相同名称的任何函数都将覆盖此处的函数。这样做可以防止用户使能了中断却没有设置中断处理程序时造成的崩溃。Default_Handler函数只是进入一个无限循环以保留系统状态供调试器检查。 los_startup_gcc.S启动引导文件动态运行 现在我们来单步调测运行los_startup_gcc.S,启动调测后,系统会暂停在Reset_Handler函数的第一行代码cpsid i,此语句用来关中断,执行前后,观察寄存器primask值的变化,会发现由0变为1。继续执行语句" ldr sp, =_estack",同样观察寄存器,寄存器sp的值变化了。如下图: 继续运行单步调测,观察如何调用LoopCopyVectorInit和CopyVectorInit,实现把中断向量从Flash复制到RAM的。在调测过程中,寄存器的数值可能是10进制进行展示的,如果想查看其他进制展示的数值,可以在调测界面的监视器窗口输入$寄存器名称+进制代码来切换进制查看,如$r0,x来查看r0寄存器的16进制。详细的进制代码如下: 进制切换如图所示: 由于循环次数较多,如果想跨过中断向量的复制,继续下面的代码,可以设置断点,然后F5继续调测到断点处。如下图,我们在118行设置了断点,继续执行会完成向量表的复制,去执行数据段data的初始化。 以此类推,通过Studio边调测、边分析启动过程的后续代码。当执行到语句“bl main”,再按F11跳入继续执行时,就会跳转到C代码的main函数。下文继续分析main函数。 main函数介绍 LiteOS的main函数定义在targetsSTM32F769IDISCOVERYSrcmain.c。main函数主要负责LiteOS的初始化工作。代码如下: INT32 main(VOID){ HardwareInit(); PRINT_RELEASE("n********Hello Huawei LiteOS********n" "nLiteOS Kernel Version : %sn" "build data : %s %snn" "**********************************n", HW_LITEOS_KERNEL_VERSION_STRING, __DATE__, __TIME__); UINT32 ret = OsMain(); if (ret != LOS_OK) { return LOS_NOK; } OsStart(); return 0;} 硬件初始化函数HardwareInit()和主要芯片相关,这里不做详细介绍。下面介绍LiteOS内核的初始化,代码如下: LITE_OS_SEC_TEXT_INIT UINT32 OsMain(VOID){ UINT32 ret;#ifdef LOSCFG_EXC_INTERACTION ret = OsMemExcInteractionInit((UINTPTR)&__bss_end); if (ret != LOS_OK) { return ret; }#endif /* 初始化动态内存池 */ ret = OsMemSystemInit((UINTPTR)&__bss_end + g_excInteractMemSize); if (ret != LOS_OK) { return ret; } /* * 配置最大支持的任务个数、信号量个数、互斥锁个数、 * 队列个数以及软件定时器个数,设置g_sysClock和 * g_tickPerSecond全局变量 */ OsRegister();#ifdef LOSCFG_SHELL_LK OsLkLoggerInit(NULL);#endif#ifdef LOSCFG_SHELL_DMESG ret = OsDmesgInit(); if (ret != LOS_OK) { return ret; }#endif/* * 初始化硬中断,此后LiteOS就会接管系统的中断, * 使用中断前需要先注册中断并使能 */ OsHwiInit(); /* * 设置中断向量的中断处理函数,包括 * Hard Fault硬件故障中断、 * Non Maskable Interrupt不可屏蔽中断(NMI)、 * Memory Management内存管理中断、 * Bus Fault 总线故障中断、 * Usage Fault使用故障中断、 * SVCall利用SVC指令调用系统服务的中断 */ ArchExcInit(); ret = OsTickInit(GET_SYS_CLOCK(), LOSCFG_BASE_CORE_TICK_PER_SECOND); if (ret != LOS_OK) { return ret; }#ifdef LOSCFG_PLATFORM_UART_WITHOUT_VFS uart_init();#ifdef LOSCFG_SHELL extern int uart_hwiCreate(void); /* HuaWeiChange */ uart_hwiCreate();#endif /* LOSCFG_SHELL */#endif /* LOSCFG_PLATFORM_UART_WITHOUT_VFS */ /* * 初始化任务链表包括任务的排序链表, * 初始化优先级消息队列链表(用于管理不同优先级任务) */ ret = OsTaskInit(); if (ret != LOS_OK) { PRINT_ERR("OsTaskInit errorn"); return ret; }#ifdef LOSCFG_KERNEL_TRACE ret = LOS_TraceInit(NULL, LOS_TRACE_BUFFER_SIZE); if (ret != LOS_OK) { PRINT_ERR("LOS_TraceInit errorn"); return ret; }#endif/* * 初始化任务监视器 */#ifdef LOSCFG_BASE_CORE_TSK_MONITOR OsTaskMonInit();#endif/* * OsIpcInit包括初始化消息队列链表、互斥锁链表和信号量链表 */ ret = OsIpcInit(); if (ret != LOS_OK) { return ret; } /* * CPUP should be inited before first task creation which depends on the semaphore * when LOSCFG_KERNEL_SMP_TASK_SYNC is enabled. So don't change this init sequence * if not necessary. The sequence should be like this: * 1. OsIpcInit * 2. OsCpupInit -> has first task creation * 3. other inits have task creation */#ifdef LOSCFG_KERNEL_CPUP ret = OsCpupInit(); if (ret != LOS_OK) { PRINT_ERR("OsCpupInit errorn"); return ret; }#endif/* * OsSwtmrInit对软件定时器和其在percpu上的排序链表进行初始化, * 并初始化定期器处理函数的内存池,同时还会创建软件定时器 * 的消息队列和定时器任务 */#ifdef LOSCFG_BASE_CORE_SWTMR ret = OsSwtmrInit(); if (ret != LOS_OK) { return ret; }#endif#ifdef LOSCFG_KERNEL_SMP (VOID)OsMpInit();#endif#ifdef LOSCFG_KERNEL_DYNLOAD ret = OsDynloadInit(); if (ret != LOS_OK) { return ret; }#endif#if defined(LOSCFG_HW_RANDOM_ENABLE) || defined (LOSCFG_DRIVERS_RANDOM) random_alg_context.ra_init_alg(NULL); run_harvester_iterate(NULL);#endif/* 创建空闲任务 */ ret = OsIdleTaskCreate(); if (ret != LOS_OK) { return ret; }#ifdef LOSCFG_KERNEL_RUNSTOP ret = OsWowWriteFlashTaskCreate(); if (ret != LOS_OK) { return ret; }#endif#ifdef LOSCFG_DRIVERS_BASE ret = OsDriverBaseInit(); if (ret != LOS_OK) { return ret; }#ifdef LOSCFG_COMPAT_LINUX (VOID)do_initCalls(LEVEL_ARCH);#endif#endif#ifdef LOSCFG_KERNEL_PERF ret = LOS_PerfInit(NULL, LOS_PERF_BUFFER_SIZE); if (ret != LOS_OK) { return ret; }#endif/* * LOSCFG_PLATFORM_OSAPPINIT宏默认已经在.config、menuconfig.h中定义。 * OsAppInit创建了一个名为“app_Task”的任务,该任务处理函数为 * app_init,任务优先级为10; * OsTestInit创建了一个名为“IT_TST_IN”的任务,该任务处理函数为 * TestTaskEntry,任务优先级为25。该函数暂时没有开源。 */#ifdef LOSCFG_PLATFORM_OSAPPINIT ret = osAppInit();#else /* LOSCFG_TEST */ ret = OsTestInit();#endif if (ret != LOS_OK) { return ret; } return LOS_OK;} 完成内核的初始化后,调用OsStart()开始任务调度,自此LiteOS开始正常工作。OsStart函数的代码如下: LITE_OS_SEC_TEXT_INIT VOID OsStart(VOID){ LosTaskCB *taskCB = NULL; /* 获取当前执行任务的CPU ID,STM32F769是单核芯片,cpuid为0 */ UINT32 cpuid = ArchCurrCpuid(); /* * 配置Tick中断向量,其中断处理函数为OsTickHandler。 * 初始化System Tick Timer及其中断,并启动此Timer。 * 计数器会产生周期性中断 */ OsTickStart(); LOS_SpinLock(&g_taskSpin); /* 获取最高优先级任务队列中的第一个任务,赋给taskCB */ taskCB = OsGetTopTask();#ifdef LOSCFG_KERNEL_SMP /* * attention: current cpu needs to be set, in case first task deletion * may fail because this flag mismatch with the real current cpu. */ taskCB->currCpu = (UINT16)cpuid;#endif /* 设置32位的调度flag,第CPU ID位设置为1 */ OS_SCHEDULER_SET(cpuid); PRINTK("cpu %u entering schedulern", cpuid); /* * 调度g_runTask即taskCB任务,OsStartToRun函数 * 定义在los_dispatch.S汇编文件中 */ OsStartToRun(taskCB);}main函数动态运行 现在我们来单步调测运行main.c源代码,LiteOS Studio在调测时,可以同步展示当前运行的源代码行,及对应的反汇编文件行,如下图: 在调测过程中,变量的数值可能是10进制进行展示的,如果想查看其他进制展示的数值,可以在调测界面的监视器窗口输入变量名称名称+进制代码来切换进制查看,如memStart,x来查看变量memStart的16进制。如图: 本期分享使用LiteOS Studio查看LiteOS启动过程,同时展示了使用LiteOS Studio调测的技巧,大家可以继续边调测、边分析后续的代码,会看到LiteOS整个启动流程:从板子复位上电开始,调用汇编代码Reset_Handler进入启动引导文件,完成C代码运行环境的准备工作、最后跳转到main函数。在main函数中完成硬件初始化和LiteOS内核的初始化,并通过汇编跳转到执行第一个最高优先级的任务命令的地址上,从而开始LiteOS的运行。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1298 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1310 浏览 1 评论
721 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
531 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1327 浏览 2 评论
1730浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
440浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
393浏览 3评论
381浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
361浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-20 21:44 , Processed in 0.858005 second(s), Total 46, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号