keil下的s3c2440启动代码分析
s3c2410ARM9启动代码分析

ADS下C语言的入口方式和ROM镜像文件的生成这部分介绍下ADS下如何生成可以运行的ROM镜像文件,我们知道当程序下载到flash中运行的时候,对于RW、ZI数据就存在着两个环境,一个load环境,一个是exec环境,有时候由于速度的需要RO数据也要重新加载,那么对RO数据也是有两个环境。
编译器产生ROM镜像文件时候,这三块数据的存放依次为RO、RW、ZI,并且地址空间时连续的。
但是到了运行的时候,RW数据必须被拷贝到SDRAM(SRAM)中以支持读写,这就是我们所谓的运行环境。
那么就要有一段代码去完成这个任务,在本章中我们介绍如何生成这段代码。
玩过2410的朋友都知道2410初始化代码中有一段搬运RW和ZI初始化的代码,没错,它确实能够在一定程度上完成上面所说的任务,只要我们在生成二进制可执行代码的时候在编译器链接项的地方填写正确的RO&RW地址,(比如RO = 0, RW = 0x30000000), 那么将程序下到NOR flash的零地址并从nor flash启动,启动代码会将RW&ZI数据弄到0x30000000,程序就能跑起来了。
但是各位有没有想过,怎么把RO代码弄到SDRAM中(有时候这是必须的,比方后面我将提到用nor flash的bootloader烧写nor flash)?如果直接设RO=0x30000000,那么这段代码下载到0地址肯定跑不起来,除非是ROPI,这个要求就高了。
这里我们有必要从介绍ADS 中规定的C语言入口开始,ADS中从初始化汇编代码跳到main函数有两种方式,main和__main:1,在__main入口的模式下,汇编代码的指令为b __main, 编译器在跳转到main之前还要作一系列的工作,这其中就包括对运行环境的初始化,在<ADS COMPILE GUIDE>中提到:copies nonroot(RO&RW) execution regions from load addr to exec addr, and Zeros ZI region. 借助编译器,我们就可以定义更为复杂的运行环境,这里要用到scatter文件(.scf),比如我们要的目标运行环境是:将启动代码以外的所有代码都拷贝到SDRAM的初始地址中运行,比且把RW段设在0x30800000,那么对应的scf文件如下:FLASH 0x0 0x200000{EXEC1 0x0 0x200000{2410init.o(Init, +First)__main.o(+RO) ; copy code* (Region$$Table) ; RO/RW addresses to copy* (ZISection$$Table) ; ZI addresses to zero}EXEC2 0x30000000 0x00800000{*(+RO)}SDRAM 0x30800000 0x00800000{*(+RW,+ZI)}};Sections named Region$$Table and ZISection$$Table which contain the addresses of the code/data to be copied.当然,在这种模式下,有些入口函数必须自己重定义,比如__user_initial_stackheap,具体参见ADS文档。
基于S3C2440的U-boot启动分析

