0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

bootloader的原理及實(shí)現(xiàn)過(guò)程詳解

嵌入式應(yīng)用開(kāi)發(fā) ? 來(lái)源:嵌入式應(yīng)用開(kāi)發(fā) ? 作者:嵌入式應(yīng)用開(kāi)發(fā) ? 2022-06-18 17:57 ? 次閱讀

一、背景

嵌入式操作系統(tǒng)中,BootLoader是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行??梢猿跏蓟布O(shè)備、建立內(nèi)存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核準(zhǔn)備好正確的環(huán)境。在嵌入式系統(tǒng)中,通常并沒(méi)有像BIOS那樣的固件程序

二、實(shí)現(xiàn)思路

bootloader其實(shí)就是一段啟動(dòng)程序,它在芯片啟動(dòng)的時(shí)候首先被執(zhí)行,它可以用來(lái)做一些硬件的初始化,當(dāng)初始化完成之后跳轉(zhuǎn)到對(duì)應(yīng)的應(yīng)用程序中去。

我們可以將內(nèi)存分為兩個(gè)區(qū),一個(gè)是啟動(dòng)程序區(qū)(0x0800 0000 - 0x0800 2000 )大小為8K Bytes,剩下的為應(yīng)用程序區(qū)(0x0800 2000 - 0x0801 0000)。

芯片上電時(shí)先運(yùn)行啟動(dòng)程序,然后跳轉(zhuǎn)到應(yīng)用程序區(qū)執(zhí)行應(yīng)用程序。

三、程序跳轉(zhuǎn)

bootloader一個(gè)主要的功能就是首先程序的跳轉(zhuǎn)。在STM32中只要將要跳轉(zhuǎn)的地址直接寫(xiě)入PC寄存器,就可以跳轉(zhuǎn)到對(duì)應(yīng)的地址中去。

怎么實(shí)現(xiàn)呢?

當(dāng)我們實(shí)現(xiàn)一個(gè)函數(shù)的時(shí)候,這個(gè)函數(shù)最終會(huì)占用一段內(nèi)存,而它的函數(shù)名代表的就是這段內(nèi)存的起始地址。當(dāng)我們調(diào)用這個(gè)函數(shù)的時(shí)候,單片機(jī)會(huì)將這段

內(nèi)存的首地址(函數(shù)名對(duì)應(yīng)的地址)加載到PC寄存器中,從而跳轉(zhuǎn)到這段代碼來(lái)執(zhí)行。那么我們也可以利用這個(gè)原理,定義一個(gè)函數(shù)指針,將這個(gè)指針指向我們

想要跳轉(zhuǎn)的地址,然后調(diào)用這個(gè)函數(shù),就可以實(shí)現(xiàn)程序的跳轉(zhuǎn)了。

代碼如下:

#define  APP_ADDR  0x08002000   //應(yīng)用程序首地址定義 
typedef void (*APP_FUNC)(); //函數(shù)指針類(lèi)型定義

APP_FUNC jump2app; //定義一個(gè)函數(shù)指針

jump2app = ( APP_FUNC )(APP_ADDR + 4); //給函數(shù)指針賦值
jump2app(); //調(diào)用函數(shù)指針,實(shí)現(xiàn)程序跳轉(zhuǎn)

上面的代碼實(shí)現(xiàn)了我們要的跳轉(zhuǎn)功能,但是為什么要跳轉(zhuǎn)到(APP_ADDR + 4) 這個(gè)地址,而不是APP_ADDR.

首先我們要了解主控芯片的啟動(dòng)過(guò)程。以STM32為例,在芯片上電的時(shí)候,首先會(huì)從內(nèi)存地址位0x0800 0000(由啟動(dòng)模式?jīng)Q定)的地方加載棧頂?shù)刂罚?字節(jié)),從0x0800 0004的地方加載程序復(fù)位地址(4字節(jié)),然后跳轉(zhuǎn)到對(duì)應(yīng)的復(fù)位地址去執(zhí)行。

所以上面的程序會(huì)中,jump2app這個(gè)函數(shù)指針的地址為(APP_ADDR + 4),調(diào)用這個(gè)函數(shù)指針的時(shí)候,芯片內(nèi)核會(huì)自動(dòng)跳轉(zhuǎn)到這個(gè)指針指向的內(nèi)存地址,也即是應(yīng)用程序的復(fù)位地址。

