例程目的:
利用nand启动,将Nandflash最前面4kB大小的内容拷贝到片内内存中,然后0地址指向片内内存的开始,当运行完一些函数后,开始运行存在nandflash的函数,则说明nandflash驱动成功。
head.S文件源码及分析:
.text
.global _start
_start:
?ldr sp,=4096? @以下三个函数均是调用c语言函数 所以要用栈保存函数参数、返回值、和一些寄存器的值。
?bl disable_watch_dog @关看门狗
?bl memsetup @初始化2440的存储控制器
?bl nand_init? @初始化2440的nandflash相关寄存器
?
?
?ldr r0,=0x30000000??
?mov r1,#4096
?mov r2,#2048
?bl nand_read @nand_read函数的参数依次是 拷贝到的地址 要拷贝nandflash的地址 要拷贝的大小? 此例是将nandflash的main.c函数拷贝到sdram上运行
?
?ldr sp,=0x34000000 @当上面的一些初始化函数运行完后 将栈顶端指向sdram的顶端?因为下面的main函数是在sdram上运行的。sdram大小为128MB?起始地址为0x30000000
?ldr lr,=halt_loop @将main函数的返回地址指向下面的死循环
?ldr pc,=main @将pc指向main函数的地址
halt_loop:
?b halt_loop @分支指令B的访问空间大小问 前后32MB
init.c文件源码及分析:
#include "s3c2440.h"
#define ?MEM_CTL_BASE??0x48000000
void disable_watch_dog()
{
?WTCON=0x0;
}
/* 设置控制SDRAM的13个寄存器 */
void memsetup()
{
?int ?i = 0;
?unsigned long *p = (unsigned long *)MEM_CTL_BASE;
??? /* SDRAM 13个寄存器的值 */
??? unsigned long? const??? mem_cfg_val[]={ 0x22011110,???? //BWSCON
??????????????????????????????????????????? 0x00000700,???? //BANKCON0
??????????????????????????????????????????? 0x00000700,???? //BANKCON1
??????????????????????????????????????????? 0x00000700,???? //BANKCON2
??????????????????????????????????????????? 0x00000700,???? //BANKCON3?
??????????????????????????????????????????? 0x00000700,???? //BANKCON4
??????????????????????????????????????????? 0x00000700,???? //BANKCON5
??????????????????????????????????????????? 0x00018005,???? //BANKCON6
??????????????????????????????????????????? 0x00018005,???? //BANKCON7
??????????????????????????????????????????? 0x008C07A3,???? //REFRESH
??????????????????????????????????????????? 0x000000B1,???? //BANKSIZE
??????????????????????????????????????????? 0x00000030,???? //MRSRB6
??????????????????????????????????????????? 0x00000030,???? //MRSRB7
??????????????????????????????????? };
?for(; i < 13; i++)
??p[i] = mem_cfg_val[i];
}
nand.c文件及源码分析:
typedef unsigned int S3C24X0_REG32;
typedef struct {
??? S3C24X0_REG32?? NFCONF;
??? S3C24X0_REG32?? NFCONT;
??? S3C24X0_REG32?? NFCMD;
??? S3C24X0_REG32?? NFADDR;
??? S3C24X0_REG32?? NFDATA;
??? S3C24X0_REG32?? NFMECCD0;
??? S3C24X0_REG32?? NFMECCD1;
??? S3C24X0_REG32?? NFSECCD;
??? S3C24X0_REG32?? NFSTAT;
??? S3C24X0_REG32?? NFESTAT0;
??? S3C24X0_REG32?? NFESTAT1;
??? S3C24X0_REG32?? NFMECC0;
??? S3C24X0_REG32?? NFMECC1;
??? S3C24X0_REG32?? NFSECC;
??? S3C24X0_REG32?? NFSBLK;
??? S3C24X0_REG32?? NFEBLK;?
}S3C2440_NAND;? //S3C24X0_REG32大小为4字节 所以结构体中的变量地址相差4字节
static S3C2440_NAND *s3c2440nand=(S3C2440_NAND*)0x4e000000;//指向nandflash相关寄存器的起始地址
static void wait_idle(void)
{
?int i;
?volatile unsigned char *p=(volatile unsigned char *)&s3c2440nand->NFSTAT; //nandflash状态寄存器 最低位为1时nandflash空闲,为0时则表示nandflash繁忙
?while(!(*p&1))
??for(i=0;i<10;i++);
}
static void select_chip(void)
{
?int i;
?s3c2440nand->NFCONT &=~(1<<1); //NFCONT寄存器的1位为0时片选nandflash 为0时取消片选nandflash
?for(i=0; i<10; i++);?
}
static void deselect_chip(void)
{
?int i;
?s3c2440nand->NFCONT |=(1<<1);
?for(i=0; i<10; i++);?
}
static void write_cmd(int cmd)
{
?volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;//往NFCMD中写指令就可以将指令发送给nandflash
?*p=cmd;
}
static void write_addr(unsigned int addr)
{
?int i;
?volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
?int col,page;
?col = addr & 2047;//2047
?page = addr/2048;//2048
?
?*p = col & 0xff;???/* Column Address A0~A7 */
?for(i=0; i<10; i++);??
?*p = (col >> 8) & 0x0f; ?/* Column Address A8~A11 */
?for(i=0; i<10; i++);
?*p = page & 0xff;???/* Row Address A12~A19 */
?for(i=0; i<10; i++);
?*p = (page >> 8) & 0xff;?/* Row Address A20~A27 */
?for(i=0; i<10; i++);
?*p = (page >> 16) & 0x03;?/* Row Address A28~A29 */
?for(i=0; i<10; i++);
}
static unsigned char read_data(void)
{
??? volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;//发出读命令和地址后 NFDATA寄存器中存储的就是该地址的数据
??? return *p;
}
static void reset()
{
?select_chip();//选中nandflash
?write_cmd(0xff);//发出复位命令
?wait_idle();//等待nandflash空闲
?deselect_chip();//取消片选
}
void nand_init(void)
{
#define TACLS?? 0
#define TWRPH0? 3
#define TWRPH1? 0
??????? s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
??????? s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);//片选nandflash?时能nandflash控制器
??
??reset();
}
void nand_read(unsigned char *buf,unsigned long start_addr,int size)
{
?int i,j;
?if((start_addr&2047)||(size&2047)) //确保起始地址是在每一页的开始位置 且拷贝的大小为整页的整数倍?,因为读操作是以页为单位?擦除操作是以块为单位
?{
??return ;
?}
?select_chip();
?for(i=start_addr;i<(start_addr+size);){
??write_cmd(0);?//发出1st读指令
??write_addr(i); //写地址
??write_cmd(0x30); //?发出2st读指令
??wait_idle();//等待nand空闲
??for(j=0;j<2048;j++,i++)
??{
???*buf=read_data();
???buf++;
??}
??deselect_chip();
??return ;
?}
?
}
main文件及源码:
#include "s3c2440.h"
void? wait(volatile unsigned long dly)
{
?for(; dly > 0; dly--);
}
int main(void)
{
?unsigned long i = 0;
?GPFCON = GPF4_out|GPF5_out|GPF6_out;??// 将LED1-3对应的GPF4/5/6三个引脚设为输出
?while(1){
??wait(30000);
??GPFDAT = (~(i<<4));? ?// 根据i的值,点亮LED1-3
??if(++i == 8)
???i = 0;
?}
?return 0;
}
nand.lds文件源码及分析:
SECTIONS {
? firtst? ?0x00000000 : { head.o init.o nand.o}
? second ?0x30000000 : AT(4096) { main.o }
}
可见:head.o init.o nand.o运行地址为0,它们在生成的映像文件(nand.bin)中的偏移地址也为0(从0开始存放)
?????????? main.o的运行地址为0x30000000,它在生成的映像文件(nand.bin)中的偏移地址为4096
Makefile文件:
nand.bin : head.S init.c nand.c main.c
?arm-linux-gcc -Wall -c -o head.o head.S
?arm-linux-gcc -Wall -c -o init.o init.c
?arm-linux-gcc -Wall -c -o nand.o nand.c
?arm-linux-gcc -Wall -c -o main.o main.c
?arm-linux-ld -Tnand.lds head.o init.o nand.o main.o -o nand_elf??? //表示按照脚本文件中的存放顺序来给这些文件在镜像文件中排序
?arm-linux-objcopy -O binary -S nand_elf nand.bin
?arm-linux-objdump -D -m arm nand_elf > nand.dis
?
clean:
?rm -f? nand.dis nand.bin nand_elf *.o?
将上述文件编译后 在反汇编后得到的文件
00000000 <_start>:
0000002c <halt_loop>:
00000038 <disable_watch_dog>:
00000054 <memsetup>:
00000140 <wait_idle>:
000001a8 <select_chip>:
00000200 <deselect_chip>:
00000258 <write_cmd>:
00000294 <write_addr>:
00000414 <read_data>:
0000044c <reset>:
00000470 <nand_init>:
000004a8 <nand_read>:
0000058c <s3c2440nand>:
30000000 <wait>:
30000034 <main>:
可见除了main文件中的函数 其它的函数均是运行在片内的4k内存中 而main文件中的main函数和wait函数则是运行在sdram中
?
??