六:mini2440實現自己寫bootloader

自己實現Uboot啓動:

前言:

想想 uboot 的代碼量,我們說自己寫一個 bootloader 是不是口出狂言了?然而並沒有,bootloader 的唯一目的只有一個,那便是啓動內核。內核就是一大段可執行程序,我們只要跳轉到它的入口地址去執行不就OK? 所以,寫一個簡單的 bootloader 並不困難。
現在來思考一下,目的是啓動內核,那麼內核在哪裏?剛上電的時候,內核肯定是位於 nandflash 裏的,我們得具備初始化 nandflash 並讀取的功能。那麼,我們將內核去讀到 sdram 然後跳轉到入口地址去執行就夠了麼?然而還不行,bootloader 啓動內核時還需要給內核傳遞一些信息(tag),兩個必不可少的信息是 內存標記和命令行參數。信息傳遞完,那麼內核就一定能起得來麼?未必,啓動內核時,我們還會傳遞一個機器ID,如果Uboot傳遞進去的機器ID和內核支持的機器ID不匹配,那麼內核也無法啓動。想必,分析過 uboot 的同學對這個並不陌生。

一、自己寫 bootloader ,或者移植 uboot ,需要知道的一些信息
1、內核在 nandflash 中的地址,是 uImage 還是 zImage ,我這裏用的是 uImage ,在 nandflash 裏的 0x60000處,uImage 是用來支持 uboot 啓動的,不過我們自己寫的話用 uImage 也沒關係,因爲 uImage 就是在 zImage 的基礎上加了一個 64 字節的頭部,用來告訴 uboot 內核的信息,比如版本號、加載地址、鏈接地址、編譯時間等。uboot 會獲取到這個頭部,幹一些事情。我們自己寫的話,就不需要頭部了,從NAND FLASH裏把內核讀入內存,直接跳到 uImage 啓示地址 + 64 的地方去讀就OK 。
2、內核的鏈接地址:0x30008000 ,這個連接地址實際上應該說是“真正”內核的鏈接地址,如果是 uImage ,不應該包含它的頭部。知道什麼意思了吧,使用 uImage 時,我們應當將整個 uImage 拷貝到 0x30008000 - 64 的地方去,也就是 0x30007fc0 。使用uImage的時候就是0x30008000 。

3、bootloader 的連接地址:uboot的鏈接地址一般爲 0x3ff80000 處,內存是64M的,最大地址爲0x3ff80000 ,我們自己寫的也用這個地址好了。說到這裏,必須得提一下,對於2440來說,不管是 nand 啓動,還是 nor 啓動,剛上電的時候我們的 bootloader 並不是運行在鏈接地址處,那麼這時候跑在非鏈接地址處的這些指令就得有特殊要求——位置無關碼。我們要在將自身代碼拷貝到鏈接地址處之前,能用匯編寫的儘量不用C寫,因爲用匯編我們自己可以分得清哪些是位置無關碼,迫不得已的情況下用C寫,寫完看反彙編,看看那些跳轉指令是否依賴於當前PC值。

4、標記 tag 的地址,2440 常用的做法是放在 0x30000100 處,我們同樣也放在這裏。其實放那都行,地址會作爲參數傳遞給內核的。tag的放置方法,可以參考 uboot ,必須以 ATAG_CORE 類型的開頭,以 ATAG_NONE 類型的結尾。
5、啓動內核時傳遞給內核的參數,3個,第一個默認0,第三個是前邊提到的 tag 的地址,第二個是機器ID。內核中所有支持的“機器”或者稱作開發板、單板都用一個 MACHINE_START 宏來定義,這個宏的作用就是填充一個 machine_desc 類型的結構體,填充的過程中會對它的 .nr 成員賦值,這個 nr 就是所謂的機器ID。
6、內核剛啓動時會打印一些信息,但是那時候內核自己並不會初始化串口,也爲了方便自己調試,bootloader裏需要初始化串口。

