TI Cortex M3串口转以太网例程分析2-----bootloader

[复制链接]
 楼主| 发表于 2015-7-20 20:50 | 显示全部楼层 |阅读模式
bootloader是TI串口转以太网代码的一小部分,位于Flash开始的4KB空间内。它的一个重要作用是在应用远程升级,可以通过串口、USB、IIC、以太网等通道进行远程固件升级。bootloader是CPU启动后最先执行的程序,它会把自己拷贝到SRAM,并判断是否有固件升级,如果有升级请求,则执行升级程序;反之,执行用户程序。  一.流程图      
           由于这里只考虑基于以太网的bootloader,其流程图如图2-1所示:

图2-1
二.配置文件     
        由于bootlaoder可以使用串口、USB、IIC、以太网等通道进行远程固件升级,那么怎么样配置才可以使用以太网呢?这就牵扯到bl_config文件。此文件是专门配置bootloader的。代码就不贴了,看一下这里面几个必须配置的选项:
1. 以下至少且只能定义一个,用于指明使用何种方式升级。

 楼主| 发表于 2015-7-20 20:51 | 显示全部楼层
  1. CAN_ENABLE_UPDATE,      

  2.         ENET_ENABLE_UPDATE,

  3.         I2C_ENABLE_UPDATE,

  4.         SSI_ENABLE_UPDATE,

  5.         UART_ENABLE_UPDATE,

  6.         USB_ENABLE_UPDATE
2. 以下必须定义
  1. APP_START_ADDRESS                        用户程序启动地址

  2.         VTABLE_START_ADDRESS                 用户程序向量表起始地址

  3.         FLASH_PAGE_SIZE                               Flash页大小,TI的目前为止都为1K

  4.         STACK_SIZE                                           堆栈大小
3. 当选择了以太网升级后,以下必须定义
  1. CRYSTAL_FREQ                                     目标板晶振频率




 楼主| 发表于 2015-7-20 20:53 | 显示全部楼层
