历史上的今天
返回首页

历史上的今天

今天是:2025年02月13日(星期四)

正在发生

2019年02月13日 | MDK S3C2440启动代码简单分析

2019-02-13 来源:eefocus

ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。


一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口,设备初始化,变量初始化等。


 ;/*****************************************************************************/


;/*S3C2440A.S: Startup file for Samsung S3C440A            */


;/*****************************************************************************/


;/*<<< Use Configuration Wizard in Context Menu >>>         */


;/*****************************************************************************/


;/*This file is part of the uVision/ARM development tools.       */


;/*Copyright (c) 2005-2006 Keil Software. All rights reserved.    */


;/*This software may only be used under the terms of a valid, current, */


;/*end user licence from KEIL for a compatible version of KEIL software */


;/*development tools. Nothing else gives you the right to use this software. */


;/*****************************************************************************/;


下面这些参数是与CPSR状态寄存器有关


;这里各个模式的参数是由寄存器CPSR的模式位设置M[4:0]得来的,


;比如这里的用户模式,CPSR的M[4:0]设置为10000就是0x10。


;Mode_USR      -- 用户模式,正常程序执行模式,用于应用程序


;Mode_FIQ        --快速中断模式,一般用于高速数据传输和通道处理。


;Mode_IRQ              --外部中断模式,一般用于通用的中断处理。


;Mode_SVC      -- 管理模式,供操作系统使用的一种保护模式。


;Mode_ABT       -- 数据访问中止模式,用于虚拟存储用存储保护


;Mode_UND      -- 未定义指令中止模式,当未定义指令执行时进入此模式。


;Mode_SYS       -- 系统模式,用于特权级的操作系统任务。


;I_Bit                  --如果I位被置1,则外部中断被禁止(IRQ isdisabled)


;F_Bit                 -- 如果F位被置1,则快速中断被禁止(FIQ isdisabled)


;;----------------------------------------------------------------------


Mode_USR         EQU    0x10


Mode_FIQ           EQU     0x11


Mode_IRQ          EQU     0x12


Mode_SVC         EQU     0x13


Mode_ABT          EQU     0x17


Mode_UND         EQU     0x1B


Mode_SYS         EQU     0x1F


 


I_Bit       EQU    0x80            ; when Ibit is set, IRQ is disabled


F_Bit      EQU    0x40            ; when Fbit is set, FIQ is disabled


 


;----------------------------- Stack Configuration-----------------------------------


;下面这些主要是栈配置,系统的栈空间设定


;


;UND_Stack_Size           -- 未定义模式的栈大小


;SVC_Stack_Size             -- 管理模式的栈大小


;ABT_Stack_Size            -- 数据访问终止模式的栈大小


;FIQ_Stack_Size             -- 快速中断模式的栈大小


;IRQ_Stack_Size            -- 中断模式的栈大小


;USR_Stack_Size           -- 用户模式的栈大小


;ISR_Stack_Size             -- 总堆栈的大小,也就是所有模式下堆栈相加


-----------------------------------------------------------------------


UND_Stack_Size      EQU     0x00000000


SVC_Stack_Size              EQU    0x00000008


ABT_Stack_Size       EQU     0x00000000


FIQ_Stack_Size        EQU    0x00000000


IRQ_Stack_Size        EQU    0x00000080


USR_Stack_Size       EQU     0x00000400


ISR_Stack_Size        EQU    (UND_Stack_Size + SVC_Stack_Size +ABT_Stack_Size + \


                                               FIQ_Stack_Size +IRQ_Stack_Size)


;-----------------------------------------------------------------------


;AREA --     是一个伪指令,用于段定义。ARM的汇编程序由段组成,段是相对独立的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性。


;STACK      -- AREA指令的一个参数,定义段名称


;NOINIT       -- AREA指令的一个参数,指定本数据段仅仅保留了内在单元,而将句初始值写入内存单元,也即将内存单元值初始化为0


;READWRITE-- 指定本段为可读可写,数据段默认为READWRITE。


;                         READWRITE(读写)、READONLY(只读)


;ALIGN --    是一个伪指令,指定对齐方式。ALIGN n 指令的对齐值有两种方案,即n 或 2^n,这里采用第二种方案即指定后面的指令8字节对齐。


;ATPCS规定数据栈必须为FD类型,并且对数据栈的操作时8字节对齐的


;下面这句话意思是:开辟一个堆栈段,段名字为STACK,定义为可读可写,将内存单元初始化为0,


;-----------------------------------------------------------------------


                AREA    STACK, NOINIT, READWRITE, ALIGN=3


;-----------------------------------------------------------------------


;SPACE-- 伪指令,用于分配一块内存单元,并用0初始化,与%同义


;其指令格式为:


;   {lable}  SPACE  expr


;lable-- 内存起始地址标号  expr -- 所要分配的内存字节数  


;-----------------------------------------------------------------------


Stack_Mem      SPACE   USR_Stack_Size    ;堆栈内存起始地址标号


__initial_sp   SPACE   ISR_Stack_Size    ;汇编代码的地址标号


 


Stack_Top   ;堆栈段内容结束,在这里放个标号,用来获得堆栈顶部地址


 


