热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TX2440开发板学习笔记---uboot

TX2440开发板学习笔记---uboot--Linux通用技术-Linux编程与内核信息,下面是详情阅读。
按照gooogleman老兄的建议,从优龙2440板子的bootloader学起。首先先将程序运行起来,step执行,搞清楚每步做了什么,为什么这么做。将整体的流程学习一遍。等1个月,2个月,无论多长时间,当自己真正掌握后,再将整体的代码加上注释,做成PDF文档。分给后来者,去帮助像我现在这样水平的小小鸟。
OK,第一话开始:
程序入口点:
程序最开始跳到2440init.s文件,执行如下代码:b ResetHandler 跳转到复位异常处理程序。
ResetHandler
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
(将看门狗定时器清零,查看datasheet,WTCON的第0位是看门狗定时器复位输出信号开关。为0,则程序关闭了S3C2440A的看门狗复位功能。)
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
(将中断屏蔽寄存器全部置1,将对应的中断全部关闭。)
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable `
str r1,[r0]
(将子中断屏蔽寄存器全不置1,将子中断屏蔽寄存器对应的中断全部关闭。)
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str 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:Pclk
ldr r0,=CLKDIVN
ldr r1,=CLKDIV_VAL ; 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语言里面的
Ifdef
Else
Endif)
(CLKDIVN是时钟分频器控制寄存器,设置的值为CLKDIV_VAL宏。我这里设置的是CLKDIV_VAL EQU 5 ;1:4:8)
继续执行:
[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
|
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
mcr p15,0,r0,c1,c0,0
]
由于我这里CLKDIV_VAL的值为5,所以执行
mrc p15,0,r0,c1,c0,0 <1>
orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA <2>
mcr p15,0,r0,c1,c0,0 <3>
<1> mrc是协处理器命令。用于读取协处理器中的寄存器的数据到ARM处理器的寄存器里面。这句话的意思应该是读协处理器中的寄存器数据到ARM处理器的r0里面。应该是ARM访问MMU,一般cp15就是MMU。这三条指令的目的是将MMU的30,31位置1。
功能如下:31位(iA bit)Function:Asynchronous clock select (选择异步时钟)
30位(nF bit)Function: notFastBus select
ldr r0,=UPLLCON
ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
str r1,[r0]
(配置UPLL,一般UPLL的值设置为48MHZ,或者96MHZ,因为一般较难找到一个合适的PLL值,所以手册上推荐了一些。本程序中有如下宏定义:#define UCLK 48000000(在option.h文件中),则对应手册上的推荐值,MDIV=56,PDIV=2,SDIV=2)
(在option.inc文件中又有如下代码,通过这段代码已经确定了U_MDIV,U_PDIV ,U_SDIV值,那么上面的代码就是将相应分频值写入到UPLLCON。详细的内容去看数据手册的第7章,时钟与电源管理部分。)
[ UCLK = 48000000
U_MDIV EQU 56 ;Fin=12.0MHz Fout=48MHz
U_PDIV EQU 2
[ CPU_SEL = 32440001
U_SDIV EQU 2 ; 2440A(我们设置的是这个值,因为用的芯片是S3C2440A)
|
U_SDIV EQU 1 ; 2440X
]
]
程序继续执行:
nop
nop
nop
nop
nop
nop
nop
这里面插入了7个nop,在设置完UPLLCON寄存器后,需要至少延时7-clocks,等待硬件的配置完成。
;Configure MPLL
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz
str r1,[r0]
接下来配置MPLLCON寄存器,与UPLLCON部分相同,优龙2440的板子主频是400MHZ。
[ FCLK = 400000000
CLKDIV_VAL EQU 5 ;1:4:8
M_MDIV EQU 92 ;Fin=12.0MHz Fout=400MHz
M_PDIV EQU 1
[ CPU_SEL = 32440001
M_SDIV EQU 1 ; 2440A
|
M_SDIV EQU 0 ; 2440X
]
]
则M_MDIV=92,M_PDIV=1,M_SDIV=1.本程序段将这几个值写入到了MPLLCON寄存器。
;Check if the boot is caused by the wake-up from SLEEP mode.
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2
;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
bne WAKEUP_SLEEP
检查引导程序是否是从休眠模式被唤醒的,如果是的话,就跳转到相应的程序段进行处理。
这里面用到了一个tst指令。首先了解一下这个指令。
tst是位测试指令,根据测试结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
再来看GSTATUS2这个寄存器,查询芯片手册,GSTATUS2是复位状态寄存器,本程序测试的是它的第1位(0010),“Boot is caused by wakeup reset in sleep mode”,这个标志代表引导程序是从休眠模式被唤醒的。由于我这里并不是从休眠模式唤醒的,所以程序没有跳转,继续顺序执行。
;Set memory control registers
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful!, hzh
ldr r1,=BWSCON ;BWSCON Address
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
mov r0, #&1000
1
subs r0, r0, #1
bne %B1
这里是设置存储器控制寄存器。首先还是了解一下adrl指令,它是中等范围的地址读取指令,比ADR伪指令可以读取更大范围的地址。SMRDATA是一个标号,将这个标号处的地址加载到了r0。BWSCON是总线宽度与等待控制寄存器,将这个寄存器的地址加载到了r1。然后将SMRDATA+52地址值加载到r2,这个地址是SMRDATA的尾地址。在SMRDATA地址处存放的是用DCD指令分配的一定大小的字内存单元,这段内存存放的就是与存储器相关的控制寄存器的配置参数。再来看BWSCON的地址是0x48000000,然后是BANKCON0(Bank0 控制寄存器)的地址是0x48000004,BANKCON1(Bank0 控制寄存器)的地址是0x48000008,以此类推,一直到BANKCON7的地址是0x48000020。接着是REFRESH(SDRAM 刷新控制寄存)地址是:0x48000024,BANKSIZE(可调的bank 大小寄存器)地址是:0x48000028,MRSRB6(模式寄存器集寄存器bank6)地址是:0x4800002C,MRSRB7(模式寄存器集寄存器bank7)地址是:0x48000030。上面这些寄存器都是存储器控制的相关寄存器,地址全部连续,相差0x04. 那么现在知道了为什么ldr r3, [r0], #4,str r3, [r1], #4,这两段代码,先将SMRDATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed
ldr r0,=GPFCON
ldr r1,=0x0
str r1,[r0]
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0]
ldr r1,=GPFDAT
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
bne %F1
; Clear SDRAM Start
ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0] ;LED=****
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldr r9,=0x4000000 ;64MB
ldr r0,=0x30000000
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
;Clear SDRAM End
1
;Initialize stacks
bl InitStacks
接下来是这段比较长的代码,总体的作用就是,如果 EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM。分析之前先搞清一个知识点,这段代码里面有一个bne %B0,还有一个bne %F1,这两句代码是什么意思呢?%B代表向前搜索,%F代表向后搜索,“0”“1”只是标号而已。也就是不等于则向前后者向后跳转到标号0或者标号1的位置。
ldr r0,=GPFCON
ldr r1,=0x0
str r1,[r0]
GPF0-GPF7都被设置成了input。
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0]
GPF0-GPF7都被禁止上拉。
ldr r1,=GPFDAT
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
bne %F1
这段代码则是检测EINT0的输入。有输入则清空SDRAM,没输入就直接向下跳到标号1
处。再来看bic指令。举个例子,BIC R1,R2,R3则是将R3的反码和R2逻辑与,结果保存到R1。这里为什么是0x1e,我也不是很理解。反正0x1e倒是可以。一会到CSDN去发帖。弄清楚了,再补充进来。tst r0,#0x1这段指令就是测试最低位是否为0.
; Clear SDRAM Start
ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0] ;LED=****
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldr r9,=0x4000000 ;64MB
ldr r0,=0x30000000
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
;Clear SDRAM End
这段代码则是清空SDRAM。
ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
GPF0-GPF3设置为中断EINT0-EINT3,GPF4-GPF7设置为输出。
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
全部禁止上拉。
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0]
将GPFDAT全部置0.GPF4-GPF7输出低电平。
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
将r1-r8寄存器内容设置为0,用来做清空SDRAM用的。
ldr r9,=0x4000000 ;64MB
ldr r0,=0x30000000
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
r9中装入的值是SDRAM的容量大小,r0中装入的值是SDRAM的首地址。
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
这段代码用来循环清零,直到SDRAM全部清空为止。
1
;Initialize stacks
bl InitStacks
当然如果在代码前段,没有按下按键的话,就直接跳到标号1处的这段代码,跳转到初始化堆栈的地方了。事实上,基本不会在此处按下按键,所以清空SDRAM的代码基本不会执行。
接着向下看:
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack ; UndefStack=0x33FF_5C00
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack ; AbortStack=0x33FF_6000
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack ; IRQStack=0x33FF_7000
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode
ldr sp,=FIQStack ; FIQStack=0x33FF_8000
bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack ; SVCStack=0x33FF_5800
这段代码则是分别初始化各种模式的堆栈。以初始化未定义模式堆栈为例。先将CPSR读取到r0,然后利用bic指令,将控制模式的低5位清零。之后设置(或上)为未定义模式,禁止中断,将结果保存到r1,然后将r1保存到CPSR。接着ldr sp,=UndefStack 设置堆栈。堆栈的地址值,为UndefStack宏,具体是多少查看宏定义即可。程序注释中也已经标注了。
需要知道orr r1,r0,#UNDEFMODE|NOINT,这条指令执行之后,r0寄存器中的值是无变化的,所以以后初始化其他堆栈的时候,可以接着拿r0来用。初始化其他模式堆栈,与此相同,不再赘述。
mov pc,lr 程序跳转回去。(转)
推荐阅读
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 31.项目部署
    目录1一些概念1.1项目部署1.2WSGI1.3uWSGI1.4Nginx2安装环境与迁移项目2.1项目内容2.2项目配置2.2.1DEBUG2.2.2STAT ... [详细]
  • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文介绍了200个经典c语言源代码,包括函数的使用,如sqrt函数、clanguagefunct等。这些源代码可以帮助读者更好地理解c语言的编程方法,并提供了实际应用的示例。 ... [详细]
  • 本文讲述了作者从最初对软件工程的选择迷茫到逐渐喜欢并坚持学习的经历。作者在大学期间通过学习专业课和参与项目开发,不断挑战自己并取得成就感。虽然曾考虑过转专业和复读,但最终决定坚持学习软件工程,并为自己的未来努力奋斗。作者还提到了大学生活与自己最初的预期不同,但对此并没有太多抱怨。 ... [详细]
  • 《2017年3月全国计算机等级考试二级C语言上机题库完全版》由会员分享,可在线阅读,更多相关《2017年3月全国计算机等级考试二级C语言上机题库完全版( ... [详细]
  • 说到C语言的语句块,真是一堆血泪史。第一大坑就是优先级。刚工作那会儿,C的书没看几本,自信满满的认为C语言都会了,拿出搞ACM培养的豪情壮志,代码倒是写得爽,却到处留 ... [详细]
author-avatar
mobiledu2502920327
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有