• <tbody id="wslfv"><pre id="wslfv"></pre></tbody>
    <span id="wslfv"></span>
    <tbody id="wslfv"><pre id="wslfv"></pre></tbody>
    <th id="wslfv"><track id="wslfv"><rt id="wslfv"></rt></track></th>

    <li id="wslfv"><acronym id="wslfv"></acronym></li>
    更多課程 選擇中心

    嵌入式培訓
    達內IT學院

    400-111-8989

    淺談嵌入式MCU軟件開發之startup過程詳解

    • 發布: 胡恩偉
    • 來源:汽車電子expert成長之路
    • 時間:2019-01-16 14:40

    引言

    1. 嵌入式MCU的復位源

    2. Startup相關的幾個問題:

    3. 嵌入式MCU Startup過程詳解

    初始化CPU寄存器/關閉全局中斷:

    初始化看門狗:

    初始化RAM ECC:

    配置存儲器控制器:

    初始化C語言堆棧(stack):

    初始化RAM(copydown):

    初始化系統時鐘:

    跳轉至main()函數:

    總結

    引言

            一般工程師都怕研究MCU的startup過程,其原因可能有:1.覺得沒有必要,startup的過程和啟動代碼在新建工程時,并且已經默認加入并配置好,能夠保證MCU正常工作,只要關系main()函數開始的用戶程序就好(這其實對于大部分工程師來說確實如此);2. Startup過程往往需要一定的MCU內核CPU匯編指令知識,很多對內核寄存器/堆棧指針的初始化、I/D-cache的初始化過程往往需要使用專門的匯編指令,所以讓很多工程師望而怯步; 但是如果你需要對RAM初始化進行個性化定義,想要搞清楚main()函數之前的所以準備工作,想要真正理解并自己開發一款嵌入式MCU的BootLoader,想成為真正的嵌入式MCU專家,就十分有必要搞清楚這個過程了。

    1. 嵌入式MCU的復位源

            嵌入式MCU在硬件復位或者系統復位后,都是從復位向量所指向的復位中斷ISR開始運行的,因此復位中斷ISR一般也是整個嵌入式應用工程的入口(_EntryPoint)函數/啟動(startup/boot)函數。

            通常導致嵌入式MCU復位的復位源如下:

     

            雖然我們用戶編程一般不涉及MCU的軟件啟動過程,用戶代碼一般都是從main()函數開始,完成系統的時鐘,工作模式和外設初始化,全局變量/數據結構的初始化,最后打開內核CPU全局中斷,進入主程序(主循環狀態機),用戶的程序設計跟標準C語言程序設計無異。但了解清楚嵌入式MCU的startup過程對于深入理解嵌入式系統軟件還是大有裨益的。

    2. Startup相關的幾個問題:

           我們先來思考幾個問題:

            a. 我們都知道,C語言中的全局變量分為有初始化值(.data段變量)和無初始化值(.bss段變量—初始化值為0的全局變量和.common段變量—無初始化值的全局變量)兩大類。我們在main()函數中,用戶代碼并沒有對全局變量進行初始化,但使用全局變量時其初始化值已經確定--.data段變量已為其定義時的初始化值,而 .bss/.common段變量全為零,這是如何做到的呢 (要知道,嵌入式MCU中這些全局變量都是被分配到RAM中的,其每次上電之后的值時隨機的。) ?如果我們想要某些全局變量在只在POR上電復位時被初始化而其他系統復位時不初始化,有該如何實現呢?

            b. 在汽車MCU中,為了保證RAM數據的可靠,其RAM也常帶有ECC功能(比如Qorivva MPC56xx/57xx系列MCU和S32K系列MCU),而每次上電之后RAM中的數據是隨機的,如果不對其進行初始化就去讀取其數據,就極容易產生ECC錯誤,從而進入系統異常,那么對RAM的初始化又是如何完成的呢?

            c. C語言正常運行所需要的堆棧(stack)是如何指向RAM中用戶指定的地址空間的呢?

            d. 我們的用戶程序都是從main()開始運行的,那么可不可以是其他的函數呢?main()函數一定是必須運行的嗎?

    3. 嵌入式MCU Startup過程詳解

            你知道到嗎?以上準備工作幾乎全是在startup的過程中完成的,且看以下嵌入式MCU的一般startup流程:

     

    具體每一步完成的初始化工作如下:

            初始化CPU寄存器/關閉全局中斷:每次POR上電或者復位之后,CPU寄存器除了PC寄存器有意見復位邏輯賦以存儲在默認復位向量中的復位函數ISR(即_EntryPoint()/startup()函數) 地址外,其余的CPU寄存器值都是隨機的,所以有必要對其進行初始化,然后再使用;除此之外,為了保證整個startup過程不受外設中斷的影響,需要將內核CPU全局中斷關閉(disable);

            初始化看門狗:為了保證整個startup初始化過程正常進行,有必要對MCU內部看門狗進行初始化,關閉或者初始化一個溢出周期并在初始化過程中進行喂狗;(這個過程一般由編譯器預編譯變量控制,在工程屬性編譯器設置,對于有些MCU,比如S12系列MCU,其片上COP看門狗在正常模式(normal single chip mode)下只能配置一次,這樣如果在startup的過程將其關閉了,在用戶程序中就無法重新使能和配置了);

            初始化RAM ECC:如果使用的MCU其RAM帶有ECC功能(比如Qorivva MPC56x/57xx系列MCU),必須在使用前對其進行初始化(其過程就是往RAM中寫出初始化數據已產生確定的ECC結果,一般是將之前的CPU寄存器值循環寫入整個RAM空間,當然,對其賦值零也是可以的,之所以使用CPU寄存器是因為其訪問速度快,而且有專門的單指令多數據(SIMD)支持將多個CPU寄存器寫入RAM),否則會造成ECC錯誤,進入系統異常(比如PowerPC e200Z0內核的IVOR1—machine check/IVOR2—data storge exception);

            下表列出了Freescale/NXP的汽車MCU存儲器ECC功能:

           配置存儲器控制器對于很多32位MCU來說,由于其內核CPU運行速度比較快(100~300MHz)而存儲器的工作時鐘頻率往往較低,所以一般器存儲器控制器都設計有buffer來控制訪問效率;

    比如Qorivva MPC564xA系列MCU通過BIUCR寄存器的WWSC和RWSC位來抽空讀寫片上P-Flash時的總線等待周期,當內核系統時鐘較高時就需要減小等待周期以保證MCU正常工作:

     

    另外,如果所使用的MCU內核CPU有片上指令/數據緩存(I-cache和D-cache,比如S32K14x和MPC57xx系列MCU),還需要對其進行初始化—Flush操作;

            初始化C語言堆棧(stack):從鏈接結果中,讀取棧頂地址將其寫入CPU寄存器的SP寄存器,從而完成堆棧(stack)的初始化工作,這之后內核CPU就可以正常運行C語言代碼了。

            初始化RAM(copydown):在對RAM初始化時,內核CPU會讀取編譯鏈接結果中的啟動結構體(鏈接器自定義,不同的編譯器其結構和形式可能不同),從中獲得RAM的初始化信息,其包括如下信息:

            1. .data段全局變量初始化值在Flash中的存儲地址和在其RAM中的運行時地址,以及長度(單位為字節);

            2. .bss/.common段全局變量在RAM中的運行時地址,以及長度(單位為字節);


    根據這些信息,內核CPU就可以對RAM進行初始化了:

    (注意:編譯器默認都是把所有相同段的數據放在連續的地址空間以提高初始化效率)

            .data段全局變量區:從Flash中讀取初始化值并將其寫到對應的RAM地址空間;

            .bss/.common段全局變量區:對其RAM地址寫入零一完成初始化;

    (從以上分析可知,.bss/.common段全局變量是不占Flash空間的,即在編譯結果S19文件中也沒有其初始化值)

    下面是一個S12G128的具體工程編譯鏈接結果:

    啟動結構體—startupData存儲在地址0xC044(P-Flash地址),占用6個字節,包含RAM初始化信息: 

           

     在工程map信息中可以看到工程鏈接后系統棧頂(__SEG_END_SSTACK, stack結束地址+1)結果,期用于startup工程中對SP寄存器進行初始化:

     

            該工程中的全局變量定義以及其默認編譯鏈接結果:

     

    初始化系統時鐘:可以將MCU的時鐘初始化放在main()函數之前,以縮短startup的時間。根據不同的編譯器,其為可選配置。

            跳轉至main()函數: 在完成以上startup過程之后,在startup函數的最后就是調用main()函數,跳轉至用戶應用程序執行;(PS: 這里,其實我們可以修改讓內核CPU跳轉到自定義的任何函數,而非默認的main()函數)

    總結

            以上介紹的時嵌入式MCU startup的一般流程,不同的MCU其片上資源和特性存在差異,所以上述初始化步驟也可能有所差異。

    預約申請免費試聽課

    填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

    上一篇:圖文并茂,了解ARM體系結構與編程模型
    下一篇:嵌入式Linux系統基礎概念梳理

    裸編程怎么做?裸編程具體做法

    嵌入式編程中你必須知道的小知識

    嵌入式C語言編程小知識總結

    有哪些工具可以讓嵌入式開發事半功倍?

    • 掃碼領取資料

      回復關鍵字:視頻資料

      免費領取 達內課程視頻學習資料

    • 視頻學習QQ群

      添加QQ群:1143617948

      免費領取達內課程視頻學習資料

    Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

    選擇城市和中心
    黑龍江省

    吉林省

    河北省

    湖南省

    貴州省

    云南省

    廣西省

    海南省

    欧美一级高清片,一级欧美免费大片视频,欧美三级在线电影免费 百度 好搜 搜狗
    <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>