自己写bootloader笔记3---init.c分析

来源:互联网 发布:激战2选阿苏拉捏脸数据 编辑:程序博客网 时间:2024/05/16 06:40
/* 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))


/* GPIO */
#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHUP               (*(volatile unsigned long *)0x56000078)


/* UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)


#define TXD0READY   (1<<2)




void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);



//nor flash启动和nand flash启动的判断:利用nor flash的特点,nor flash可以像内存一样读,但不可以像内存一样写.nand flash启动,0地址对应片内内存,可读可写。因此可从是否能写0地址来判断
int isBootFromNorFlash(void)

{

//p指针指向0地址

volatile int *p = (volatile int *)0;
int val;
//先读取0地址的值

val = *p;

//修改0地址的值

*p = 0x12345678;

//如果修改成功,证明是nand flash启动,否则是nor flash启动

if (*p == 0x12345678)
{

/* 写成功, 是nand启动 */

恢复修改前的0地址的值

*p = val;
return 0;
}
else
{
/* NOR不能像内存一样写 */
return 1;
}
}

//从flash拷贝代码到SDRAM , src是源地址,dest是目的地址,lens是要拷贝的长度

src, dest, len这三个参数是从汇编程序中传过来的(看start.S)

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{
int i = 0;

/* 如果是NOR启动 */
if (isBootFromNorFlash())

{

循环拷贝代码,其中len是以字节为单位的,因而每次拷贝一字节,每拷贝完一次i值累加

while (i < len)
{
dest[i] = src[i];
i++;
}
}
else
{

//nand_init();

从源地址src读到目的地址dest, 读取的长度为len

nand_read((unsigned int)src, dest, len);
}
}

//清除bss段
void clear_bss(void)

{

__bss_start, __bss_end定义为外部的整型变量

extern int __bss_start, __bss_end;

定义指针指向bss段的首地址

int *p = &__bss_start;
循环把bss段中变量赋为0,直到bss段的结尾
for (; p < &__bss_end; p++)
*p = 0;
}

//因为无论是nor flash启动还是nand flash启动,都会从nand flash读取内核到SDRAM 

nand flash的初始化函数参考http://blog.csdn.net/qingkongyeyue/article/details/52132868

nand_init函数

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

//nand flash的片选、取消片选、发命令、发地址、空闲等待,读数据函数参考http://blog.csdn.net/qingkongyeyue/article/details/52132195

//片选

void nand_select(void)

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

//取消片选
void nand_deselect(void)
{
NFCONT |= (1<<1);
}

//发命令
void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD = cmd;
for (i = 0; i < 10; i++);
}

//发地址
void nand_addr(unsigned int addr)
{
unsigned int col  = addr % 2048;
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));
}

//读数据
unsigned char nand_data(void)
{
return NFDATA;
}

//nand flash读函数参考http://blog.csdn.net/qingkongyeyue/article/details/52086786

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;

/* 1. 选中 */
nand_select();


while (i < len)
{
/* 2. 发出读命令00h */
nand_cmd(0x00);


/* 3. 发出地址(分5步发出) */
nand_addr(addr);


/* 4. 发出读命令30h */
nand_cmd(0x30);


/* 5. 判断状态 */
nand_wait_ready();


/* 6. 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i] = nand_data();
i++;
addr++;
}

col = 0;
}


/* 7. 取消选中 */
nand_deselect();
}


#define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
#define UART_BAUD_RATE  115200      // 波特率
#define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)


/*
 * 初始化UART0
 * 115200,8N1,无流控
 */

void uart0_init(void)
{
    GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3内部上拉


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


/*
 * 发送一个字符
 */

void putc(unsigned char c)
{
    /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
    while (!(UTRSTAT0 & TXD0READY));
    
    /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
    UTXH0 = c;

}

//循环打印字符串
void puts(char *str)
{

int i = 0;

//循环打印字符

while (str[i])
{
putc(str[i]);
i++;
}
}

//输出16进制数
void puthex(unsigned int val)
{
/* 0x1234abcd */
int i;
int j;
打印头部
puts("0x");


for (i = 0; i < 8; i++)
{

j = (val >> ((7-i)*4)) & 0xf;

if ((j >= 0) && (j <= 9))
putc('0' + j);
else
putc('A' + j - 0xa);

}

}
0 0
原创粉丝点击