ESP32:系统初始化启动过程

esp32开发程序中有且只能有一个app_main函数,该函数是用户程序的入口,至关于其它系统中的main函数。但在app_main以前,系统还有一段初始化的过程,其大体能够分为如下三个过程:缓存

  • ROM中的第一级引导加载程序将闪存偏移0x1000的第二级引导加载程序映像加载到RAMIRAMDRAM);
  • 第二级引导程序从闪存加载分区表和主应用程序映像,主应用程序包含RAM段和经过闪存缓存映射的只读段;
  • 主应用程序执行,此时能够启动第二个CPURTOS调度程序。

STEP1

系统first-stage bootload启动,对于系统的first-stage bootloader,其主要任务是负责从Flash的地址0X1000开始加载bootloader镜像到RAM中(此工程的bootloader文件由esp-idf中的component目录下的bootloader/subproject/main/bootloader_start.c能够查看源码)。在SoC复位后,PRO CPU将当即开始运行,执行复位向量代码,而APP CPU将保持复位。在启动过程当中,PRO CPU执行全部初始化。call_start_cpu0应用程序启动代码功能中的APP CPU复位被取消置位。复位向量代码位于ESP32芯片掩码ROM中的地址0x40000400,不能修改。安全

从复位向量调用的启动代码经过检查GPIO_STRAP_REG(gpio_reg.h定义的)引导引脚状态的寄存器来肯定引导模式。根据复位缘由,发生如下状况。app

从深度睡眠复位

若是RTC_CNTL_STORE6_REG值为非零,而且RTC存储器的CRCRTC_CNTL_STORE7_REG有效,RTC_CNTL_STORE6_REG则将其用做入口点地址并当即跳转。若是RTC_CNTL_STORE6_REG为零,或RTC_CNTL_STORE7_REG包含无效的CRC,或者一旦调用经过RTC_CNTL_STORE6_REG返回的代码,继续进行启动,就好像是上电复位同样。注意,此时运行自定义代码,提供了一个深度睡眠存根机制。函数

对于上电复位,软件SOC复位和看门狗SOC复位

GPIO_STRAP_REG若是要求UARTSDIO下载模式,请检查寄存器。若是是这种状况,请配置UARTSDIO,并等待下载代码。不然,继续进行启动,就好像是因为软件CPU复位。布局

对于软件CPU复位和看门狗CPU复位

根据EFUSE值配置SPI闪存,并尝试从闪存加载代码。若是从闪存加载代码失败,将BASIC解释器解压缩到RAM中并启动它。当发生这种状况时,RTC看门狗仍然使能,所以除非解释器接收到任何输入,不然看门狗将在几百毫秒内重置SOC,重复整个过程。若是解释器从UART接收到任何输入,它将禁用看门狗。加密

能够看出,第一阶段主要是为了第二阶段作铺垫,应用程序二进制从地址0x1000开始从闪存加载。第一个4kB闪存扇区用于存储安全引导IV和应用程序映像的签名。code

STEP2

ESP-IDF中,闪存中位于0x1000位置的二进制映像是第二级引导加载程序。ESP-IDF的组件bootloader目录中提供了第二阶段引导加载程序源代码。这种安排并非ESP32芯片中惟一的可能,也能够编写一个功能齐全的应用程序,当闪存到0x1000时,该应用程序将工做,ESP-IDF中使用第二阶段引导加载程序来增长闪存布局的灵活性(使用分区表),并容许发生与闪存加密,安全引导和空中更新(OTA)相关的各类流程。component

当第一阶段引导加载程序完成检查和加载第二阶段引导加载程序时,它跳转到二进制映像头中找到的第二阶段引导加载程序入口点。事件

第二阶段引导程序读取在偏移0x8000处找到的分区表。引导加载程序找到工厂和OTA分区,并根据在OTA信息分区中找到的数据来决定哪个进行引导。内存

对于所选分区,第二级引导加载程序将映射到IRAMDRAM的数据和代码段复制到其加载地址。对于在DROMIROM区域中具备加载地址的部分,Flash MMU配置为提供正确的映射。第二阶段引导加载程序为PROAPP CPU配置闪存MMU,但只能为PRO CPU启用闪存MMU。这样作的缘由是第二阶段引导程序代码被加载到APP CPU缓存使用的内存区域中。启用APP CPU的缓存的功能被传递给应用程序。一旦加载了代码而且设置了闪存MMU,则第二级引导加载程序将跳转到二进制映像头中的应用程序入口点。

目前,官方并不支持加载程序添加应用程序定义来本身定义应用程序分区选择逻辑。

STEP3

主函数镜像开始执行(即main_task,应用程序入口点是call_start_cpu0,可在components/esp32/cpu_start.c中找到),这个功能的两个主要做用是启用堆分配器并使APP CPU跳到其入口点call_start_cpu1PRO CPU上的代码设置APP CPU的入口点,取消置位APP CPU复位,并等待由APP CPU上运行的代码设置的全局标志,表示已启动。一旦完成,PRO CPU跳转到start_cpu0功能,而且APP CPU将跳转到start_cpu1功能。

start_cpu0start_cpu的功能并非不可修改的,start_cpu0根据所作的选择启用或初始化组件默认实现,能够经过查看components/esp32/cpu_start.c观察最新的执行步骤列表,不过值得注意的是,此阶段将调用应用程序中存在的全部C++全局构造函数。一旦全部基本组件都被初始化,则建立主任务,并启动FreeRTOS调度程序。esp32是一个双核cpu,在这个过程当中,当PRO CPUstart_cpu0功能中进行初始化时,APP CPU会自动start_cpu1运行功能,等待在PRO CPU上启动调度程序。一旦在PRO CPU上启动了调度程序,APP CPU上的代码也启动了调度程序。

main_task的任务是能够配置主任务堆栈大小和优先级,固然咱们可使用此任务进行初始的应用程序特定设置,例如启动其它任务。应用程序还可使用事件循环和其它通用活动的主要任务。可是须要注意的是,若是app_main函数返回,main_task将被删除。

相关文章
相关标签/搜索