三.bootloader启动代码分析
          不少人不喜欢分析汇编文件,甚至总想绕过汇编。网络上也出现一些人教导初学者学习单片机的时候直接用C语言编程,避开汇编。我个人是极其不同意这种“速成”方法的。作为一名合格的嵌入式工程师或者说爱好者,汇编绝不可回避。汇编能帮助理解硬件,特别是CPU结构、存储和寻址等等;现在的嵌入式程序虽然绝大多数是用C编写的,但要想精通C语言,必须具有汇编基础,任何技术都是入门容易,精通难,因此要想深入理解C的指针、数组甚至是变量存储,还非少不了汇编不可;再者,有些地方必须使用汇编,比如一些实时性要求高的模块(不常见),还有就是接下来要说的启动代码。先附源代码。
  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.         ;  
  1. ldr     pc, =Reset_Handler_In_SRAM       ;进入SRAM执行程序  
  1.    


 楼主| 发表于 2015-7-20 20:53 | 显示全部楼层
  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. ; Initialize the processor.
  16. ;
  17. bl ProcessorInit

  18. ;
  19. ; Branch to the SRAM copy of the NMI handler.
  20. ;
  21. ldr pc, =NmiSR_In_SRAM
  22. else
  23. ;
  24. ; Loop forever since there is nothing that we can do about a NMI.
  25. ;
  26. b .
  27. endif

  28. ;******************************************************************************
  29. ;
  30. ; The hard fault handler.
  31. ;
  32. ;******************************************************************************
  33. FaultISR
  34. ;
  35. ; Loop forever since there is nothing that we can do about a hard fault.
  36. ;
  37. b .

  38. ;******************************************************************************
  39. ;
  40. ; The update handler, which gets called when the application would like to
  41. ; start an update.
  42. ; 升级服务函数,当应用程序想要开始升级时,调用这个函数.
  43. ;
  44. ;******************************************************************************
  45. UpdateHandler
  46. ;
  47. ; Initialize the processor. 初始化处理器
  48. ;
  49. bl ProcessorInit ;调用子程序

  50. ;
  51. ; Branch to the SRAM copy of the update handler.
  52. ;
  53. ldr pc, =UpdateHandler_In_SRAM

  54. ;******************************************************************************
  55. ;
  56. ; This portion of the file goes into the text section.
  57. ;
  58. ;******************************************************************************
  59. align 4
  60. area ||.text||, code, readonly, align=2

  61. Reset_Handler_In_SRAM
  62. ;
  63. ; Call the user-supplied low level hardware initialization function
  64. ; if provided.
  65. ; 如果用户提供了底层硬件初始化函数,则调用这个函数
  66. ;
  67. if :def:_BL_HW_INIT_FN_HOOK
  68. import $_BL_HW_INIT_FN_HOOK
  69. bl $_BL_HW_INIT_FN_HOOK
  70. endif

  71. ;
  72. ; See if an update should be performed.
  73. ; 检查是否有升级请求
  74. ;
  75. import CheckForceUpdate
  76. bl CheckForceUpdate
  77. cbz r0, CallApplication ;结果为零则转移(只能跳到下一行)

  78. ;
  79. ; Configure the microcontroller.
  80. ;
  81. EnterBootLoader
  82. if :def:_ENET_ENABLE_UPDATE
  83. import ConfigureEnet
  84. bl ConfigureEnet
  85. elif :def:_CAN_ENABLE_UPDATE
  86. import ConfigureCAN
  87. bl ConfigureCAN
  88. elif :def:_USB_ENABLE_UPDATE
  89. import ConfigureUSB
  90. bl ConfigureUSB
  91. else
  92. import ConfigureDevice
  93. bl ConfigureDevice
  94. endif

  95. ;
  96. ; Call the user-supplied initialization function if provided.
  97. ; 如果用户提供了初始化函数,则调用.
  98. ;
  99. if :def:_BL_INIT_FN_HOOK
  100. import $_BL_INIT_FN_HOOK
  101. bl $_BL_INIT_FN_HOOK
  102. endif

  103. ;
  104. ; Branch to the update handler.
  105. ; 进入升级处理程序
  106. ;
  107. if :def:_ENET_ENABLE_UPDATE
  108. import UpdateBOOTP
  109. b UpdateBOOTP
  110. elif :def:_CAN_ENABLE_UPDATE
  111. import UpdaterCAN
  112. b UpdaterCAN
  113. elif :def:_USB_ENABLE_UPDATE
  114. import UpdaterUSB
  115. b UpdaterUSB
  116. else
  117. import Updater
  118. b Updater
  119. endif

  120. ;
  121. ; This is a second symbol to allow starting the application from the boot
  122. ; loader the linker may not like the perceived jump.
  123. ;
  124. export StartApplication
  125. StartApplication
  126. ;
  127. ; Call the application via the reset handler in its vector table. Load the
  128. ; address of the application vector table.
  129. ;
  130. CallApplication
  131. ;
  132. ; Copy the application's vector table to the target address if necessary.
  133. ; Note that incorrect boot loader configuration could cause this to
  134. ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
  135. ; of SRAM) is safe since this will use the same memory that the boot loader
  136. ; already uses for its vector table. Great care will have to be taken if
  137. ; other addresses are to be used.
  138. ; 如果必要的话,复制应用程序的向量表到目标地址.
  139. ; 请注意,不正确的boot loader配置会破坏整个程序!设置VTABLE_START_ADDRESS为
  140. ; 0x2000 0000(从SRAM启动)也是可以的,因为这将和boot loader使用同样的内存
  141. ;
  142. if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) ;看应用程序的起始地址是否和应用程序的向量表存储地址相同
  143. movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
  144. if (_VTABLE_START_ADDRESS > 0xffff)
  145. movt r0, #(_VTABLE_START_ADDRESS >> 16)
  146. endif
  147. movw r1, #(_APP_START_ADDRESS & 0xffff)
  148. if (_APP_START_ADDRESS > 0xffff)
  149. movt r1, #(_APP_START_ADDRESS >> 16)
  150. endif

  151. ;
  152. ; Calculate the end address of the vector table assuming that it has the
  153. ; maximum possible number of vectors. We don't know how many the app has
  154. ; populated so this is the safest approach though it may copy some non
  155. ; vector data if the app table is smaller than the maximum.
  156. ; 计算向量表的结束地址,假设向量表有最大数目. 我们不知道应用程序使用了多少
  157. ; 向量表,但这样是最安全的
  158. ;
  159. movw r2, #(70 * 4)
  160. adds r2, r2, r0
  161. VectorCopyLoop
  162. ldr r3, [r1], #4
  163. str r3, [r0], #4
  164. cmp r0, r2
  165. blt VectorCopyLoop
  166. endif

  167. ;
  168. ; Set the vector table address to the beginning of the application.
  169. ; 将向量表重定位到应用程序开始处
  170. ;
  171. movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
  172. if (_VTABLE_START_ADDRESS > 0xffff)
  173. movt r0, #(_VTABLE_START_ADDRESS >> 16)
  174. endif
  175. movw r1, #(NVIC_VTABLE & 0xffff) ;向量表偏移寄存器
  176. movt r1, #(NVIC_VTABLE >> 16)
  177. str r0, [r1]

  178. ;
  179. ; Load the stack pointer from the application's vector table.
  180. ; 从应用程序向量表装载用户堆栈.
  181. ;
  182. if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
  183. movw r0, #(_APP_START_ADDRESS & 0xffff)
  184. if (_APP_START_ADDRESS > 0xffff)
  185. movt r0, #(_APP_START_ADDRESS >> 16)
  186. endif
  187. endif
  188. ldr sp, [r0]

  189. ;
  190. ; Load the initial PC from the application's vector table and branch to
  191. ; the application's entry point.
  192. ;
  193. ldr r0, [r0, #4]
  194. bx r0

  195. ;******************************************************************************
  196. ;
  197. ; The update handler, which gets called when the application would like to
  198. ; start an update.
  199. ; 升级处理函数,当用户程序想要开始升级时,调用此函数
  200. ;
  201. ;******************************************************************************
  202. UpdateHandler_In_SRAM
  203. ;
  204. ; Load the stack pointer from the vector table.
  205. ; 从boot loader向量表中装载堆栈指针
  206. ;
  207. if :def:_FLASH_PATCH_COMPATIBLE
  208. movs r0, #0x1000
  209. else
  210. movs r0, #0x0000
  211. endif
  212. ldr sp, [r0]

  213. ;
  214. ; Call the user-supplied low level hardware initialization function
  215. ; if provided.
  216. ; 调用用户提供的底层硬件初始化函数
  217. ;
  218. if :def:_BL_HW_INIT_FN_HOOK
  219. bl $_BL_HW_INIT_FN_HOOK
  220. endif

  221. ;
  222. ; Call the user-supplied re-initialization function if provided.
  223. ; 调用用户提供的初始化函数
  224. ;
  225. if :def:_BL_REINIT_FN_HOOK
  226. import $_BL_REINIT_FN_HOOK
  227. bl $_BL_REINIT_FN_HOOK
  228. endif

  229. ;
  230. ; Branch to the update handler.
  231. ; 进入升级例程
  232. ;
  233. if :def:_ENET_ENABLE_UPDATE
  234. b UpdateBOOTP ;在bl_enet.c中
  235. elif :def:_CAN_ENABLE_UPDATE
  236. import AppUpdaterCAN
  237. b AppUpdaterCAN
  238. elif :def:_USB_ENABLE_UPDATE
  239. import AppUpdaterUSB
  240. b AppUpdaterUSB
  241. else
  242. b Updater
  243. endif

  244. ;******************************************************************************
  245. ;
  246. ; The NMI handler.
  247. ; NMI异常服务例程,处理主振荡器失败
  248. ;
  249. ;******************************************************************************
  250. if :def:_ENABLE_MOSCFAIL_HANDLER
  251. NmiSR_In_SRAM
  252. ;
  253. ; Restore the stack frame.
  254. ;
  255. mov lr, r12
  256. stm sp, {r4-r11}

  257. ;
  258. ; Save the link register.
  259. ;
  260. mov r9, lr

  261. ;
  262. ; Call the user-supplied low level hardware initialization function
  263. ; if provided.
  264. ;
  265. if :def:_BL_HW_INIT_FN_HOOK
  266. bl _BL_HW_INIT_FN_HOOK
  267. endif

  268. ;
  269. ; See if an update should be performed.
  270. ;
  271. bl CheckForceUpdate
  272. cbz r0, EnterApplication

  273. ;
  274. ; Clear the MOSCFAIL bit in RESC.
  275. ;
  276. movw r0, #(SYSCTL_RESC & 0xffff)
  277. movt r0, #(SYSCTL_RESC >> 16)
  278. ldr r1, [r0]
  279. bic r1, r1, #SYSCTL_RESC_MOSCFAIL
  280. str r1, [r0]

  281. ;
  282. ; Fix up the PC on the stack so that the boot pin check is bypassed
  283. ; (since it has already been performed).
  284. ;
  285. ldr r0, =EnterBootLoader
  286. bic r0, #0x00000001
  287. str r0, [sp, #0x18]

  288. ;
  289. ; Return from the NMI handler. This will then start execution of the
  290. ; boot loader.
  291. ;
  292. bx r9

  293. ;
  294. ; Restore the link register.
  295. ;
  296. EnterApplication
  297. mov lr, r9

  298. ;
  299. ; Copy the application's vector table to the target address if necessary.
  300. ; Note that incorrect boot loader configuration could cause this to
  301. ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
  302. ; of SRAM) is safe since this will use the same memory that the boot loader
  303. ; already uses for its vector table. Great care will have to be taken if
  304. ; other addresses are to be used.
  305. ;
  306. if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
  307. movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
  308. if (_VTABLE_START_ADDRESS > 0xffff)
  309. movt r0, #(_VTABLE_START_ADDRESS >> 16)
  310. endif
  311. movw r1, #(_APP_START_ADDRESS & 0xffff)
  312. if (_APP_START_ADDRESS > 0xffff)
  313. movt r1, #(_APP_START_ADDRESS >> 16)
  314. endif

  315. ;
  316. ; Calculate the end address of the vector table assuming that it has the
  317. ; maximum possible number of vectors. We don't know how many the app has
  318. ; populated so this is the safest approach though it may copy some non
  319. ; vector data if the app table is smaller than the maximum.
  320. ;
  321. movw r2, #(70 * 4)
  322. adds r2, r2, r0
  323. VectorCopyLoop2
  324. ldr r3, [r1], #4
  325. str r3, [r0], #4
  326. cmp r0, r2
  327. blt VectorCopyLoop2
  328. endif

  329. ;
  330. ; Set the application's vector table start address. Typically this is the
  331. ; application start address but in some cases an application may relocate
  332. ; this so we can't assume that these two addresses are equal.
  333. ;
  334. movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
  335. if (_VTABLE_START_ADDRESS > 0xffff)
  336. movt r0, #(_VTABLE_START_ADDRESS >> 16)
  337. endif
  338. movw r1, #(NVIC_VTABLE & 0xffff)
  339. movt r1, #(NVIC_VTABLE >> 16)
  340. str r0, [r1]

  341. ;
  342. ; Remove the NMI stack frame from the boot loader's stack.
  343. ;
  344. ldmia sp, {r4-r11}

  345. ;
  346. ; Get the application's stack pointer.
  347. ;
  348. if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
  349. movw r0, #(_APP_START_ADDRESS & 0xffff)
  350. if (_APP_START_ADDRESS > 0xffff)
  351. movt r0, #(_APP_START_ADDRESS >> 16)
  352. endif
  353. endif
  354. ldr sp, [r0, #0x00]

  355. ;
  356. ; Fix up the NMI stack frame's return address to be the reset handler of
  357. ; the application.
  358. ;
  359. ldr r10, [r0, #0x04]
  360. bic r10, #0x00000001

  361. ;
  362. ; Store the NMI stack frame onto the application's stack.
  363. ;
  364. stmdb sp!, {r4-r11}

  365. ;
  366. ; Branch to the application's NMI handler.
  367. ;
  368. ldr r0, [r0, #0x08]
  369. bx r0
  370. endif

  371. ;******************************************************************************
  372. ;
  373. ; The default interrupt handler.
  374. ;
  375. ;******************************************************************************
  376. IntDefaultHandler
  377. ;
  378. ; Loop forever since there is nothing that we can do about an unexpected
  379. ; interrupt.
  380. ;
  381. b .

  382. ;******************************************************************************
  383. ;
  384. ; Provides a small delay. The loop below takes 3 cycles/loop.
  385. ; 提供一个小的延时函数. 循环一次需要3个时钟周期.
  386. ;
  387. ;******************************************************************************
  388. export Delay
  389. Delay
  390. subs r0, #1
  391. bne Delay
  392. bx lr

  393. ;******************************************************************************
  394. ;
  395. ; This is the end of the file.
  396. ;
  397. ;******************************************************************************
  398. align 4
  399. end


 楼主| 发表于 2015-7-20 20:54 | 显示全部楼层
1. 汇编文件正文的第一句
  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标号处开始执行。



发表于 2015-7-20 22:00 来自手机 | 显示全部楼层
感谢分享,很不错的资料
发表于 2015-7-27 22:36 | 显示全部楼层
不明觉厉
发表于 2015-7-28 08:51 | 显示全部楼层
汇编能帮助理解硬件,C编程方便
发表于 2015-7-28 09:32 | 显示全部楼层
很有用的资料,收藏先
发表于 2015-7-28 09:49 | 显示全部楼层
上电后程序先到Flash地址0x00处装载堆栈地址,这跟以前接触过的处理器不同
发表于 2015-7-28 10:12 | 显示全部楼层
感谢分享
发表于 2015-7-29 00:05 | 显示全部楼层
用户程序存在于Flash地址0x1000处,bootloader存放于Flash地址0x00处
发表于 2015-7-29 10:38 | 显示全部楼层
如果调用CheckForceUpdate函数检测到有升级请求,则配置以太网,跳转到升级程序UpdateBOOTP处执行。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

265

帖子

0

粉丝
快速回复 返回顶部 返回列表