Heap_Size      EQU     0x00000000    ;定义堆大小设置


               ;开辟一个名字为HEAP可读可写,不初始化内存单的内存单元。


               AREA    HEAP, NOINIT, READWRITE, ALIGN=3


__heap_base    ;堆的基址


Heap_Mem       SPACE   Heap_Size    ;堆内存起始地址标号


__heap_limit   ;堆结束


 


;----------------------------内存初始化定义-----------------------------


;在一些应用系统中除了扩展Flash,RAM挂接在外部存储器接口上外,可能还有其它


;的外设挂接在外部存储器接口上,不同外设的操作时序什么的都是不一样的,所以


;在使用这些外设之前必须初始化连接这些外设存储器接口。这里因为没扩展,所以


;只定义一个片上内存基地址。


;-----------------------------------------------------------------------


 


IRAM_BASE      EQU     0x40000000    ;片上SRAM的基地址,即内存基地址


 


;-------------------------看门狗初始化定义------------------------------


;看门狗在防止程序跑飞,进入无限死循环时起着重要作用。有些应用可能用不上


;看门狗功能,也可能有些应用会用到外部看门狗。在这个时候内部看门狗必须禁


;止,所以有时候会在初始化时将内部看门狗禁止,当以后应用用到时再开启它。


;看门狗定时器包括三个寄存器:


;WTCON-- 看门狗控制寄存器,设定看门狗定时器模式


;WTDAT-- 看门狗数据寄存器,用于设定超时宽度


;WTCNT-- 看门狗计数寄存器,里面存放的是看门狗定时器当前值


;


;WT_BASE  -- 看门狗定时器基地址


;WTCON_OFS-- 看门狗控制寄存器偏移地址,相对于基址


;WTDAT_OFS-- 看门狗数据寄存器偏移地址,相对于基址


;WTCNT_OFS-- 看门狗计数寄存器偏移地址,相对于基址


;WT_SETUP -- 看门狗设置


;WTCON_Val-- 看门狗控制寄存器设置,关闭看门狗


;WTDAT_Val-- 看门狗数据寄存器设置,初始值即为0x8000


;-----------------------------------------------------------------------


 


WT_BASE        EQU     0x53000000      ; WatchdogTimer Base Address


WTCON_OFS     EQU    0x00      ; Watchdog Timer Control RegisterOffset


WTDAT_OFS      EQU    0x04       ; Watchdog Timer DataRegister    Offset


WTCNT_OFS      EQU    0x08       ; Watchdog Timer CountRegister   Offset


 


WT_SETUP       EQU     0


WTCON_Val      EQU     0x00000000


WTDAT_Val      EQU     0x00008000


 


 


;----------------------------时钟与电源管理定义-------------------------


;S3C2440A中的时钟控制逻辑可以产生必须的时钟信号,包括CPU的FCLK,AHB总线的


;HCLK以及APB总线外设的PCLK3C2440A内部有两个锁相环(PLL):一个提供FCLK,


;HCLK及PCLK,另一个专用于USB模块(48MHz).


;


;CLOCK_BASE  -- 时钟基地址


;LOCKTIME_OFS-- 锁相环锁定时间计数寄存器偏移地址,相对于基址


;MPLLCON_OFS -- MPLL配置寄存器偏移地址,相对于基址,主时钟源PLL


;UPLLCON_OFS -- UPLL配置寄存器偏移地址,相对于基址,USB时钟源PLL


;CLKCON_OFS  -- 时钟控制寄存器偏移地址,相对于基址


;CLKSLOW_OFS -- 时钟减慢控制寄存器偏移地址,相对于基址


;CLKDIVN_OFS -- 时钟分频器控制寄存器偏移地址,相对于基址


;CAMDIVN_OFS -- 摄像头时钟分频器控制寄存器偏移地址,相对于基址,UPLL提供


;


;CLOCK_SETUP -- 时钟设置


;LOCKTIME_Val-- PLL锁定时间计数器值


;MPLLCON_Val -- MPLL配置寄存器值


;UPLLCON_Val -- UPLL配置寄存器值


;CLKCON_Val  -- 时钟配置寄存器值


;CLKSLOW_Val -- 时钟减慢控制寄存器值


;CLKDIVN_Val -- 时钟分频控制寄存器值


;CAMDIVN_Val -- 摄像头分频控制寄存器值


;-----------------------------------------------------------------------


CLOCK_BASE     EQU     0x4C000000      ; ClockBase Address


LOCKTIME_OFS   EQU     0x00    ; PLL Lock Time CountRegister   Offset


MPLLCON_OFS    EQU     0x04    ; MPLL ConfigurationRegister    Offset


UPLLCON_OFS    EQU     0x08     ; UPLL ConfigurationRegister    Offset


CLKCON_OFS     EQU     0x0C      ; ClockGenerator Control Reg    Offset


CLKSLOW_OFS    EQU     0x10     ; Clock SlowControl Register    Offset


CLKDIVN_OFS    EQU    0x14        ; Clock Divider ControlRegister Offset


CAMDIVN_OFS    EQU     0x18       ;Camera Clock Divider Register  Offset


 


CLOCK_SETUP    EQU     0


LOCKTIME_Val   EQU     0x0FFF0FFF


MPLLCON_Val    EQU     0x00043011


UPLLCON_Val    EQU     0x00038021


CLKCON_Val     EQU     0x001FFFF0


CLKSLOW_Val    EQU     0x00000004


CLKDIVN_Val    EQU     0x0000000F


CAMDIVN_Val    EQU     0x00000000


 


;--------------------存储控制器设置定义---------------------------------


;下面这些都是一些关于存储控制器的地址宏定义


;


;MC_BASE     -- 存储控制器基地址


;BWSCON_OFS  -- 总线宽度和等待控制寄存器偏移地址


;BANKCON0_OFS-- BANK1控制寄存器偏移地址


;  .


;  .


;BANKCON7_OFS-- BANK7控制寄存器偏移地址


;REFRESH_OFS -- DRAM/SDRAM刷新控制寄存器偏移地址


;BANKSIZE_OFS-- 可调的bank大小寄存器偏移地址


;MRSRB6_OFS  -- bank6模式控制寄存器偏移地址


;MRSRB7_OFS  -- bank7模式控制寄存器偏移地址


;


;MC_SETUP    -- 存储器控制寄存器设置


;BWSCON_Val  -- 写入总线宽度和等待控制寄存值


;BANKCON0_Val-- 写入Blank0的值


;  .


;  .


;BANKCON7_Val-- 写入BANK7 的值


;REFRESH_Val -- 写入DRAM/SDRAM刷新控制寄存的值


;BANKSIZE_Val-- 写入可调的bank大小寄存的值


;MRSRB6_Val  -- 写入bank6模式控制寄存器的值


;MRSRB7_Val  -- 写入bank7模式控制寄存器的值


;-----------------------------------------------------------------------


MC_BASE        EQU     0x48000000      ; MemoryController Base Address


BWSCON_OFS     EQU     0x00     ; Bus Width and WaitStatus Ctrl Offset


BANKCON0_OFS   EQU     0x04    ; Bank 0 ControlRegister        Offset


BANKCON1_OFS   EQU     0x08     ; Bank 1 ControlRegister        Offset


BANKCON2_OFS   EQU     0x0C     ; Bank 2 ControlRegister        Offset


BANKCON3_OFS   EQU     0x10      ; Bank 3Control Register        Offset


BANKCON4_OFS   EQU     0x14      ; Bank 4Control Register        Offset


BANKCON5_OFS   EQU     0x18       ;Bank 5 Control Register        Offset


BANKCON6_OFS   EQU     0x1C       ; Bank 6Control Register        Offset


BANKCON7_OFS   EQU     0x20        ;Bank 7 Control Register        Offset


REFRESH_OFS    EQU    0x24          ; SDRAM RefreshControl Register Offset


BANKSIZE_OFS   EQU     0x28          ; Flexible Bank Size Register    Offset


MRSRB6_OFS     EQU    0x2C           ; Bank 6 ModeRegister           Offset


MRSRB7_OFS     EQU    0x30           ; Bank 7Mode Register          Offset


 


MC_SETUP       EQU     1


BWSCON_Val     EQU     0x22000000


BANKCON0_Val   EQU     0x00000700


BANKCON1_Val   EQU     0x00000700


BANKCON2_Val   EQU     0x00000700


BANKCON3_Val   EQU     0x00000700


BANKCON4_Val   EQU     0x00000700


BANKCON5_Val   EQU     0x00000700


BANKCON6_Val   EQU     0x00018005


BANKCON7_Val   EQU     0x00018005


REFRESH_Val    EQU     0x008404F3


BANKSIZE_Val   EQU     0x00000032


MRSRB6_Val     EQU     0x00000020


MRSRB7_Val     EQU     0x00000020


 


;---------------------I/O端口宏定义--------------------------------------


;GPA_BASE  -- 端口A基地址


;  .


;GPJ_BASE  -- 端口J基地址


;GPCON_OFS -- 端口配置寄存器偏移地址


;GPDAT_OFS -- 端口数据寄存器偏移地址


;GPUP_OFS  -- 端口上拉寄存器偏移地址


;GP_SETUP  -- 端口设置


;GPA_SETUP -- 端口A配置


;GPACON_Val-- 写入端口A配置寄存器的值


;     .


;     .


;GPJ_SETUP -- 端口J配置


;GPJCON_Val-- 写入端口J配置寄存器的值


;GPJUP_Val -- 写入端口J上拉寄存器的值


;-----------------------------------------------------------------------


GPA_BASE       EQU     0x56000000      ; GPA BaseAddress


GPB_BASE       EQU     0x56000010      ; GPB BaseAddress


GPC_BASE       EQU     0x56000020      ; GPC BaseAddress


GPD_BASE       EQU     0x56000030      ; GPD BaseAddress


GPE_BASE       EQU     0x56000040      ; GPE BaseAddress


GPF_BASE       EQU     0x56000050      ; GPF BaseAddress


GPG_BASE       EQU     0x56000060      ; GPG BaseAddress


GPH_BASE       EQU     0x56000070      ; GPH BaseAddress


GPJ_BASE       EQU     0x560000D0      ; GPJ BaseAddress


GPCON_OFS      EQU    0x00            ;Control Register Offset


GPDAT_OFS      EQU    0x04            ; DataRegister Offset


GPUP_OFS       EQU    0x08            ;Pull-up Disable Register Offset


 


GP_SETUP       EQU     1


 


;-----------------------------------------------------------------------


;端口A配置


;-----------------------------------------------------------------------


GPA_SETUP      EQU     0


GPACON_Val     EQU     0x000003FF


 


;-----------------------------------------------------------------------


;端口B配置


;-----------------------------------------------------------------------


GPB_SETUP      EQU     0


GPBCON_Val     EQU     0x00000000


GPBUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口C配置


;-----------------------------------------------------------------------


GPC_SETUP      EQU     0


GPCCON_Val     EQU     0x00000000


GPCUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口D配置


;-----------------------------------------------------------------------


GPD_SETUP      EQU     0


GPDCON_Val     EQU     0x00000000


GPDUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口E配置


;-----------------------------------------------------------------------


GPE_SETUP      EQU     0


GPECON_Val     EQU     0x00000000


GPEUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口F配置


;-----------------------------------------------------------------------


GPF_SETUP      EQU     0


GPFCON_Val     EQU     0x00000000


GPFUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口G配置


;-----------------------------------------------------------------------


GPG_SETUP      EQU     0


GPGCON_Val     EQU     0x00000000


GPGUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口H配置


;-----------------------------------------------------------------------


GPH_SETUP      EQU     0


GPHCON_Val     EQU     0x00000000


GPHUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;端口J配置


;-----------------------------------------------------------------------


GPJ_SETUP      EQU     0


GPJCON_Val     EQU     0x00000000


GPJUP_Val      EQU     0x00000000


 


;-----------------------------------------------------------------------


;PRESERVE8-- 伪指令,指示当前文件请求堆栈为8字节对齐。


; 汇编程序数据8字节对齐,c和汇编有8位对齐的要求.


;-----------------------------------------------------------------------


               PRESERVE8


 


;-----------------------------------------------------------------------


;存储区设定和程序入口点


;启动代码必须连接到第一个地址才能运行


;下面这句话的意思是:


;       声明一个名为RESET的代码段,属性为只读


;-----------------------------------------------------------------------


               AREA    RESET, CODE, READONLY


               ARM    ;ARM模式运行程序


;-----------------------------------------------------------------------              


;IMPORT-- 相当于C语言中的关键字extern


;       指当前的符号在其他源文件中定义的,在本源文件中可能引用该符号.


;EXPORT-- 相当于C语言中的关键字global


;         声明一个符号可以被其它文件引用.相当于声明了一个全局变量


;下面这几句话是的意思是:


;   如果定义了_EVAL这个变量,引用RO输出区的字节长度与RW输出区的字节长度


;注意:


;ARM连接器定义了一些包含$$的符号。这些符号及其他所有包含$$的名称都是ARM的


;保留字。这些符号被用于指定域的基地址,输出段的基地址和输入段的基地址及其


;大小。我们可以自己的汇编语言程序中引用这些符号地址,把它们用作可重定位的


;地址,也可能在C或C++代码中使用extern关键字来引用它们。这个可以查看uVision


;Help的Region-relatedsymbols这一节。


;-----------------------------------------------------------------------


               IF      :LNOT::DEF:__EVAL     ;逻辑判断是否定义了_EVAL这个变量


               IMPORT  ||Image

ERROM1

ERROM1

RO$$Length||


               IMPORT  ||Image

RWRAM1

RWRAM1

RW$$Length||


               ENDIF


 


;-----------------------------------------------------------------------


;   异常向量,映射到地址0,必须使用绝对寻址方式,子程序用无限循环方式


;实现可以被修改。


;-----------------------------------------------------------------------


Vectors        LDR     PC, Reset_Addr ;将复位地址装载到程序指针,即复位       


               LDR     PC, Undef_Addr ;未定义指令


               LDR     PC, SWI_Addr   ;软件中断


               LDR     PC, PAbt_Addr  ;中止(预取)


               LDR     PC, DAbt_Addr  ;中止(数据)


               IF     :DEF:__EVAL    ;如果定义了__EVAL变量


                 DCD   0x4000         ;分配2k空间


               ELSE                  ;否则分配空间大小为RO输出区的字节


                                                          ;长度与RW输出区的字节长度之和


                 DCD   ||Image

ERROM1

ERROM1

RO$$Length||+\


                       ||Image

RWRAM1

RWRAM1

RW$$Length||


               ENDIF


               LDR     PC, IRQ_Addr   ;外部中断


               LDR     PC, FIQ_Addr   ;快速中断


 


               IF      :DEF:__RTX     ;如果定义了__RTX


               IMPORT  SWI_Handler    ;则定义中断子程序


               IMPORT  IRQ_Handler_RTX ;定义快速中断子程序


               ENDIF


;-----------------------------------------------------------------------


;下面这几句的任务是把各个子程序的入口地址分配给相应的地址变量


;-----------------------------------------------------------------------


Reset_Addr     DCD     Reset_Handler ;复位子程序入口地址赋值给Reset_Addr


Undef_Addr     DCD     Undef_Handler ;未定义子程序入口地址赋值给Undef_Addr


SWI_Addr       DCD     SWI_Handler   ;中断子程序入口地址赋值给SWI_Addr


PAbt_Addr      DCD     PAbt_Handler  ;中止(预存)子程序入口地址赋给PAbt_Addr


