韦东山移植学习----005uboot --编写第一阶段

uboot 第一阶段主要涉及文件:

start.S uboot.lds init,c makefiles
start.S
a.关看门狗 (让寄存器 0x53000000 置0)
b.设置时钟 (FCLK=200M,PCLK=50M)
cpu总线设置为异步模式
c.初始化SDRAM,把值写入SDRAM(可以c语言版,也可以汇编版式)
d.初始化nand flash 、(设置栈c语言)代码重定位 ==>init.c、uboot.lds
bl nand_init
--------------------------------------------------
//想用c语言来写的话先设置栈
mov r0,#0 /源:r0表示第一个参数,第一个参数是0/
ldr r1,=_start /目的地:连接地址,0x33f80000;第一个标号:_start/
ldr r2,=_bss_start /*伪汇编指令,两个,直接得到这个值*/
sub r2,r2,r1 /长度,要写Makefile和连接地址/
-----------------------------------------------------------
bl copy_code_to_sdram
bl clean_bss
void clean_bss(void)
{ //c语言里面引用链接脚本里的_bss_start, __bss_end :固定语法
extern int __bss_start, __bss_end; /定义为外部的变量/
int *p = &__bss_start; /取他们的地址/
for(;p<& __bss_end;p++)
{ *p=0; }
}
e.执行main函数 ==>main.c
ldr lr, =halt /设置main的返回地址/
ldr pc, =main /想让他跳到main函数执行/
/假设main能够返回,有返回值/
init.c
copy_code_to_sdram
if(isBootFromNorFlash()) //判断Nor启动还是nand启动
else
nand_read((unsigned int)addr,dest,len);/参数哪里来?从汇编里调入/
nand_select();
/b.发出读命令00h/
nand_cmd(0x00);
/c.发出地址(分5步发出)/
nand_addr(addr);
/d.发出读命令30h–确定要读/
nand_cmd(0x30);
/e.判断状态/
nand_wait_ready();
/f.读数据/
buf[i] =nand_data();

**

具体程序

**

Start.S

#define s3c2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define s3c2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE 0x48000000

.text /代码段/
.global _start //全局标号
_start:
/a.关看门狗/
ldr r0,=0x53000000 //伪汇编指令
mov r1,#0
str r1,[r0] //r1->0

/*b.设置时钟,让CPU运行快点 */
/FCLK:HCLK:1:2:4,HDIVN=1,PDIVN=1/
ldr r0,=0x4c000014
mov r1,#0x03
str r1,[r0]

/手册要求,如果HDIVN非0,CPU总线模式应该从"fast bus mode"变为"asynchronous"/
mrc p15,0,r1,c1,c0,0 /读出控制寄存器/
orr r1,r1,#0xc0000000 /设置为asynchronous/
mcr p15,0,r1,c1,c0,0

/* MPLLCON=s3c2440_MPLL_200MHZ*/ //FCLK=200M,PCLK=50M
ldr r0,=0x4c000004
ldr r1,=s3c2440_MPLL_200MHZ/MHZ/
str r1,[r0]

/*启动ICACHE
mrc p15,0,r0,c1,c0,0 @ read control reg
orr r0,r0,#(1<<12)
mcr p15,0,r0,c1,c0,0 @ write it back

*/

/c.初始化SDRAM/
ldr r0,=MEM_CTL_BASE
adr r1,sdram_config /伪指令,得到标号的当前地址,非连接地址/
add r3,r0,#(4*13) /读出内存末地址/
1:
ldr r2,[r1],#4 /读出来之后地址+4 ,从r1读出一个值给r2 ,然后r1+4/
str r2,[r0],#4 /存r2的值/
cmp r0,R3
bne 1b /如果不相等,跳回去,1b:后面的1标号 1f:前面的1标号,可以有多个1标号/

/d.重定位(把bootload本身的代码从flash复制到它的连接地址)/
ldr sp,= 0x34000000 /想调用C语言前,要先设置栈/
/*设置栈,让栈指向一块内存就可以了,
*这个内存是64M,基地址是0x30000000,
让他指向最高内存,往下增长/

bl nand_init					/*如果nor启动,就没有调用nandflash,
								 *但最后还是要从nandflash把内核,也要调用nand_init*/
								 
								/*nand_read的参数哪里来*/
mov r0,#0						/*源:r0表示第一个参数,第一个参数是0*/
ldr r1,=_start					/*目的地:连接地址,0x33f80000;第一个标号:_start*/
ldr r2,=__bss_start				/*伪汇编指令,两个_,直接得到这个值*/
sub r2,r2,r1					/*长度,要写Makefile和连接地址*/
//想用c语言来写的话
bl copy_code_to_sdram
bl clean_bss					//bl相对跳转