前面的是引用的一篇總結的好的博文

我主要寫我自己遇到的問題:

在這裏插入圖片描述
Uboot基本實現的是:關閉看門狗,設置時鐘,初始化SDRAM,代碼重定位,執行main。
在這裏插入圖片描述
在這裏插入圖片描述
Sdram_config:中記錄的是每一個寄存器所需要的值,依次賦給內存控制器的寄存器。
Bne 1b 的b的意思是back ,向後跳轉,所以可以有很多個1標號。1f是向前跳轉。
但是我自己寫用的是以前調試好的C函數。這裏注意了要用到函數一定要先設置堆棧。

現在lyboot是實現啓動內核功能,那麼就需要將nandflash裏面的內核拷貝到sdram裏面啓動起來,就要做nand初始化,nand讀操作。初始化nand,需要對照nand芯片手冊進行時序的設置。只需要去看CPU能設置的時序就行了。這裏寫nand初始化的時候我還沒有看裸機的nand分析,但是跟到韋老師仍然是可以實現的,但是遇到了很大一個問題,在後面會說明。先看nand的時序:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

1.根據nand芯片查到的twp間隔最小是15/12ns,設置TWRPH0在寄存器NFCONF裏面。
在這裏插入圖片描述
HCLK爲100MHZ,則10ns*(TWRPH0+1)>15/12ns,TWRPH0可以設置爲1以上。
2.根據nand芯片查到的tcls間隔最小也是15/12ns,對應的TACLS可以爲0表示同時發出,那麼設置TACLS在寄存器NFCONF裏面。
3.根據nand芯片查到的tclh間隔最小是5ns,那麼設置TWRPH1在寄存器NFCONF裏面。
HCLK爲100MHZ,則10ns*(TWRPH0+1)>10/5ns,TWRPH0可以設置爲0以上。
這樣初始化的代碼基本可以確定了:

void Nand_init(void)
{
	#define TACLS  0
	#define TWRPH0 2
	#define TWRPH1 0
	/*設置時序*/
	NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
	/*使能Nand控制器,初始化ECC-校驗碼,禁止片選*/
	NFCONT = (1<<4)|(1<<1)|(1<<0);
	
}

接下來是對nandflash進行讀操作:
在這裏插入圖片描述
在這裏插入圖片描述
讀寫nand,要了解nand flash的分佈,根據原理圖來看nand連接了8位地址線,但是nand flash那麼大,8位肯定不夠,所以有地址週期來發送地址信號。一個nand有128K頁,一個大小爲2048B加64B的OOB(nand有缺陷的,需要校驗碼ECC,這裏OOB看韋老師的博客寫的內容),然後讀寫時根據列地址,確定第幾列,由行地址確定是哪一頁。

讀操作的時序:

在這裏插入圖片描述
要操作Nand時,先要發出片選信號,然後發送命令00,然後發送地址信息,再發送命令0x30,然後就可以讀取數據了。這就是nand讀操作的所有內容。代碼在後面貼出來。

在這裏開始說明我遇到的問題:在看韋老師的視頻的時候並沒有發現我有這個巨大的問題,也可能是我碰巧遇到了,但是細想下來還是自己理解不到位,不能準確的發現這個問題-----Nand_Read函數的傳參是起始地址src,目的地址dest,讀多大lenth;
這三個參數第一個不是指針要做類型轉換,第二個是指針沒有問題,第三個是長度。
問題就出在第三個問題上面,如果不去驗證,永遠發現不了,這個拷貝的長度是有問題的 ,我在做函數傳參的時候,是在C函數裏面寫的。

void copynor2sdram(void)
{
	extern unsigned int text_start,bss_start;
	volatile unsigned int *dest = (volatile unsigned int *)&text_start;
	volatile unsigned int *src = (volatile unsigned int *)0;
	volatile unsigned int *end = (volatile unsigned int *)&bss_start;
	a = (unsigned int)dest;
	b = (unsigned int)end;
	len = b-a;
	if(isBootFromNorFlash())
	{ 
		while(dest<=end)
		{
			*dest++ = *src++;
		}	
	}
	else
	{
		/**Nand啓動**/
		Nand_init();
		/**拷貝代碼**/
		Nand_read((unsigned int )src,(unsigned char *)dest,(unsigned int)(b-a));
	}
}

這裏可以看到,我的len,是自己做的減法,但是沒有驗證的話,不知道對不對。然後我做了驗證函數:

void putlen(void)
{
	len = b-a;
	printHex(len);
	puts("\n\r");
	printHex(a);
	puts("\n\r");
	printHex(b);
	puts("\n\r");
	printHex(b-a);
	puts("\n\r");
	
}

沒有查錯之前,驗證發現len=0xFFFFFFFF,這肯定是不對的,查錯之後纔對。
這個問題困擾了很久,也從側面反映出自己的理解還不夠深刻,比如:調用C函數之前,一定要指定棧指針的位置,打印字符之前,要先做串口初始化等。
總的來說還是收穫很深。我這裏啓動不了內核是因爲我的flash裏面是沒有內核存在的 。所以nand拷貝不到是很正常的,最後運行到ERROR纔是完整的。

在這裏插入圖片描述
附錄1:
start.S


.text
.global _start
_start:

/*******1.關閉看門狗*******/
	ldr r0 ,=0x53000000
	ldr r1 ,=0
	str r1 ,[r0]
	
/*******2.設置時鐘400M :F:H:P = 400:100:50*******/	
	/*set LOCKTIME(0x4C000000) =0xFFFFFFFF*/
	ldr r0,=0x4C000000
	ldr r1,=0xFFFFFFFF
	str r1,[r0]
	
	/*設置分頻係數CLKDIVN(0x4C000014 )= 0x5 1:4:8*/
	ldr r0,=0x4C000014
	ldr r1,=0x5
	str r1,[r0]
	
	/*必須設置異步模式MMU_SetAsyncBusMode*/
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/*設置鎖相環set MPLLCON(0x0x4C000004) = (127<<12)|(2<<4)|(1<<0)
	 *一旦設置了PLL , 就會鎖定lock time,直到頻率輸出穩定,CPU工作於新的頻率
	 *---set MDIV = 127 ;PDIV = 2 ;SDIV = 1.*/	 
	ldr r0,=0x4C000004
	ldr r1,=((127<<12)|(2<<4)|(1<<0))  /*S3C2440_MPLL_400MHZ*/
	str r1,[r0]
	




/********4. 設置堆棧和初始化內存SDRAM***********/
	
	bl sdram_init 
	ldr sp,=0x34000000
	
	
	
	
	
/********5. 判斷是nor還是nand啓動,將代碼複製到SDRAM實現重定位*********/
	/*往0地址處寫0,如果讀出來是0,則說明硬盤被修改了,是nand啓動,如果不是0,則是nor啓動*/	
	//ldr r0 ,= 0
	//ldr r1 , [r0] 		/*存儲0地址初始值*/
	//str r0 , [r0]
	//ldr r2 , [r0] 		/*存儲寫了0之後的值*/
	//cmp r0 , r2 		/*判斷r0 == r2?*/
	/*不等爲nor啓動,從nor複製代碼到SDRAM*/
	//bne copynor2sdram 	
		
	/*等則是nand啓動,從Nand複製代碼到SDRAM,要先將初始值還原*/
	//streq r1 , [r0]
	//beq CopyNand2Sdram
	bl copynor2sdram
	
	
	bl uart0_init
	
	bl putnand
	bl putlen
	
	
/********6. 清除BSS段,不用匯編傳遞參數********/ 
	bl  clearBSS 

