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 plain copy
  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 plain copy
  1. ldr     pc, =Reset_Handler_In_SRAM       ;进入SRAM执行程序  
[plain]  view plain copy
  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 plain copy
  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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值