TI Cortex M3串口轉以太網例程分析2-----bootloader

bootloader是TI串口轉以太網代碼的一小部分,位於Flash開始的4KB空間內。它的一個重要作用是在應用遠程升級,可以通過串口、USB、IIC、以太網等通道進行遠程固件升級。bootloader是CPU啓動後最先執行的程序,它會把自己拷貝到SRAM,並判斷是否有固件升級,如果有升級請求,則執行升級程序;反之,執行用戶程序。

  一.流程圖       

           由於這裏只考慮基於以太網的bootloader,其流程圖如圖2-1所示:


圖2-1

 二.配置文件     

        由於bootlaoder可以使用串口、USB、IIC、以太網等通道進行遠程固件升級,那麼怎麼樣配置纔可以使用以太網呢?這就牽扯到bl_config文件。此文件是專門配置bootloader的。代碼就不貼了,看一下這裏面幾個必須配置的選項:

1. 以下至少且只能定義一個,用於指明使用何種方式升級。

        CAN_ENABLE_UPDATE,       

        ENET_ENABLE_UPDATE,

        I2C_ENABLE_UPDATE,

        SSI_ENABLE_UPDATE,

        UART_ENABLE_UPDATE,

        USB_ENABLE_UPDATE

2. 以下必須定義

        APP_START_ADDRESS                        用戶程序啓動地址

        VTABLE_START_ADDRESS                 用戶程序向量表起始地址

        FLASH_PAGE_SIZE                               Flash頁大小,TI的目前爲止都爲1K

        STACK_SIZE                                           堆棧大小

3. 當選擇了以太網升級後,以下必須定義

        CRYSTAL_FREQ                                     目標板晶振頻率

三.bootloader啓動代碼分析

          不少人不喜歡分析彙編文件,甚至總想繞過彙編。網絡上也出現一些人教導初學者學習單片機的時候直接用C語言編程,避開彙編。我個人是極其不同意這種“速成”方法的。作爲一名合格的嵌入式工程師或者說愛好者,彙編絕不可迴避。彙編能幫助理解硬件,特別是CPU結構、存儲和尋址等等;現在的嵌入式程序雖然絕大多數是用C編寫的,但要想精通C語言,必須具有彙編基礎,任何技術都是入門容易,精通難,因此要想深入理解C的指針、數組甚至是變量存儲,還非少不了彙編不可;再者,有些地方必須使用匯編,比如一些實時性要求高的模塊(不常見),還有就是接下來要說的啓動代碼。先附源代碼。