/********7. 跳轉main函數,進行第二階段*********/ 
	ldr pc,=main
halt:
	b halt  /*加一個死循環*/


附錄二:
init.c

#include"lyboot.h"
/*******SDARAM 寄存器*******/
#define BWSCON   ((volatile unsigned int *)0x48000000)/*Bank寬度控制寄存器*/
#define BANKCON6 ((volatile unsigned int *)0x4800001C)/*Bank6設置爲SDRAM*/
#define BANKCON7 ((volatile unsigned int *)0x48000020)/*Bank7設置爲SDRAM*/
#define REFRESH  ((volatile unsigned int *)0x48000024)/*刷新寄存器*/
#define BANKSIZE ((volatile unsigned int *)0x48000028)/*Bank大小設置寄存器*/
#define MRSRB6   ((volatile unsigned int *)0x4800002C)/*Bank6 SDRAM模式寄存器*/
#define MRSRB7   ((volatile unsigned int *)0x48000030)/*Bank7 SDRAM模式寄存器*/
/*************************/

/***Nand flash控制器寄存器****/
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)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))
/**************************/



volatile unsigned int len = 0;
volatile unsigned int a = 0;
volatile unsigned int b = 0;



/**************************/
/***Nand還是nor啓動********/
/**************************/
int isBootFromNorFlash(void)
{
    volatile unsigned int *p = (volatile unsigned int *)0;
    unsigned int val = *p;

    *p = 0x12345678;
    if (*p == 0x12345678)
    {
        /* 寫成功, 對應nand啓動 */
        *p = val;
        return 0;
    }
    else
    {
        return 1;
    }
}


/**************************/
/***Nand flash初始化*******/
/**************************/
void Nand_init(void)
{
	#define TACLS  0
	#define TWRPH0 2
	#define TWRPH1 0
	/*設置時序*/
	NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
	/*使能Nand控制器,初始化ECC-校驗碼,禁止片選*/
	NFCONT = (1<<4)|(1<<1)|(1<<0);
	
}

/**************************/
/***CPU讀Nand flash操作*******/
/**************************/
void Nand_Seclect(void)
{
	/*初始化裏面已經做了控制寄存器的設置,這裏允許片選就行了*/
	NFCONT &= ~(1<<1);
}

void Nand_Send_Command(unsigned char cmd )
{
	volatile int i;
	/*發出命令--將命令寫到NFCMMD寄存器*/
	NFCMMD = cmd;
	/*韋老師經驗--發出命令時要等待一會,否則發送失敗*/
	for(i=0;i<10;i++);
}

