TI Cortex M3串口转以太网例程分析2-----bootloader
来源:互联网 发布:成都知美术馆案例分析 编辑:程序博客网 时间:2024/05/02 01:16
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的指针、数组甚至是变量存储,还非少不了汇编不可;再者,有些地方必须使用汇编,比如一些实时性要求高的模块(不常见),还有就是接下来要说的启动代码。先附源代码。
;******************************************************************************;; bl_startup_rvmdk.S - Startup code for RV-MDK.;; Copyright (c) 2007-2010 Texas Instruments Incorporated. All rights reserved.; Software License Agreement; ; Texas Instruments (TI) is supplying this software for use solely and; exclusively on TI's microcontroller products. The software is owned by; TI and/or its suppliers, and is protected under applicable copyright; laws. You may not combine this software with "viral" open-source; software in order to form a larger program.; ; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL; DAMAGES, FOR ANY REASON WHATSOEVER.; ; This is part of revision 6288 of the Stellaris Firmware Development Package.;;****************************************************************************** include bl_config.inc;******************************************************************************;; A couple of defines that would normally be obtained from the appropriate C; header file, but must be manually provided here since the Keil compiler does; not have a mechanism for passing assembly source through the C preprocessor.; 以下定义通常在C头文件中定义过,但仍要在这里定义,因为keil编译器没有从汇编器直接; 调用C预编译器的机制.;;******************************************************************************SYSCTL_RESC equ 0x400fe05c ;复位原因SYSCTL_RESC_MOSCFAIL equ 0x00010000NVIC_VTABLE equ 0xe000ed08 ;向量表偏移量寄存器;******************************************************************************;; Put the assembler into the correct configuration.;;****************************************************************************** thumb ;thumb指令 require8 preserve8;******************************************************************************;; The stack gets placed into the zero-init section.; 将堆放到零初始化区;;****************************************************************************** area ||.bss||, noinit, align=2 ;4字节对齐,2的2次幂;******************************************************************************;; Allocate storage for the stack.; 为堆分配空间,STACK_SIZE在bl_config.h中定义的宏,通过bl_config.inc加载armcc;;******************************************************************************g_pulStack space _STACK_SIZE * 4;******************************************************************************;; This portion of the file goes into the reset section.;;****************************************************************************** area RESET, code, readonly, align=3 ;8字节对齐?;******************************************************************************;; The minimal vector table for a Cortex-M3 processor.;;****************************************************************************** export __Vectors__Vectors dcd g_pulStack + (_STACK_SIZE * 4) ; Offset 00: Initial stack pointer 初始化堆栈指针 if :def:_FLASH_PATCH_COMPATIBLE dcd Reset_Handler + 0x1000 ; Offset 04: Reset handler 为某些Flash打了补丁的器件 dcd NmiSR + 0x1000 ; Offset 08: NMI handler dcd FaultISR + 0x1000 ; Offset 0C: Hard fault handler else dcd Reset_Handler ; Offset 04: Reset handler dcd NmiSR ; Offset 08: NMI handler dcd FaultISR ; Offset 0C: Hard fault handler endif dcd IntDefaultHandler ; Offset 10: MPU fault handler dcd IntDefaultHandler ; Offset 14: Bus fault handler dcd IntDefaultHandler ; Offset 18: Usage fault handler dcd 0 ; Offset 1C: Reserved dcd 0 ; Offset 20: Reserved dcd 0 ; Offset 24: Reserved dcd 0 ; Offset 28: Reserved if :def:_FLASH_PATCH_COMPATIBLE dcd UpdateHandler + 0x1000 ; Offset 2C: SVCall handler SVC异常 else dcd UpdateHandler ; Offset 2C: SVCall handler endif dcd IntDefaultHandler ; Offset 30: Debug monitor handler dcd 0 ; Offset 34: Reserved dcd IntDefaultHandler ; Offset 38: PendSV handler if :def:_ENET_ENABLE_UPDATE import SysTickIntHandler dcd SysTickIntHandler ; Offset 3C: SysTick handler else dcd IntDefaultHandler ; Offset 3C: SysTick handler endif if :def:_UART_ENABLE_UPDATE :land: :def:_UART_AUTOBAUD import GPIOIntHandler dcd GPIOIntHandler ; Offset 40: GPIO port A handler else dcd IntDefaultHandler ; Offset 40: GPIO port A handler endif if :def:_USB_ENABLE_UPDATE :lor: \ (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) :lor: \ :def:_FLASH_PATCH_COMPATIBLE dcd IntDefaultHandler ; Offset 44: GPIO Port B dcd IntDefaultHandler ; Offset 48: GPIO Port C dcd IntDefaultHandler ; Offset 4C: GPIO Port D dcd IntDefaultHandler ; Offset 50: GPIO Port E dcd IntDefaultHandler ; Offset 54: UART0 Rx and Tx dcd IntDefaultHandler ; Offset 58: UART1 Rx and Tx dcd IntDefaultHandler ; Offset 5C: SSI0 Rx and Tx dcd IntDefaultHandler ; Offset 60: I2C0 Master and Slave dcd IntDefaultHandler ; Offset 64: PWM Fault dcd IntDefaultHandler ; Offset 68: PWM Generator 0 dcd IntDefaultHandler ; Offset 6C: PWM Generator 1 dcd IntDefaultHandler ; Offset 70: PWM Generator 2 dcd IntDefaultHandler ; Offset 74: Quadrature Encoder 0 dcd IntDefaultHandler ; Offset 78: ADC Sequence 0 dcd IntDefaultHandler ; Offset 7C: ADC Sequence 1 dcd IntDefaultHandler ; Offset 80: ADC Sequence 2 dcd IntDefaultHandler ; Offset 84: ADC Sequence 3 dcd IntDefaultHandler ; Offset 88: Watchdog timer dcd IntDefaultHandler ; Offset 8C: Timer 0 subtimer A dcd IntDefaultHandler ; Offset 90: Timer 0 subtimer B dcd IntDefaultHandler ; Offset 94: Timer 1 subtimer A dcd IntDefaultHandler ; Offset 98: Timer 1 subtimer B dcd IntDefaultHandler ; Offset 9C: Timer 2 subtimer A dcd IntDefaultHandler ; Offset A0: Timer 2 subtimer B dcd IntDefaultHandler ; Offset A4: Analog Comparator 0 dcd IntDefaultHandler ; Offset A8: Analog Comparator 1 dcd IntDefaultHandler ; Offset AC: Analog Comparator 2 dcd IntDefaultHandler ; Offset B0: System Control if :def:_FLASH_PATCH_COMPATIBLE dcd 0x00000881 ; Offset B4: FLASH Control else dcd IntDefaultHandler ; Offset B4: FLASH Control endif endif if :def:_USB_ENABLE_UPDATE :lor: \ (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) dcd IntDefaultHandler ; Offset B8: GPIO Port F dcd IntDefaultHandler ; Offset BC: GPIO Port G dcd IntDefaultHandler ; Offset C0: GPIO Port H dcd IntDefaultHandler ; Offset C4: UART2 Rx and Tx dcd IntDefaultHandler ; Offset C8: SSI1 Rx and Tx dcd IntDefaultHandler ; Offset CC: Timer 3 subtimer A dcd IntDefaultHandler ; Offset D0: Timer 3 subtimer B dcd IntDefaultHandler ; Offset D4: I2C1 Master and Slave dcd IntDefaultHandler ; Offset D8: Quadrature Encoder 1 dcd IntDefaultHandler ; Offset DC: CAN0 dcd IntDefaultHandler ; Offset E0: CAN1 dcd IntDefaultHandler ; Offset E4: CAN2 dcd IntDefaultHandler ; Offset E8: Ethernet dcd IntDefaultHandler ; Offset EC: Hibernation module if :def: _USB_ENABLE_UPDATE import USB0DeviceIntHandler dcd USB0DeviceIntHandler ; Offset F0: USB 0 Controller else dcd IntDefaultHandler ; Offset F0: USB 0 Controller endif endif;******************************************************************************;; Initialize the processor by copying the boot loader from flash to SRAM, zero; filling the .bss section, and moving the vector table to the beginning of; SRAM. The return address is modified to point to the SRAM copy of the boot; loader instead of the flash copy, resulting in a branch to the copy now in; SRAM.; 初始化处理器,将boot loader从flash拷贝到SRAM,将.bss区用零填充并将向量表重映射到; SRAM的开始处.;;****************************************************************************** export ProcessorInitProcessorInit ; ; Copy the code image from flash to SRAM. ; if :def:_FLASH_PATCH_COMPATIBLE movs r0, #0x1000 else movs r0, #0x0000 endif movs r1, #0x0000 movt r1, #0x2000 ;将16位的立即数放到寄存器的高16位,低位不受影响 import ||Image$SRAM$ZI$Base|| ;为汇编器提供一个在当前汇编程序中未定义的符号 ldr r2, =||Image$SRAM$ZI$Base||;SRAM区中的ZI输出节执行地址copy_loop ldr r3, [r0], #4 str r3, [r1], #4 cmp r1, r2 blt copy_loop ; ; Zero fill the .bss section.将.bss区用零填充 ; movs r0, #0x0000 import ||Image$SRAM$ZI$Limit|| ;SRAM区中ZI 输出节末尾地址后面的字节地址 ldr r2, =||Image$SRAM$ZI$Limit||zero_loop str r0, [r1], #4 cmp r1, r2 blt zero_loop ; ; Set the vector table pointer to the beginning of SRAM.; 将向量表指针指向SRAM开始处 ; movw r0, #(NVIC_VTABLE & 0xffff);放入r0低16位,高位清零 movt r0, #(NVIC_VTABLE >> 16);NVIC_VTABLE=0xe000ed08(向量表偏移量寄存器) movs r1, #0x0000 movt r1, #0x2000 str r1, [r0];向量表重定位到0x2000 0000处 ; ; Return to the caller.返回 ; bx lr;******************************************************************************;; The reset handler, which gets called when the processor starts.;;****************************************************************************** export Reset_HandlerReset_Handler ; ; Initialize the processor. ; bl ProcessorInit ; ; Branch to the SRAM copy of the reset handler. ;
ldr pc, =Reset_Handler_In_SRAM ;进入SRAM执行程序
;******************************************************************************;; The NMI handler.;;******************************************************************************NmiSR if :def:_ENABLE_MOSCFAIL_HANDLER ; ; Grab the fault frame from the stack (the stack will be cleared by the ; processor initialization that follows). ; ldm sp, {r4-r11} mov r12, lr ; ; Initialize the processor. ; bl ProcessorInit ; ; Branch to the SRAM copy of the NMI handler. ; ldr pc, =NmiSR_In_SRAM else ; ; Loop forever since there is nothing that we can do about a NMI. ; b . endif;******************************************************************************;; The hard fault handler.;;******************************************************************************FaultISR ; ; Loop forever since there is nothing that we can do about a hard fault. ; b .;******************************************************************************;; The update handler, which gets called when the application would like to; start an update.; 升级服务函数,当应用程序想要开始升级时,调用这个函数.;;******************************************************************************UpdateHandler ; ; Initialize the processor.初始化处理器 ; bl ProcessorInit ;调用子程序 ; ; Branch to the SRAM copy of the update handler. ; ldr pc, =UpdateHandler_In_SRAM;******************************************************************************;; This portion of the file goes into the text section.;;****************************************************************************** align 4 area ||.text||, code, readonly, align=2Reset_Handler_In_SRAM ; ; Call the user-supplied low level hardware initialization function ; if provided.; 如果用户提供了底层硬件初始化函数,则调用这个函数 ; if :def:_BL_HW_INIT_FN_HOOK import $_BL_HW_INIT_FN_HOOK bl $_BL_HW_INIT_FN_HOOK endif ; ; See if an update should be performed.; 检查是否有升级请求 ; import CheckForceUpdate bl CheckForceUpdate cbz r0, CallApplication ;结果为零则转移(只能跳到下一行) ; ; Configure the microcontroller. ;EnterBootLoader if :def:_ENET_ENABLE_UPDATE import ConfigureEnet bl ConfigureEnet elif :def:_CAN_ENABLE_UPDATE import ConfigureCAN bl ConfigureCAN elif :def:_USB_ENABLE_UPDATE import ConfigureUSB bl ConfigureUSB else import ConfigureDevice bl ConfigureDevice endif ; ; Call the user-supplied initialization function if provided.; 如果用户提供了初始化函数,则调用. ; if :def:_BL_INIT_FN_HOOK import $_BL_INIT_FN_HOOK bl $_BL_INIT_FN_HOOK endif ; ; Branch to the update handler. ; 进入升级处理程序; if :def:_ENET_ENABLE_UPDATE import UpdateBOOTP b UpdateBOOTP elif :def:_CAN_ENABLE_UPDATE import UpdaterCAN b UpdaterCAN elif :def:_USB_ENABLE_UPDATE import UpdaterUSB b UpdaterUSB else import Updater b Updater endif ; ; This is a second symbol to allow starting the application from the boot ; loader the linker may not like the perceived jump. ; export StartApplicationStartApplication ; ; Call the application via the reset handler in its vector table. Load the ; address of the application vector table. ;CallApplication ; ; Copy the application's vector table to the target address if necessary. ; Note that incorrect boot loader configuration could cause this to ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start ; of SRAM) is safe since this will use the same memory that the boot loader ; already uses for its vector table. Great care will have to be taken if ; other addresses are to be used.; 如果必要的话,复制应用程序的向量表到目标地址.; 请注意,不正确的boot loader配置会破坏整个程序!设置VTABLE_START_ADDRESS为; 0x2000 0000(从SRAM启动)也是可以的,因为这将和boot loader使用同样的内存 ; if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) ;看应用程序的起始地址是否和应用程序的向量表存储地址相同 movw r0, #(_VTABLE_START_ADDRESS & 0xffff) if (_VTABLE_START_ADDRESS > 0xffff) movt r0, #(_VTABLE_START_ADDRESS >> 16) endif movw r1, #(_APP_START_ADDRESS & 0xffff) if (_APP_START_ADDRESS > 0xffff) movt r1, #(_APP_START_ADDRESS >> 16) endif ; ; Calculate the end address of the vector table assuming that it has the ; maximum possible number of vectors. We don't know how many the app has ; populated so this is the safest approach though it may copy some non ; vector data if the app table is smaller than the maximum.; 计算向量表的结束地址,假设向量表有最大数目. 我们不知道应用程序使用了多少; 向量表,但这样是最安全的 ; movw r2, #(70 * 4) adds r2, r2, r0VectorCopyLoop ldr r3, [r1], #4 str r3, [r0], #4 cmp r0, r2 blt VectorCopyLoop endif ; ; Set the vector table address to the beginning of the application.; 将向量表重定位到应用程序开始处 ; movw r0, #(_VTABLE_START_ADDRESS & 0xffff) if (_VTABLE_START_ADDRESS > 0xffff) movt r0, #(_VTABLE_START_ADDRESS >> 16) endif movw r1, #(NVIC_VTABLE & 0xffff) ;向量表偏移寄存器 movt r1, #(NVIC_VTABLE >> 16) str r0, [r1] ; ; Load the stack pointer from the application's vector table.; 从应用程序向量表装载用户堆栈. ; if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) movw r0, #(_APP_START_ADDRESS & 0xffff) if (_APP_START_ADDRESS > 0xffff) movt r0, #(_APP_START_ADDRESS >> 16) endif endif ldr sp, [r0] ; ; Load the initial PC from the application's vector table and branch to ; the application's entry point. ; ldr r0, [r0, #4] bx r0;******************************************************************************;; The update handler, which gets called when the application would like to; start an update.; 升级处理函数,当用户程序想要开始升级时,调用此函数;;******************************************************************************UpdateHandler_In_SRAM ; ; Load the stack pointer from the vector table.; 从boot loader向量表中装载堆栈指针 ; if :def:_FLASH_PATCH_COMPATIBLE movs r0, #0x1000 else movs r0, #0x0000 endif ldr sp, [r0] ; ; Call the user-supplied low level hardware initialization function ; if provided.; 调用用户提供的底层硬件初始化函数 ; if :def:_BL_HW_INIT_FN_HOOK bl $_BL_HW_INIT_FN_HOOK endif ; ; Call the user-supplied re-initialization function if provided.; 调用用户提供的初始化函数 ; if :def:_BL_REINIT_FN_HOOK import $_BL_REINIT_FN_HOOK bl $_BL_REINIT_FN_HOOK endif ; ; Branch to the update handler.; 进入升级例程 ; if :def:_ENET_ENABLE_UPDATE b UpdateBOOTP ;在bl_enet.c中 elif :def:_CAN_ENABLE_UPDATE import AppUpdaterCAN b AppUpdaterCAN elif :def:_USB_ENABLE_UPDATE import AppUpdaterUSB b AppUpdaterUSB else b Updater endif;******************************************************************************;; The NMI handler.; NMI异常服务例程,处理主振荡器失败;;****************************************************************************** if :def:_ENABLE_MOSCFAIL_HANDLERNmiSR_In_SRAM ; ; Restore the stack frame. ; mov lr, r12 stm sp, {r4-r11} ; ; Save the link register. ; mov r9, lr ; ; Call the user-supplied low level hardware initialization function ; if provided. ; if :def:_BL_HW_INIT_FN_HOOK bl _BL_HW_INIT_FN_HOOK endif ; ; See if an update should be performed. ; bl CheckForceUpdate cbz r0, EnterApplication ; ; Clear the MOSCFAIL bit in RESC. ; movw r0, #(SYSCTL_RESC & 0xffff) movt r0, #(SYSCTL_RESC >> 16) ldr r1, [r0] bic r1, r1, #SYSCTL_RESC_MOSCFAIL str r1, [r0] ; ; Fix up the PC on the stack so that the boot pin check is bypassed ; (since it has already been performed). ; ldr r0, =EnterBootLoader bic r0, #0x00000001 str r0, [sp, #0x18] ; ; Return from the NMI handler. This will then start execution of the ; boot loader. ; bx r9 ; ; Restore the link register. ;EnterApplication mov lr, r9 ; ; Copy the application's vector table to the target address if necessary. ; Note that incorrect boot loader configuration could cause this to ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start ; of SRAM) is safe since this will use the same memory that the boot loader ; already uses for its vector table. Great care will have to be taken if ; other addresses are to be used. ; if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) movw r0, #(_VTABLE_START_ADDRESS & 0xffff) if (_VTABLE_START_ADDRESS > 0xffff) movt r0, #(_VTABLE_START_ADDRESS >> 16) endif movw r1, #(_APP_START_ADDRESS & 0xffff) if (_APP_START_ADDRESS > 0xffff) movt r1, #(_APP_START_ADDRESS >> 16) endif ; ; Calculate the end address of the vector table assuming that it has the ; maximum possible number of vectors. We don't know how many the app has ; populated so this is the safest approach though it may copy some non ; vector data if the app table is smaller than the maximum. ; movw r2, #(70 * 4) adds r2, r2, r0VectorCopyLoop2 ldr r3, [r1], #4 str r3, [r0], #4 cmp r0, r2 blt VectorCopyLoop2 endif ; ; Set the application's vector table start address. Typically this is the ; application start address but in some cases an application may relocate ; this so we can't assume that these two addresses are equal. ; movw r0, #(_VTABLE_START_ADDRESS & 0xffff) if (_VTABLE_START_ADDRESS > 0xffff) movt r0, #(_VTABLE_START_ADDRESS >> 16) endif movw r1, #(NVIC_VTABLE & 0xffff) movt r1, #(NVIC_VTABLE >> 16) str r0, [r1] ; ; Remove the NMI stack frame from the boot loader's stack. ; ldmia sp, {r4-r11} ; ; Get the application's stack pointer. ; if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS) movw r0, #(_APP_START_ADDRESS & 0xffff) if (_APP_START_ADDRESS > 0xffff) movt r0, #(_APP_START_ADDRESS >> 16) endif endif ldr sp, [r0, #0x00] ; ; Fix up the NMI stack frame's return address to be the reset handler of ; the application. ; ldr r10, [r0, #0x04] bic r10, #0x00000001 ; ; Store the NMI stack frame onto the application's stack. ; stmdb sp!, {r4-r11} ; ; Branch to the application's NMI handler. ; ldr r0, [r0, #0x08] bx r0 endif;******************************************************************************;; The default interrupt handler.;;******************************************************************************IntDefaultHandler ; ; Loop forever since there is nothing that we can do about an unexpected ; interrupt. ; b .;******************************************************************************;; Provides a small delay. The loop below takes 3 cycles/loop.; 提供一个小的延时函数. 循环一次需要3个时钟周期.;;****************************************************************************** export DelayDelay subs r0, #1 bne Delay bx lr;******************************************************************************;; This is the end of the file.;;****************************************************************************** align 4 end
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标号处开始执行。
- TI Cortex M3串口转以太网例程分析2-----bootloader
- TI Cortex M3串口转以太网例程分析2-----bootloader
- TI Cortex M3串口转以太网例程分析1-----概述
- TI Cortex M3串口转以太网例程分析1-----概述
- TI Cortex M3串口转以太网例程分析3-----lwIP1.3.2移植
- Cortex-M3启动分析
- 走近Cortex-M3(2)
- Cortex-M3-----(2)
- Cortex-M3启动代码分析
- 基于Cortex-M3的嵌入式以太网门禁系统设计
- cortex-m3/m0汇编启动代码分析
- ARM cortex-M3 异常处理分析
- Cortex-m3启动代码分析笔记
- ARM Cortex M3 启动文件分析
- 串口转以太网技术的概念分析
- Cortex-M3
- Cortex-M3
- TI am335x 内核分析----以太网移植
- 继承-----具体表继承-----每个子类一张表
- ULN2003的工作原理。
- JAVA读取WORD,EXCEL,PDF,TXT,RTF,HTML文件文本内容的方法
- 网络广告名词解释
- SQL Server 如何生成更改脚本
- TI Cortex M3串口转以太网例程分析2-----bootloader
- Js 获取HTML DOM节点元素的几种方法
- sharepiont2010 站点权限更改后混乱以致打开网页出现500错误的解决方法。
- MySQL分区
- Android-ExpandableListActivity
- Oracle Flashback 技术 总结
- 工作流系统设计-面临新的问题,需要新的思路
- 在GridView控件中的RowCommand事件里获得行信息的方法
- 在Linux系统下如何调整文件打开方式