[plain] view plaincopy
  1. ;******************************************************************************  
  2. ;  
  3. ; bl_startup_rvmdk.S - Startup code for RV-MDK.  
  4. ;  
  5. ; Copyright (c) 2007-2010 Texas Instruments Incorporated.  All rights reserved.  
  6. ; Software License Agreement  
  7. ;   
  8. ; Texas Instruments (TI) is supplying this software for use solely and  
  9. ; exclusively on TI's microcontroller products. The software is owned by  
  10. ; TI and/or its suppliers, and is protected under applicable copyright  
  11. ; laws. You may not combine this software with "viral" open-source  
  12. ; software in order to form a larger program.  
  13. ;   
  14. ; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.  
  15. ; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT  
  16. ; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR  
  17. ; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY  
  18. ; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL  
  19. ; DAMAGES, FOR ANY REASON WHATSOEVER.  
  20. ;   
  21. ; This is part of revision 6288 of the Stellaris Firmware Development Package.  
  22. ;  
  23. ;******************************************************************************  
  24.   
  25.     include bl_config.inc  
  26.   
  27. ;******************************************************************************  
  28. ;  
  29. ; A couple of defines that would normally be obtained from the appropriate C  
  30. ; header file, but must be manually provided here since the Keil compiler does  
  31. ; not have a mechanism for passing assembly source through the C preprocessor.  
  32. ; 以下定義通常在C頭文件中定義過,但仍要在這裏定義,因爲keil編譯器沒有從彙編器直接  
  33. ; 調用C預編譯器的機制.  
  34. ;  
  35. ;******************************************************************************  
  36. SYSCTL_RESC                     equ     0x400fe05c    ;復位原因  
  37. SYSCTL_RESC_MOSCFAIL            equ     0x00010000  
  38. NVIC_VTABLE                     equ     0xe000ed08    ;向量表偏移量寄存器  
  39.   
  40. ;******************************************************************************  
  41. ;  
  42. ; Put the assembler into the correct configuration.  
  43. ;  
  44. ;******************************************************************************  
  45.     thumb              ;thumb指令  
  46.     require8  
  47.     preserve8  
  48.   
  49. ;******************************************************************************  
  50. ;  
  51. ; The stack gets placed into the zero-init section.  
  52. ; 將堆放到零初始化區  
  53. ;  
  54. ;******************************************************************************  
  55.     area    ||.bss||, noinit, align=2    ;4字節對齊,2的2次冪  
  56.   
  57. ;******************************************************************************  
  58. ;  
  59. ; Allocate storage for the stack.  
  60. ; 爲堆分配空間,STACK_SIZE在bl_config.h中定義的宏,通過bl_config.inc加載armcc  
  61. ;  
  62. ;******************************************************************************  
  63. g_pulStack  
  64.     space   _STACK_SIZE * 4  
  65.   
  66. ;******************************************************************************  
  67. ;  
  68. ; This portion of the file goes into the reset section.  
  69. ;  
  70. ;******************************************************************************  
  71.     area    RESET, code, readonly, align=3    ;8字節對齊?  
  72.   
  73. ;******************************************************************************  
  74. ;  
  75. ; The minimal vector table for a Cortex-M3 processor.  
  76. ;  
  77. ;******************************************************************************  
  78.     export  __Vectors  
  79. __Vectors  
  80.     dcd     g_pulStack + (_STACK_SIZE * 4)  ; Offset 00: Initial stack pointer 初始化堆棧指針  
  81.     if      :def:_FLASH_PATCH_COMPATIBLE  
  82.     dcd     Reset_Handler + 0x1000          ; Offset 04: Reset handler   爲某些Flash打了補丁的器件  
  83.     dcd     NmiSR + 0x1000                  ; Offset 08: NMI handler  
  84.     dcd     FaultISR + 0x1000               ; Offset 0C: Hard fault handler  
  85.     else  
  86.     dcd     Reset_Handler                   ; Offset 04: Reset handler  
  87.     dcd     NmiSR                           ; Offset 08: NMI handler  
  88.     dcd     FaultISR                        ; Offset 0C: Hard fault handler  
  89.     endif  
  90.     dcd     IntDefaultHandler               ; Offset 10: MPU fault handler  
  91.     dcd     IntDefaultHandler               ; Offset 14: Bus fault handler  
  92.     dcd     IntDefaultHandler               ; Offset 18: Usage fault handler  
  93.     dcd     0                               ; Offset 1C: Reserved  
  94.     dcd     0                               ; Offset 20: Reserved  
  95.     dcd     0                               ; Offset 24: Reserved  
  96.     dcd     0                               ; Offset 28: Reserved  
  97.     if      :def:_FLASH_PATCH_COMPATIBLE  
  98.     dcd     UpdateHandler + 0x1000          ; Offset 2C: SVCall handler   SVC異常  
  99.     else  
  100.     dcd     UpdateHandler                   ; Offset 2C: SVCall handler  
  101.     endif  
  102.     dcd     IntDefaultHandler               ; Offset 30: Debug monitor handler  
  103.     dcd     0                               ; Offset 34: Reserved  
  104.     dcd     IntDefaultHandler               ; Offset 38: PendSV handler  
  105.     if      :def:_ENET_ENABLE_UPDATE  
  106.     import  SysTickIntHandler  
  107.     dcd     SysTickIntHandler               ; Offset 3C: SysTick handler  
  108.     else  
  109.     dcd     IntDefaultHandler               ; Offset 3C: SysTick handler  
  110.     endif  
  111.     if      :def:_UART_ENABLE_UPDATE :land: :def:_UART_AUTOBAUD  
  112.     import  GPIOIntHandler  
  113.     dcd     GPIOIntHandler                  ; Offset 40: GPIO port A handler  
  114.     else  
  115.     dcd     IntDefaultHandler               ; Offset 40: GPIO port A handler  
  116.     endif  
  117.     if      :def:_USB_ENABLE_UPDATE :lor:                                     \  
  118.             (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) :lor:               \  
  119.             :def:_FLASH_PATCH_COMPATIBLE  
  120.     dcd     IntDefaultHandler               ; Offset 44: GPIO Port B  
  121.     dcd     IntDefaultHandler               ; Offset 48: GPIO Port C  
  122.     dcd     IntDefaultHandler               ; Offset 4C: GPIO Port D  
  123.     dcd     IntDefaultHandler               ; Offset 50: GPIO Port E  
  124.     dcd     IntDefaultHandler               ; Offset 54: UART0 Rx and Tx  
  125.     dcd     IntDefaultHandler               ; Offset 58: UART1 Rx and Tx  
  126.     dcd     IntDefaultHandler               ; Offset 5C: SSI0 Rx and Tx  
  127.     dcd     IntDefaultHandler               ; Offset 60: I2C0 Master and Slave  
  128.     dcd     IntDefaultHandler               ; Offset 64: PWM Fault  
  129.     dcd     IntDefaultHandler               ; Offset 68: PWM Generator 0  
  130.     dcd     IntDefaultHandler               ; Offset 6C: PWM Generator 1  
  131.     dcd     IntDefaultHandler               ; Offset 70: PWM Generator 2  
  132.     dcd     IntDefaultHandler               ; Offset 74: Quadrature Encoder 0  
  133.     dcd     IntDefaultHandler               ; Offset 78: ADC Sequence 0  
  134.     dcd     IntDefaultHandler               ; Offset 7C: ADC Sequence 1  
  135.     dcd     IntDefaultHandler               ; Offset 80: ADC Sequence 2  
  136.     dcd     IntDefaultHandler               ; Offset 84: ADC Sequence 3  
  137.     dcd     IntDefaultHandler               ; Offset 88: Watchdog timer  
  138.     dcd     IntDefaultHandler               ; Offset 8C: Timer 0 subtimer A  
  139.     dcd     IntDefaultHandler               ; Offset 90: Timer 0 subtimer B  
  140.     dcd     IntDefaultHandler               ; Offset 94: Timer 1 subtimer A  
  141.     dcd     IntDefaultHandler               ; Offset 98: Timer 1 subtimer B  
  142.     dcd     IntDefaultHandler               ; Offset 9C: Timer 2 subtimer A  
  143.     dcd     IntDefaultHandler               ; Offset A0: Timer 2 subtimer B  
  144.     dcd     IntDefaultHandler               ; Offset A4: Analog Comparator 0  
  145.     dcd     IntDefaultHandler               ; Offset A8: Analog Comparator 1  
  146.     dcd     IntDefaultHandler               ; Offset AC: Analog Comparator 2  
  147.     dcd     IntDefaultHandler               ; Offset B0: System Control  
  148.     if      :def:_FLASH_PATCH_COMPATIBLE  
  149.     dcd     0x00000881                      ; Offset B4: FLASH Control  
  150.     else  
  151.     dcd     IntDefaultHandler               ; Offset B4: FLASH Control  
  152.     endif  
  153.     endif  
  154.     if      :def:_USB_ENABLE_UPDATE :lor:                                     \  
  155.             (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)  
  156.     dcd     IntDefaultHandler               ; Offset B8: GPIO Port F  
  157.     dcd     IntDefaultHandler               ; Offset BC: GPIO Port G  
  158.     dcd     IntDefaultHandler               ; Offset C0: GPIO Port H  
  159.     dcd     IntDefaultHandler               ; Offset C4: UART2 Rx and Tx  
  160.     dcd     IntDefaultHandler               ; Offset C8: SSI1 Rx and Tx  
  161.     dcd     IntDefaultHandler               ; Offset CC: Timer 3 subtimer A  
  162.     dcd     IntDefaultHandler               ; Offset D0: Timer 3 subtimer B  
  163.     dcd     IntDefaultHandler               ; Offset D4: I2C1 Master and Slave  
  164.     dcd     IntDefaultHandler               ; Offset D8: Quadrature Encoder 1  
  165.     dcd     IntDefaultHandler               ; Offset DC: CAN0  
  166.     dcd     IntDefaultHandler               ; Offset E0: CAN1  
  167.     dcd     IntDefaultHandler               ; Offset E4: CAN2  
  168.     dcd     IntDefaultHandler               ; Offset E8: Ethernet  
  169.     dcd     IntDefaultHandler               ; Offset EC: Hibernation module  
  170.     if      :def: _USB_ENABLE_UPDATE  
  171.     import  USB0DeviceIntHandler  
  172.     dcd     USB0DeviceIntHandler            ; Offset F0: USB 0 Controller  
  173.     else  
  174.     dcd     IntDefaultHandler               ; Offset F0: USB 0 Controller  
  175.     endif  
  176.     endif  
  177.   
  178. ;******************************************************************************  
  179. ;  
  180. ; Initialize the processor by copying the boot loader from flash to SRAM, zero  
  181. ; filling the .bss section, and moving the vector table to the beginning of  
  182. ; SRAM.  The return address is modified to point to the SRAM copy of the boot  
  183. ; loader instead of the flash copy, resulting in a branch to the copy now in  
  184. ; SRAM.  
  185. ; 初始化處理器,將boot loader從flash拷貝到SRAM,將.bss區用零填充並將向量表重映射到  
  186. ; SRAM的開始處.  
  187. ;  
  188. ;******************************************************************************  
  189.     export  ProcessorInit  
  190. ProcessorInit  
  191.     ;  
  192.     ; Copy the code image from flash to SRAM.  
  193.     ;  
  194.     if      :def:_FLASH_PATCH_COMPATIBLE  
  195.     movs    r0, #0x1000  
  196.     else  
  197.     movs    r0, #0x0000        
  198.     endif  
  199.     movs    r1, #0x0000  
  200.     movt    r1, #0x2000      ;將16位的立即數放到寄存器的高16位,低位不受影響  
  201.     import  ||Image$SRAM$ZI$Base||  ;爲彙編器提供一個在當前彙編程序中未定義的符號  
  202.     ldr     r2, =||Image$SRAM$ZI$Base|| ;SRAM區中的ZI輸出節執行地址  
  203. copy_loop  
  204.         ldr     r3, [r0], #4  
  205.         str     r3, [r1], #4  
  206.         cmp     r1, r2  
  207.         blt     copy_loop  
  208.   
  209.     ;  
  210.     ; Zero fill the .bss section.將.bss區用零填充  
  211.     ;  
  212.     movs    r0, #0x0000  
  213.     import  ||Image$SRAM$ZI$Limit||    ;SRAM區中ZI 輸出節末尾地址後面的字節地址  
  214.     ldr     r2, =||Image$SRAM$ZI$Limit||  
  215. zero_loop  
  216.         str     r0, [r1], #4  
  217.         cmp     r1, r2  
  218.         blt     zero_loop  
  219.   
  220.     ;  
  221.     ; Set the vector table pointer to the beginning of SRAM.  
  222.     ; 將向量表指針指向SRAM開始處  
  223.     ;  
  224.     movw    r0, #(NVIC_VTABLE & 0xffff)     ;放入r0低16位,高位清零  
  225.     movt    r0, #(NVIC_VTABLE >> 16)      ;NVIC_VTABLE=0xe000ed08(向量表偏移量寄存器)  
  226.     movs    r1, #0x0000  
  227.     movt    r1, #0x2000  
  228.     str     r1, [r0]                        ;向量表重定位到0x2000 0000處  
  229.   
  230.     ;  
  231.     ; Return to the caller.返回  
  232.     ;  
  233.     bx      lr  
  234.   
  235. ;******************************************************************************  
  236. ;  
  237. ; The reset handler, which gets called when the processor starts.  
  238. ;  
  239. ;******************************************************************************  
  240.     export  Reset_Handler  
  241. Reset_Handler  
  242.     ;  
  243.     ; Initialize the processor.  
  244.     ;  
  245.     bl      ProcessorInit  
  246.   
  247.     ;  
  248.     ; Branch to the SRAM copy of the reset handler.  
  249.     ;  
