写点什么

ESP32-C3 应用程序的启动流程

作者:矜辰所致
  • 2022 年 10 月 09 日
    江苏
  • 本文字数:2629 字

    阅读完需:约 9 分钟

ESP32-C3 应用程序的启动流程
网上说明一大堆,基本是官网文档复制没有额外解释!对于ESP32-C3的 risc-v 内核,是我选择他的原因之一,了解芯片上电后的启动流程,有利于我们更加深入理解芯片。
复制代码


前言

对于 ARM 内核的 STM32 的启动流程,我以前的博文详细分析过,搞懂了 STM32 的启动流程对于芯片的使用和理解来说就会更上一个等级。现在我们新接触的 risc-v 内核的 ESP32-C3,如果能够搞明白他的启动流程,就能更深的理解 ESP32-C3。


在写文章之前也看了很多网上的文章,然后官方的说明也看过了,网上绝大多数都是官网文档复制一遍,这倒没什么,毕竟官网权威,问题是,复制一遍过来没有做过多的解释,没有额外的分析,还写个原创,我真是 XX 了。当然不排除我没看到的好的文章,也正是因为基本没有看到更加详细的分析,我决定要自己写一篇记录,一来当做自己记录,二来底层有些地方目前来说我确实不是理解透彻,肯定有不到位的地方,希望大家多提意见,能让文章更加完善。


按照惯例,我把能找到的文章和官方的资料都看了好多遍,官方提到的 3 大步骤:



对于上述提到的 3 大步骤,最简单的清晰的是第三步,第二步也有源码,倒是可以查看试着分析一下,但是第一步确实,只是知道这么回事,具体的实现方式因为程序是在 ESP32-C3 的内部 ROM 中,确实找不到可以分析的源码和资料。


芯片的启动流程,大多离不开启动文件和链接文件。ESP32-C3 应该也是这样,本来按照理解,应该找到底层的启动文件和连接文件开始按照步骤分析,但是查看了一会底层代码,因为对底层架构深入了解得还不够,没有找到= =! 所以想着怎么办?


不能按照从最开始到结束的顺序来,那么就按照从结束到开始的顺序来!我们从app_main 函数反过来一层一层网前看,看看经过了一些什么处理,程序才执行到app_main 函数的!


注意,文章以倒叙的方式说明~ ~


本文是基于 VScode 插件的工程结构来说明(Ubuntu 环境),环境搭建见下面博文:


ESP32-C3 VScode 开发环境搭建(基于乐鑫官方 ESP-IDF——Windows 和 Ubuntu 双环境)

https://xie.infoq.cn/article/5b639e112cabba00cc1b8941a

一、应用程序启动阶段

1.1 app_main.c

我们从app_main.c的主函数app_main中,我们直接通过转到定义看看上一层:


1.2 port_common.c

app_main 往上找的文件是 port_common.c,路径如下:



是哪一个任务调用了app_main 呢,我们直接往上就能看到,main_task调用了app_main ,而main_task这个任务就在esp_startup_start_app_common函数中创建:



知道了esp_startup_start_app_common 函数创建了main_task这个任务,那么这个函数在哪边有调用呢?我们继续往上看,找到esp_startup_start_app函数中调用了esp_startup_start_app_common,调用完成以后就开启了 FreeRTOS 任务调度。



对应的,我们看一下启动 LOG:


1.3 port.c

我们又进入了一个新的文件 port.c,路径如下:



接着上面的,从esp_startup_start_app函数往上找,又找到一个start_cpu0_default函数,如图:


1.4 startup.c

又找到一个新文件startup.c,路径如下:



start_cpu0_default


startup.c 文件的 start_cpu0_default函数,其中进行了很多关键步骤,具体可以自行查看代码:



对应的,我们看一下启动 LOG:



我们还想看 start_cpu0_default函数从哪里调用,但是这时候已经无法跳转了,这时候我们依然在startup.c文件中搜索,可以找到下面一句话:



