天天看點

補充第二章 ESP32的啟動過程

  • 關注嘉友創科技公衆号
    補充第二章 ESP32的啟動過程

目标

  1. 了解app_main之前ESP32幹了什麼
  2. 了解ESP32複位原因

ESP32啟動總流程

ESP32開發程式中有且隻能有一個app_main函數,該函數是使用者程式的入口,相當于其它系統中的main函數。但在app_main之前,系統還有一段初始化的過程,其大緻可以分為以下三個過程:

ROM中的第一級引導加載程式将閃存偏移0x1000的第二級引導加載程式映像加載到RAM(IRAM和DRAM);

第二級引導程式從閃存加載分區表和主應用程式映像,主應用程式包含RAM段和通過閃存緩存映射的隻讀段;

主應用程式執行,此時可以啟動第二個CPU和RTOS排程程式。

ESP32啟動詳細過程(可以不看了)

第一階段

系統first-stage bootload啟動,對于系統的first-stage bootloader,其主要任務是負責從Flash的位址0X1000開始加載bootloader鏡像到RAM中。此工程源碼在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定義的)引導引腳 [GPIO0, GPIO2, GPIO4, MTDO, GPIO5]狀态的寄存器來确定引導模式。

如果GPIO0和GPIO2同時為低電平,則會進入下載下傳模式,等待序列槽通信資訊。

如果GPIO0為高電平,則會進入Flash 運作模式,啟動SPI 驅動,并加載Flash中的程式段。

本次啟動ESP32可知道上次複位的原因,有以下幾種可能。

從深度睡眠複位

如果RTC_CNTL_STORE6_REG值為非零,并且RTC存儲器的CRC值RTC_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如果要求UART或SDIO下載下傳模式,請檢查寄存器。如果是這種情況,請配置UART或SDIO,并等待下載下傳代碼。否則,繼續進行啟動,就好像是由于軟體CPU複位。

對于軟體CPU複位和看門狗CPU複位

根據EFUSE值配置SPI閃存,并嘗試從閃存加載代碼。如果從閃存加載代碼失敗,将BASIC解釋器解壓縮到RAM中并啟動它。當發生這種情況時,RTC看門狗仍然使能,是以除非解釋器接收到任何輸入,否則看門狗将在幾百毫秒内重置SOC,重複整個過程。如果解釋器從UART接收到任何輸入,它将禁用看門狗。

ESP32複位源

補充第二章 ESP32的啟動過程
補充第二章 ESP32的啟動過程

第一階段總結:可以看出,第一階段主要是為了第二階段做鋪墊,應用程式二進制從位址0x1000開始從閃存加載。第一個4kB閃存扇區用于存儲安全引導IV和應用程式映像的簽名。

第二階段

在ESP-IDF中,閃存中位于0x1000位置的二進制映像是第二級引導加載程式。ESP-IDF的元件bootloader目錄中提供了第二階段引導加載程式源代碼。這種安排并不是ESP32晶片中唯一的可能,也可以編寫一個功能齊全的應用程式,當閃存到0x1000時,該應用程式将工作,ESP-IDF中使用第二階段引導加載程式來增加閃存布局的靈活性(使用分區表),并允許發生與閃存加密,安全引導和空中更新(OTA)相關的各種流程。

當第一階段引導加載程式完成檢查和加載第二階段引導加載程式時,它跳轉到二進制映像頭中找到的第二階段引導加載程式入口點。

第二階段引導程式讀取在偏移0x8000處找到的分區表。引導加載程式找到工廠和OTA分區,并根據在OTA資訊分區中找到的資料來決定哪一個進行引導。

對于所選分區,第二級引導加載程式将映射到IRAM和DRAM的資料和代碼段複制到其加載位址。對于在DROM和IROM區域中具有加載位址的部分,Flash MMU配置為提供正确的映射。第二階段引導加載程式為PRO和APP CPU配置閃存MMU,但隻能為PRO CPU啟用閃存MMU。這樣做的原因是第二階段引導程式代碼被加載到APP CPU緩存使用的記憶體區域中。啟用APP CPU的緩存的功能被傳遞給應用程式。一旦加載了代碼并且設定了閃存MMU,則第二級引導加載程式将跳轉到二進制映像頭中的應用程式入口點。

目前,官方并不支援加載程式添加應用程式定義來自己定義應用程式分區選擇邏輯。

第三階段

主函數鏡像開始執行(即main_task,應用程式入口點是call_start_cpu0,可在components/esp32/cpu_start.c中找到),這個功能的兩個主要作用是啟用堆配置設定器并使APP CPU跳到其入口點call_start_cpu1。PRO CPU上的代碼設定APP CPU的入口點,取消置位APP CPU複位,并等待由APP CPU上運作的代碼設定的全局标志,表示已啟動。一旦完成,PRO CPU跳轉到start_cpu0功能,并且APP CPU将跳轉到start_cpu1功能。

start_cpu0和start_cpu的功能并不是不可修改的,start_cpu0根據所做的選擇啟用或初始化元件預設實作,可以通過檢視components/esp32/cpu_start.c觀察最新的執行步驟清單,不過值得注意的是,此階段将調用應用程式中存在的所有C++全局構造函數。一旦所有基本元件都被初始化,則建立主任務,并啟動FreeRTOS排程程式。esp32是一個雙核cpu,在這個過程中,當PRO CPU在start_cpu0功能中進行初始化時,APP CPU會自動start_cpu1運作功能,等待在PRO CPU上啟動排程程式。一旦在PRO CPU上啟動了排程程式,APP CPU上的代碼也啟動了排程程式。

main_task的任務是可以配置主任務堆棧大小和優先級,當然我們可以使用此任務進行初始的應用程式特定設定,例如啟動其它任務。應用程式還可以使用事件循環和其它通用活動的主要任務。但是需要注意的是,如果app_main函數傳回,main_task将被删除。

ESP32啟動總結

  • 再不需要修改boot結構的情況下就不用看了,了解有好幾個階段即可。
  • 如果實在想搞清楚啟動流程,就把源碼好好閱讀一遍。反正我沒看。

​​

繼續閱讀