關於esp32的系統初始化啟動過程及設計學習方法


對於esp32,其開發程序中有且只能有一個app_main函數,該函數是用戶程序的入口,這在沒有調用FreeRTOS的系統中相當於函數main,但其實在app_main之前,系統還有一段初始化的過程,其大致可以分為以下三個過程:

  1. ROM中的第一級引導加載程序將閃存偏移0x1000的第二級引導加載程序映像加載到RAM(IRAM和DRAM)。
  2. 第二級引導程序從閃存加載分區表和主應用程序映像。主應用程序包含RAM段和通過閃存緩存映射的只讀段。
  3. 主應用程序圖像執行。此時可以啟動第二個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定義的)引導引腳狀態的寄存器來確定引導模式根據復位原因,發生以下情況:

  1. 從深度睡眠復位:如果值為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返回的代碼,繼續進行啟動,就好像是上電復位一樣。注意:此時運行自定義代碼,提供了一個深度睡眠存根機制。請參閱深度睡眠文檔。
  2. 對於上電復位,軟件SOC復位和看門狗SOC復位:GPIO_STRAP_REG如果要求UART或SDIO下載模式,請檢查寄存器。如果是這種情況,請配置UART或SDIO,並等待下載代碼。否則,繼續進行啟動,就好像是由於軟件CPU復位。
  3. 對於軟件CPU復位和看門狗CPU復位:根據EFUSE值配置SPI閃存,並嘗試從閃存加載代碼。這一步在下面的段落中有更詳細的描述。如果從閃存加載代碼失敗,請將BASIC解釋器解壓縮到RAM中並啟動它。請注意,當發生這種情況時,RTC看門狗仍然使能,因此除非解釋器接收到任何輸入,否則看門狗將在幾百毫秒內重置SOC,重復整個過程。如果解釋器從UART接收到任何輸入,它將禁用看門狗。

    可以看出,第一階段主要是為了第二階段做鋪墊,應用程序二進制從地址0x1000開始從閃存加載。第一個4kB閃存扇區用於存儲安全引導IV和應用程序映像的簽名。請檢查安全引導文檔以獲取有關的詳細信息。

STEP2:

   在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,則第二級引導加載程序將跳轉到二進制映像頭中的應用程序入口點。

    目前,官方並不支持加載程序添加應用程序定義來自己定義應用程序分區選擇邏輯。例如:根據GPIO的狀態,可能需要加載不同的應用程序映像。(但據說未來會支持),現在我們能做的是,通過將bootloader組件復制到應用程序目錄中並在那里進行必要的更改來定制自己的Bootloader。在這種情況下,ESP-IDF構建系統將編譯應用程序目錄中的組件而不是ESP-IDF組件目錄。

STEP3:

    主函數鏡像開始執行,即main_task,(ESP-IDF應用程序入口點是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根據所做的選擇啟用或初始化組件默認實現menuconfig,你可以通過查看omponents/esp32/cpu_start.c觀察最新的執行步驟列表,不過值得注意的是,此階段將調用應用程序中存在的所有C++全局構造函數。一旦所有基本組件都被初始化,則創建主任務,並啟動FreeRTOS調度程序。對於esp32我們知道的是,他是一個雙核cpu,在這個過程中,當PRO CPU在start_cpu0功能中進行初始化時,APP CPU會自動start_cpu1運行功能,等待在PRO CPU上啟動調度程序。一旦在PRO CPU上啟動了調度程序,APP CPU上的代碼也啟動了調度程序。

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

下面將源碼中的main_task貼出來

static void main_task(void* args)
{
    // Now that the application is about to start, disable boot watchdogs
    REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
    REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
#if !CONFIG_FREERTOS_UNICORE
    // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
    while (port_xSchedulerRunning[1] == 0) {
        ;
    }
#endif
    //Enable allocation in region where the startup stacks were located.
    heap_caps_enable_nonos_stack_heaps();
    app_main();
    vTaskDelete(NULL);
    
}

可以看到,其主要任務是關閉看門狗,並調用app_main函數(即用戶二次開發時的主函數入口),因為main_task中沒有循環,在app_main執行后,vTaskDelet函數就將這個任務刪除了。

 

  下面說一下,關於esp32的開發,在開發這種Wi-Fi cpu時 。因為非arm芯片,官方也沒有提供詳細的寄存器配置文檔,雖然寄存器和引腳功能都在esp-idf中以英文注釋給出來了,但是esp開頭的api基本都是以鏈接庫方式提供的,你是看不到它的實現方式,所以比較合理快捷的開發方式,由於官方給出的esp-idf中自帶FreeRTOS操作系統,且官方文檔中給出來相關函數的API手冊中,已經將相關應用需要用到的API函數接口給出的比較詳細了,且esp-idf中對於相關的應用給出了大量的示例(esp-idf/examples),所以對於esp32學習來說,我覺得比較好的學習方法是:

   對於沒有嵌入式操作系統基礎的人來說,最好是先學習下FreeRTOS的操作系統,重點學習相關隊列及任務調度部分的應用,如果有過操作系統的學習和應用,但是使用的並不是FreeRTOS而是ucos之類的操作系統,那么建議看下FreeRTOS的API手冊就可以開始進行開發了。對於esp32部分,這里建議學習下官方提供的例程,學習自己需要用到功能部分的API的調用和使用方法,並以此學習相關功能的應用方法,(這一部分將是我后面文章的重點部分)最終完成產品的相關設計。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM