guizw625的个人空间 https://blog.eetop.cn/1189354 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

关于ATMEL的SAM3S中程序启动分析

已有 2237 次阅读| 2013-10-20 20:39 |个人分类:嵌入式培训

关于ATMEL的SAM3S中程序启动分析

作者:卢老师,华清远见嵌入式学院讲师。


在分析启动代码之前,需要了解C和汇编代码通过那些步骤转化为可执行代码,从而最终在硬件上运行。通常的流程分4步。

1 用编译器把源代码编译成ELF(executable and linking format )目标文件。
        2 用链接器把目标文件链接成ELF格式的可执行映像文件。
        3 用FROMELF工具把可执行的映像文件转化为二进制映像文件。
        4 烧写二进制映像文件到目标板。

以上步骤是有IAR软件完成。

Flash.icf文件

在链接步骤中IAR软件会调用配置文件Flash.icf,这个文件在启动的时候会进入对应的Flash段进行操作,与之对应的有ram.icf,ram.icf主要应用模式仿真,并不对实际外设操作。Flash,icf描述了SAM3S4B的RAM和FLASH的段分配,以及映射位置,在各存储段的操作方式。

/*###ICF### Section handled by ICF editor, don't touch! ****/
        /*-Editor annotation file-*/
        /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
        /*-Vector table start*/
        define symbol __ICFEDIT_vector_start__ = 0x00400000;
        /*-Memory Regions-*/
        define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
        define symbol __ICFEDIT_region_RAM_end__ = 0x2000BFFF;//48kbytes ram
        define symbol __ICFEDIT_region_ROM_start__ = 0x00400000;
        define symbol __ICFEDIT_region_ROM_end__ = 0x0043FFFF;//256Kbytes Flash
        /*-Sizes-*/
        if (!isdefinedsymbol(__ICFEDIT_size_cstack__)) {

                define symbol __ICFEDIT_size_cstack__ = 0x2000;

        }
        if (!isdefinedsymbol(__ICFEDIT_size_heap__)) {

                define symbol __ICFEDIT_size_heap__ = 0x200;

        }
        /**** End of ICF editor section. ###ICF###*/

        define memory mem with size = 4G; //统一寻址最大容量
        define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
        define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];

        define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };//对齐方式和容量
        define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };

        initialize by copy { readwrite };
        do not initialize { section .noinit };

        place at address mem:__ICFEDIT_vector_start__ { readonly section .intvec };//放在ROM中的内容为只读内容,即const型等

        place in ROM_region { readonly };

        place in RAM_region { readwrite, block CSTACK, block HEAP };//放在RAM中的内容为可读可写的内容和CSTACK等段

startup_sam3.c功能描述

/* Exception Table */
        #pragma language=extended
        #pragma segment="CSTACK"

        /* The name "__vector_table" has special meaning for C-SPY: */
        /* it is where the SP start value is found, and the NVIC vector */
        /* table register (VTOR) is initialized to this address if != 0 */

        #pragma section = ".intvec"
        #pragma location = ".intvec"
        constintvec_elem __vector_table[] = {
                {.__ptr = __sfe("CSTACK")},    /*__sfe是IAR的“段操作符”segment operator。表示取某个段的后一个字节的地址*/

                Reset_Handler, 
                NMI_Handler,
                HardFault_Handler,
                MemManage_Handler,
                BusFault_Handler,
                UsageFault_Handler,
                (0UL),        /* Reserved */
                (0UL),        /* Reserved */
                (0UL),        /* Reserved */
                (0UL),        /* Reserved */
                SVC_Handler,
                DebugMon_Handler,
                (0UL),        /* Reserved */
                //PendSV_Handler,
                //SysTick_Handler,
                        //IMPORT OS_CPU_PendSVHandler
        OS_CPU_PendSVHandler,

                        //IMPORT OS_CPU_SysTickHandler
        OS_CPU_SysTickHandler,
                /* Configurable interrupts */
                SUPC_Handler,    /* 0 Supply Controller */
                RSTC_Handler,    /* 1 Reset Controller */
                RTC_Handler,    /* 2 Real Time Clock */
                RTT_Handler,    /* 3 Real Time Timer */
                WDT_Handler,    /* 4 Watchdog Timer */
                PMC_Handler,    /* 5 PMC */
                EFC0_Handler,    /* 6 EFC 0 */
                EFC1_Handler,    /* 7 EFC 1 */
                UART_Handler,    /* 8 UART */
        #ifdef _SAM3XA_SMC_INSTANCE_
                SMC_Handler,    /* 9 SMC */
        #else
                (0UL),        /* 9 Reserved */
        #endif     /* _SAM3XA_SMC_INSTANCE_ */
        #ifdef _SAM3XA_SDRAMC_INSTANCE_
                SDRAMC_Handler,    /* 10 SDRAMC */
        #else
                (0UL),        /* 10 Reserved */
        #endif     /* _SAM3XA_SDRAMC_INSTANCE_ */
                PIOA_Handler,    /* 11 Parallel IO Controller A */
                PIOB_Handler,    /* 12 Parallel IO Controller B */
        #ifdef _SAM3XA_PIOC_INSTANCE_
                PIOC_Handler,    /* 13 Parallel IO Controller C */
        #else
                (0UL),        /* 13 Reserved */
        #endif    /* _SAM3XA_PIOC_INSTANCE_ */
        #ifdef _SAM3XA_PIOD_INSTANCE_
                PIOD_Handler,    /* 14 Parallel IO Controller D */
        #else
                (0UL),        /* 14 Reserved */
        #endif     /* _SAM3XA_PIOD_INSTANCE_ */
        #ifdef _SAM3XA_PIOE_INSTANCE_
                PIOE_Handler,    /* 15 Parallel IO Controller E */
        #else
                (0UL),        /* 15 Reserved */
        #endif     /* _SAM3XA_PIOE_INSTANCE_ */
        #ifdef _SAM3XA_PIOF_INSTANCE_
                PIOF_Handler,    /* 16 Parallel IO Controller F */
        #else
                (0UL),        /* 16 Reserved */
        #endif     /* _SAM3XA_PIOF_INSTANCE_ */
                USART0_Handler,    /* 17 USART 0 */
                USART1_Handler,    /* 18 USART 1 */
                USART2_Handler,    /* 19 USART 2 */
        #ifdef _SAM3XA_USART3_INSTANCE_
                USART3_Handler,    /* 20 USART 3 */
        #else
                (0UL),        /* 20 Reserved */
        #endif     /* _SAM3XA_USART3_INSTANCE_ */
                HSMCI_Handler,    /* 21 MCI */
                TWI0_Handler,    /* 22 TWI 0 */
                TWI1_Handler,    /* 23 TWI 1 */
                SPI0_Handler,    /* 24 SPI 0 */
        #ifdef _SAM3XA_SPI1_INSTANCE_
                SPI1_Handler,    /* 25 SPI 1 */
        #else
                (0UL),        /* 25 Reserved */
        #endif     /* _SAM3XA_SPI1_INSTANCE_ */
                SSC_Handler,    /* 26 SSC */
                TC0_Handler,    /* 27 Timer Counter 0 */
                TC1_Handler,     /* 28 Timer Counter 1 */
                TC2_Handler,    /* 29 Timer Counter 2 */
                TC3_Handler,    /* 30 Timer Counter 3 */
                TC4_Handler,    /* 31 Timer Counter 4 */
                TC5_Handler,    /* 32 Timer Counter 5 */
        #ifdef _SAM3XA_TC2_INSTANCE_
                TC6_Handler,    /* 33 Timer Counter 6 */
                TC7_Handler,    /* 34 Timer Counter 7 */
                TC8_Handler,    /* 35 Timer Counter 8 */
        #else
                (0UL),        /* 33 Reserved */
                (0UL),        /* 34 Reserved */
                (0UL),        /* 35 Reserved */
        #endif     /* _SAM3XA_TC2_INSTANCE_ */
                PWM_Handler,    /* 36 PWM */
                ADC_Handler,    /* 37 ADC controller */
                DACC_Handler,    /* 38 DAC controller */
                DMAC_Handler,    /* 39 DMA Controller */
                UOTGHS_Handler,    /* 40 USB OTG High Speed */
                TRNG_Handler,    /* 41 True Random Number Generator */
        #ifdef _SAM3XA_EMAC_INSTANCE_
                EMAC_Handler,    /* 42 Ethernet MAC */
        #else
                (0UL),        /* 42 Reserved */
        #endif     /* _SAM3XA_EMAC_INSTANCE_ */
                CAN0_Handler,    /* 43 CAN Controller 0 */
                CAN1_Handler    /* 44 CAN Controller 1 */
        };

上面一段函数是嵌套向量中断控制器NVIC向量表所对应的中断函数的名字,而中断函数的体,需要程序员自行写出。在Flash.icf中place at address mem:__ICFEDIT_vector_start__ { readonly section .intvec };将中断向量表,放入对应的地址。

启动代码与应用程序接口

在完成映射后,程序首先执行的是Reset_Handler(),通常我们所说的上电进入复位状态,启动函数。

voidReset_Handler(void)
        {
                __iar_program_start();
        }

__iar_program_start();函数是用汇编实现的,在IAR环境中无法直接显示,因为在编译时,IAR软件直接将__iar_program_start;嵌入代码中,不需要程序员编写。

__iar_program_start:
        #if AT91_REMAP
                ; The memory controller is initialized immediately before the remap
        ldr r10, =EBI_init_table ; EBI register initialization table
                ; If pc > 0x100000
        movs r0, pc, LSR #20
                ; Mask the 12 highest bits of the address
        moveq r10, r10, LSL #12
        moveq r10, r10, LSR #12

                ; Load the address where to jump
        ldr r12, =after_remap ; get the real jump address ( after remap )

                ; Copy chip select register image to memory controller and command remap
        ldmia r10!, {r0-r9,r11}   ; load the complete image and the EBI base
        stmia r11!, {r0-r9}      ; store the complete image with the remap command

                ; jump to ROM at its new address
                ; this instruction was loaded into the pipeline before the remap was done
        mov    pc, r12      ; jump and break the pipeline

                ; Put constant table here.
        LTORG

                ; EBI initialization table
                ; 32,768 MHz master clock assumed for timing
        EBI_init_table:
        dc32    0x0100252d ; Flash at 0x01000000, 16MB, 2 hold, 16 bits, 4 WS
        dc32    0x02002121 ; RAM  at 0x02000000, 1MB, 0 hold, 16 bits, 1 WS
        dc32    0x20000000 ; unused
        dc32    0x30000000 ; unused
        dc32    0x40000000 ; unused
        dc32    0x50000000 ; unused
        dc32    0x60000000 ; unused
        dc32    0x70000000 ; unused
        dc32    0x00000001 ; REMAP command
        dc32    0x00000006 ; standard read
        dc32    __EBI_CSR0 ; EBI Base address

        after_remap:
        #endif
                ; Execute C startup code.
        b ?cstartup
        ;---------------------------------------------------------------
        ; ?CSTARTUP
        ;---------------------------------------------------------------

        SECTION FIQ_STACK:DATA:NOROOT(3)
        SECTION IRQ_STACK:DATA:NOROOT(3)
        SECTION SVC_STACK:DATA:NOROOT(3)
        SECTION ABT_STACK:DATA:NOROOT(3)
        SECTION UND_STACK:DATA:NOROOT(3)
        SECTION CSTACK:DATA:NOROOT(3)
        SECTION text:CODE:NOROOT(2)
        EXTERN ?main
        ARM
        ?cstartup
        ; Execution starts here.
        ; After a reset, the mode is ARM, Supervisor, interrupts disabled.

        ; Add initialization nedded before setup of stackpointers here

        ; Initialize the stack pointers.
        ; The pattern below can be used for any of the exception stacks:
        ; FIQ, IRQ, SVC, ABT, UND, SYS.
        ; The USR mode uses the same stack as SYS.
        ; The stack segments must be defined in the linker command file,
        ; and be declared above.

        mrs   r0,cpsr               ; Original PSR value
        bic   r0,r0,#MODE_BITS           ; Clear the mode bits
        orr   r0,r0,#SVC_MODE           ; Set SVC mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(SVC_STACK)          ; End of SVC_STACK

        bic   r0,r0,#MODE_BITS          ; Clear the mode bits
        orr   r0,r0,#UND_MODE           ; Set UND mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(UND_STACK)          ; End of UND_STACK

        bic   r0,r0,#MODE_BITS          ; Clear the mode bits
        orr   r0,r0,#ABT_MODE           ; Set ABT mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(ABT_STACK)            ; End of ABT_STACK

        bic   r0,r0,#MODE_BITS          ; Clear the mode bits
        orr   r0,r0,#FIQ_MODE           ; Set FIQ mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(FIQ_STACK)          ; End of FIQ_STACK

        bic   r0,r0,#MODE_BITS          ; Clear the mode bits
        orr   r0,r0,#IRQ_MODE           ; Set IRQ mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(IRQ_STACK)          ; End of IRQ_STACK

        bic   r0,r0,#MODE_BITS          ; Clear the mode bits
        orr   r0,r0,#SYS_MODE           ; Set System mode bits
        msr   cpsr_c,r0              ; Change the mode
        ldrsp,=SFE(CSTACK)            ; End of CSTACK

        #ifdef __ARMVFP__
        ; Enable the VFP coprocessor.
        mov   r0, #0x40000000         ; Set EN bit in VFP
        fmxrfpexc, r0            ; FPEXC, clear others.

        ; Disable underflow exceptions by setting flush to zero mode.
        ; For full IEEE 754 underflow compliance this code should be removed
        ; and the appropriate exception handler installed.
        mov   r0, #0x01000000        ; Set FZ bit in VFP
        fmxrfpscr, r0           ; FPSCR, clear others.
        #endif

        ; Add more initialization here
        ; Continue to ?main for more IAR specific system startup

        ldr   r0,=?main//进入main主程序
        bx   r0//带状态切换指令的跳转

        END

以上部分给出了程序在目标板上电后,进入main()函数前的具体工作。

嵌入式培训:http://www.farsight.com.cn


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 0

    好友
  • 0

    获赞
  • 0

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-1 18:36 , Processed in 0.026852 second(s), 18 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部