[plain] view plaincopy
  1. ldr     pc, =Reset_Handler_In_SRAM       ;進入SRAM執行程序  
[plain] view plaincopy
  1. ;******************************************************************************  
  2. ;  
  3. ; The NMI handler.  
  4. ;  
  5. ;******************************************************************************  
  6. NmiSR  
  7.     if      :def:_ENABLE_MOSCFAIL_HANDLER  
  8.     ;  
  9.     ; Grab the fault frame from the stack (the stack will be cleared by the  
  10.     ; processor initialization that follows).  
  11.     ;  
  12.     ldm     sp, {r4-r11}  
  13.     mov     r12, lr  
  14.   
  15.     ;  
  16.     ; Initialize the processor.  
  17.     ;  
  18.     bl      ProcessorInit  
  19.   
  20.     ;  
  21.     ; Branch to the SRAM copy of the NMI handler.  
  22.     ;  
  23.     ldr     pc, =NmiSR_In_SRAM  
  24.     else  
  25.     ;  
  26.     ; Loop forever since there is nothing that we can do about a NMI.  
  27.     ;  
  28.     b       .  
  29.     endif  
  30.   
  31. ;******************************************************************************  
  32. ;  
  33. ; The hard fault handler.  
  34. ;  
  35. ;******************************************************************************  
  36. FaultISR  
  37.     ;  
  38.     ; Loop forever since there is nothing that we can do about a hard fault.  
  39.     ;  
  40.     b       .  
  41.   
  42. ;******************************************************************************  
  43. ;  
  44. ; The update handler, which gets called when the application would like to  
  45. ; start an update.  
  46. ; 升級服務函數,當應用程序想要開始升級時,調用這個函數.  
  47. ;  
  48. ;******************************************************************************  
  49. UpdateHandler  
  50.     ;  
  51.     ; Initialize the processor. 初始化處理器  
  52.     ;  
  53.     bl      ProcessorInit         ;調用子程序  
  54.   
  55.     ;  
  56.     ; Branch to the SRAM copy of the update handler.  
  57.     ;  
  58.     ldr     pc, =UpdateHandler_In_SRAM  
  59.   
  60. ;******************************************************************************  
  61. ;  
  62. ; This portion of the file goes into the text section.  
  63. ;  
  64. ;******************************************************************************  
  65.     align   4  
  66.     area    ||.text||, code, readonly, align=2  
  67.   
  68. Reset_Handler_In_SRAM  
  69.     ;  
  70.     ; Call the user-supplied low level hardware initialization function  
  71.     ; if provided.  
  72.     ; 如果用戶提供了底層硬件初始化函數,則調用這個函數  
  73.     ;  
  74.     if      :def:_BL_HW_INIT_FN_HOOK  
  75.     import  $_BL_HW_INIT_FN_HOOK  
  76.     bl      $_BL_HW_INIT_FN_HOOK  
  77.     endif  
  78.   
  79.     ;  
  80.     ; See if an update should be performed.  
  81.     ; 檢查是否有升級請求  
  82.     ;  
  83.     import  CheckForceUpdate  
  84.     bl      CheckForceUpdate  
  85.     cbz     r0, CallApplication    ;結果爲零則轉移(只能跳到下一行)  
  86.   
  87.     ;  
  88.     ; Configure the microcontroller.  
  89.     ;  
  90. EnterBootLoader  
  91.     if      :def:_ENET_ENABLE_UPDATE  
  92.     import  ConfigureEnet  
  93.     bl      ConfigureEnet  
  94.     elif    :def:_CAN_ENABLE_UPDATE  
  95.     import  ConfigureCAN  
  96.     bl      ConfigureCAN  
  97.     elif    :def:_USB_ENABLE_UPDATE  
  98.     import  ConfigureUSB  
  99.     bl      ConfigureUSB  
  100.     else  
  101.     import  ConfigureDevice  
  102.     bl      ConfigureDevice  
  103.     endif  
  104.   
  105.     ;  
  106.     ; Call the user-supplied initialization function if provided.  
  107.     ; 如果用戶提供了初始化函數,則調用.  
  108.     ;  
  109.     if      :def:_BL_INIT_FN_HOOK  
  110.     import  $_BL_INIT_FN_HOOK  
  111.     bl      $_BL_INIT_FN_HOOK  
  112.     endif  
  113.   
  114.     ;  
  115.     ; Branch to the update handler.  
  116.     ; 進入升級處理程序  
  117.     ;  
  118.     if      :def:_ENET_ENABLE_UPDATE  
  119.     import  UpdateBOOTP  
  120.     b       UpdateBOOTP  
  121.     elif    :def:_CAN_ENABLE_UPDATE  
  122.     import  UpdaterCAN  
  123.     b       UpdaterCAN  
  124.     elif    :def:_USB_ENABLE_UPDATE  
  125.     import  UpdaterUSB  
  126.     b       UpdaterUSB  
  127.     else  
  128.     import  Updater  
  129.     b       Updater  
  130.     endif  
  131.   
  132.     ;  
  133.     ; This is a second symbol to allow starting the application from the boot  
  134.     ; loader the linker may not like the perceived jump.  
  135.     ;  
  136.     export StartApplication  
  137. StartApplication  
  138.     ;  
  139.     ; Call the application via the reset handler in its vector table.  Load the  
  140.     ; address of the application vector table.  
  141.     ;  
  142. CallApplication  
  143.     ;  
  144.     ; Copy the application's vector table to the target address if necessary.  
  145.     ; Note that incorrect boot loader configuration could cause this to  
  146.     ; corrupt the code!  Setting VTABLE_START_ADDRESS to 0x20000000 (the start  
  147.     ; of SRAM) is safe since this will use the same memory that the boot loader  
  148.     ; already uses for its vector table.  Great care will have to be taken if  
  149.     ; other addresses are to be used.  
  150.     ; 如果必要的話,複製應用程序的向量表到目標地址.  
  151.     ; 請注意,不正確的boot loader配置會破壞整個程序!設置VTABLE_START_ADDRESS爲  
  152.     ; 0x2000 0000(從SRAM啓動)也是可以的,因爲這將和boot loader使用同樣的內存  
  153.     ;  
  154.     if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) ;看應用程序的起始地址是否和應用程序的向量表存儲地址相同  
  155.     movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)  
  156.     if (_VTABLE_START_ADDRESS > 0xffff)  
  157.     movt    r0, #(_VTABLE_START_ADDRESS >> 16)  
  158.     endif  
  159.     movw    r1, #(_APP_START_ADDRESS & 0xffff)  
  160.     if (_APP_START_ADDRESS > 0xffff)  
  161.     movt    r1, #(_APP_START_ADDRESS >> 16)  
  162.     endif  
  163.   
  164.     ;  
  165.     ; Calculate the end address of the vector table assuming that it has the  
  166.     ; maximum possible number of vectors.  We don't know how many the app has  
  167.     ; populated so this is the safest approach though it may copy some non  
  168.     ; vector data if the app table is smaller than the maximum.  
  169.     ; 計算向量表的結束地址,假設向量表有最大數目. 我們不知道應用程序使用了多少  
  170.     ; 向量表,但這樣是最安全的  
  171.     ;  
  172.     movw    r2, #(70 * 4)  
  173.     adds    r2, r2, r0  
  174. VectorCopyLoop  
  175.         ldr     r3, [r1], #4  
  176.         str     r3, [r0], #4  
  177.         cmp     r0, r2  
  178.         blt     VectorCopyLoop  
  179.     endif  
  180.   
  181.     ;  
  182.     ; Set the vector table address to the beginning of the application.  
  183.     ; 將向量表重定位到應用程序開始處  
  184.     ;  
  185.     movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)  
  186.     if (_VTABLE_START_ADDRESS > 0xffff)  
  187.     movt    r0, #(_VTABLE_START_ADDRESS >> 16)  
  188.     endif  
  189.     movw    r1, #(NVIC_VTABLE & 0xffff)             ;向量表偏移寄存器  
  190.     movt    r1, #(NVIC_VTABLE >> 16)  
  191.     str     r0, [r1]  
  192.   
  193.     ;  
  194.     ; Load the stack pointer from the application's vector table.  
  195.     ; 從應用程序向量表裝載用戶堆棧.  
  196.     ;  
  197.     if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)  
  198.     movw    r0, #(_APP_START_ADDRESS & 0xffff)  
  199.     if (_APP_START_ADDRESS > 0xffff)  
  200.     movt    r0, #(_APP_START_ADDRESS >> 16)  
  201.     endif  
  202.     endif  
  203.     ldr     sp, [r0]  
  204.   
  205.     ;  
  206.     ; Load the initial PC from the application's vector table and branch to  
  207.     ; the application's entry point.  
  208.     ;  
  209.     ldr     r0, [r0, #4]  
  210.     bx      r0  
  211.   
  212. ;******************************************************************************  
  213. ;  
  214. ; The update handler, which gets called when the application would like to  
  215. ; start an update.  
  216. ; 升級處理函數,當用戶程序想要開始升級時,調用此函數  
  217. ;  
  218. ;******************************************************************************  
  219. UpdateHandler_In_SRAM  
  220.     ;  
  221.     ; Load the stack pointer from the vector table.  
  222.     ; 從boot loader向量表中裝載堆棧指針  
  223.     ;  
  224.     if      :def:_FLASH_PATCH_COMPATIBLE  
  225.     movs    r0, #0x1000  
  226.     else  
  227.     movs    r0, #0x0000  
  228.     endif  
  229.     ldr     sp, [r0]  
  230.   
  231.     ;  
  232.     ; Call the user-supplied low level hardware initialization function  
  233.     ; if provided.  
  234.     ; 調用用戶提供的底層硬件初始化函數  
  235.     ;  
  236.     if      :def:_BL_HW_INIT_FN_HOOK  
  237.     bl      $_BL_HW_INIT_FN_HOOK  
  238.     endif  
  239.   
  240.     ;  
  241.     ; Call the user-supplied re-initialization function if provided.  
  242.     ; 調用用戶提供的初始化函數  
  243.     ;  
  244.     if      :def:_BL_REINIT_FN_HOOK  
  245.     import  $_BL_REINIT_FN_HOOK  
  246.     bl      $_BL_REINIT_FN_HOOK  
  247.     endif  
  248.   
  249.     ;  
  250.     ; Branch to the update handler.  
  251.     ; 進入升級例程  
  252.     ;  
  253.     if      :def:_ENET_ENABLE_UPDATE  
  254.     b       UpdateBOOTP        ;在bl_enet.c中  
  255.     elif    :def:_CAN_ENABLE_UPDATE  
  256.     import  AppUpdaterCAN  
  257.     b       AppUpdaterCAN  
  258.     elif    :def:_USB_ENABLE_UPDATE  
  259.     import  AppUpdaterUSB  
  260.     b       AppUpdaterUSB  
  261.     else  
  262.     b       Updater  
  263.     endif  
  264.   
  265. ;******************************************************************************  
  266. ;  
  267. ; The NMI handler.  
  268. ; NMI異常服務例程,處理主振盪器失敗  
  269. ;  
  270. ;******************************************************************************  
  271.     if      :def:_ENABLE_MOSCFAIL_HANDLER  
  272. NmiSR_In_SRAM  
  273.     ;  
  274.     ; Restore the stack frame.  
  275.     ;  
  276.     mov     lr, r12  
  277.     stm     sp, {r4-r11}  
  278.   
  279.     ;  
  280.     ; Save the link register.  
  281.     ;  
  282.     mov     r9, lr  
  283.   
  284.     ;  
  285.     ; Call the user-supplied low level hardware initialization function  
  286.     ; if provided.  
  287.     ;  
  288.     if      :def:_BL_HW_INIT_FN_HOOK  
  289.     bl      _BL_HW_INIT_FN_HOOK  
  290.     endif  
  291.   
  292.     ;  
  293.     ; See if an update should be performed.  
  294.     ;  
  295.     bl      CheckForceUpdate  
  296.     cbz     r0, EnterApplication  
  297.   
  298.         ;  
  299.         ; Clear the MOSCFAIL bit in RESC.  
  300.         ;  
  301.         movw    r0, #(SYSCTL_RESC & 0xffff)  
  302.         movt    r0, #(SYSCTL_RESC >> 16)  
  303.         ldr     r1, [r0]  
  304.         bic     r1, r1, #SYSCTL_RESC_MOSCFAIL  
  305.         str     r1, [r0]  
  306.   
  307.         ;  
  308.         ; Fix up the PC on the stack so that the boot pin check is bypassed  
  309.         ; (since it has already been performed).  
  310.         ;  
  311.         ldr     r0, =EnterBootLoader  
  312.         bic     r0, #0x00000001  
  313.         str     r0, [sp, #0x18]  
  314.           
  315.         ;  
  316.         ; Return from the NMI handler.  This will then start execution of the  
  317.         ; boot loader.  
  318.         ;  
  319.         bx      r9  
  320.   
  321.     ;  
  322.     ; Restore the link register.  
  323.     ;  
  324. EnterApplication  
  325.     mov     lr, r9  
  326.   
  327.     ;  
  328.     ; Copy the application's vector table to the target address if necessary.  
  329.     ; Note that incorrect boot loader configuration could cause this to  
  330.     ; corrupt the code!  Setting VTABLE_START_ADDRESS to 0x20000000 (the start  
  331.     ; of SRAM) is safe since this will use the same memory that the boot loader  
  332.     ; already uses for its vector table.  Great care will have to be taken if  
  333.     ; other addresses are to be used.  
  334.     ;  
  335.     if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)  
  336.     movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)  
  337.     if (_VTABLE_START_ADDRESS > 0xffff)  
  338.     movt    r0, #(_VTABLE_START_ADDRESS >> 16)  
  339.     endif  
  340.     movw    r1, #(_APP_START_ADDRESS & 0xffff)  
  341.     if (_APP_START_ADDRESS > 0xffff)  
  342.     movt    r1, #(_APP_START_ADDRESS >> 16)  
  343.     endif  
  344.   
  345.     ;  
  346.     ; Calculate the end address of the vector table assuming that it has the  
  347.     ; maximum possible number of vectors.  We don't know how many the app has  
  348.     ; populated so this is the safest approach though it may copy some non  
  349.     ; vector data if the app table is smaller than the maximum.  
  350.     ;  
  351.     movw    r2, #(70 * 4)  
  352.     adds    r2, r2, r0  
  353. VectorCopyLoop2  
  354.         ldr     r3, [r1], #4  
  355.         str     r3, [r0], #4  
  356.         cmp     r0, r2  
  357.         blt     VectorCopyLoop2  
  358.     endif  
  359.   
  360.     ;  
  361.     ; Set the application's vector table start address.  Typically this is the  
  362.     ; application start address but in some cases an application may relocate  
  363.     ; this so we can't assume that these two addresses are equal.  
  364.     ;  
  365.     movw    r0, #(_VTABLE_START_ADDRESS & 0xffff)  
  366.     if (_VTABLE_START_ADDRESS > 0xffff)  
  367.     movt    r0, #(_VTABLE_START_ADDRESS >> 16)  
  368.     endif  
  369.     movw    r1, #(NVIC_VTABLE & 0xffff)  
  370.     movt    r1, #(NVIC_VTABLE >> 16)  
  371.     str     r0, [r1]  
  372.   
  373.     ;  
  374.     ; Remove the NMI stack frame from the boot loader's stack.  
  375.     ;  
  376.     ldmia   sp, {r4-r11}  
  377.   
  378.     ;  
  379.     ; Get the application's stack pointer.  
  380.     ;  
  381.     if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)  
  382.     movw    r0, #(_APP_START_ADDRESS & 0xffff)  
  383.     if (_APP_START_ADDRESS > 0xffff)  
  384.     movt    r0, #(_APP_START_ADDRESS >> 16)  
  385.     endif  
  386.     endif  
  387.     ldr     sp, [r0, #0x00]  
  388.   
  389.     ;  
  390.     ; Fix up the NMI stack frame's return address to be the reset handler of  
  391.     ; the application.  
  392.     ;  
  393.     ldr     r10, [r0, #0x04]  
  394.     bic     r10, #0x00000001  
  395.   
  396.     ;  
  397.     ; Store the NMI stack frame onto the application's stack.  
  398.     ;  
  399.     stmdb   sp!, {r4-r11}  
  400.   
  401.     ;  
  402.     ; Branch to the application's NMI handler.  
  403.     ;  
  404.     ldr     r0, [r0, #0x08]  
  405.     bx      r0  
  406.     endif  
  407.   
  408. ;******************************************************************************  
  409. ;  
  410. ; The default interrupt handler.  
  411. ;  
  412. ;******************************************************************************  
  413. IntDefaultHandler  
  414.     ;  
  415.     ; Loop forever since there is nothing that we can do about an unexpected  
  416.     ; interrupt.  
  417.     ;  
  418.     b       .  
  419.   
  420. ;******************************************************************************  
  421. ;  
  422. ; Provides a small delay.  The loop below takes 3 cycles/loop.  
  423. ; 提供一個小的延時函數. 循環一次需要3個時鐘週期.  
  424. ;  
  425. ;******************************************************************************  
  426.     export  Delay  
  427. Delay  
  428.     subs    r0, #1  
  429.     bne     Delay  
  430.     bx      lr  
  431.   
  432. ;******************************************************************************  
  433. ;  
  434. ; This is the end of the file.  
  435. ;  
  436. ;******************************************************************************  
  437.     align   4  
  438.     end  

1. 彙編文件正文的第一句

[plain] view plaincopy
  1. include bl_config.inc  

包含bl_config.inc,這個文件是什麼,從哪裏來,有什麼作用?再看bootloader工程Options---User---Run User Programs Before Build/Rebuild內的用戶命令(見圖2-2)又是什麼?


圖2-2

         所有的一切,要從keil MDK的彙編器說起,在啓動代碼中要用到配置文件bl_config.h中定義的一些配置選項,但因爲MDK彙編器不能通過C預處理器運行彙編代碼,所以bl_config.h中的相關內容需要 轉化爲彙編格式幷包含到MDK的啓動代碼中。這需要手動運行C預編譯器進行格式轉化。圖2-2中紅色部分圈出的內容正是爲了完成這個轉換。在點擊Build/Rebuild編譯按鈕之後,會先運行圖2-2指定的命令,再進行編譯。先來分析一下這條命令:

                                armcc --device DLM -o bl_config.inc -E bl_config.c

          這條命令的作用是將bl_config.c(包含bl_config.h文件)進行而且僅進行預編譯處理,並生成bl_config.inc文件。

          armcc是Keil MDK提供的C編譯工具,語法爲:

                                 armcc [Options]  file1  file2  ...  file n

           介紹一下這裏用到的Options選項:

                                   --device<dev>:設置目標的設備類型,DLM爲Luminary的設備標識。

                                   -I<directory>   :目錄列表

                                   -E                      :僅執行預處理

                                   -o<file>            :指定輸出文件的名字

2. 看一下目標板上電後啓動代碼的運行流程

          上電後程序先到Flash地址0x00處裝載堆棧地址,這跟以前接觸過的處理器不同,以前0x00處都是放置的復位處理代碼,但Cortex M3內核卻不是,0x00處是放置的堆棧地址,而不是跳轉指令。

           堆棧設置完成後,跳轉到Reset處理程序處,調用處理器初始化函數ProcessorInit,該函數將bootloader從Flash拷貝到SRAM,將.bss區用零填充並將向量表重映射到SRAM開始處。

           之後跳轉到Reset_Handler_In_SRAM函數,在該函數中,如果用戶提供了底層硬件初始化函數(在bl_config.h中使能),則調用這個函數。然後調用CheckForceUpdate函數,檢查是否有升級請求。如果沒有升級請求,跳轉到CallApplication函數,在該函數中,將向量表重映射到應用程序開始處(這裏爲地址0x1000),裝載用戶程序堆棧地址,跳轉到用戶程序的Reset服務函數。

           如果調用CheckForceUpdate函數檢測到有升級請求,則配置以太網,跳轉到升級程序UpdateBOOTP處執行。

3. 如何在用戶程序中調用升級程序

          用戶程序存在於Flash地址0x1000處,bootloader存放於Flash地址0x00處,並且用戶程序在執行的時候已經將向量表重映射到了Flash地址0x1000處了,那麼應用程序是如何調用位於bootloader中的升級程序呢?

        再看bootloader啓動代碼的中斷向量表,在Flash地址的0x2C中存放的是CPU SVC異常服務跳轉地址:

                    dcd     UpdateHandler                   ; Offset 2C: SVCall handler

        而bootloader正是用這個異常來處理升級請求的。那麼,應用程序只要執行該地址處的跳轉指令,就能進行一次程序升級,在應用程序中的swupdate.c中,使用瞭如下C代碼來執行位於Flash地址0x2C內的跳轉程序:

                    (*((void (*)(void))(*(unsigned long *)0x2c)))();  

         對C語言還沒有入門的同學可能會比較的頭痛,這像謎一樣的語句是如何執行位於bootloader的SVC異常服務例程呢?還是分解一下吧:

                      (*(unsigned long *)0x2c):將0x2C強制轉化爲unsigned long類型指針,並指向該地址所在的數據;

                      void (*)(void)                      :函數指針,指針名爲空,該函數參數爲空,返回值爲空

                     (void (*)(void))(*(unsigned long *)0x2c):將Flash地址0x2C中的內容強制轉化爲函數指針,該函數參數爲空,返回值爲空

                     (*((void (*)(void))(*(unsigned long *)0x2c)))();:調用函數,即開始從啓動代碼中的UpdateHandler標號處開始執行。

轉載:http://blog.csdn.net/zhzht19861011/article/details/6675170

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章