四、加載棧地址

實(shí)際運(yùn)行會(huì)發(fā)現(xiàn),上面的程序可能會(huì)出現(xiàn)問(wèn)題。因?yàn)槲覀冞€缺少了一個(gè)棧地址的加載過(guò)程,也就是芯片上電的第一個(gè)動(dòng)作。這里要用到一點(diǎn)匯編的知識(shí):

__asm void MSR_MSP(uint32_t addr)
{
    MSR MSP, r0
    BX r14;
}
__asm void MSR_MSP(uint32_t addr) 是MDK嵌入式匯編形式。

MSR MSP, r0 意思是將r0寄存器中的值加載到MSP(主棧寄存器,復(fù)位時(shí)默認(rèn)使用)寄存器中,r0中保存的是參數(shù)值,即addr的值

BX r14 跳轉(zhuǎn)到連接寄存器保存的地址中,即退出函數(shù),跳轉(zhuǎn)到函數(shù)調(diào)用地址

完整的程序如下:

#define APP_ADDR 0x08002000 //應(yīng)用程序首地址定義 
typedef void (*APP_FUNC)(); //函數(shù)指針類(lèi)型定義

/**
  * @brief
  * @param
  * @retval
  */
__asm void MSR_MSP(uint32_t addr)
{
    MSR MSP, r0
    BX r14;
}


/**
  * @brief
  * @param
  * @retval
  */
void run_app(uint32_t app_addr)
{
    uint32_t reset_addr = 0;
    APP_FUNC jump2app;
    
    /* 跳轉(zhuǎn)之前關(guān)閉相應(yīng)的中斷 */
    NVIC_DisableIRQ(SysTick_IRQn);
    NVIC_DisableIRQ(LPUART_IRQ);
    
    /* 棧頂?shù)刂肥欠窈戏?這里sram大小為8k) */
    if(((*(uint32_t *)app_addr)&0x2FFFE000) == 0x20000000)
    {
        /* 設(shè)置棧指針 */
        MSR_MSP(app_addr);
        /* 獲取復(fù)位地址 */
        reset_addr = *(uint32_t *)(app_addr+4);
        jump2app = ( APP_FUNC )reset_addr;
        jump2app();
    }
    else
    {
        printf("APP Not Found!n");
    }
}

五、編譯設(shè)置

我們需要在設(shè)置界面將默認(rèn)(0x8000000)改為我們的應(yīng)用程序地址(0x8002000)

poYBAGKtoIGAOtpZAAGKkMPFU-E907.png

六、中斷向量表重映射

完成了上面的工作,實(shí)際測(cè)試發(fā)現(xiàn)程序還是無(wú)法正確運(yùn)行。原因是我們沒(méi)有進(jìn)行中斷向量表的重映射。向量表映射?什么時(shí)候有做過(guò)這個(gè)工作,我們來(lái)看一下:

.s文件里有如下代碼:

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler                 [WEAK]
        IMPORT  __main
        IMPORT  SystemInit  
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

這代碼表示,程序在執(zhí)行main函數(shù)之前,會(huì)先執(zhí)行SystemInit這個(gè)函數(shù)。下面看看這個(gè)函數(shù):

/**
  * @brief  Setup the microcontroller system.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
/*!< Set MSION bit */
  RCC->CR |= (uint32_t)0x00000100U;

  /*!< Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], MCOSEL[2:0] and MCOPRE[2:0] bits */
  RCC->CFGR &= (uint32_t) 0x88FF400CU;

  /*!< Reset HSION, HSIDIVEN, HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFF6U;

  /*!< Reset HSI48ON  bit */
  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;

  /*!< Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFFU;

  /*!< Reset PLLSRC, PLLMUL[3:0] and PLLDIV[1:0] bits */
  RCC->CFGR &= (uint32_t)0xFF02FFFFU;

  /*!< Disable all interrupts */
  RCC->CIER = 0x00000000U;

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

從上面的代碼可以看到,這個(gè)函數(shù)主要是做了時(shí)鐘的初始化和中斷初始化,還有就是中斷向量表的映射,就是最后那一段代碼

poYBAGKtoMKAO1bzAAD8OXA5lO8440.png

再看看FLASH_BASE 和 VECT_TAB_OFFSET的定義:

poYBAGKtoOCAIUjEAAEZB3-GFsQ012.png

這里默認(rèn)映射地址就是FLASH的初始地址,所以只要將其改成我們程序的起始地址就行了: SCB->VTOR = 0x08002000

編譯,運(yùn)行,下載.

七、總結(jié)

程序跳轉(zhuǎn)完成,對(duì)于bootloader來(lái)說(shuō)也就完成了一大半。剩下的就是根據(jù)自己的需求去完善相應(yīng)功能了,比如我的在線升級(jí)功能,就要在bootloader里做固件接收和校驗(yàn)的功能。這里有一點(diǎn)需要特別注意的是,跳轉(zhuǎn)程序之前最好把你用到的中斷都關(guān)了,不然跳轉(zhuǎn)之后的程序沒(méi)有對(duì)應(yīng)的中斷處理函數(shù),那就又可能使得程序進(jìn)入死循環(huán)中。

審核編輯:符乾江

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19126

    瀏覽量

    305302
  • Boot
    +關(guān)注

    關(guān)注

    0

    文章

    149

    瀏覽量

    35840
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    自定義RISC V的bootloader-v2

    在生成SoC時(shí),會(huì)生成一個(gè)預(yù)定義bootloader .bin文件,用于指定soc的工程運(yùn)行的地址,這包括在flash的存儲(chǔ)地址 ,加載到外存中的運(yùn)行地址及在外存中分配的存儲(chǔ)空間的大小 。下面我們
    的頭像 發(fā)表于 10-31 12:37 ?622次閱讀
    自定義RISC V的<b class='flag-5'>bootloader</b>-v2

    SATA主機(jī)協(xié)議的物理層的實(shí)現(xiàn)過(guò)程

    這里講解SATA主機(jī)協(xié)議的物理層的實(shí)現(xiàn)過(guò)程
    的頭像 發(fā)表于 10-22 15:17 ?300次閱讀
    SATA主機(jī)協(xié)議的物理層的<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>過(guò)程</b>

    bootloader和應(yīng)用程序之間共享FEE塊

    電子發(fā)燒友網(wǎng)站提供《在bootloader和應(yīng)用程序之間共享FEE塊.pdf》資料免費(fèi)下載
    發(fā)表于 10-10 09:18 ?0次下載
    在<b class='flag-5'>bootloader</b>和應(yīng)用程序之間共享FEE塊

    如何開(kāi)發(fā)不帶Flash API 的Bootloader實(shí)現(xiàn)在線升級(jí)

    電子發(fā)燒友網(wǎng)站提供《如何開(kāi)發(fā)不帶Flash API 的Bootloader實(shí)現(xiàn)在線升級(jí).pdf》資料免費(fèi)下載
    發(fā)表于 09-12 09:41 ?0次下載
    如何開(kāi)發(fā)不帶Flash API 的<b class='flag-5'>Bootloader</b><b class='flag-5'>實(shí)現(xiàn)</b>在線升級(jí)

    簡(jiǎn)述拉曼散射效應(yīng)的實(shí)現(xiàn)過(guò)程

    拉曼散射效應(yīng),作為一種重要的光學(xué)現(xiàn)象,其實(shí)現(xiàn)過(guò)程涉及光與物質(zhì)之間復(fù)雜的相互作用。以下將詳細(xì)闡述拉曼散射效應(yīng)的實(shí)現(xiàn)過(guò)程,包括基本原理、實(shí)驗(yàn)觀察、理論解釋以及應(yīng)用等方面。
    的頭像 發(fā)表于 08-16 17:08 ?566次閱讀

    PLC對(duì)模擬量信號(hào)的處理過(guò)程及方法 詳解

    )。 PLC通過(guò)計(jì)算轉(zhuǎn)換,將這些模擬量信號(hào)轉(zhuǎn)換為內(nèi)部的數(shù)值信號(hào)。從而實(shí)現(xiàn)系統(tǒng)的監(jiān)控及控制。從現(xiàn)場(chǎng)的物理信號(hào)到PLC內(nèi)部處理的數(shù)值信號(hào),有以下幾個(gè)步驟: 從以上PLC模擬量的信號(hào)輸入流程可以看到,在自動(dòng)化過(guò)程控制系統(tǒng)中,模擬量信號(hào)的輸入是非
    的頭像 發(fā)表于 07-30 16:31 ?423次閱讀
    PLC對(duì)模擬量信號(hào)的處理<b class='flag-5'>過(guò)程</b>及方法 <b class='flag-5'>詳解</b>版

    YTM32的HA系列微控制器啟動(dòng)過(guò)程詳解

    見(jiàn),以確保信息安全的需要。然而,開(kāi)發(fā)者在自行編譯固件時(shí),需要配合BOOT ROM中的bootloader,才能正常地引導(dǎo)到用戶應(yīng)用程序,完成啟動(dòng)過(guò)程。
    的頭像 發(fā)表于 07-15 09:24 ?428次閱讀
    YTM32的HA系列微控制器啟動(dòng)<b class='flag-5'>過(guò)程</b><b class='flag-5'>詳解</b>

    LwIP協(xié)議棧源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《LwIP協(xié)議棧源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 07-03 11:22 ?3次下載

    IDF-4.4.2在修改boot過(guò)程中,編譯有提示bootloader受到partition-table offset的限制,為什么?

    我在 IDF-4.4.2在修改boot過(guò)程中,編譯有提示bootloader受到partition-table offset的限制,如下圖 可當(dāng)我用menuconfig修改后,發(fā)現(xiàn)從0XC000
    發(fā)表于 06-14 06:27

    如何才能將Bootloader和Application關(guān)聯(lián)起來(lái)

    接下來(lái),我們要利用該Bootloader調(diào)試目標(biāo)Application Project,如何才能將Bootloader和Application關(guān)聯(lián)起來(lái)呢?就需要借助剛才提到的Bootloader Project Build所生成
    的頭像 發(fā)表于 06-12 14:32 ?699次閱讀
    如何才能將<b class='flag-5'>Bootloader</b>和Application關(guān)聯(lián)起來(lái)

    請(qǐng)問(wèn)STM32的bootloader怎么制作?

    我對(duì)STM32也算是比較熟悉了,但是呢, 沒(méi)有弄過(guò) STM32的bootloader。也不知道怎么弄的。像,Linux,藍(lán)牙等 都有 類(lèi)型的demo 供你學(xué)習(xí)和開(kāi)發(fā)。 請(qǐng)問(wèn),STM32的bootloader 官方有Demo嗎?謝謝!
    發(fā)表于 03-07 07:50

    STM32案例:BootLoader是怎么跳到App

    BootLoader項(xiàng)目程序和App項(xiàng)目程序是分開(kāi)的,所以需要分別搭建對(duì)應(yīng)的項(xiàng)目工程文件,分開(kāi)搭建文件是為了好配置,同時(shí)也是方便對(duì)項(xiàng)目進(jìn)行管理。
    發(fā)表于 03-04 09:35 ?4286次閱讀
    STM32案例:<b class='flag-5'>BootLoader</b>是怎么跳到App

    關(guān)于bootloader與bootloadable img合并的問(wèn)題求解

    我們實(shí)現(xiàn)bootloader功能時(shí), app0 當(dāng)作bootloader, app1 當(dāng)作bootloadable image,我們想讓app0和app1 訪問(wèn)同一片EEPROM 8K的空間。但我
    發(fā)表于 02-21 08:17

    STM32無(wú)法進(jìn)入片上Bootloader的處理方法

    STM32無(wú)法進(jìn)入片上Bootloader的處理方法? 當(dāng)STM32芯片無(wú)法進(jìn)入片上Bootloader時(shí),我們需要采取一系列的處理方法來(lái)解決這個(gè)問(wèn)題。以下將詳細(xì)介紹一些常見(jiàn)的處理方法。 1.編程器
    的頭像 發(fā)表于 02-02 14:33 ?2093次閱讀

    請(qǐng)問(wèn)IMC101T-038是否支持bootloader下載程序?

    想請(qǐng)問(wèn)一下,038這款MCU是否支持bootloader下載程序呢?現(xiàn)在用這款芯片作為內(nèi)置的風(fēng)機(jī)驅(qū)動(dòng)板,但用戶后期想升級(jí)程序,請(qǐng)問(wèn)一下可以怎么實(shí)現(xiàn)呢?如果這個(gè)實(shí)現(xiàn)不了,有沒(méi)有其他型號(hào)的產(chǎn)品可以進(jìn)行替換呢?只要能
    發(fā)表于 01-23 07:07