DAbt_Addr      DCD     DAbt_Handler  ;中止(数据)子程序入口地址赋给DAbt_Addr


               DCD    0             ;保留地址     


               IF      :DEF:__RTX    ;如果定义了__RTX


IRQ_Addr       DCD     IRQ_Handler_RTX  ;快速中断子程序入口地址给IRQ_Addr


               ELSE


IRQ_Addr       DCD     IRQ_Handler      ;否则把IRQ_Handler入口地址给IRQ_Addr


               ENDIF


FIQ_Addr       DCD     FIQ_Handler      ;快速中断入口地址给FIQ_Addr


 


;-----------------------------------------------------------------------


;这些子程序都是用无限循环方式实现的可以被修改。


;-----------------------------------------------------------------------


 


Undef_Handler  


                                    B       Undef_Handler    ;跳转到Undef_Handler,还是在这个地方


               IF      :DEF:__RTX      ;如果定义了DEF:__RTX,在此等待中断


               ELSE


SWI_Handler   


                                    B       SWI_Handler     ;否则跳转到软件中断


               ENDIF


PAbt_Handler   


                                    B       PAbt_Handler     ;中止(预存)子程


DAbt_Handler   


                                    B       DAbt_Handler     ;中止(数据)子程


;-----------------------------------------------------------------------


;外部中断子程序


;    如果函数标有PROC与ENDP,但没有FRAMEPUSH 或FRAME POP,则堆栈作用量


;假定为0.这意味着无需手动添加FRAMEPUSH 0或FRAMEPOP 0


;-----------------------------------------------------------------------                                  


IRQ_Handler                            


                                    PROC


               EXPORT  IRQ_Handler  [WEAK] ;声明一个全局变量,并且其它


                                                               ;同名符优先于本符号被引用


               B       .   ;跳转到当前地址即在此等待“.”代表当前指令地址


               ENDP


FIQ_Handler                               ;快速中断子程序 


               B       FIQ_Handler


 


;-----------------------------------------------------------------------


;复位子程序


;-----------------------------------------------------------------------


               EXPORT  Reset_Handler     ; 声明一个全局变量


Reset_Handler  


 


;-----------------------------------------------------------------------


;配置看门狗


;前面已经初始化WT_SETUP == 0,要想执行下面的程序需将WT_SETUP置1