/e.执行main/
//bl main /相对跳转,根据当前指令,找到main函数的偏差值,跳过去/

ldr lr, =halt /*设置main的返回地址*/
ldr pc, =main /*想让他跳到main函数执行*/
				/*假设main能够返回,有返回值*/

halt:
b halt

//把这些值存放到SDRAM里面去
sdram_config:
.long 0x22011110 /BWSCON/
.long 0x00000700 /BANKCON0/
.long 0x00000700 /BANKCON1/
.long 0x00000700 /BANKCON2/
.long 0x00000700 /BANKCON3/
.long 0x00000700 /BANKCON4/
.long 0x00000700 /BANKCON5/
.long 0x00018005 /BANKCON6/
.long 0x00018005 /BANKCON7/
.long 0x008c04F4 /REFRESH/
.long 0x000000B1 /BANKSIZE/
.long 0x00000030 /MRSRB6/
.long 0x00000030 /MRSRB7/

初始化SDRAM(c语言版本,要先设置栈)
在这里插入图片描述
设置nand_flash时序在这里插入图片描述
在这里插入图片描述

init.c

/oob是为了解决nand_flash的位反转问题
怎么访问00B
1)OOB里的第0字节
2)这一页里的第2048个
/nand FLASH 控制器/
#define NFCONF (
(volatile unsigned long )0x4E000000) /(volatile unsigned char )0x4E000000为指针/
#define NFCONT (*(volatile unsigned char )0x4E000004) / (volatile unsigned char )0x4E000004为指针的值/
#define NFCMMD (
(volatile unsigned char )0x4E000008)
#define NFADDR (
(volatile unsigned char )0x4E00000C)
#define NFDATA (
(volatile unsigned char )0x4E000010)
#define NFSTAT (
(volatile unsigned char *)0x4E000020)

/GPIO配置串口,GPH2,GPH3用做TXD0,RXD0/
#define GPHCON (*(volatile unsigned long )0x56000070)
#define GPHUP (
(volatile unsigned long *)0x56000078)

/UART0 registers/
#define ULCON0 (*(volatile unsigned long )0x50000000)
#define UCON0 (
(volatile unsigned long )0x50000004)
#define UFCON0 (
(volatile unsigned long )0x50000005)
#define UMCON0 (
(volatile unsigned long )0x5000000C)
#define UTRSTAT0 (
(volatile unsigned long )0x50000010)
#define UTXH0 (
(volatile unsigned long )0x50000020)
#define URXH0 (
(volatile unsigned long )0x50000024)
#define UBRDIV0 (
(volatile unsigned long *)0x50000028)

#define UART_BRD 115200

void nand_init(void);
void uart0_init(void);
void putc(unsigned char c);
void puts(char *str);
void uart0_init(void)
{
GPHCON |= 0xa0; /GPH2,GPH3用做TXD0,RXD0/
GPHUP = 0x0c; /GPH2,GPH3内部上拉/

ULCON0 = 0x03;				/*8n1(8个数据位,无校验,一个停止位)*/
UCON0  = 0x05;				/*查询方式,UART时钟源为PCLK*/
UFCON0 = 0x00;				/*不适应FIFO*/
UMCON0 = 0x00;				/*不使用流控*/
UBRDIV0 = UART_BRD;			/*波特率为115200*/

}

void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/设置时序 nandflash手册 芯片2440 对照/
NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
/使能NAND Flash控制器,初始化ECC,禁止片选/
NFCONT = (1<<4)|(1<<1)|(1<<0);
}

void putc(unsigned char c)
{
while(!(UTRSTAT0 & (1<<2)));
UTXH0=c;
}

void puts(char *str)
{
int i=0;
while(str[i])
{
putc(str[i]);
i++;
}

}

void nand_select()
{
NFCONT &=~(1<<1);
}

void disnand_select()
{
NFCONT |= (1<<1);
}

void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD =cmd;
for(i = 0;i < 10; i++); /发完命令后要加等待才算真正发了出去,立刻发可能会有问题/
}

