红联Linux门户
Linux帮助

nandflash读取 2048k的都可以

发布时间:2011-04-05 20:53:36来源:红联作者:txgc_wm
[i=s] 本帖最后由 txgc_wm 于 2011-4-5 21:01 编辑 [/i]

先看下链接脚本文件:
ENTRY(_start)

SECTIONS

{

. = 0x00000000;

.text1 :{

start.o nand.o(.text)

}

.text2 0x30000000 : AT(4096){

main.o(.text)

}



. = ALIGN(32);

.data :{

*(.data)

}

. = ALIGN(32);

.bss :{

*(.bss)

}

}
意思在前面一篇已经讲过,这里实现的主要功能是,前4k的内容由CPU自动拷贝到内部SRAM中去执行,这前4k的代码包含start.s 和 nand.c文件,这前4k的代码执行一定的初始化的工作,并将NANDFLASH中位于4k之后的代码main.c拷贝到SDRAM中的0X30000000地址处,并执行,main.c主要实现二进制加法的跑马灯。
看下start.S:
/******************************************************************

*定义各模式堆栈空间

*******************************************************************/

.equ FIQ_STACK, 0x36FFF000

.equ IRQ_STACK, 0x36FFE000

.equ ABORT_STACK, 0x36FFD000

.equ UNDEFINE_STACK, 0x36FFC000

.equ USER_STACK, 0x36FFB000

.equ SVC_STACK, 0x36FFA000

/******************************************************************

*中断向量表

*******************************************************************/

.text

.global _start

_start: b start_code @0x00,复位异常

ldr pc, undefined_instruction @0x04,未定义指令异常

ldr pc, software_interrupt @0x08,软中断

ldr pc, prefetch_abort @0x0c,指令预取终止异常

ldr pc, data_abort @0x10,数据访问终止异常

ldr pc, not_used @0x14,保留

ldr pc, irq @0x18,中断

ldr pc, fiq @0x1c,快速中断

/******************************************************************

*代码开始

*******************************************************************/

start_code:

mrs r0, cpsr @设置为管理模式

bic r0, r0, #0x1F @ARM指令,禁止中断

orr r0, r0, #0xD3

msr cpsr, r0



ldr r0, =0x53000000 @关闭看门狗

mov r1, #0x0

str r1, [r0]



ldr r0, =0x4C000014 @设置时钟分频比

mov r1, #0x05 @FCLK:HCLK:PCLK = 1:4:8

str r1, [r0]



mrc p15, 0, r0, c1, c0, 0 @如果HDIVN不为0,使其从

orr r0, r0, #0xC0000000 @由快总线模式变为异步总线模式

mcr p15, 0, r0, c1, c0, 0



ldr r0, =0x4C000008 @设置UCLK=48MHz

ldr r1, =0x00038022 @(56<<12)|(2<<4)|(2)

str r1, [r0]



ldr r0, =0x4C000004 @设置FCLK=400MHz

ldr r1, =0x0005C011 @(92<<12)|(1<<4)|(1)

str r1, [r0]



mov r1, #0x48000000 @设置SDRAM

adrl r2, mem_cfg_val

add r3, r1, #52

1:

ldr r4, [r2], #4

str r4, [r1], #4

cmp r1, r3

bne 1b

/******************************************************************

*设置各模式堆栈

*******************************************************************/

mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xDB

msr cpsr, r0

ldr sp, =UNDEFINE_STACK



mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xD7

msr cpsr, r0

ldr sp, =ABORT_STACK



mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xD2

msr cpsr, r0

ldr sp, =IRQ_STACK



mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xD1

msr cpsr, r0

ldr sp, =FIQ_STACK



mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xD0

msr cpsr, r0

ldr sp, =USER_STACK



mrs r0, cpsr

bic r0, r0, #0x1F

orr r0, r0, #0xD3

msr cpsr, r0

ldr sp, =SVC_STACK

/******************************************************************

*从nandflash复制代码到SDRAM,点灯,跳入第二阶段执行

*******************************************************************/

ldr sp, =4096

bl s3c2440_nand_init

ldr r0, =0x30000000

mov r1, #4096

mov r2, #2048

bl s3c2440_nand_read


ldr lr, =halt_loop

ldr pc, =main



halt_loop:

b halt_loop



/*******************************************************************

*存储控制器13个寄存器的设置值

********************************************************************/

.align 4

mem_cfg_val:

.long 0x22011110

.long 0x00000700

.long 0x00000700

.long 0x00000700

.long 0x00000700

.long 0x00000700

.long 0x00000700

.long 0x00018005

.long 0x00018005

.long 0x008C07A3

.long 0x000000B2

.long 0x00000030

.long 0x00000030



/*******************************************************************

*中断处理

********************************************************************/

undefined_instruction:

b undefined_instruction

software_interrupt:

b software_interrupt

prefetch_abort:

b prefetch_abort

data_abort:

b data_abort

not_used:

b not_used

irq:

b irq

fiq:

b fiq
核心代码就是下面几句啦:
ldr sp, =4096

bl s3c2440_nand_init

