esp32
開發程序中有且只能有一個app_main
函數,該函數是用戶程序的入口,至關於其它系統中的main
函數。但在app_main
以前,系統還有一段初始化的過程,其大體能夠分爲如下三個過程:緩存
ROM
中的第一級引導加載程序將閃存偏移0x1000
的第二級引導加載程序映像加載到RAM
(IRAM
和DRAM
);RAM
段和經過閃存緩存映射的只讀段;CPU
和RTOS
調度程序。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
存儲器的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
接收到任何輸入,它將禁用看門狗。加密
能夠看出,第一階段主要是爲了第二階段作鋪墊,應用程序二進制從地址0x1000
開始從閃存加載。第一個4kB
閃存扇區用於存儲安全引導IV
和應用程序映像的簽名。code
STEP2
在ESP-IDF
中,閃存中位於0x1000
位置的二進制映像是第二級引導加載程序。ESP-IDF
的組件bootloader
目錄中提供了第二階段引導加載程序源代碼。這種安排並非ESP32
芯片中惟一的可能,也能夠編寫一個功能齊全的應用程序,當閃存到0x1000
時,該應用程序將工做,ESP-IDF
中使用第二階段引導加載程序來增長閃存佈局的靈活性(使用分區表),並容許發生與閃存加密,安全引導和空中更新(OTA
)相關的各類流程。component
當第一階段引導加載程序完成檢查和加載第二階段引導加載程序時,它跳轉到二進制映像頭中找到的第二階段引導加載程序入口點。事件
第二階段引導程序讀取在偏移0x8000
處找到的分區表。引導加載程序找到工廠和OTA
分區,並根據在OTA
信息分區中找到的數據來決定哪個進行引導。內存
對於所選分區,第二級引導加載程序將映射到IRAM
和DRAM
的數據和代碼段複製到其加載地址。對於在DROM
和IROM
區域中具備加載地址的部分,Flash MMU
配置爲提供正確的映射。第二階段引導加載程序爲PRO
和APP 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_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
將被刪除。