void nand_addr(unsigned char addr)
{ /5个周期,前两个是列地址Column Address/
unsigned int col = addr %2048; /col这一页内哪一个地址(列地址),2048是11位/
unsigned int page = addr /2048; /**/
volatile int i;
NFADDR = col & 0xff;
for(i = 0;i < 10; i++);
NFADDR = (col >> 8) & 0xff;/表示从这一页的哪一列开始访问/
for(i = 0;i < 10; i++);

NFADDR = page & 0xff;/*要访问哪一页*/
for(i = 0;i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for(i = 0;i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for(i = 0;i < 10; i++);

}

void nand_wait_ready(void)
{
while(!(NFSTAT & 1)); /1表示接收完成/

}

unsigned char nand_data()
{
return NFDATA; /读这个寄存器就可以/

}

void nand_read(unsigned int addr,unsigned char *buf,unsigned int len)
{
int col = addr/2048; /有可能不是从0开始,而是从一页的某一列地址开始/
int i=0;
/a.选中/
nand_select();

while(i<len)

{
/b.发出读命令00h/
nand_cmd(0x00);
/c.发出地址(分5步发出)/
nand_addr(addr);
/d.发出读命令30h–确定要读/
nand_cmd(0x30);
/e.判断状态/
nand_wait_ready();
/f.读数据/
for(;(col<2048) && (i<len);col++)
{
buf[i] =nand_data();
i++;
addr++;
}
col=0;
}

}

int isBootFromNorFlash(void)
{

unsigned int val;
volatile int *p=(volatile int *)0;  /*建立一个指针值向0地址*/
val = *p;
*p = 0x12345678;
if (*p==0x12345678)
{
	*p =val;
	return 0;						/*boot from nand,nand启动==>对应的是内存*/
}
else
{
	*p=val;							/*NOR不能像内存一样读*/
	return 1;
}

}

void copy_code_to_sdram(unsigned char *addr,unsigned char *dest,unsigned int len)
{
/从哪里拷贝:addr 目的地是dest,长度是len/

unsigned int i=0;
/*如果是NOR启动*/
if(isBootFromNorFlash())
{
	while(i<len)
	{
	   dest[i]=addr[i];  //*dest = *src 
	}
}
else
{
	nand_read((unsigned int)addr,dest,len);/*参数哪里来?从汇编里调入*/
}

}

void clean_bss(void)
{ //c语言里面引用链接脚本里的_bss_start, __bss_end :固定语法
extern int __bss_start, __bss_end; /定义为外部的变量/
int *p = &__bss_start; /取他们的地址/
for(;p<& __bss_end;p++)
{ *p=0; }
}

boot.lds
SECTIONS {
. = 0x33f80000; //省麻烦,跟最高地址相差512K 直接放在512K
.text : { *(.text) }

. = ALIGN(4);				//当前地址取整
.rodata : {*(.rodata)}

. = ALIGN(4);
.data : {*(.data)}

__bss_start = .;			/*文件的大小等于这个地址-0x33f80000*/
.bss : { *(.bss)  *(COMMON)}//bss段:未初始化的变量或初始化为0的变量
__bss_end = .;				//编译出来的二进制文件里面不含有为0

}

Makefile
CC = arm-linux-gcc
LD = arm-linux-ld
AR = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump

CFLAGS := -Wall -O2
CPPFLAGS := -nostdinc -fno-builtin

objs := start.o init.o boot.o

boot.bin:$(objs)
${LD} -Tboot.lds -o boot_elf $^
${OBJCOPY} -O binary -S boot_elf $@
${OBJDUMP} -D -m arm boot_elf > boot.dis

%.o:%.c
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S
${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:
rm -f *.o *.bin *_elf *.dis

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
也可去华为网盘下载! http://dl.dbank.com/c0f2x98c6n# 第1课 环境搭建及工具、概念介绍 第2课 GPIO实验 第3课 存储管理器实验 第4课 MMU实验 第5课 NAND FLASH控制器 第6课 中断控制器 第7课 系统时钟和UART实验 第8课 LCD实验 第9课第1节 u-boot分析之编译体验 第9课第2节 u-boot分析之Makefile结构分析 第9课第3节 u-boot分析之源码第1阶段 第9课第3节 u-boot分析之源码第2阶段 第9课第4节 u-boot分析之u-boot命令实现 第9课第5节 u-boot分析_uboot启动内核 第10课第1节 内核启动流程分析之编译体验 第10课第2节 内核启动流程分析之配置 第10课第3节 内核启动流程分析之Makefile 第10课第4节 内核启动流程分析之内核启动 第11课第1节 构建根文件系统之启动第1个程序 第11课第2节 构建根文件系统之init进程分析 第11课第3节 构建根文件系统之busybox 第11课第4节 构建根文件系统之构建根文件系统 第12课第1节 字符设备驱动程序之概念介绍 第12课第2.1节 字符设备驱动程序之LED驱动程序_编写编译 第12课第2.2节 字符设备驱动程序之LED驱动程序_测试改进 第12课第2.3节 字符设备驱动程序之LED驱动程序_操作LED 第12课第3节 字符设备驱动程序之查询方式的按键驱动程序 第12课第4.1节 字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构 第12课第4.2节 字符设备驱动程序之中断方式的按键驱动_Linux中断处理结构 第12课第4.3节 字符设备驱动程序之中断方式的按键驱动_编写代码 第12课第5节 字符设备驱动程序之poll机制 第12课第6节 字符设备驱动程序之异步通知 第12课第7节 字符设备驱动程序之同步互斥阻塞
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值