ESP32学习五-启动流程

news2025/1/16 8:16:28

一、简介

        在ESP32的开发中,通常我们会从app_main函数中开始我们的代码开发。但是为什么是app_main呢?app_main又是从哪里被调用的app_main之前又做了什么操作呢?今天我们就来详细分析一下。

        官方参考文档:应用程序的启动流程 - ESP32 - — ESP-IDF 编程指南 release-v5.0 文档

二、app_main

        在我们的开发中,最先接触的就是app_main。esp-idf提供的所有例程,也都是从app_main开始,就像下图这样的。

        开发者自己添加的代码,也都是从app_main函数这里开始。那我们app_main之前是什么呢?

         我们直接打开esp-idf/components/esp32/cpu_start.c。在这个文件里边,我们找到了app_main函数被调用的地方。

         这里可以看到app_main被main_task调用。显然main_task是一个任务。那再看看main_task在哪里被调用。

        

         这里追溯到main_task是一个被创建的任务。而这个任务是在start_cpu0_default中被调用的。同时也可以看到,在创建了mai_task之后,才启动vTaskStartScheduler。那就可以确定,start_cpu0_default就是程序最初开始执行的地方了。

        这里再看一下main_task这个任务,创建时只有任务栈大小优先级

         可以看到,优先级也是很低的,只比空闲任务高了一级

         而任务栈的大小,可以看到给到了4096Byte

        那我们再返回看一下main_task。

         可以看到,main_task任务在调用完app_main之后,就删除任务结束了

        而start_cpu0_default是在哪里被调用呢?我们在cpu_start.c文件中只找到了这句话。 

         这句代码什么意思呢?我们继续往下看。

