先看下链接脚本文件:
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中,可以看到跑马灯的效果。我已测试通过。


sjh835170 于 2014-04-15 10:10:45发表:
:0)1好帖,顶起,虽然没看懂。
txgc_wm 于 2011-04-06 01:14:32发表:
顶一下!
txgc_wm 于 2011-04-05 20:54:57发表:
摘自http://my.chinaunix.net/space.php?uid=18921523&do=blog&id=184183