一、目的
編寫一個能夠加載并啟動OS內核的bootloader。
二、思路
第一階段:
(1)arm920t的異常向量表有兩種存放方式,一種是低端存放(從0x00000000處開始存放),另一種是高端存放(從0xfff000000處開始存放)。選擇低端存放,建立異常向量表。
(2)s3c2440的看門狗在上電啟動時默認是開啟的,所有要先把看門狗關了先。免得代碼運行還沒完成就強制復位。
(3)屏蔽掉所有中斷。
(4)初始化時鐘。
(5)初始化內存。
(6)清零bss段。
(7)設置好各個模式下的棧空間。
(8)重定位代碼,使得代碼的運行地址與鏈接地址相對應,之后就可以直接使用絕對地址。
(9)使用絕對跳轉指令跳轉到第二階段,用c語言來實現。
第二階段:
(1)初始化串口0,一方面方便我們的調試,一方面也為內核啟動時打印信息做好初始化。
(2)初始化nand flash,需要把nand flash里的內核鏡像拷貝到內存。
(3)把內核鏡像拷貝到內存指定位置。
(4)設置好傳遞給內核的參數,并放置在約定的位置。
(5)跳轉到內核起始地址處開始啟動內核。
完畢。
三、流程圖設計
四、代碼樹結構
(1)drivers里的src目錄放置與外圍設備相關配置的編程文件,inc目錄放置相關頭文件。對應的makefile放在drivers目錄里。
①drivers/Makefile
#把src目錄下的所有.c文件的字符串替換成.o字符串
TARGET := $(patsubst %.c,%.o,$(notdir $(wildcard ./src/*.c)) )
TARGET += $(patsubst %.S,%.o,$(notdir $(wildcard ./src/*.S)) )
all:$(TARGET)
echo "$(TARGET) 編譯完成"
GPATH=$(PWD)
vpath %.c ./src
vpath %.S ./src
%.o:%.c
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
%.o:%.S
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o
②drivers/inc
nand.h
#ifndef _NAND_H
#define _NAND_H
/**
*提取出頁內列號,塊內頁號,塊號
*/
#define dnand_addr2ColAddr(addr) (addr & 0x7FF)
#define dnand_addr2RowAddr(addr) (( addr & 0xFC00 ) >> 11)
#define dnand_addr2BlockAddr(addr) (addr >> 17)
//初始化NAND Flash , 時鐘頻率改變了這個一定要記得改
#define dnand_init()
do{
NFCONT = 0x73;
NFCONF = (3<<12) | (1<<8) | (1<<4);
}while(0)
//復位
void fnand_reset(void);
//等待NAND Flash就緒
#define dnand_waitReady() while(!(NFSTAT & 0x1))
//發出片選信號
#define dnand_enable() (NFCONT &= ~(1<<1))
//取消片選信號
#define dnand_disable() (NFCONT |= (1<<1))
//發出命令
#define dnand_writeCmd(cmd) (NFCMMD = cmd)
//讀數據
#define dnand_readData() (*(volatile unsigned char *)&NFDATA)
//寫數據
#define dnand_writeData(data) *(volatile unsigned char *)&NFDATA = data
//寫地址
#define dnand_writeAddr(addr)
do{ NFADDR = addr & 0xff;
NFADDR = (addr >> 8) & 0x0f;
NFADDR = (addr >> 11) & 0xff;
NFADDR = (addr >> 19) & 0xff;
}while(0)
//擦除塊
unsigned char fnand_eraseBlocks(unsigned int startBlockNum , unsigned int blockCount);
//從nand閃存里的sourAddr地址處讀取size大小的數據到內存destAddr處。
void fnand_readOfSize(unsigned char *destAddr , unsigned int sourAddr , unsigned int size);
//。從內存sourAddr處讀取size大小的數據到nand閃存里的destAddr地址處
unsigned char fnand_writeOfSize(unsigned char *sourAddr , unsigned int destAddr , unsigned int size);
#endif
uart0.h
#ifndef UART0_H
#define UART0_H
#define TXD0_READY (0x01<<1)
#define UBRDIV0_VAL (101250000UL/(115200*16)-1)
/**********初始化uart0中斷的配置***********/
void uart0_init(void);
/*******把string消息通過uart0發送出去******/
void uart0_sent_msg(char *string);
void uart0_sent_byte(char byte);
/*打印hex數據*/
void uart0_sent_hex_word(unsigned int val);
#endif
③drivers/src
nand.c
#include "nand.h"
#include "s3c2440.h"
/**
* 復位
*/
void fnand_reset(void)
{
dnand_enable();
dnand_writeCmd(0xff); // 復位命令
dnand_waitReady();
dnand_disable();
}
/**
*塊擦除函數
*/
unsigned char fnand_eraseBlocks(unsigned int startBlockNum , unsigned int blockCount)
{
unsigned int i;
dnand_enable();
for( i = 0 ; i < blockCount ; i++ ){
//發送擦除命令
dnand_writeCmd( 0x60 );
dnand_writeAddr( startBlockNum << 6 );
dnand_writeCmd(0xD0);
dnand_waitReady();
//讀取狀態
dnand_writeCmd( 0x70 );
if ( ( dnand_readData() & 0x01 ) ){
return 1;
}
startBlockNum += 1;
}
dnand_disable();
return 0;
}
void fnand_readOfSize(unsigned char *destAddr , unsigned int sourAddr , unsigned int size)
{
unsigned int j , col;
col = sourAddr & 0x7FF ; //該地址可能不是從頁的0地址開始讀 ,所以要先取出列地址
dnand_enable();
for( j = 0 ; j < size ; ){
//發出read命令
dnand_writeCmd( 0x00 );
dnand_writeAddr( sourAddr );
dnand_writeCmd( 0x30 );
dnand_waitReady( );
//開始讀一頁數據到destAddr里 ,
for( ; (col < 2048)&&(j
j++;
sourAddr++;
}
col = 0;
}
dnand_disable();
}
/**
*從內存的sourAddr處寫入pageCount頁數據到nand flash的destAddr地址處
*/
unsigned char fnand_writeOfSize(unsigned char *sourAddr , unsigned int destAddr , unsigned int size)
{
unsigned int col, j;
unsigned int startBlockNum , blockCount ,pageCount;
col = destAddr & 0x7FF ;
pageCount = size/2048 + ( (col)? 1 : 0 ) ;
startBlockNum = dnand_addr2BlockAddr( destAddr ) ;
blockCount = ( dnand_addr2RowAddr( destAddr ) + pageCount ) >> 6 ;
if ( ( dnand_addr2RowAddr( destAddr ) + pageCount ) & 0x3F ){
blockCount++;
}
if ( fnand_eraseBlocks( startBlockNum , blockCount ) ){
return 1;
}
dnand_enable();
for( j = 0 ; j < size ; ){
//發出read命令
dnand_writeCmd( 0x80 );
dnand_writeAddr( destAddr );
//開始寫一頁數據到destAddr里
for( ; (col < 2048)&&(j < size) ; col++ ){
dnand_writeData( *sourAddr++ );
destAddr++;
j++;
}
col = 0;
dnand_writeCmd( 0x10 );
dnand_waitReady();
//發送讀取狀態命令
dnand_writeCmd( 0x70 );
if ( ( dnand_readData() & 0x01 ) ){
return 1;
}
}
dnand_disable();
return 0;
}
uart0.c
#include "Uart0.h"
#include "s3c2440.h"
/*
****************************************
初始化uart0中斷的配置
****************************************
*/
void uart0_init(void)
{
GPHCON |= 0xa0;
GPHUP |= 0x0f;
ULCON0 = 0x03; //普通模式,禁止奇偶校驗,1個結束位,8-bit字長
UBRDIV0 = UBRDIV0_VAL; //波特率選擇115200,所以UBRDIV0=54
UCON0 = 0x005; //時鐘源=PCLK
//Rx,Tx水平觸發,禁止接收超時中斷,禁止接收錯誤狀態中斷,
//不使用回路模式,不發送break信號
//中斷方式發送接收數據到緩沖寄存器
}
/*
*****************************************************
*uart0發送消息
***************************************************
*/
void uart0_sent_msg(char *string)
{
do {
while( !(UTRSTAT0&TXD0_READY) );
UTXH0 = *string++;
}while(*string != '
主站蜘蛛池模板:
得荣县|
庆安县|
三穗县|
沙洋县|
五常市|
运城市|
嘉义市|
孟村|
新泰市|
东乌珠穆沁旗|
正宁县|
宾阳县|
万载县|
泌阳县|
商都县|
泰顺县|
洪湖市|
浠水县|
刚察县|
大渡口区|
达尔|
新营市|
扎囊县|
锡林郭勒盟|
新丰县|
比如县|
甘德县|
北辰区|
陈巴尔虎旗|
柘荣县|
雅安市|
万山特区|
电白县|
资源县|
庆云县|
长沙市|
徐闻县|
奉化市|
伊春市|
阿拉善左旗|
射洪县|