三、引导程序

        根据官方文档介绍,ESP32从上电到运行app_main函数中间所经历的步骤,大致上可以分为如下3个步骤:

  1. 一级引导程序。该程序被固化在了ESP32内部的ROM中,它会从Flash的0x1000偏移地址处引导二级程序至RAM(IRAM&DRAM)中。
  2. 二级引导程序。该程序从Flash中加载分区表主程序镜像至内存中,主程序中包含了RAM段和通过flash高速缓存映射的只读段。
  3. 应用程序启动阶段。该阶段,第二个CPU和RTOS的调度器会被启动。

        一级引导程序

        SoC复位后,PRO CPU会立即开始运行,执行复位向量代码,而APP CPU仍然保持复位状态。在启动过程中,PRO CPU会执行所有的初始化操作。APP CPU的复位状态会在应用程序启动代码的call_start_cpu0函数中失效。复位向量代码位于ESP32芯片掩膜ROM处,且不能被修改

        复位向量调用的启动代码会根据GPIO_STRAP_REG寄存器的值来确定ESP32的启动模式,该寄存器保存着复位后bootstrap引脚的电平状态。根据不同的复位原因,程序会执行如下操作:

  1. 从深度睡眠模式复位:如果RTC_CNTL_STORE6_REG寄存器的值非零,且RTC_CNTL_STORE7_REG寄存器中的RTC内存的CRC校验值有效,那么程序会使用RTC_CNTL_STORE6_REG寄存器的值作为入口地址,并立即跳转到该地址运行。如果RTC_CNTL_STORE6_REG的值为零,或RTC_CNTL_STORE7_REG中的CRC校验值无效,又或通过RTC_CNTL_STORE6_REG调用的代码返回,那么则像上电复位一样继续启动。注意:如果想从这里运行自定义的代码,可以参考 深度睡眠 文档里面介绍的深度睡眠存根机制方法。
  2. 上电复位、软件SOC复位、看门狗SOC复位:检查GPIO_STRAP_REG寄存器,判断是否请求自定义启动模式,如UART下载模式。如果是,ROM会执行此自定义加载器模式。否则会像软件CPU复位一样继续启动。请参考ESP32技术规格书了解SOC启动模式以及具体执行过程。
  3. 软件CPU复位、看门狗CPU复位:根据EFUSE中配置SPI FLASH,然后尝试从Flash中加载代码,这部分将会在后面详细介绍。

        注:正常启动模式下会使能RTC看门狗,因此,如果进程中断或停止,看门狗将会自动重置SOC并重复启动过程。如果strapping GPIOs已更改,则可能导致SOC陷入新的启动模式。

        二级引导程序二进制镜像会从FLASH的0x1000偏移地址处加载。如果正在使用Secure Boot,则flash的第一个4K扇区用于存储安全启动IV以及引导程序镜像的摘要,否则不使用该扇区。

        二级引导程序

        在ESP-IDF中,存放在flash的0x1000偏移地址处的二进制镜像就是二级引导程序。二级引导程序的源码可以在ESP-IDF的esp-idf/components/bootloader/subproject/main/bootloader_start.c中找到。ESP-IDF使用二级引导程序可以增加FLASH分区的灵活性(使用分区表),并且方便实现FLASH加密,安全引导和空中升级(OTA)等功能。

        当一级引导程序校验并加载完二级引导程序后,它会从二进制镜像的头部找到二级引导程序的入口点,并跳转过去运行。

        二级引导程序默认从flash的0x8000偏移地址处(可配置的值)读取分区表。可参考上一篇文章(ESP32学习四-自定义分区表_t_guest的博客-CSDN博客)。引导程序会寻找工厂分区和OTA应用程序分区。如果在分区表中找到了OTA应用程序分区,引导程序将查询otadata分区以确定应引导哪个分区。

        关于 ESP-IDF 引导程序可用的配置选项,请参考 引导加载程序 (Bootloader)。

        对于选定的分区,二级引导程序将从flash逐段读取二进制镜像:

  • 对于在内部IRAM(指令RAM)或DRAM(数据RAM)中具有加载地址的段,将把数据从flash复制到它们的加载地址处。
  • 对于一些加载地址位于DROM(数据存储在FLASH中)或IROM(代码从flash中运行)区域的段,通过配置flash MMU,可为从flash到加载地址提供正确的映射。

        注:二级引导程序同时为PRO CPU和APP CPU配置flash MMU,但仅使能PRO CPU的flash MMU。原因是二级引导程序代码已加载到APP CPU的高速缓存使用的内存区域中。因此使能APP CPU高速缓存的任务就交给了应用程序。

        一旦处理完所有段(即加载了代码并设置了flash MMU),二级引导程序将验证应用程序的完整性,并从二进制镜像文件的头部寻找入口地址,然后跳转到该地址处运行。

        总结

        简单,总结一下:

  • 一级引导程序是固化在ROM中的。从flash的0x1000偏移地址处加载boot程序
  • 二级引导程序,就是bootloader程序,从flash的0x8000处加载分区表。根据分区表运行应用程序
  • bootloader程序在esp-idf/components/bootloader/subproject/main/bootloader_start.c文件中

四、应用程序

        端口初始化

        ESP-IDF应用程序的入口是esp-idf/components/esp_32/cpu_star.c文件中的call_start_cpu0函数。这个函数由二级引导加载程序执行,并且从不返回

        该端口层的初始化功能会初始化基本的C运行环境(“CRT”),并针对SOC的内部硬件进行了初始配置。

  • 为应用程序重新配置CPU异常(运行应用程序中断处理程序运行,并使用为应用程序配置的选项来处理严重错误,并不是使用ROM提供的简易版错误处理程序处理)。
  • 如果没有设置选型CONFIG_BOOTLOADER_WDT_ENABLE,则不使能RTC看门狗定时器
  • 初始化内部存储器(数据和bss)
  • 完成MMU高速缓存配置
  • 如果配置了PSRM,则使能PSRAM
  • 将CPU时钟设置为项目配置的频率
  • 根据应用程序头部设置重新配置主SPI FLASH,这是为了与ESP-IDF V4.0之前的引导程序版本兼容。
  • 如果应用程序被配置为在多个内核上运行,则启动另一个内核并等待其初始化(在类似的“端口层”初始化函数call_start_cpu1)

        call_start_cpu0完成运行后,将调用在同一文件下的初始化函数start_cpu0

         系统初始化

        默认情况下,start_cpu0与start_cpu0_default函数弱链接。这意味着可以覆盖这个函数,增加一些额外的初始化步骤。

         主要的系统初始化阶段包括:

  • 如果默认的日志级别允许,则记录该应用程序的相关信息(项目名称、应用程序版本)等
  • 初始化堆分配器(在这之前,所有分配必须是静态的或在堆栈上)
  • 初始化newlib组件的系统个调用和时间函数
  • 配置断电检测器
  • 根据串行控制台配置设置libc stdin、stdout和stderr
  • 执行与安全相关的检查,包括为该配置烧录efuse(包括禁用ESP32 V3的ROM下载模式、CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE).
  • 初始化SPI flash API支持
  • 调用全局C++构造函数和任何标有__attribute__((constructor))的C函数。

        二级系统初始化允许单个组件被初始化。如果一个组件有一个用ESP_SYSTEM_INIT_FN宏注释的初始化函数,它将作为二级初始化的一部分被调用。

        

