文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用LiteOS Studio揭秘LiteOS在STM32上如何运行

2024-12-01 18:04

关注

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

本文基于LiteOS一站式开发工具LiteOS Studio,通过单步调试,来动态分析LiteOS的启动流程,给开发者一个更直观的展示。

了解LiteOS系统,我们可以先从它的启动流程开始。不同的芯片和编译工具,其启动流程可能会有一些差异,本文基于码云 LiteOS开源站点 master分支12月的代码,以STM32F769IDISCOVERY(ARM Cortex M7)开发板和GCC编译工具为例,使用LiteOS Studio的单步调试,动态分析LiteOS的启动流程。

1、LiteOS Studio环境准备

在开始前,需要准备好LiteOS Studio环境,包含LiteOS Studio安装、新建工程、编译、烧录,掌握LiteOS Studio如何调测等等,可以参考官网文档站点https://liteos.gitee.io/liteos_studio/#/project_stm32。

注意,如果开发板使用的是板载ST-LINK仿真器,需要刷为JLINK。请参考 st-link仿真器单步调测。

另外,执行单步调测,默认停止在main()函数。LiteOS操作系统的启动是从main函数开始的。而ARM Cortex-M芯片从上电到执行main函数,中间经过了Reset_Handler等函数。LiteOS系统重启、复位等都是从Reset_Handler函数开始执行的。在LiteOS Studio工程找到文件.vscode\launch.json,把其中的postLaunchCommands属性下面的"b main"改为"b Reset_Handler"。如下图:

重新开始调测,系统会暂停在Reset_Handler函数处。如下图:

2、los_startup_gcc.S启动引导文件介绍

当对STM32F769IDISCOVERY开发板进行上电操作或者复位操作时,该开发板会从异常向量表中获取Reset_Handler函数的地址并执行该函数。汇编文件targets\STM32F769IDISCOVERY\los_startup_gcc.S定义了该函数。

los_startup_gcc.S是启动引导文件,从Reset_Handler开始到执行main函数,主要工作就是准备C代码的运行环境,具体包括:

代码如下:

Reset_Handler:
cpsid i
ldr sp, =_estack

movs r1, #0
b LoopCopyVectorInit
CopyVectorInit:
ldr r3, =_si_liteos_vector_data
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyVectorInit:
ldr r0, =_s_liteos_vector
ldr r3, =_e_liteos_vector
adds r2, r0, r1
cmp r2, r3
bcc CopyVectorInit

movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss

FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss

bl SystemInit



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、_sbss、_ebss,这些符号都定义在targets\STM32F769IDISCOVERY\liteos.ld链接脚本中。

链接脚本根据应用需要,设置堆栈大小和栈地址,并控制每个段的存放位置。对于中断向量和data段,既要放到Flash中,也需要放到RAM中,并通过链接脚本的AT关键字把Flash的地址设定为load地址。

注:链接脚本中的相关代码可以访问https://gitee.com/LiteOS/LiteOS/blob/master/targets/STM32F769IDISCOVERY/liteos.ld查看。

los_startup_gcc.S启动引导文件中除了定义Reset_Handler函数,还定义了其他中断异常处理函数Default_Handler,并为Default_Handler的每个异常处理程序提供弱别名。所谓弱别名,即具有相同名称的任何函数都将覆盖此处的函数。这样做可以防止用户使能了中断却没有设置中断处理程序时造成的崩溃。Default_Handler函数只是进入一个无限循环以保留系统状态供调试器检查。

3、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函数。

4、main函数介绍

LiteOS的main函数定义在targets\STM32F769IDISCOVERY\Src\main.c。main函数主要负责LiteOS的初始化工作。代码如下:

INT32 main(VOID)
{
HardwareInit();
PRINT_RELEASE("\n********Hello Huawei LiteOS********\n"
"\nLiteOS Kernel Version : %s\n"
"build data : %s %s\n\n"
"**********************************\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;
}

OsRegister();
#ifdef LOSCFG_SHELL_LK
OsLkLoggerInit(NULL);
#endif
#ifdef LOSCFG_SHELL_DMESG
ret = OsDmesgInit();
if (ret != LOS_OK) {
return ret;
}
#endif

OsHwiInit();

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);
uart_hwiCreate();
#endif
#endif

ret = OsTaskInit();
if (ret != LOS_OK) {
PRINT_ERR("OsTaskInit error\n");
return ret;
}
#ifdef LOSCFG_KERNEL_TRACE
ret = LOS_TraceInit(NULL, LOS_TRACE_BUFFER_SIZE);
if (ret != LOS_OK) {
PRINT_ERR("LOS_TraceInit error\n");
return ret;
}
#endif

#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
OsTaskMonInit();
#endif

ret = OsIpcInit();
if (ret != LOS_OK) {
return ret;
}

#ifdef LOSCFG_KERNEL_CPUP
ret = OsCpupInit();
if (ret != LOS_OK) {
PRINT_ERR("OsCpupInit error\n");
return ret;
}
#endif

#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

#ifdef LOSCFG_PLATFORM_OSAPPINIT
ret = osAppInit();
#else
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;

UINT32 cpuid = ArchCurrCpuid();

OsTickStart();
LOS_SpinLock(&g_taskSpin);

taskCB = OsGetTopTask();
#ifdef LOSCFG_KERNEL_SMP

taskCB->currCpu = (UINT16)cpuid;
#endif

OS_SCHEDULER_SET(cpuid);
PRINTK("cpu %u entering scheduler\n", cpuid);

OsStartToRun(taskCB);
}

复制

5、main函数动态运行

现在我们来单步调测运行main.c源代码,LiteOS Studio在调测时,可以同步展示当前运行的源代码行,及对应的反汇编文件行,如下图:

在调测过程中,变量的数值可能是10进制进行展示的,如果想查看其他进制展示的数值,可以在调测界面的监视器窗口输入变量名称名称+进制代码来切换进制查看,如memStart,x来查看变量memStart的16进制。如图:

小结

本期分享使用LiteOS Studio查看LiteOS启动过程,同时展示了使用LiteOS Studio调测的技巧,大家可以继续边调测、边分析后续的代码,会看到LiteOS整个启动流程:从板子复位上电开始,调用汇编代码Reset_Handler进入启动引导文件,完成C代码运行环境的准备工作、最后跳转到main函数。在main函数中完成硬件初始化和LiteOS内核的初始化,并通过汇编跳转到执行第一个最高优先级的任务命令的地址上,从而开始LiteOS的运行。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