网上说明一大堆,基本是官网文档复制没有额外解释!
对于ESP32-C3的 risc-v 内核,是我选择他的原因之一,
了解芯片上电后的启动流程,有利于我们更加深入理解芯片。
目录
- 前言
- 一、应用程序启动阶段
-
- 1.1 app_main.c
- 1.2 port_common.c
- 1.3 port.c
- 1.4 startup.c
- 1.5 startup_internal.h
- 1.6 cpu_start.c
- 1.7 esp32c3.project.ld.in
- 二、二级引导程序
- 结语
前言 对于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双环境)
一、应用程序启动阶段 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()
在哪里调用了。【ESP32-C3|ESP32-C3 应用程序的启动流程】因为是头文件,找函数调用就复杂一点,但是问题不大,如下图:
文章图片
点进去确实发现是我所需要查找的文件,如果找不到,可以在目录下面搜索,先小目录,还是找不到,再用上层目录。 这也是看底层源码的基本方法。
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 内核和架构还是处于模糊的状态,希望小伙伴多多给些意见。
文章整体只能算是代码的流程解析,并没有分析函数的功能,这是我不满意的地方,冰冻三尺非一日之寒,加油!
文章会随着博主的理解深入保持更新,希望以后能有时间从内存,从架构好好的完善一下文章!
推荐阅读
- 工具|Vscode常用快捷键
- 前端|VScode 主题和打字特效配置,让你的VScode活“”起来
- python|Python绘制概率曲线三
- python|Python绘制概率曲线二
- #|一个辅助 VSCode 下开发 STM32 的脚本
- STM32f103学习笔记|Vscode下搭建STM32开发环境 -- Ubuntu 20.04
- #|VSCode 搭建 STM32 开发环境
- C语言|vscode配置C语言环境
- 学习记录|C语言学习(1)VScode配置C语言环境(超详细)