五、总结

        1.一级引导从flash的0x1000处加载bootloader程序

        2.bootlader程序在esp-idf/components/bootloader/bootloader_start.c中。运行call_start_cpu0函数。并打印相关信息

         3.在Bootloader中,从flash的0x8000中获取分区表,并根据分区表,找到应用程序地址,加载应用程序

        4.在esp-idf/components/esp32/cpu_start.c中调用call_start_cpu0函数,开始应用程序的初始化,并打印相关信息。结尾调用start_cpu0函数

         5.因为start_cpu0和start_cpu0_default为弱链接,所以接下来调用start_cpu0_default函数,任务中创建main_task任务,并且启动任务调度器

         6.在main_task中,调用app_main函数,开始执行用户的应用程序代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

柔性作业车间生产调度中MK算例文本各行数字表示的含义以及算例的数据

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 MK算例其他MK02~MK10柔性作业车间数据 MK算例 Brandimarte给出了10组柔性作业车间的实例分别是MK01~Mk10,下方即为MK01的实例数据 10 6 26 2 1…

Kubernetes Operator开发

Kubernetes Operator开发 1.kubebuilder 创建项目 2.Crontroller开发与部署 开发环境准备 kubebuilder 介绍 CRD的开发与部署 Crontroller开发与部署 Operator功能设计 借助operator完成 和企业内部注册中心打通 这里以Traefiketcd的模式为例进行演示说明 在这里etcd provi…

现在学习云计算,还有出路吗?

现在学习云计算,还有出路吗? 当然有出路,现在正是学习云计算的好时机。只要你专业技术过关,有一定的项目经验,有的企业甚至接受应届生;其次是具备一定的职业素养,学历在大专及以上,年…

潇洒郎: git配置、拉取、提交代码

git配置拉取代码 git 配置全局变量 git config --global user.name "xuxiaosa" git config --global user.email "xuxiaosamigu.cn" 配置ssh key 1、打开git-bash 输入ssh-keygen 一直回车,会提示文件保存的地址 id_rsa,id_rsa.pub两个文…

谷粒商城二十二订单服务支付

我们支付暂时只开发支付宝, 按照正规的流程,我们的系统要接入支付宝,肯定是需要大量的审核过程,而且需要我们的项目上线。 那现在我们就想测试该怎么办?支付宝为我们提供了沙箱环境,我们可以在应用未上线之…

易观千帆 | 2023年3月银行APP月活跃用户规模盘点

易观:2023年3月手机银行服务应用活跃人数53289.05万,环比增长2.15%,同比增长8.87%。 2023年3月信用卡服务应用活跃人数10800.71万,环比增长1.87%,同比增长18.64%。 2023年3月城商行手机银行服务应用活跃人数3827.43万&…

【项目篇1】一个在线OJ系统

目录 一、前言:项目背景 功能1:能够管理题目 功能2:可以展示题目列表 功能3:题目详情页 功能4:可以令用户提交代码,并验证提交的情况 注意事项: 功能5:反馈运行的结果 二、项…

不同的场景上线时钟同步系统需要注意些什么

时钟同步系统一般都是用在学校或者医院的环境当中,一般时钟同步系统由硬件和软件相组成。对于局域网部署,通常使用NTP协议。对于广域网部署,通常需要考虑网络延迟和安全性等因素。此外,时钟同步系统在不同的使用场景当中的需求也不…