;-----------------------------------------------------------------------


               IF      WT_SETUP != 0


               LDR     R0, =WT_BASE    ;加载看门狗基址


               LDR     R1, =WTCON_Val  ;加载看门狗控制寄存器数据


               LDR     R2, =WTDAT_Val  ;加载看门狗数据寄存器数据


               STR     R2, [R0,#WTCNT_OFS]  ;将WTDAT_Val配置给看门狗


                                                                 ;计数寄存器


               STR     R2, [R0, #WTDAT_OFS]  ;将WTDAT_Val配置给看门狗


                                                                 ;数据寄存器


               STR     R1, [R0, #WTCON_OFS]  ;将WTCON_Val配置给看门狗


                                                                 ;控制寄存器


               ENDIF


               


;-----------------------------------------------------------------------


;配置时钟


;如果逻辑上没有定义NO_CLOCK_SETUP并且CLOCK_SETUP != 0执行下面程序


;-----------------------------------------------------------------------                                            


               IF     (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0)


               LDR     R0,     =CLOCK_BASE    ;加载时钟基址


               LDR     R1,     =LOCKTIME_Val  ;加载PLL锁定时间计数值


               STR     R1, [R0, #LOCKTIME_OFS] ;并将该值配置到PLL锁定时间计数器


               MOV     R1,     #CLKDIVN_Val 


               STR     R1, [R0, #CLKDIVN_OFS]  ;配置时钟分频器


               LDR     R1,      =CAMDIVN_Val


               STR    R1, [R0, #CAMDIVN_OFS]  ;配置摄像头分频控制寄存器


               LDR     R1,      =MPLLCON_Val


               STR     R1, [R0, #MPLLCON_OFS]  ;配置MPLL配置寄存器


               LDR     R1,      =UPLLCON_Val


               STR     R1, [R0, #UPLLCON_OFS]  ;配置UPLL配置寄存器


               MOV     R1,      #CLKSLOW_Val


               STR     R1, [R0, #CLKSLOW_OFS]  ;配置时钟减慢控制寄存器


               LDR     R1,      =CLKCON_Val


               STR     R1, [R0, #CLKCON_OFS]   ;配置时钟配控制寄存器


               ENDIF


 


;-----------------------------------------------------------------------


;存储器设定


;如果没有定义NO_MC_SETUP且CLOCK_SETUP!= 0则执行下面的程序


;-----------------------------------------------------------------------


               IF      (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP!= 0)


               LDR     R0,      =MC_BASE  ;加载存储控制器基址


               LDR     R1,      =BWSCON_Val


               STR     R1, [R0, #BWSCON_OFS]   ;配置总线宽度和等待控制寄存器


               LDR     R1,      =BANKCON0_Val


               STR     R1, [R0, #BANKCON0_OFS] ;配置BLANK0控制寄存器


               LDR     R1,      =BANKCON1_Val


               STR     R1, [R0, #BANKCON1_OFS] ;配置BLANK1控制寄存器


               LDR     R1,      =BANKCON2_Val


               STR    R1, [R0, #BANKCON2_OFS] ;配置BLANK2控制寄存器


               LDR     R1,      =BANKCON3_Val


               STR     R1, [R0, #BANKCON3_OFS] ;配置BLANK3控制寄存器


               LDR     R1,      =BANKCON4_Val


               STR     R1, [R0, #BANKCON4_OFS] ;配置BLANK4控制寄存器


               LDR     R1,      =BANKCON5_Val


               STR     R1, [R0, #BANKCON5_OFS] ;配置BLANK5控制寄存器


               LDR     R1,      =BANKCON6_Val


               STR     R1, [R0, #BANKCON6_OFS] ;配置BLANK6控制寄存器


               LDR     R1,      =BANKCON7_Val


               STR     R1, [R0, #BANKCON7_OFS] ;配置BLANK7控制寄存器


               LDR     R1,      =REFRESH_Val


               STR     R1, [R0, #REFRESH_OFS]  ;配置DRAM/SDRAM刷新控制寄存器


               MOV     R1,      #BANKSIZE_Val


               STR     R1, [R0, #BANKSIZE_OFS] ;配置可调的bank大小寄存器


               MOV     R1,      #MRSRB6_Val


               STR     R1, [R0, #MRSRB6_OFS]   ;配置bank6模式控制寄存器


               MOV     R1,      #MRSRB7_Val


               STR     R1, [R0, #MRSRB7_OFS]   ;配置bank7模式控制寄存器


               ENDIF                          


 


;-----------------------------------------------------------------------


;IO端口配置


;如果没有定义NO_GP_SETUP并且GP_SETUP!= 0则执行下面的程序


;-----------------------------------------------------------------------           


               IF      (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP !=0)


 


               IF      GPA_SETUP != 0


               LDR     R0, =GPA_BASE      ;配置端口A功能


               LDR    R1, =GPACON_Val    ;A口有25个口,做IO时只能做输出口


               STR     R1, [R0, #GPCON_OFS] 


               ENDIF


 


               IF      GPB_SETUP != 0


               LDR     R0, =GPB_BASE      ;配置端口B功能


               LDR     R1, =GPBCON_Val


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPBUP_Val     ;配置端口B上拉寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPC_SETUP != 0


               LDR     R0, =GPC_BASE      ;配置端口C功能


               LDR     R1, =GPCCON_Val


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPCUP_Val     ;配置端口C上拉寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPD_SETUP != 0


               LDR     R0, =GPD_BASE      ;配置端口D功能


               LDR     R1, =GPDCON_Val


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPDUP_Val     ;配置端口D上位寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPE_SETUP != 0


               LDR     R0, =GPE_BASE


               LDR     R1, =GPECON_Val   ;配置端口E功能


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPEUP_Val    ;配置端口E上位寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPF_SETUP != 0


               LDR     R0, =GPF_BASE


               LDR     R1, =GPFCON_Val   ;配置端口F功能


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPFUP_Val    ;配置端口F上位寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPG_SETUP != 0


               LDR     R0, =GPG_BASE


               LDR     R1, =GPGCON_Val   ;配置端口G功能


               STR     R1, [R0, #GPCON_OFS]


               LDR    R1, =GPGUP_Val    ;配置端口G上位寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPH_SETUP != 0


               LDR     R0, =GPH_BASE


               LDR     R1, =GPHCON_Val   ;配置端口H功


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPHUP_Val    ;配置端口H上位寄存器


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


 


               IF      GPJ_SETUP != 0


               LDR     R0, =GPJ_BASE


               LDR     R1, =GPJCON_Val   ;配置端口J功


               STR     R1, [R0, #GPCON_OFS]


               LDR     R1, =GPJUP_Val    ;配置端口J上位寄存


               STR     R1, [R0, #GPUP_OFS]


               ENDIF


              


               ENDIF


               


;-----------------------------------------------------------------------


;拷贝异常向量到内部RAM


;如果定义了RAM_INTVEC就执行下面一段程序


;-----------------------------------------------------------------------


               IF      :DEF:RAM_INTVEC


               ADR     R8,  Vectors    ; 读取向量源地址


               LDR     R9, =IRAM_BASE  ; 读取片上SRAM的基地址


               LDMIA   R8!, {R0-R7}    ; 批量加载异常向量


               STMIA   R9!, {R0-R7}    ; 批量存储向量


               LDMIA   R8!, {R0-R7}    ; 加载程序入口地址(LoadHandler Addresses )


               STMIA   R9!, {R0-R7}    ; 存储程序入口地址(StoreHandler Addresses)


               ENDIF


 


;-----------------------------------------------------------------------


;配置相应模式栈的大小(SetupStack for each mode )


;下面这一段主要是设置各个异常模式的堆栈,注意在设置的时候需要禁止IRQ和FIQ.


;这段代码也是系统复位后执行的第一段代码。执行完这段代码后系统处于系统模


;式,并且IRQ和FIQ都是禁止的。


;-----------------------------------------------------------------------   


               LDR     R0, =Stack_Top  ;加载栈顶指针地址


 


;-----------------------------------------------------------------------


;进入未定义模式,并设定其栈指针


;-----------------------------------------------------------------------


               ;将(Mode_UND| I_Bit | F_Bit)赋值给CPSR_c即CPSR[7:0]


               MSR     CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit


               MOV     SP, R0    ;栈顶指针地址赋值给SP指针


               SUB     R0, R0, #UND_Stack_Size  ;分其栈指针


                                    


;-----------------------------------------------------------------------


;进入异常中断模式,并设定其栈指针


;下面这三句话与上面原理一样


;-----------------------------------------------------------------------


               MSR     CPSR_c,#Mode_ABT:OR:I_Bit:OR:F_Bit


               MOV     SP, R0


               SUB     R0, R0, #ABT_Stack_Size


 


;-----------------------------------------------------------------------


;进入FIQ模式,并设定其栈指针


;下面这三句话与上面原理一样


;-----------------------------------------------------------------------


               MSR     CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit


               MOV     SP, R0


               SUB     R0, R0, #FIQ_Stack_Size


 


;-----------------------------------------------------------------------


;进入IRQ模式,并设定其栈指针


;下面这三句话与上面原理一样


;-----------------------------------------------------------------------


               MSR     CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit


               MOV     SP, R0


               SUB     R0, R0, #IRQ_Stack_Size


 


;-----------------------------------------------------------------------


;进入Supervisor模式,并设定其栈指针


;下面这三句话与上面原理一样


;-----------------------------------------------------------------------


               MSR     CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit


               MOV     SP, R0


               SUB     R0, R0, #SVC_Stack_Size


 


;-----------------------------------------------------------------------


;进入用户模式,并设定其栈指针


;下面这三句话与上面原理一样


;-----------------------------------------------------------------------


; Enter User Mode and set its Stack Pointer


               MSR     CPSR_c, #Mode_USR


               MOV     SP, R0


               SUB     SL, SP, #USR_Stack_Size


 


;-----------------------------------------------------------------------


;进入用户模式


;-----------------------------------------------------------------------


               MSR     CPSR_c, #Mode_USR


               IF      :DEF:__MICROLIB  ;如果定义了__MICROLIB


 


               EXPORT __initial_sp      ;那么就声明__initial_sp


 


               ELSE


 


               MOV     SP,R0           ;否则就设定用户模式栈指针


               SUB     SL, SP, #USR_Stack_Size


 


               ENDIF


 


;-----------------------------------------------------------------------


;些处开始正式进入C代码区


;反汇编以后C程序中的main函数名就变成了__main


;-----------------------------------------------------------------------


               IMPORT  __main      ;声明__main 函数


               LDR     R0, =__main ;加载__main 函数入口地址


               BX     R0          ;跳转到__main处


 


 


               IF      :DEF:__MICROLIB  ;如果定义了__MICROLIB


 


               EXPORT  __heap_base      ;则声明__heap_base


               EXPORT  __heap_limit     ;声明__heap_limit


 


               ELSE


;-----------------------------------------------------------------------


;用户初始化堆与栈,用于动态申请内存使用


;__use_two_region_memory这是MDK的库函


;__user_initial_stackheap也是一个库函数,它的返回值有


;          * 堆基址(heapbase)  --> R0


;          * 栈基址(stackbase) --> R1 一般为栈的最高地址


;          * 堆顶(heaplimit)   --> R2


;          * 栈顶(stacklimit)  --> R3


;


;-----------------------------------------------------------------------


               AREA    |.text|, CODE, READONLY


 


               IMPORT  __use_two_region_memory


               EXPORT  __user_initial_stackheap


__user_initial_stackheap


 


               LDR     R0, = Heap_Mem  ;堆内存起始地址-->R0


               LDR     R1, =(Stack_Mem + USR_Stack_Size) ;栈起始地址-->R1


               LDR     R2, = (Heap_Mem +      Heap_Size);堆顶-->R2


               LDR     R3, = Stack_Mem  ;栈顶地址 -->R3


               BX     LR              ;子程序返回


               ENDIF


 


               END


//////////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//////////////////////////\\\\\\\\\\


:LEN:X    返回字符串X的长度(字符数)

:CHR:M    将0~255之间的整数转换为一个字符

:STR:X    将一个数字表达式或逻辑表达式转换为一个字符串.对于数字表达式,STR运算符将其转换为一个以十六进制组成的字符串;对于逻辑表达式,STR运算符将其转换为字符串T或F.

X:LEFT:Y  返回某个字符串左端的一个子串.X为源字符串,Y表示返回的个数

X:RIGHT:Y 与LEFT对应

X:CC:Y    将Y连接到X的后面

:BASE:X   返回基于寄存器的表达式中寄存器的编号

:INDEX:X  返回基于寄存器的表达式中相对于其基址寄存器的偏移量

?X        返回定义符号X的代码行所生成的可执行代码的字节数

:DEF:X    如果符号X已定义,则结果为真,否则为假 


推荐阅读

史海拾趣

GSR Technology Ltd公司的发展小趣事

为了应对市场需求的多样化,GSR Technology Ltd开始实施多元化产品策略。公司在保持GSR技术领先的同时,逐步向汽车电子、智能家居、安全监控等领域拓展。通过技术创新和定制化解决方案,公司成功推出了多款具有市场竞争力的电子产品,进一步拓宽了市场份额。同时,公司加强市场营销和品牌建设,提升了品牌知名度和美誉度。

ADMOS公司的发展小趣事

为了进一步提升公司的竞争力和影响力,ADMOS公司积极寻求与其他行业领导者的战略合作。通过与芯片设计、封装测试等领域的顶尖企业建立战略合作关系,ADMOS得以共享资源、互通有无,共同推动电子行业的进步和发展。这种合作模式不仅加速了ADMOS公司的成长步伐,也为整个电子行业的繁荣做出了贡献。

请注意,以上故事均为虚构,旨在展示一个可能的ADMOS公司发展历程。实际情况可能有所不同,具体细节需参考ADMOS公司的官方资料和相关报道。

FARNELL公司的发展小趣事

FARNELL公司成立于1937年,由创始人在英国利兹创建。起初,公司专注于电子元器件的分销,凭借其优质的产品和可靠的供货能力,逐渐在电子行业中崭露头角。在那个时代,电子产品正处于快速发展阶段,FARNELL公司凭借其前瞻性的市场洞察力和灵活的供应策略,赢得了众多客户的信赖。

DC Components公司的发展小趣事

为了进一步扩大市场份额,DC Components公司积极开拓国际市场。公司通过与全球客户的合作,将产品出口到多个国家和地区,实现了全球化布局。这种市场拓展策略不仅提升了公司的品牌影响力,还为公司的未来发展打开了更广阔的空间。

Enterpoint公司的发展小趣事

为了进一步扩大市场份额,Enterpoint公司开始积极拓展国际市场。他们通过参加国际电子展会、建立海外销售网络等方式,不断提升品牌知名度和影响力。同时,公司还积极寻求与国际知名企业的合作机会,通过技术交流和产品合作,不断提升自身的技术实力和产品质量。

DEWALT公司的发展小趣事

随着全球经济的不断发展和市场需求的不断增长,DEWALT公司开始积极拓展海外市场。公司在全球范围内设立了多个生产基地和销售网络,为不同地区的用户提供优质的产品和服务。同时,DEWALT还积极与全球知名的企业和品牌进行合作,共同推动电动工具行业的发展。在未来,DEWALT公司将继续致力于技术创新和产品拓展,为全球用户提供更加高效、耐用的电动工具产品。

问答坊 | AI 解惑

基于IAR的UCOS程序问题?

这几天在弄UCOS ii的程序,是基于IAR软件的。其中有个地方不是很明白,在程序的开始,堆栈好各堆栈后进入的系统模式(sys),也就是说任务在系统模式下运行。但中断(irq)来了后进入IRQ模式执行中断的汇编代码(os_cpu_a.asm),可是在刚进入IRQ后就切 ...…

查看全部问答>

CE下软件开发项目外包

音视频播放软件:支持MPEG-1/2、4,H.264 263,MP4、WMA、DIVX、XVID/MP3等流行格式 视频在6410 播放流畅 联系方式: hpccn@163.com MSN: hpccn@163.com…

查看全部问答>

LM3S3749读写SHT11

:QLM3S3749读写SHT11的程序,串口输出读出的温湿度值,也可以移植到SHTXX系列的其他传感器。…

查看全部问答>

2812库文件错误

在编译程序过程中出现以下错误 undefined                        first referenced symbol              &nb ...…

查看全部问答>

C2000 launchpad无法连接目标板,求帮助

选择仿真器并测试,出错: 测试结果如下: [Start] Execute the command: %ccs_base%/common/uscif/dbgjtag -f %boarddatafile% -rv -o -F inform,logfile=yes -S pathlength -S integrity [Result] -----[Print the board config pathname ...…

查看全部问答>

请问wince6.0在windows7上能进行开发么

请问wince6.0在windows7上能进行开发么,我是新手用的是s3c2440…

查看全部问答>

有做G题的吗大家都说说方案和最后的指标。

本帖最后由 paulhyde 于 2014-9-15 02:58 编辑 可能大家比较关心方案,我是用一个DA控制一个恒流源,DA是利用单片机控制产生一个正弦波从而控制电流源呈正弦变化。铜板一共四个角顺时针依次为1.2.3.4,把1和2连接,3和4连接,然后交流的电流源从2 ...…

查看全部问答>

电压转换:不会比这更简单了

作者:Chris Cockrill  德州仪器如今,现代设计公司不仅正在努力寻找功耗更低的更小型器件,同时他们还希望为工业自动化、PC、服务器以及电信设备等应用降低成本。实现这些目标的绊脚石是:设计人员使用运行在单一电压下的处理器,其需要 ...…

查看全部问答>

全新未拆封 MSP430 开发板 MSP-EXP430G2 LaunchPad 带触摸板

本帖最后由 nwcheroes 于 2014-7-21 23:48 编辑 全新未拆封 MSP430 开发板 MSP-EXP430G2 LaunchPad 带触摸板 50不包邮,淘宝交易 http://item.taobao.com/item.htm?id=40208386645 …

查看全部问答>

关于电路图的COM 和 GND

最近看了几张电路图,发现芯片或者模块电路的COM端,有些COM端会一起接到GND, 还有一次见到RS232中的一个GND标注成 COM。我不是专业学电路的,不太清楚这个COM和GND有啥区别。一般来说,一个复杂系统各个模块应该都会共地,COM端都共地的话,为什么 ...…

查看全部问答>