void Nand_Send_Addr(unsigned char addr )
{
	 
	//unsigned int col = addr % (2048-1);
	//unsigned int page = addr / 2048;
	
	volatile int i;
	//發送地址信息
	NFADDR =  addr;
	for(i=0;i<10;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)
{
	/*原理圖上看出讀RnB(Ready n(低電平) Busy)引腳*/
	/*讀狀態寄存器NFSTAT最低位爲RnB,如果最低位爲0,則爲準備好,一直卡。*/
	while(!(NFSTAT & 1));
}

unsigned char Nand_Read_Data(void)
{
	/*讀NFDATA寄存器就行*/
	return NFDATA ;
}

void Nand_Deseclect(void)
{
	/*初始化裏面已經做了控制寄存器的設置,這裏允許片選就行了*/
	NFCONT |=  (1<<1);
}

void Nand_read(unsigned int addr,unsigned char *buf,unsigned int lenth)
{
	int col = addr%2048;
	int page= addr/2048;
	int i=0;
	
	/*1.片選 */
	Nand_Seclect();
	
	while(i<lenth)
	{
		/*2.發出讀命令00h */
		Nand_Send_Command(0x00);
		
		/*3.發出地址(分5步) */
		Nand_Send_Addr(col&0xff);
		Nand_Send_Addr((col>>8)&0xff);
		Nand_Send_Addr(page&0xff);
		Nand_Send_Addr((page>>8)&0xff);
		Nand_Send_Addr((page>>8)&0xff);
		
		
		/*4.發出讀命令30h */
		Nand_Send_Command(0x30);
		
		/*5.判斷狀態,等待就緒*/
		Nand_Wait_Ready();
		
		/*6.讀數據*/
		for(;(col<2048)&&(i<lenth);col++)
		{
			buf[i] = Nand_Read_Data();
			i++;
			//addr++;
		}
		if(i==lenth)
			break;
		
		col = 0;
		page ++;
	}
	
	/*7.取消選中*/
	Nand_Deseclect();

}

/**************************/
/********SDRAM初始化*******/
/**************************/
void sdram_init(void)
{
	*BWSCON   = 0x22000000;
	
	*BANKCON6 = 0x18001; 
	*BANKCON7 = 0x18001; 
	
	*REFRESH  = 0X8404f5;
	
	*BANKSIZE = 0Xb1;
	
	*MRSRB6     = 0X20;
	*MRSRB7     = 0X20;
}



/**************************/
/******點亮一個led燈*******/
/**************************/
void delay(int count)
{
	while(count--);
}


int led_on()
{
	unsigned int *pGPBCON = (unsigned int *)0x56000010;
	unsigned int *pGPBDAT = (unsigned int *)0x56000014;
	int val = 0;
	int tmp;
	*pGPBCON = 0x5400;
	//
	while(2)
	{
		tmp = ~val;
		tmp &= 7;
		*pGPBDAT &= ~(7<<5);
		*pGPBDAT |= (tmp<<5);
		delay(1000000 );
		val++;	
		if(val == 8)
				val = 0;
	}

	return 0;
}



/**************************/
/******Nor代碼重定位*******/
/**************************/
void copynor2sdram(void)
{
	 
	extern unsigned int text_start,bss_start;
	volatile unsigned int *dest = (volatile unsigned int *)&text_start;
	volatile unsigned int *src = (volatile unsigned int *)0;
	volatile unsigned int *end = (volatile unsigned int *)&bss_start;
	a = (unsigned int)dest;
	b = (unsigned int)end;
	len = b-a;
	
	
	if(isBootFromNorFlash())
	{
		 
		while(dest<=end)
		{
			*dest++ = *src++;
		}
		
	}
	else
	{
		/**Nand啓動**/
		Nand_init();
		/**拷貝代碼**/
		Nand_read((unsigned int )src,(unsigned char *)dest,(unsigned int)(b-a));
		
	}
	

}

void putlen(void)
{
	len = b-a;
	printHex(len);
	puts("\n\r");
	printHex(a);
	puts("\n\r");
	printHex(b);
	puts("\n\r");
	printHex(b-a);
	puts("\n\r");
	
}

void putnand(void)
{
	puts("nand flash \n\r");
	
}

/**************************/
/********清除BSS段*********/
/**************************/
void clearBSS(void)
{
	extern unsigned int bss_start ,bss_end;
	volatile unsigned int *Bend   = (volatile unsigned int *)&bss_end;
	volatile unsigned int *start = (volatile unsigned int *)&bss_start;

	while(start <= Bend)
	{
		*start++ =0;
	}

}



附錄三:
lyboot.c

#include"lyboot.h"
#include"setup.h"


static struct tag *params;

/*規定起始參數的標記規則*/
void setup_start_tag(void)
{
	params = (struct tag *) 0x30000100;

	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size (tag_core);	//這裏設置了大小爲5個空間,內存是4字節對齊進行加的。

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;

	params = tag_next(params);   	//指向下一個標記的起始地址
									//tag_next在setup.h裏面定義
									
}
/*規定內存參數的標記規則*/
void setup_memory_tags(void)
{	 
	params->hdr.tag = ATAG_MEM;
	params->hdr.size = tag_size (tag_mem32); //這裏設置了大小爲4個空間 

	params->u.mem.start = 0x30000000;  	 //內存起始地址
	params->u.mem.size  = 64*1024*1024;		//內存大小64M

	params = tag_next (params);
	
}


/*規定命令行參數的標記規則*/
int strlen(char *str)
{
	int i = 0;
	while(str[i])
	{
		i++;
	}
	return i;
}

void strcpy(char *dest,char *src)
{
	//char *tmp = dest;
	while ((*dest++ = *src++) != '\0')
	{
		;
	}
		 
	
}
void setup_commandline_tag(char *cmdline )
{
	int len = strlen(cmdline) + 1;  //計算命令行長度,加上結束的轉義字符。
	
	params->hdr.tag = ATAG_CMDLINE;
	params->hdr.size =(sizeof (struct tag_header) + len + 3) >> 2; //大小向4取整

	strcpy(params->u.cmdline.cmdline, cmdline);  	//用首地址將cmdline拷貝到結構體中,在標記列表中依次放到flash上面

	params = tag_next (params);
	
}

/*規定結束參數的標記規則*/
void setup_end_tag(void)
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
	
}


