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將被刪除。

相關文章
相關標籤/搜索