根据韦东山老师教材编写的
K9F2G08U0A
的驱动程序编写方法
,改编
K9F2G08U0A
驱动代码,在天嵌开发板上验证成功,下面给出完整工程。芯片datasheet详见:
http://wenku.baidu.com/link?url=NAiybcJG_7IR28CXapf4kLtlaXpwscozV3zOPnSIfACrppXfboAhKHYcWfcSWBYkvjz6MOo_hBSXxPmmvWCiqs9JLThoL8v7BGOAqmPfgo7
附录:
(1)head.S
(5)Makefile
附录:
(1)head.S
@******************************************************************************
@ File:head.s
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************
.text
.global _start
_start:
@函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
ldr sp, =4096 @设置堆栈
bl disable_watch_dog @关WATCH DOG
bl clock_init
bl memsetup @初始化SDRAM
bl nand_init @初始化NAND Flash
bl RdNF2SDRAM1
ldr sp, =0x34000000 @设置栈
ldr lr, =halt_loop @设置返回地址
ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
halt_loop:
b halt_loop
(2)inc.c
(3)main.c
(4
)nand.c
/* WOTCH DOG register */
#define
WTCON
(*(volatile unsigned long *)0x53000000)
#define
CLKDIVN
(*(volatile unsigned long *)0x4c000014)
#define
MPLLCON
(*(volatile unsigned long *)0x4c000004)
/* SDRAM regisers */
#define S3C2440_MPLL_400MHZ ((0x7f<<12)|(0x02<<4)|(0x01))
#define
MEM_CTL_BASE
0x48000000
void disable_watch_dog();
void memsetup();
void clock_init(void);
/*上电后,WATCH DOG默认是开着的,要把它关掉 */
void disable_watch_dog()
{
WTCON
= 0;
}
void clock_init(void)
{
// LOCKTIME = 0x00ffffff; // 使用默认值即可
CLKDIVN = 0x05; // FCLK:HCLK:PCLK=1:4:8, HDIVN=2,PDIVN=1
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */
"orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */
"mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */
);
MPLLCON = S3C2440_MPLL_400MHZ; /* 现在,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
}
/* 设置控制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];
}
(3)main.c
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define led1out (1<<2*5)
//实验中跑马灯有四个灯要循环,故此需要四组输出控制来配置GPBCON
#define led2out (1<<2*6)
#define led3out (1<<2*7)
#define led4out (1<<2*8)
void delay(unsigned long i)
{
while(i--);
}
int main()
{
GPBCON |= led1out|led2out|led3out|led4out; //配置GPB5到GPB8端口输出属性
int i=0;
while(1)
{
GPBDAT = ~(1<<(i%4+5)); //亮灯
delay(10000); //延时
i++; //换灯变量
}
return 0;
}
#define TACLS 1
#define TWRPH0 5
#define TWRPH1 0
#define NFDATA
(*(volatile unsigned char *)0x4e000010)
//nand flash数据寄存器
typedef unsigned int S3C24X0_REG32;
/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA0;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
} S3C2440_NAND;
static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
void SendAD(unsigned long AD)
{
//s3c2440nand->NFADDR=AD;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
*p=AD;
}
/* 发出片选信号 */
static void s3c2440_nand_select_chip(void)
{
s3c2440nand->NFCONT &= ~(1<<1);
}
/* 取消片选信号 */
static void s3c2440_nand_deselect_chip(void)
{
s3c2440nand->NFCONT |= (1<<1);
}
/* S3C2440的NAND Flash操作函数 */
/* 复位 */
static void s3c2440_nand_reset(void)
{
s3c2440nand->NFCONT &= ~(1<<1);
s3c2440nand->NFSTAT |= (1<<2);
s3c2440nand->NFCMD = (0xff);
while(!(s3c2440nand->NFSTAT&(1<<2))); //test busy
s3c2440nand->NFCONT |= (1<<1);
}
/* 等待NAND Flash就绪 */
void s3c2440_wait_idle(void)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
while(!(*p & (1<<2)));
}
/* 初始化NAND Flash */
void nand_init(void)
{
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(3<<2)|(1<<1);
s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
s3c2440nand->NFSTAT =0x0;
s3c2440_nand_reset();
}
void nand_read(unsigned int block,unsigned int page,unsigned char *dstaddr)
{
int i;
unsigned int blockpage=(block<<6)+page;
s3c2440_nand_reset();
s3c2440nand->NFCONT &= ~(1<<1);
s3c2440nand->NFSTAT |= (1<<2);
s3c2440nand->NFCMD = (0x00);//send_cmd(readp1);
SendAD(0x00);
SendAD(0x00);
SendAD((blockpage)&0xff);
SendAD((blockpage>>8)&0xff);
SendAD((blockpage>>16)&0x01);
s3c2440nand->NFCMD = (0x30);//send_cmd(readp2);
while(!(s3c2440nand->NFSTAT&(1<<2))); //test busy
for(i=0;i<2048;i++)
{
dstaddr[i]=NFDATA;
}
s3c2440nand->NFCONT |= (1<<1);
return ;
}
void RdNF2SDRAM(void)
//将nand flash的代码复制到sdram中去
{
unsigned int i;
unsigned int start_addr =4096;
//4096表示第4096个字节
unsigned char * dstaddr = (unsigned char *)0x30000000;/*留心指针类型转换*/
unsigned int size = 2048; //大小2018 B
for(i = (start_addr >> 11); size > 0;i ++ )
//因为NAND_SECTOR_SIZE等于2048个字节,所以page就等于start_addr右移了11位,因为
{
//2^11=2048。这里i表示页的绝对地址,即该页距离第0页的绝对地址
nand_read(i/64,i%64, dstaddr);
size -= 2048;
dstaddr += 2048;
}
}
/* 发出地址 */
static void s3c2440_write_addr(unsigned int addr)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
*p = addr&0xff;
*p = addr&0xf0;
*p = (addr >> 11) & 0xff;
*p = (addr >> 19) & 0xff;
*p = (addr >> 27) & 0x01;
}
void RdNF2SDRAM1(void)
//将nand flash的代码复制到sdram中去
{
unsigned int i,j;
unsigned int start_addr =4096;
//4096表示第4096个字节
unsigned char * dstaddr = (unsigned char *)0x30000000;/*留心指针类型转换*/
unsigned int size = 2048; //大小2048B
unsigned int blockpage=start_addr>>11;
for(i=start_addr;i<start_addr+size;)
{
s3c2440_nand_reset();
s3c2440nand->NFCONT &= ~(1<<1);
s3c2440nand->NFSTAT |= (1<<2);
s3c2440nand->NFCMD = (0x00);//send_cmd(readp1);
s3c2440_write_addr(i);
s3c2440nand->NFCMD = (0x30);//send_cmd(readp2);
while(!(s3c2440nand->NFSTAT&(1<<2))); //test busy
for(j=0;j<size;j++,i++)
{
dstaddr[j]=NFDATA;
}
s3c2440nand->NFCONT |= (1<<1);
}
}
objs := head.o init.o nand.o main.o
nand.bin : $(objs)
arm-linux-ld -Tnand.lds
-o nand_elf $^
arm-linux-objcopy -O binary -S nand_elf $@
arm-linux-objdump -D -m arm nand_elf > nand.dis
%.o:%.c
arm-linux-gcc -nostdlib -Wall -c -o $@ $<
%.o:%.S
arm-linux-gcc -nostdlib -Wall -c -o $@ $<
clean:
rm -f nand.dis nand.bin nand_elf *.o
(6)nand.lds
SECTIONS {
firtst
0x00000000 : { head.o init.o nand.o }
second
0x30000000 : AT(4096)
{main.o}
}