ldr r0, =0x30000000

mov r1, #4096

mov r2, #2048

bl s3c2440_nand_read


ldr lr, =halt_loop

ldr pc, =main



halt_loop:

b halt_loop


第一句,设置栈空间,因为下面即将要调用C语言函数,接着调用S3C2440_nand_init对nandflash进行初始化,接着根据APTCS法则,向s3c2440_nand_read函数传递3个参数,分别为r0,r1,r2,意思分别为,目的地址,起始地址,长度。s3c2440_nand_read主要实现从起始地址复制长度为R2的数据到目的地址中去,这里长度写为2048,main的大小肯定不会大于2k的了,所以一定会复制过去的,之后,便是保存返回地址,调用main函数。


下面分别看看nand相关的操作函数,在文件nand.c中:
#define TACLS 0

#define TWRPH0 3

#define TWRPH1 0



#define BUSY 1



#define NAND_SECTOR_SIZE 2048 //一页2K大小

#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)



#define _REGb(x) (*(volatile unsigned char *)(x))

#define _REGi(x) (*(volatile unsigned int *)(x))



#define NANDFLASH_BASE 0x4E000000 //配置寄存器基地址



#define NANDFLASH_CONF _REGi(NANDFLASH_BASE + 0x0)

#define NANDFLASH_CONT _REGi(NANDFLASH_BASE + 0x4)

#define NANDFLASH_CMD _REGb(NANDFLASH_BASE + 0x8)

#define NANDFLASH_ADDR _REGb(NANDFLASH_BASE + 0xC)

#define NANDFLASH_DATA _REGb(NANDFLASH_BASE + 0x10)

#define NANDFLASH_STAT _REGb(NANDFLASH_BASE + 0x20)





static void s3c2440_wait_idle(void);

static void s3c2440_nand_select_chip(void);

static void s3c2440_nand_deselect_chip(void);

static void s3c2440_write_cmd(int);







static void delay(void)

{

int i;

for(i=0; i<10; i++);

}



static void s3c2440_nand_reset(void)

{

s3c2440_nand_select_chip();

s3c2440_write_cmd(0xff);

s3c2440_wait_idle();

s3c2440_nand_deselect_chip();

}



static void s3c2440_wait_idle(void)

{

while(!(NANDFLASH_STAT & BUSY))

delay();

}



static void s3c2440_nand_select_chip(void)

{

NANDFLASH_CONT &= ~(1<<1);

delay();

}



static void s3c2440_nand_deselect_chip(void)

{

NANDFLASH_CONT |= (1<<1);

delay();

}



static void s3c2440_write_cmd(int cmd)

{

NANDFLASH_CMD = cmd;

}



static void s3c2440_write_addr(unsigned int addr)

{

int col, page;



col = addr & NAND_BLOCK_MASK; //取地址的低11位,所为行地址

page = addr / NAND_SECTOR_SIZE; //去掉地址的低11位,保留其余位,也就是剩下的都作为列地址



NANDFLASH_ADDR = col & 0xff;

delay();

NANDFLASH_ADDR = (col >> 8) & 0x0f;

delay();

NANDFLASH_ADDR = page & 0xff;

delay();

NANDFLASH_ADDR = (page >> 8) & 0xff;

delay();

NANDFLASH_ADDR = (page >> 16) & 0xff;

delay();

}



void s3c2440_nand_init(void)

{

NANDFLASH_CONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

NANDFLASH_CONT = (1<<4)|(1<<1)|(1<<0);



s3c2440_nand_reset();

}



void s3c2440_nand_read(unsigned char *buf, unsigned int start_addr, int size)

{

int i,j;



if((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

return; //地址或长度不对齐

s3c2440_nand_select_chip();

for(i=start_addr; i<(start_addr + size);)

{

s3c2440_write_cmd(0x00);

s3c2440_write_addr(i);

s3c2440_write_cmd(0x30);

s3c2440_wait_idle();



for(j=0; j
{

*buf = (NANDFLASH_DATA & 0xFF);

buf++;

}

}



s3c2440_nand_deselect_chip();

}


这里看看其实不难的,主要按照nandflash提供的方法来写程序,主要有两句
col = addr & NAND_BLOCK_MASK; //取地址的低11位,所为行地址

page = addr / NAND_SECTOR_SIZE; //去掉地址的低11位,保留其余位,也就是剩下的都作为列地址




我已经做了注释,可以好好理解。
实在不行可以看看韦东山大哥的书nandflash那一章,好好理解。


接下来main.c和以前的一样,将生成的nand.bin文件用JTAG小板烧到NANDFLASH中,可以看到跑马灯的效果。我已测试通过。
文章评论

共有 3 条评论

  1. sjh835170 于 2014-04-15 10:10:45发表:

    :0)1好帖,顶起,虽然没看懂。

  2. txgc_wm 于 2011-04-06 01:14:32发表:

    顶一下!

  3. txgc_wm 于 2011-04-05 20:54:57发表:

    摘自http://my.chinaunix.net/space.php?uid=18921523&do=blog&id=184183