int main()
{
	/*定義了一個函數指針*/
	void (*theKernel)(int zero ,int arch ,unsigned int params);
	volatile unsigned int *p = (volatile unsigned int *)0x33f80000;
	volatile unsigned int *q = (volatile unsigned int *)0x0;
	
	/*0. 設置串口0:內核啓動時,從串口打印信息,但是內核一開始沒有初始化串口*/

	
	/*1. 從nand flash裏面將內核讀入內存*/
	puts("Copy kernel form nand \r\n");
	printHex(*p);
	printHex(*q);
	Nand_read((unsigned int )(0x60000+64),(unsigned char *)0x30008000,(unsigned int)0x200000);  /*src,dest,size*/
	
	
	/*2. 設置參數*/
	puts("Set boot params \r\n");
	setup_start_tag();
	setup_memory_tags();
	setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
	setup_end_tag();
	
	
	/*3. 跳轉執行*/ 
	puts("Boot kernel \r\n");
	theKernel = (void (*)(int,int,unsigned int))0x30008000;
	 
	
	/*函數指針指向0x30008000,相當於mov pc ,#0x30008000*/ 
	theKernel(0,362,0x30000100);  
	puts("Error\r\n");
	/*如一切正常,不會執行到這裏*/
	return -1;

}



附錄四:
uart.c


#define GPHCON   ((volatile unsigned int  *)0x56000070)/*uart模式寄存器*/
#define GPHUP    ((volatile unsigned int  *)0x56000078)/*uart上拉寄存器*/
#define UCON0    ((volatile unsigned int  *)0x50000004)/*uart控制寄存器*/
#define UBRDIV0  ((volatile unsigned int  *)0x50000028)/*uart波特率分配寄存器*/
#define ULCON0   ((volatile unsigned int  *)0x50000000)/*uart數據格式控制寄存器*/
#define UTRSTAT0 ((volatile unsigned int  *)0x50000010)/*uart狀態寄存器--讀*/
#define UTXH0    ((volatile unsigned char *)0x50000020)/*CPU寫uart數據寄存器*/
#define URXH0    ((volatile unsigned char *)0x50000024)/*CPU讀uart數據寄存器*/
 
 

 
#define GPH2_CL  (3<<4)
#define GPH3_CL  (3<<6)
#define GPH2_ST  (2<<4)
#define GPH3_ST  (2<<6)

#define GPHUP2_CL    (1<<2)
#define GPHUP3_CL    (1<<3)
 

//#define UCON0CLK_CL         ( 3<<10)
//#define UCON0CLK_ST         ( 0<<10)
//#define UCON0_RT_MODE_CL    (15<<10)
//#define UCON0_RT_MODE_ST    ( 5<<10)

