<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      痞子衡嵌入式:飛思卡爾Kinetis系列MCU啟動那些事(2)- KBOOT形態(ROM/Bootloader/Flashloader)


        大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾Kinetis系列MCU的KBOOT形態

        痞子衡在前一篇文章里簡介了 KBOOT架構,我們知道KBOOT是一個完善的Bootloader解決方案,這個解決方案主要設計用于Kinetis芯片上,目前Kinetis芯片起碼有上百種型號,KBOOT在這上百種Kinetis芯片里存在的形式并不是完全一樣的,KBOOT主要有三種存在形式(ROM Bootloader、Flashloader、Flash-Resident Bootloader),下面痞子衡為大家細說這三種形態:

      一、KBOOT形態區別

        KBOOT有三種形態,分別是如下圖所示的ROM Bootloader、Flashloader、Flash-Resident Bootloader,三種形態共享大部分KBOOT源碼,僅在一些細節上有差別,這些細節在KBOOT源碼里是用條件編譯加以區分的,對應的條件編譯宏分別是BL_TARGET_ROM, BL_TARGET_RAM, BL_TARGET_FLASH。三種形態最大的區別其實是在鏈接文件上,經過匯編器后的read only section分別鏈接在了Kinetis芯片System memory空間里的ROM(起始地址0x1c000000)、RAM(區間地址0x20000000)、Flash(起始地址0x00000000)區域。

        下表是KBOOT三種形態的對比,分別從use case、delivery mechanism、supported device、clock configuration、feature五大角度進行了對比:

        總結來說,可以這么看KBOOT這三種存在的由來:

      • 對于2014年初及以后問世的Kinetis芯片(比如MKL03、MKL27、MKL43、MKL80、MKE18F等),芯片內基本都是含ROM空間的,因此KBOOT是以ROM Bootloader的形式存在的;
      • 對于2014年初及以后主推的Kinetis芯片(比如MK22、MK65、MKV31、MKS22等),芯片內雖然沒有ROM空間,但飛思卡爾希望能給客戶提供至少一次免編程器燒錄Application(用于量產)的機會,因此KBOOT是以Flashloader的形式存在的;
      • 對于在市場上主流又暢銷的Kinetis芯片(比如MKL25、MK22、MK66、MKL28等),不管芯片內是否有ROM空間,飛思卡爾都希望能夠給出Bootloader源碼,以便讓客戶自由修改來滿足其個性化需求,因此KBOOT是以Flash-Resident Bootloader的形式存在的;

      二、KBOOT各形態實現

      2.1 ROM Bootloader

        KBOOT的ROM Bootloader形態是放在ROM空間里的,隨著芯片一起Tape-out出廠,固化在芯片里面,所以該形態可以被當做硬件模塊,可以被無限次使用。
        因為有了ROM的存在,所以芯片上電啟動便有了兩種選擇:從ROM啟動、從內部Flash啟動,這種啟動選擇是由芯片系統決定的。
        如果是從ROM啟動,那么我們可以借助ROM將Application燒寫進Flash(內部/外部)的起始空間并跳轉過去執行。跳轉至Flash執行分為:從內部Flash執行、從外部QSPI NOR Flash執行,這種執行選擇是由ROM代碼決定的。
        如果已經使用ROM將Application下載進內部Flash起始地址,并在系統設置里設置芯片從內部Flash啟動,那么下次芯片復位啟動完全可以繞開ROM直接從內部Flash起始地址執行Application。

      2.2 Flash-Resident Bootloader

        KBOOT的Flash-Resident Bootloader形態是放在內部Flash起始空間的,以源代碼的形式提供給客戶,客戶需要自己編譯KBOOT工程并使用編程器/調試器將編譯生成的KBOOT binary下載進芯片內部Flash起始地址,除非使用調試器將其擦除,否則其也可以被無限次使用。
        對于沒有ROM的芯片,芯片上電只能從內部Flash起始地址處開始啟動,因為Flash-Resident Bootloader已經占據了內部Flash的起始空間,所以芯片永遠是先執行Flash-Resident Bootloader。借助Flash-Resident Bootloader只能將Application燒寫進內部Flash一定偏移處(這個偏移地址由Flash-Resident Bootloader指定)并跳轉過去執行。

      2.3 Flashloader

        KBOOT的Flashloader形態其實也是放在內部Flash起始空間的,不過與Flash-Resident Bootloader形態在Flash里執行不同之處在于Flashloader形態是在SRAM里執行的,眾所周知,SRAM斷電是不保存數據的,因此Flashloader需要一個放在內部Flash里的配套loader程序,在芯片上電時先運行Flash里的loader程序,由loader程序將Flashloader從Flash中搬運到SRAM中并跳轉到SRAM中運行。
        Flashloader是在芯片出廠之后由飛思卡爾產品工程師將其binary預先下載進內部Flash再售賣給客戶,所以客戶拿到芯片之后至少可以使用一次Flashloader,客戶借助Flashloader可以將Application燒寫進內部Flash起始空間(同時也覆蓋了原Flashloader-loader),這就是Flashloader只能被使用一次的原因。

      2.3.1 loader機制

        關于loader機制與實現,有必要詳細講解一下,讓我們結合代碼分析,首先從官網下載NXP_Kinetis_Bootloader_2_0_0.zip包,就以KS22芯片為例(\targets\MKS22F25612\bootloader.eww):

        使用IAR EWARM 7.80.x開發環境打開KS22的Bootloader工程,可以看到有如下三個工程,其中flashloader.ewp便是主角,其源碼文件與ROM和Flash-Resident Bootloader是一樣,只是工程鏈接文件有區別,其代碼段鏈接在于SRAM里;maps_bootloader.ewp便是Flash-Resident Bootloader,不是此處討論的重點;flashloader_loader.ewp就是Flashloader能在SRAM里執行的關鍵所在。

        flashloader_loader.ewp工程里除了必要的芯片startup文件外,只有三個源文件:flashloader_image.c/h,bl_flashloader.c,其中bl_flashloader.c里包含了工程main函數,讓我們試著分析這個文件以及main函數,下面是bl_flashloader.c的文件內容:

      #include <string.h>
      #include "bootloader_common.h"
      #include "fsl_device_registers.h"
      #include "bootloader/flashloader_image.h"
      
      #if DEBUG
      #include "debug/flashloader_image.c"
      #else
      #include "release/flashloader_image.c"
      #endif
      
      typedef void (*call_function_t)(void);
      call_function_t s_callFunction = 0;
      
      ////////////////////////////////////////////////////////////////////////////////
      // Code
      ////////////////////////////////////////////////////////////////////////////////
      
      // @brief Run the bootloader.
      void bootloader_run(void)
      {
          // Copy flashloader image to RAM.
      	// 關鍵拷貝,實現了flashloader binary從Flash到RAM的轉移
          memcpy((void *)g_flashloaderBase, g_flashloaderImage, g_flashloaderSize);
      
          // Turn off interrupts.
          __disable_irq();
      
          // Set the VTOR to default.
          SCB->VTOR = 0x0;
      
          // Memory barriers for good measure.
          __ISB();
          __DSB();
      
          // Set main stack pointer and process stack pointer.
          __set_MSP(g_flashloaderStack);
          __set_PSP(g_flashloaderStack);
      
          // Jump to flashloader entry point, does not return.
      	// 關鍵跳轉,執行位置從Flash切換到了RAM
          s_callFunction = (call_function_t)g_flashloaderEntry;
          s_callFunction();
      }
      
      // @brief Main bootloader entry point.
      int main(void)
      {
          bootloader_run();
      
          // Should never end up here.
          while (1);
      }
      

        從上述bl_flashloader.c的文件里我們可以看到,其實loader工程的main函數特別簡單,它就是將內部Flash里的g_flashloaderImage[]數據(即flashloader.ewp編譯生成的binary)拷貝到g_flashloaderBase地址(即flashloader binary起始地址)處,并將SP和PC分別指向g_flashloaderStack(即flashloader初始SP)和g_flashloaderEntry(即flashloader的Reset Handler入口)。
        那么g_flashloaderXX常量都放在哪里的呢?打開\targets\MKS22F25612\iar\flashloader\output\Release\flashloader_image.c可以找到答案:

      const uint8_t g_flashloaderImage[] = {
          0x70, 0x62, 0x00, 0x20, 0x11, 0xc4, 0xff, 0x1f, 0xeb, 0xc4, 0xff, 0x1f, 0x75, 0xef, 0xff, 0x1f, 
          // 此處省略41552 bytes
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
      };
      const uint32_t g_flashloaderSize = 41584U;
      const uint32_t g_flashloaderBase = 0x1fffc000;
      const uint32_t g_flashloaderEntry = 0x1fffc411;
      const uint32_t g_flashloaderStack = 0x20006270;
      

        loader機制越來越清晰了,現在只剩最后一個問題了,flashloader_image.c文件是哪里來的?這個文件當然可以手動創建,文件里的信息都可以從flashloader.ewp工程生成的elf/map文件里中找到,但本著高效的原則,但凡能腳本自動生成的決不手動創建,是的這個flashloader_image.c文件就是腳本自動生成的,在flashloader.ewp的Option選項的Build Actions里可以看到調用腳本的命令,這個腳本名叫create_flashloader_image.bat。

        在\bin目錄下存放了所有腳本文件,當然也包括create_flashloader_image.bat,先打開這個腳本看一下:

      cd /d %1
      ielftool --bin output\%2\flashloader.elf flashloader.bin
      python ..\..\..\..\bin\create_fl_image.py output\%2\flashloader.elf flashloader.bin output\%2\flashloader_image.c
      

        ielftool.exe是IAR軟件目錄下的工具,可以將elf文件轉換成bin文件。最核心的腳本其實是create_fl_image.py,這個python腳本根據elf文件和bin文件生成了flashloader_image.c文件。打開create_fl_image.py文件如下(作了一些異常判斷的刪減,為了突出腳本主邏輯):

      import sys
      import os
      import elf
      
      # usage: create_fl_image.py <elffile> <binfile> <cfile> 
      
      def main(argv):
          # Collect arguments
          elfFilename = argv[0]
          binFilename = argv[1]
          cFilename = argv[2]
      
          # Open files
          binFile = open(binFilename, 'rb')
          cFile = open(cFilename, 'w')
      	# 創建了elfData對象,用于后續處理.elf格式文件
          elfData = elf.ELFObject()
      	with open(elfFilename, 'rb') as elfFile:
      	    # 開始處理輸入的.elf文件
      		elfData.fromFile(elfFile)
      		if elfData.e_type != elf.ELFObject.ET_EXEC:
      			raise Exception("No executable")
      		# 開始從.elf里獲取關鍵信息
      		resetHandler = elfData.getSymbol("Reset_Handler")
      		vectors = elfData.getSymbol("__Vectors")
      		stack = elfData.getSymbol("CSTACK$$Limit")
      
          # Print header
          print >> cFile, 'const uint8_t g_flashloaderImage[] = {'
          # Print byte data
          totalBytes = 0
          while True:
              data = binFile.read(16)
              dataLen = len(data)
              if dataLen == 0: break
              totalBytes += dataLen;
              cFile.write('    ')
              for i in range(dataLen):
                  cFile.write('0x%02x, ' % ord(data[i]))
              print >> cFile
          print >> cFile, '};\n'
      
          # Print size and other info
          cFile.write('const uint32_t g_flashloaderSize = %dU;\n' % totalBytes)
          cFile.write('const uint32_t g_flashloaderBase = 0x%x;\n' % vectors.st_value)
          cFile.write('const uint32_t g_flashloaderEntry = 0x%x;\n' % resetHandler.st_value)
          cFile.write('const uint32_t g_flashloaderStack = 0x%x;\n' % stack.st_value)
      
      if __name__ == "__main__":
         main(sys.argv[1:])
      

        create_fl_image.py腳本里除了普通文件操作外,最關鍵的是這句elfData = elf.ELFObject(),調用了elf.py文件提供的elf格式文件操作接口,通過這些接口得到了flashloader里的關鍵信息(vectors、resetHandler、stack),感興趣的可以自己去分析elf.py文件。

      三、KBOOT各形態芯片支持

        截止目前(2017年),KBOOT支持的Kinetis芯片全部列出在下表:

        至此,飛思卡爾Kinetis系列MCU的KBOOT形態痞子衡便介紹完畢了,掌聲在哪里~~~

      歡迎訂閱

      文章會同時發布到我的 博客園主頁CSDN主頁微信公眾號 平臺上。

      微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

      posted @ 2017-04-04 21:49  痞子衡  閱讀(1554)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 激情五月开心综合亚洲| 大地资源免费视频观看| 精品综合久久久久久98| av无码精品一区二区乱子| 中文字幕亚洲日韩无线码| 昔阳县| 国产农村老熟女国产老熟女| 国产精品午夜福利合集| 精品国产乱码久久久久夜深人妻| 国产精品一品二区三四区| 俄罗斯少妇性XXXX另类| 四虎永久免费高清视频| 97人妻人人揉人人躁人人| av亚洲在线一区二区| 亚洲av永久无码精品漫画| 亚洲春色在线视频| 超碰人人超碰人人| 亚洲免费福利在线视频| 大陆一级毛片免费播放| 思热99re视热频这里只精品| 亚洲精品一区二区三区色| 国产欧美日韩亚洲一区二区三区| 真实国产老熟女无套中出| 亚洲精品第一区二区三区| 阳泉市| 国产午夜福利免费入口| 中文成人无字幕乱码精品区| 伊人色综合久久天天小片| 女子spa高潮呻吟抽搐| 亚洲成a人片在线观看中| 国产人成精品一区二区三| 泗洪县| 亚洲国产午夜理论片不卡| 日韩精品成人一区二区三| 欧美成人午夜在线观看视频| 久久亚洲色www成人欧美| 国内精品视频区在线2021| 人人妻人人做人人爽夜欢视频 | 欧美肥老太牲交大战| 国产不卡一区不卡二区| 亚洲国产成人无码影片在线播放|