Vite详解

目录 前言一、Vite简介1. Vite组成2.为什么选 Vite? 二、Vite的优缺点1.vite优点2.vite缺点 三、使用Vite创建Vue3项目1. 创建 vite 的项目2.项目的结构 前言 构建工具 Vite,目前只有vue3才可以使用Vite,如果本文对你有所帮助请三连支持博主。 一、V…

雷达人体存在感应器成品,静止存在感控方案,雷达触发联动技术应用

随着社会经济的不断发展和科技水平的不断提高,智能感应类产品越来越多的应用到我们生产与生活之中。 小到家里边的感应灯、单位里的自动门,大到安防报警等诸多领域,都能体验到它给我们带来的便利性与安全性。 雷达人体感应器可以精准探测人体…

fs文件系统模块

一、什么是 fs 文件系统模块 fs 模块是 Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。 例如: fs.readFile() 方法,用来读取指定文件中的内容 fs.writeFile() 方法,用来…

计算机网络模型、网络传输、封装分用的详细讲解

文章目录 计算机网络前言1. 初始网络2. 网络通信相关知识2.1 TCP/IP五层网络模型2.2 OSI七层模型 3. 网络传输3.1 封装3.2 分用3.3 数据传输的中间过程 计算机网络 前言 在互联网诞生之前,人们通过发电报等方式进行通信,这种方式是非常不稳定的&#x…

读写锁的原理与实现

文章目录 什么是读写锁生产消费模型 VS 读写模型 读写锁的pthread库接口读者&&写者模式 模拟实现读写锁思路1——用两个锁来实现(读者优先)模拟实现 思路2——两个条件变量一个锁(写者优先)模拟实现 可以看看之前写的文章…

d2l Nadaraya-Waston核回归

注意力机制里面的非参数注意力汇聚 目录 1.目标任务 2.数据生成 2.1构造原始数值 3.非参数注意力汇聚 4.对注意力机制的理解 1.目标任务 使用y_train(有噪声),拟合y_truth(没噪声)。给你所有的y_train,构造注意力权重生成拟合曲线。 2.数据生成 n_train 50…

五款高效易用的项目管理软件,提升团队工作效率

项目管理软件是为了协助团队或公司便捷和高效地完成工作任务和管理项目而专门设计的软件工具。有了它,团队成员可以共享资源,跟踪项目进度和成果,识别问题并及时解决。与传统的手工方式相比,项目管理软件可以提高工作效率和生产力…

Centos7上安装vscode和ssh

Centos7上安装vscode和ssh 一.前言二.Centos7上安装vscode三,Centos7上配ssh3.1 查看是否安装ssh环境3.2 配置ssh配置文件3.3 启动ssh服务 一.前言 在用linux环境编译项目的时候,比较习惯用ubuntu环境,而对centos环境的一些命令工具使用的比…

外链是什么意思,什么是外链

外链就是指在别的网站导入自己网站的链接。导入链接对于网站优化来说是非常重要的一个过程。导入链接的质量间接影响了我们的网站在搜索引擎中的权重。外链是互联网的血液,是链接的一种。没有链接的话,信息就是孤立的,结果就是我们什么都看不…

计算机网络笔记(方老师408课程)(持续更新)

文章目录 前言互联网概述互联网发展的三个阶段互联网标准化机构 互联网的组成边缘部分的通信方式核心部分的交换方式 我国计算机网络的发展计算机网络的类别计算机网络的性能速率、带宽、吞吐量时延时延带宽积往返时间RTT(Round-Trip Time)利用率非性能特…

SpringCloud分布式配置中心——Config

Config 本专栏学习内容来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 由于微服务越来越多,项目越来越庞大,每一个项目都至少有两三个不同环境的application.properties文件,不易管理,假设我们数据库迁移&#xff…

笔记--java sort() 方法排序

背景 最近在刷一道算法题 《字符串重新排序》时,发现自己有思路但是写代码的时候就无从下手了 而且看了答案之后还没看懂 关键就是基础不好 对于排序没有理解(虽然我学过常用的排序算法 但是都是理念 实践少) 目的 从实践和原理出发 重点是从…