中北 大学信 息与 通信 工程 学院 洪永 学 余 红英
[ 要] 摘 在嵌入 式的世界 中 , 通常没有像 B O 那样 的固件程序 , IS 因此整 个嵌入式 系统的加栽就完全 由B o od r o t ae 来完成, l 所以B o— o t la e是嵌入 式京 统中不可缺 少的重要部分 , 文结合 u b o一 ..部分源代码详细地分析 U— o 启动过程 , o dr 本 — o t 116 Bo t 主要是对 U— o 启 Bo t 动的关键 环节进行较 为详 细的解析 , 其对 U— o t 目 B o在 标板 ¥ C 40 3 2 4 移植分析具有一定的借鉴价值。 [ 关键 词] o t ae U— 0 启动 移植 B ol dr o Bo t 给 内 核 , 代 码 如 下 : g 一 b 一 b a h n m e : d>d >i r — u br _c U B o, — ot全称 为 U iesl ot o dr 即通 用的 B ood r是遵循 MACH TYP S D 2 1 ; 始 化 串 口 函数 只要 是 sr l n , 置 了 nvra B o a e, L ot ae , l E M K4 0初 e a it i— i设 GL P 条款 的开发代码 , 的名字“ 它 通用” 具有两层含义 : 以引导 多种操 U T控制器 , c uam9 0 sc4 Osf .中实现 。 可 AR 在 p / 2f 32 x/e a c r i 1 作 系统 、 支持 多种架构 的 C U P 。它支持如 下操作 系统 :iu 、 e S 、 Lnx N t D B () 2 检测系统 内存映射( e o a ) m m r m p y V Wo s Q X R T S A T S , 持 如 下 C U架 构 : o e C x r 、 N 、 E M 、 RO 等 支 k P Pw r 、 P 对于特定 的开发板 , 内存 的分 布是明确 的, 以可 以直接设 置 , 其 所 o d m k 4 0 m k4 0 rs s e r it m n 函数指定 了开发板 的内存起 M P 、 8 、 R N I 等 。U B o支 持大 多数 C U, 以烧 写 E T 、 b a / d 2 1/ d2 1 .中的da _ i IS x6 A M、 O S — ot P 可 X 2 Y E S 文件系统 映像 , E F2 支持 串口下 载 , 网络下载 , 提供大量 的命令 , 始地址 , 并 代码如下 : it rm i t o ) n a d 相 对于 M z 司的V v, 的使用更复杂 , i公 i i 它 i 但是可 以用来更方便地 调试 n ( i iv d 、 程序 。本文针对 A M架构 中的 s d 2 1 开发板的 U B o启动进行详 R m k4 0 — ot { g > d >b da 0.at HY _ D AM一 ; d- b 一 i rm[]t =P S S R 细分析。 sr 1 g > d >b d m[ .z d一 b - i r O s e=P S S A 2U— o t 动 过 程 分 析 . B o启 a ]i HY _ DR M— — IE lSZ ; 通常 , ot ae 是 严重 地依 赖于硬 件 而实 现的 , 多数 的 B o B l dr o 大 ot — rtr : e u n0 l dr o e启动 过程 分为两个阶段 , a 本文 以开发板 s d 2 1 为例 , U B o m k 40 其 — ot ) 属于两阶段 的B o od r 一阶段 的文件为 cu r 9 0 s r 和 ba / ot ae , l 第 p / m 2 tt . o r a /aS d () 3 获取 U B o操作命 令 — ot s mdk 41  ̄o e e. 2 0 wlv 1 S。 启 动 U B o 后 可 以在 串 口看 到 一 些 打 印 信 号 , 后 会 出 现 — ot 随 2 — ot 一阶段分析 .U B o 1 第 ”MD 4 0#” S K20 字符等待用户输人命令来启动 内核 , 因此 U B o启动内 — ot () 1硬件设备初始化 核 的主要 核心是通 过 U B o命令来 实现 , — ot 在函数 s r a bo 中进行 t _r ot a m t 依次完 成如下设 置 : C U的工作模式设 置为管理 模式 (v ) 关 相 应 的 f s_ i 0 nn — i 等 函数 后 , 入 m i l p0 过 s 将 P sc , l h i t 和 ad i t a n n0 进 a _ o 通 no = 闭 看 门狗 ( T HD G) 设置 P L , L ,C K的 比例 , 闭 MMU gt v Iot d) WA C O , C KHC KF L 关 , en ( om ” e t c 获取U B o命令 , b — ot 然后通过 rn cm a d s0 u_ o m n ( ) , 执行命 cc A HE等 等 。 令, 最终启动内核 。U B o 中的每个命令都通过 u B O M 宏来定 — ot _O TC D 义, 格式如下 : () 2 为加载 B ood r ot ae 的第二段代码 到 R M空间 l A U BOOT C 所 谓 R M空 间 , 是 初始 化 内存芯 片 , 它能 够使 用 。通过 在 A 就 使 MDn m , xrs eetbecm n , sg””e ” (a emaag, p aal, ma d” ae , l ) r o u hp 各项参数的意义 如下 : s rS t t 中调用 l l e i t a. o e l n 函数来设置控制器 , 得外接 S R M。 w v_ i 使 D A L wl v l i t o e e n 部分函数代码 如下 : i ① nm : a e 命令 的名字 , 注意 , 它不是 一个字符 串( 不要 用双引号 括
keil下的s3c2440启动代码分析

由于片面问题,所以可能会看起来不太美观,可以看附件中的内容。
ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。
由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。
一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口,设备初始化,变量初始化等。
这几天对着RealView MDK-ARM中自带的启动代码研究了一下,遇到问题又对着数据手册和指令表看了一下,总算对S3C2440A的硬件有了一个大致的了解。
学习嵌入式系统重在系统,学习ARM只是为学习嵌入式系统铺路,懒猫比较笨可能在上系统之前要裸奔几天以强化以下对S3C2440A内部结构的了解。
把MDK自带的S3C2440A.S文件的注释发一下,这些是懒猫结合数据手册与ARM指令表理解了,可能会有错误,放在这里只是引导一下像我一样还没有入门的兄弟们,希望你们不要害怕ARM害怕嵌入式,老毛他老人家说的对,世上无难事,只怕有心人,ARM指令就那么多,看一遍不会就多看几遍,还有一定要学习看软件自带的帮助文件.;/*****************************************************************************/;/* S3C2440.S: Startup file for Samsung S3C440 */;/*****************************************************************************/;/* <<< Use Configuration Wizard in Context Menu >>> */ ;/*****************************************************************************/;/* This file is part of the uVision/ARM development tools. */ ;/* Copyright (c) 2005-2008 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 softwar e */;/* development tools. Nothing else gives you the right to use this softwa re. */;/*****************************************************************************/;下面这些参数是与CPSR状态寄存器有关;参数的由来:这里各个模式的参数是由寄存器CPSR的模式位设置M[4:0]得来的,;比如这里的用户模式,CPSR的M[4:0]设置为10000就是0x10。
s3c2440的一些解释

S3c2440启动是从文件vivi/arch/s3c2440/head.S开始的1. 在这个文件中,做了这样的工作:(1) 关闭看门狗(2) 禁止所有中断(3) 初始化system clock(4) 初始化串口(5) 初始化nand flash相关的控制寄存器(6) 把vivi copy 到 SDRAM上,最后把pc指向ram(7) 设置堆栈(8) call 一个叫做main的函数。
这个函数是c写的2. main()这个函数在vivi/init/main.c中(1) 程序正常跳转到这里后,首先打印一些进本信息(2) 调用若干个初始化的函数<1> reset_handler() vivi/lib/reset_handler.c中(主要做了clear memory的工作)<2> board_init() (没找到)<3> mem_map_init() vivi/arch/mmu.c中(如果使用nand flash,会在这里使它看起来线性化;清空cache;invalidate I & D tlb)mmu_init vivi/arch/mmu.c中(初始化cache,load页表指针,mmu 使能等等)<4> heap_init 初始化堆 vivi/lib/heap.c(这里好像malloc了一段空间,具体的没看懂)<5> mtd_dev_init vivi/driver/mtd/mtdcore.c中mtd_init() 在vivi/driver/mtd/maps/s3c2440_flash.c 中,这里根据所使用的flash,做相应的cpu控制初始化,分配内存add_command(&flash_cmd) 注册了flash这个用户命令<6> init_priv_data() vivi/lib/priv_data/rw.c中读出boot的基本参数<7> misc() (没找到)init_builtin_cmds() vivi/lib/command.c中(注册用户的基本命令,包括boot, bon, load, help 等等)<8> boot_or_vivi() 就在main.c中,等待用户输入,有输入进入vivi_shell,没有输入,超时后启动linux到这里main就结束喽好像还有一件事没有记下来,就是vivi是怎么启动到linux的。
S3C2440启动代码经验总结

1、引言2、汇编基础2.1、伪操作GET 伪操作类似于C 语言里面的include,是将一个源文件包含到当前源文件中,并将被包含的文件在其当前位置进行汇编处理。
IMPORT伪操作相当于C 语言中的extern 声明,它告诉编译器当前的符号不再本源文件中定义,而是在其他源文件中定义,在本源文件中可能引用该符号。
AERA 伪操作用于定义一个代码或者数据段。
ASSERT在汇编编译器对汇编程序的扫描中,如果ASSERT 中条件不成立,ASSERT 伪操作将报告错误信息。
2.2、汇编指令LDR伪指令将一个32 位的常数或者一个地址值读取到寄存器中。
BL跳转指令,L 决定是否保存返回地址。
MRS用于将状态寄存器的内容传送到通用寄存器中。
MSR用于将通用寄存器的内容或一个立即数传送到状态寄存器中。
LDM和STM分别为批量Load/Store内存访问指令。
FD为满递减数据栈。
3、启动代码功能模块分解启动代码主要是在主程序运行之前初始化系统硬件及软件的运行环境,它的主要功能包括以下的几个方面:* 建立中断向量表* 初始化系统堆栈* 应用程序执行环境初始化* 跳转至主函数3.1、系统堆栈初始化ARM有7种模式:* 用户模式* 快速中断模式* 中断模式* 管理模式* 中止模式* 未定义模式* 系统模式系统堆栈的初始化主要是给各个处理器模式分配堆栈空间。
堆栈是为中断或程序跳转服务的,当发生中断或程序跳转时,需要将当前处理器的状态及一些参数保持在堆栈中,当中断处理完毕以后或程序执行完后返回时,再将堆栈保存的现场数据进行恢复,以保证原来的程序正确运行。
USERMODE EQU 0x10 ;用户模式FIQMODE EQU 0x11 ;快速中断模式IRQMODE EQU 0x12 ;中断模式SVCMODE EQU 0x13 ;监管模式ABORTMODE EQU 0x17 ;异常中断模式UNDEFMODE EQU 0x1b ;未定义模式MODEMASK EQU 0x1f ;模式掩码NOINT EQU 0xc0 ;取消中断;设置工作模式的堆栈的起始地址;在option.inc 中定义了_STACK_BASEADDRESS EQU 0x33ff8000 UserStack EQU (_STACK_BASEADDRESS-0x3800) ;堆栈空间0x33ff4800 SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;堆栈空间0x33ff5800 UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;堆栈空间0x33ff5c00AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;堆栈空间0x33ff6000IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;堆栈空间0x33ff7000 FIQStack EQU (_STACK_BASEADDRESS-0x0) ;堆栈空间0x33ff8000堆栈初始化的顺序决定系统最后运行在哪种处理器模式,最后初始化哪种模式的堆栈,系统就运行在哪种模式。
学习S3C2440bootloader

按照gooogleman老兄的建议,从优龙2440板子的bootloader学起。
首先先将程序运行起来,step执行,搞清楚每步做了什么,为什么这么做。
将整体的流程学习一遍。
等1个月,2个月,无论多长时间,当自己真正掌握后,再将整体的代码加上注释,做成PDF文档。
分给后来者,去帮助像我现在这样水平的小小鸟。
OK,第一话开始:程序入口点:程序最开始跳到2440init.s文件,执行如下代码:b ResetHandler 跳转到复位异常处理程序。
ResetHandlerldr r0,=WTCON ;watch dog disableldr r1,=0x0str r1,[r0](将看门狗定时器清零,查看datasheet,WTCON的第0位是看门狗定时器复位输出信号开关。
为0,则程序关闭了S3C2440A的看门狗复位功能。
)ldr r0,=INTMSKldr r1,=0xffffffff ;all interrupt disablestr r1,[r0](将中断屏蔽寄存器全部置1,将对应的中断全部关闭。
)ldr r0,=INTSUBMSKldr r1,=0x7fff ;all sub interrupt disable `str r1,[r0](将子中断屏蔽寄存器全不置1,将子中断屏蔽寄存器对应的中断全部关闭。
)ldr r0,=LOCKTIMEldr r1,=0xffffffstr r1,[r0](LOCKTIME是锁定时间计数寄存器,分别设定了UPLL 对于UCLK 的锁定时间计数值和MPLL对于FCLK、HCLK、PCLK的锁定时间计数值。
具体查看datasheet第7章时钟部分。
) [ PLL_ON_START; Added for confirm clock divide. for 2440.; Setting value Fclk:Hclk:Pclkldr r0,=CLKDIVNldr r1,=CLKDIV_V AL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.str r1,[r0](这里先明确一下,在ADS下的bootloader代码常看到[|]他们其实就相当于c语言里面的IfdefElseEndif)(CLKDIVN是时钟分频器控制寄存器,设置的值为CLKDIV_V AL宏。
S3C2440启动代码注解

;/*****************************************************************************/ ;/*S3C2440A.S:Startup file for Samsung S3C440A*/ ;/*This file is part of the uVision/ARM development tools.*/ ;/*Copyright(c)2005-2006Keil 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.*/ ;/*****************************************************************************/;elementary avocationA AND水友(rework:2008.09.15)/****************************************************************************;/欢迎各位大峡更详细的注解和改错;;(越详细越好!目标每行注解)参与的水友如下:【虚处理(子程序)是用一个无限循环实现的,它是可修改的..//(11942295)翻译】【galaxy9229发表于www.21ic2008-9-2516:51ARM程序分析与设计】参考:【龙啸九天】【飘零天堂】【METAL MAX】/****************************************************************************/ ;***启动代码(执行复位后)***;Standard definitions of Mode bits and Interrupt(I&F)flags in PSRs//;向量中断模式/非向量中断模式在PSRs设置(猜的);系统的工作模式设定Mode_USR EQU0x10;定义用户模式标志代码;//用户模式的CPSR 代码Mode_FIQ EQU0x11;定义快速中断模式标志代码;//快中断模式的CPSR代码Mode_IRQ EQU0x12;定义普通中断模式标志代码;//中断模式的CPSR 代码Mode_SVC EQU0x13;定义管理模式标志代码;//管理模式的CPSR代码Mode_ABT EQU0x17;定义中止模式标志代码;//中止模式的CPSR代码Mode_UND EQU0x1B;定义未定义模式标志代码;//未定义模式的CPSR代码Mode_SYS EQU0x1F;定义系统模式(特权模式)标志代码;//系统(特权)模式的CPSR代码I_Bit EQU0x80;//普通中断开关(0×80:打开;0×00:关闭)F_Bit EQU0x40;//快速中断开关(0×40:打开;0×00:关闭);//栈配置();系统的栈空间设定UND_Stack_Size EQU0x00000000;未定义SVC_Stack_Size EQU0x00000008;管理模式端栈长度ABT_Stack_Size EQU0x00000000;中止模式端栈长度FIQ_Stack_Size EQU0x00000000;快速中断模式端栈长度IRQ_Stack_Size EQU0x00000080;普通中断模式模式端栈长度USR_Stack_Size EQU0x00000400;用户模端栈长度;//ISR_Stack_Size EQU(UND_Stack_Size+SVC_Stack_Size+ABT_Stack_Size+ FIQ_Stack_Size+IRQ_Stack_Size);所有的堆栈大小进行相加,得到总堆栈大小/****************************************************************************** ****************;//arm的汇编程序由段组成,段是相对独立的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性:;//READWRITE(读写)READONLY(只读)******************************************************************************* ***************/AREA STACK,NOINIT,READWRITE,ALIGN=3;开辟端栈段,段名(STACK)定义为可读可写,不初始化内存单元或将内存写0,字节对齐Stack_Mem SPACE USR_Stack_Size;//申请栈内存空间__initial_sp SPACE ISR_Stack_SizeStack_Top EQU Stack_Mem+ISR_Stack_Size;//定义堆栈开始地址(最大地址,堆栈向下访问);//堆配置;//堆大小(单位字节)//Heap_Size EQU0x00000000;系统的堆空间设定//定义堆空间大小(配合最后的动态内存申请使用)AREA HEAP,NOINIT,READWRITE,ALIGN=3;//段名(HEAP)声明堆代码段(不初始化内存,可读写,字节对齐)Heap_Mem SPACE Heap_Size;//申请堆的内存空间;时钟管理定义CLK_BASE EQU0x4C000000;时钟基地址LOCKTIME_OFS EQU0x00;PLL锁定时间计数器对应基地址的偏移值MPLLCON_OFS EQU0x04;MPLL控制对应基地址的偏移值//认为MPLL分出三种模式:FCLK、HCLK、PCLKUPLLCON_OFS EQU0X08;UPLL控制对应基地址的偏移值//用于USB设备CLKCON_OFS EQU0x0C;时钟生成控制对应基地址的偏移值CLKSLOW_OFS EQU0x10;慢时钟控制对应基地址的偏移值CLKDIVN_OFS EQU0X14;时钟除法器控制对应基地址的偏移值CAMDIVN_OFS EQU0X18;摄象时钟除法器控制对应基地址的偏移值//UPLL提供CLOCK_SETUP EQU1;时钟设置LOCKTIME_Val EQU0x0FFF0FFF;PLL锁定时间计数器值MPLLCON_Val EQU0x00043011;MPLL控制值UPLLCON_Val EQU0x00038021;UPLL控制值CLKCON_Val EQU0x001FFFF0;时钟生成控制值CLKSLOW_Val EQU0x00000004;慢时钟控制值CLKDIVN_Val EQU0x0000000F;时钟除法器控制值CAMDIVN_Val EQU0x00000000;摄象时钟除法器控制值;Interrupt definitions;中断定义INTOFFSET EQU0X4A000014;中断请求源偏移地址;//中断向量表;//中断向量地址<0x20-0x3fffff78>;//中断向量表地址必须字对齐;//</e>IntVT_SETUP EQU1;中断向量设置IntVTAddress EQU0x33ffff20;中断向量地址;-----------------------存储器设定------------------------------------IRAM_BASE EQU0x40000000;//内存基地址;//看门狗定义WT_BASE EQU0x53000000;看门狗基地址WTCON_OFS EQU0x00;看门狗控制对应基地址的偏移值WTDAT_OFS EQU0x04;看门狗数据对应基地址的偏移值WTCNT_OFS EQU0x08;看门狗记数对应基地址的偏移值WT_SETUP EQU1;看门狗设置WTCON_Val EQU0x00000000;看门狗控制WTDAT_Val EQU0x00008000;看门狗数据;存储控制器设定MC_BASE EQU0x48000000;存储控制器基地址MC_SETUP EQU0;存储控制器设定BWSCON_Val EQU0x22000000;总线宽度和等待控制BANKCON0_Val EQU0x00000700;Boot ROM控制BANKCON1_Val EQU0x00000700;BANK1控制BANKCON2_Val EQU0x00000700;BANK2控制BANKCON3_Val EQU0x00000700;BANK3控制BANKCON4_Val EQU0x00000700;BANK4控制BANKCON5_Val EQU0x00000700;BANK5控制BANKCON6_Val EQU0x00018005;BANK6控制BANKCON7_Val EQU0x00018005;BANK7控制REFRESH_Val EQU0x008404F3;DRAM/SDRAM刷新控制BANKSIZE_Val EQU0x00000032;存储器大小控制MRSRB6_Val EQU0x00000020;SDRAM的模式设置寄存器控制MRSRB7_Val EQU0x00000020;SDRAM的模式设置寄存器控制;存储控制器设定结束;I/O口设定PIO_BASE EQU0x56000000;端口基地址PCONA_OFS EQU0x00;端口A控制对应基地址的偏移值PCONB_OFS EQU0x10;端口B控制对应基地址的偏移值PCONC_OFS EQU0x20;端口C控制对应基地址的偏移值PCOND_OFS EQU0x30;端口D控制对应基地址的偏移值PCONE_OFS EQU0x40;端口E控制对应基地址的偏移值PCONF_OFS EQU0x50;端口F控制对应基地址的偏移值PCONG_OFS EQU0x60;端口G控制对应基地址的偏移值PCONH_OFS EQU0x70;端口H控制对应基地址的偏移值PCONJ_OFS EQU0xD0;端口J控制对应基地址的偏移值PUPB_OFS EQU0x18;端口B上拉控制对应基地址的偏移值PUPC_OFS EQU0x28;端口C上拉控制对应基地址的偏移值PUPD_OFS EQU0x38;端口D上拉控制对应基地址的偏移值PUPE_OFS EQU0x48;端口E上拉控制对应基地址的偏移值PUPF_OFS EQU0x58;端口F上拉控制对应基地址的偏移值PUPG_OFS EQU0x68;端口G上拉控制对应基地址的偏移值PUPH_OFS EQU0x78;端口H上拉控制对应基地址的偏移值PUPJ_OFS EQU0xD8;端口J上拉控制对应基地址的偏移值;--------端口配置--------------PIO_SETUP EQU0;端口APIOA_SETUP EQU0PCONA_Val EQU0x000003FF;端口BPIOB_SETUP EQU0PCONB_Val EQU0x00000000;PUPB_Val EQU0x00000000;端口B上拉开启;端口CPIOC_SETUP EQU1PCONC_Val EQU0x00001401;PUPC_Val EQU0x00000000;端口C上拉开启;端口DPIOD_SETUP EQU0PCOND_Val EQU0x00000000;PUPD_Val EQU0x00000000;端口D上拉开启;端口EPIOE_SETUP EQU0PCONE_Val EQU0x00000000;PUPE_Val EQU0x00000000;端口E上拉开启;端口FPIOF_SETUP EQU0PCONF_Val EQU0x00000000;PUPF_Val EQU0x00000000;端口F上拉开启;端口GPIOG_SETUP EQU0PCONG_Val EQU0x00000000;PUPG_Val EQU0x00000000;端口G上拉开启;端口HPIOH_SETUP EQU0PCONH_Val EQU0x000007FFPUPH_Val EQU0x00000000;端口H上拉开启;端口JPIOJ_SETUP EQU0PCONJ_Val EQU0x00000000;PUPJ_Val EQU0x00000000;端口J上拉开启;汇编程序数据8字节对齐PRESERVE8;c和汇编有8位对齐的要求,这个伪指令可以满足此要求;//存储区设定和程序入口点;//启动代码必须连接到第一个地址才能运行。
S3C2440 NANDFLASH启动过程分析

有很多同学在移植u-boot时,都会对s3c2440从Nandflash启动的过程非常迷惑。
这里发这个帖子给大家介绍一下它的启动流程。
大部分ARM9的CPU内部都集成有一个SRAM,SRAM是英文Static RAM的缩写,它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据。
这样他不需要初始化就能够直接使用。
这与我们在外部扩展的大容量的SDRAM是不一样的,外部大容量的SDRAM是需要初始化后才能使用的,这点大家务必要搞清楚。
这点在我做过移植的处理器:s3c2410(arm920t),s3c2440(arm920t),at91rm9200(arm920t),at91sam9260(arm926t) 上都是这样的。
在s3c2440这颗CPU上这个SRAM大小为4KB,datasheet里把它叫做Stepping Stone,江湖人称“起步石”。
Nandflash和Norflash是不同的:Norflash像内存一样是直接挂在系统总线上的,这样有足够多的地址线使得CPU能够寻址到每一个存储单元上去,这也意味着CPU能够直接通过总线访问Norflash上存储的内容,同时他还支持XIP(即片上执行,不用将代码搬到内存中,直接在Norflash上就能运行)。
而Nandflash它并不是直接挂载系统总线上,而是通过Nandflash控制器(这个一般集成在CPU内部)来完成读写操作的。
如果我们把Norflash的那种寻址方式叫直接寻址的话(不是汇编里的那个直接寻址,这里指CPU能够直接通过地址线访问存储器的存储单元),那么这里的Nandflash就是间接寻址(这里需要Nandflash控制器来寻址)。
所以我们在使用Nandflash之前,一定要初始化Nandflash控制器。
理解上面的这点后,就不难理解,为什么系统能够从Norflash直接启动,而不能直接从Nandflash启动。
这是因为,ARM在CPU复位时,CPU默认会到0x0000 0000地址处去取指令,而如果我们是从Norflash启动的话(一般Norflash会挂到Bank0,nGCS0上),s3c2440 CPU就会把Norflash的空间挂接到0x0000 0000这段内存空间上。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
由于片面问题,所以可能会看起来不太美观,可以看附件中的内容。
ARM启动代码相当于我们电脑的BIOS,也就是ARM启动时对处理器的一些初始化及嵌入式系统硬件的一些初始化。
由于它直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。
一般包括:中断向量表,初始化存储器系统,初始化堆栈,初始化有特殊要求的断口,设备初始化,变量初始化等。
这几天对着RealView MDK-ARM中自带的启动代码研究了一下,遇到问题又对着数据手册和指令表看了一下,总算对S3C2440A的硬件有了一个大致的了解。
学习嵌入式系统重在系统,学习ARM只是为学习嵌入式系统铺路,懒猫比较笨可能在上系统之前要裸奔几天以强化以下对S3C2440A内部结构的了解。
把MDK自带的S3C2440A.S文件的注释发一下,这些是懒猫结合数据手册与ARM指令表理解了,可能会有错误,放在这里只是引导一下像我一样还没有入门的兄弟们,希望你们不要害怕ARM害怕嵌入式,老毛他老人家说的对,世上无难事,只怕有心人,ARM指令就那么多,看一遍不会就多看几遍,还有一定要学习看软件自带的帮助文件.;/*****************************************************************************/;/* S3C2440.S: Startup file for Samsung S3C440 */;/*****************************************************************************/;/* <<< Use Configuration Wizard in Context Menu >>> */ ;/*****************************************************************************/;/* This file is part of the uVision/ARM development tools. */ ;/* Copyright (c) 2005-2008 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 softwar e */;/* development tools. Nothing else gives you the right to use this softwa re. */;/*****************************************************************************/;下面这些参数是与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 is disabled);F_Bit -- 如果F位被置1,则快速中断被禁止(FIQ is disabled);;----------------------------------------------------------------------Mode_USR EQU 0x10Mode_FIQ EQU 0x11Mode_IRQ EQU 0x12Mode_SVC EQU 0x13Mode_ABT EQU 0x17Mode_UND EQU 0x1BMode_SYS EQU 0x1FI_Bit EQU 0x80 ; when I bit is set, IRQ is disabledF_Bit EQU 0x40 ; when F bit is set, FIQ is disabled;-----------------------------栈初始化定义-----------------------------------;下面这些主要是栈配置,系统的栈空间设定;;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 0x00000000SVC_Stack_Size EQU 0x00000008ABT_Stack_Size EQU 0x00000000FIQ_Stack_Size EQU 0x00000000IRQ_Stack_Size EQU 0x00000080USR_Stack_Size EQU 0x00000400ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_St ack_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字节对齐。
;;下面这句话的意思是:;开辟一个堆栈段,段名字为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 ; Watchdog Timer Base Address WTCON_OFS EQU 0x00 ; Watchdog Timer Control Register Offse tWTDAT_OFS EQU 0x04 ; Watchdog Timer Data Register Offs etWTCNT_OFS EQU 0x08 ; Watchdog Timer Count Register Offs etWT_SETUP EQU 0WTCON_Val EQU 0x00000000WTDAT_Val EQU 0x00008000;----------------------------时钟与电源管理定义-------------------------;S3C2440A中的时钟控制逻辑可以产生必须的时钟信号,包括CPU的FCLK,A HB总线的;HCLK 以及APB总线外设的PCLK 3C2440A内部有两个锁相环(PLL):一个提供FCLK,;HCLK及PCLK,另一个专用于USB模块(48MHz).;;CLOCK_BASE -- 时钟基地址;LOCKTIME_OFS -- 锁相环锁定时间计数寄存器偏移地址,相对于基址;MPLLCON_OFS -- MPLL配置寄存器偏移地址,相对于基址,主时钟源PLL ;UPLLCON_OFS -- UPLL配置寄存器偏移地址,相对于基址,USB时钟源P LL;CLKCON_OFS -- 时钟控制寄存器偏移地址,相对于基址;CLKSLOW_OFS -- 时钟减慢控制寄存器偏移地址,相对于基址;CLKDIVN_OFS -- 时钟分频器控制寄存器偏移地址,相对于基址;CAMDIVN_OFS -- 摄像头时钟分频器控制寄存器偏移地址,相对于基址,UP LL提供;;CLOCK_SETUP -- 时钟设置;LOCKTIME_Val -- PLL锁定时间计数器值;MPLLCON_Val -- MPLL配置寄存器值;UPLLCON_Val -- UPLL配置寄存器值;CLKCON_Val -- 时钟配置寄存器值;CLKSLOW_Val -- 时钟减慢控制寄存器值;CLKDIVN_Val -- 时钟分频控制寄存器值;CAMDIVN_Val -- 摄像头分频控制寄存器值;-----------------------------------------------------------------------CLOCK_BASE EQU 0x4C000000 ; Clock Base Address LOCKTIME_OFS EQU 0x00 ; PLL Lock Time Count Register Offs etMPLLCON_OFS EQU 0x04 ; MPLL Configuration Register Offset UPLLCON_OFS EQU 0x08 ; UPLL Configuration Register Offset CLKCON_OFS EQU 0x0C ; Clock Generator Control Reg Offse tCLKSLOW_OFS EQU 0x10 ; Clock Slow Control Register Offset CLKDIVN_OFS EQU 0x14 ; Clock Divider Control Register Offse tCAMDIVN_OFS EQU 0x18 ; Camera Clock Divider Register Offs etCLOCK_SETUP EQU 0LOCKTIME_Val EQU 0x0FFF0FFFMPLLCON_Val EQU 0x00043011UPLLCON_Val EQU 0x00038021CLKCON_Val EQU 0x001FFFF0CLKSLOW_Val EQU 0x00000004CLKDIVN_Val EQU 0x0000000FCAMDIVN_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 ; Memory Controller Base Addres sBWSCON_OFS EQU 0x00 ; Bus Width and Wait Status Ctrl Offs etBANKCON0_OFS EQU 0x04 ; Bank 0 Control Register Offset BANKCON1_OFS EQU 0x08 ; Bank 1 Control Register Offset BANKCON2_OFS EQU 0x0C ; Bank 2 Control Register Offset BANKCON3_OFS EQU 0x10 ; Bank 3 Control Register Offset BANKCON4_OFS EQU 0x14 ; Bank 4 Control Register Offset BANKCON5_OFS EQU 0x18 ; Bank 5 Control Register Offset BANKCON6_OFS EQU 0x1C ; Bank 6 Control Register Offs etBANKCON7_OFS EQU 0x20 ; Bank 7 Control Register Offs etREFRESH_OFS EQU 0x24 ; SDRAM Refresh Control Register OffsetBANKSIZE_OFS EQU 0x28 ; Flexible Bank Size Register Off setMRSRB6_OFS EQU 0x2C ; Bank 6 Mode Register Offs etMRSRB7_OFS EQU 0x30 ; Bank 7 Mode Register Offs etMC_SETUP EQU 1BWSCON_Val EQU 0x22000000BANKCON0_Val EQU 0x00000700BANKCON1_Val EQU 0x00000700BANKCON2_Val EQU 0x00000700BANKCON3_Val EQU 0x00000700BANKCON4_Val EQU 0x00000700BANKCON5_Val EQU 0x00000700BANKCON6_Val EQU 0x00018005BANKCON7_Val EQU 0x00018005REFRESH_Val EQU 0x008404F3BANKSIZE_Val EQU 0x00000032MRSRB6_Val EQU 0x00000020MRSRB7_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 Base AddressGPB_BASE EQU 0x56000010 ; GPB Base AddressGPC_BASE EQU 0x56000020 ; GPC Base AddressGPD_BASE EQU 0x56000030 ; GPD Base AddressGPE_BASE EQU 0x56000040 ; GPE Base AddressGPF_BASE EQU 0x56000050 ; GPF Base AddressGPG_BASE EQU 0x56000060 ; GPG Base AddressGPH_BASE EQU 0x56000070 ; GPH Base AddressGPJ_BASE EQU 0x560000D0 ; GPJ Base Address GPCON_OFS EQU 0x00 ; Control Register Offset GPDAT_OFS EQU 0x04 ; Data Register OffsetGPUP_OFS EQU 0x08 ; Pull-up Disable Register Offset GP_SETUP EQU 1;-----------------------------------------------------------------------;端口A配置;----------------------------------------------------------------------- GPA_SETUP EQU 0GPACON_Val EQU 0x000003FF;----------------------------------------------------------------------- ;端口B配置;----------------------------------------------------------------------- GPB_SETUP EQU 0GPBCON_Val EQU 0x00000000GPBUP_Val EQU 0x00000000;----------------------------------------------------------------------- ;端口C配置;----------------------------------------------------------------------- GPC_SETUP EQU 0GPCCON_Val EQU 0x00000000GPCUP_Val EQU 0x00000000;----------------------------------------------------------------------- ;端口D配置;----------------------------------------------------------------------- GPD_SETUP EQU 0GPDCON_Val EQU 0x00000000GPDUP_Val EQU 0x00000000;----------------------------------------------------------------------- ;端口E配置;----------------------------------------------------------------------- GPE_SETUP EQU 0GPECON_Val EQU 0x00000000GPEUP_Val EQU 0x00000000;----------------------------------------------------------------------- ;端口F配置;----------------------------------------------------------------------- GPF_SETUP EQU 0GPFCON_Val EQU 0x00000000GPFUP_Val EQU 0x00000000;----------------------------------------------------------------------- ;端口G配置;----------------------------------------------------------------------- GPG_SETUP EQU 0GPGCON_Val EQU 0x00000000GPGUP_Val EQU 0x00000000;-----------------------------------------------------------------------;端口H配置;-----------------------------------------------------------------------GPH_SETUP EQU 0GPHCON_Val EQU 0x00000000GPHUP_Val EQU 0x00000000;-----------------------------------------------------------------------;端口J配置;-----------------------------------------------------------------------GPJ_SETUP EQU 0GPJCON_Val EQU 0x00000000GPJUP_Val EQU 0x00000000;-----------------------------------------------------------------------;PRESERVE8 -- 伪指令,指示当前文件请求堆栈为8字节对齐。