//#define ULCON_CL    (7<<2)
//#define ULCON_ST    (3<<2)

#define PCLK 50000000
#define BAUD 115200

/*115200 , 8 , n , 1*/
void uart0_init()
{
	/*設置引腳用於串口*/
	/*GPH2,3用於TXD0,RXD0*/
	*GPHCON &= ~((GPH2_CL)|(GPH3_CL)); /*清位*/
	*GPHCON |=  ((GPH2_ST)|(GPH3_ST)); /*置位爲TXD0,RXD0*/
	
	/*設置TXD0引腳上拉功能*/
	/*GPH2,3設置爲enable*/
	*GPHUP &= ~((GPHUP2_CL)|(GPHUP3_CL)); /*清位--置位爲使用上拉功能,傳數據之前是高電平*/
	 

	/*設置波特率*/
	/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
	 * UART clock = ?在寄存器裏面可以選擇爲--00, 10 = PCLK 01 = UEXTCLK 11 = FCLK/n    PCLK在時鐘設置裏面已經設置爲50HZ
	 * UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1  (= 26左右)
	 */
	 
	 //*UCON0 &= ~(UCON0_RT_MODE_CL);	/*設置UART clock 爲PCLK*/
	 //*UCON0 |=   (UCON0_RT_MODE_ST);  /*設置爲中斷查詢模式*/
	 //*UBRDIV0 = 26;									/*設置波特率分配數據爲26(由上面得到)*/
	 // 設置波特率	
	 *UCON0   = 0x05;
	 *UBRDIV0 = (int)(PCLK/(BAUD*16)-1);
	
	/*設置數據格式*/
	//*ULCON0 &= ~ULCON_CL;				/*清位*/
	//*ULCON0 |=  ULCON_ST;				/*置位:不使用紅外模式,不要奇偶校驗位,一個停止位,八位數據長度*/
	*ULCON0 = 0x03;
	
	 


}

 /*寫uart一個字節*/
void put_char(unsigned char ch)
{
	
    while (!(*UTRSTAT0 & (1<<1)));   /*上一次的數據未發出去*/
	*UTXH0 = ch;  
}

 
/*寫字符串*/
void puts(const char *s)
{
	while(*s)
	{
		put_char(*s);
		s++;
	}
}
 
 /*讀uart一個字節*/
 unsigned char getc(void)
{
      while (!(*UTRSTAT0 & (1<<0)));
	  return *URXH0;
}

void printHex(unsigned int val)
{
	
	int i;
	int j;
	puts("0x");
	
	for(i = 0;i<8 ; i++)
	{
		j = (val >> ((7-i)*4))&0xf;
		if((j>=0)&&(j<=9))
			put_char('0'+j);
		else
			put_char('A'+j-0xa);
		
	}
	
} 


























附錄5:
鏈接器腳本

SECTIONS{
	. = 0x33f80000;
	
	. = ALIGN(4);	
	
	text_start = .;
	.text  :
	{
		*(.text)
	}
	
	. = ALIGN(4);
	
	.rodata :
	{
		*(.rodata)
	}
	
	. = ALIGN(4);
	
	data_start	   = .;
	.data :
	{
		*(.data)
	}  
	data_end       = .;

	. = ALIGN(4);
	
	bss_start = .;
	.bss : 
	{
		*(.bss) *(.COMMON)
	}
	bss_end = .;
}

附錄六:
頭文件

#ifndef _LYBOOT_H
#define _LYBOOT_H

void Nand_init(void);
void Nand_read(unsigned int addr,unsigned char *buf,unsigned int lenth);

void sdram_init(void);
void copynor2sdram(void);
void CopyNand2Sdram(void);

void clearBSS(void);

int led_on();
void delay(int count);

void uart0_init();
void put_char(unsigned char ch);
unsigned char getc(void);
void puts(const char *s);
void printHex(unsigned int val);


#endif

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章