这句话的意思就是使得 start_cpu0_default函数弱连接到start_cpu0函数,如果没有额外的声明,start_cpu0_default函数等价于start_cpu0函数。(有错误请指出)


继续看看与 start_cpu0函数 有关的程序,g_startup_fn好像是一个数组?如图:



尝试着对 g_startup_fn 使用转到定义,我们进入了另外一个新的文件,可以找到一个宏定义SYS_STARTUP_FN()


1.5 startup_internal.h

老样子先看文件路径如下:



这是一个头文件,所以这里面肯定都是函数的声明和宏定义,我们在这个文件中需要关注的地方就是一个宏定义#define SYS_STARTUP_FN() ((*g_startup_fn[(cpu_hal_get_core_id())])())



我们接下来要找的就是这个宏定义SYS_STARTUP_FN()在哪里调用了。


因为是头文件,找函数调用就复杂一点,但是问题不大,如下图:



点进去确实发现是我所需要查找的文件,如果找不到,可以在目录下面搜索,先小目录,还是找不到,再用上层目录。 这也是看底层源码的基本方法。

1.6 cpu_start.c

老样子先看文件路径如下:



cpu_start.c文件中,可以看到确实有上面头文件中宏定义SYS_STARTUP_FN()的调用,里面主要就是几个启动 cpu 的函数,其中是call_start_cpu0函数调用了这个宏定义:



函数的内容是很多的,这里我们就不一一分析。但是到了这里,我们再结合官方的说明文档再看一遍:



这样子去理解,感觉官方说得好简单,实际上都是层层调用。


分析到这里,我们都已经进入入口函数了,那么程序是如何调用。按照以前的理解,这个入口函数应该会在一个连接脚本里面使用 ENTRY调用,就像ENTRY(call_start_cpu0);


实际上,如果去文件夹搜索可以找到很多文件中有ENTRY(call_start_cpu0);,即便我们值选择与 ESP32-C3 有关的,也有不同的地方,那么到底是哪个呢?我们还得继续顺藤摸瓜!

1.7 esp32c3.project.ld.in

在组件的esp32c3目录下面搜索call_start_cpu0,找到一个使用了ENTRY(call_start_cpu0);的链接文件:(有错误请指出)



这个和我们的 STM32 中分析中的类似,就是进入到入口函数执行:



文件路径:



我们还得往下简单看看二级引导程序。

二、二级引导程序

二级引导程序,基于现在我的理解,还不足以能够完全的讲清楚,官方提到源码在 ESP-IDF 的 components/bootloader 目录下,我也简单的看了一下,在目录中找到比较“可能”的程序:



在这个bootloader_start.c文件中,正如官方的说明一样,ESP-IDF 使用二级引导程序可以增加 Flash 分区的灵活性(使用分区表)等一些功能:



继续查看了一些代码(具体的就是在bootloader_start.c文件相关联的地方查找),确定bootloader_start.c就是二级引导程序的代码,根据 LOG 输出判断的 = =!



在 bootloader 目录下也有 ESP32-C3 的链接文件:



在其中也有ENTRY(call_start_cpu0);的调用,这个应该是和二级引导程序中bootloader_start.c中对应的链接文件(有问题清指出)。


结语

文章在前面 C 语言启动的部分倒是还算满意,到底层以后,对陌生的 risc-v 内核和架构还是处于模糊的状态,希望小伙伴多多给些意见。


文章整体只能算是代码的流程解析,并没有分析函数的功能,这是我不满意的地方,冰冻三尺非一日之寒,加油!文章会随着博主的理解深入保持更新,希望以后能有时间从内存,从架构好好的完善一下文章!

发布于: 刚刚阅读数: 4
用户头像

矜辰所致

关注

CSDN、知乎、微信公众号: 矜辰所致 2022.08.02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
ESP32-C3 应用程序的启动流程_ESP32-C3_矜辰所致_InfoQ写作社区