Nand Flash 裸机程序

硬件平台 :JZ2440

实现功能:初始化 Nand Flash 和 sdram,并将代码从 Nand Flash 拷贝到 sdram。

start.s      --> 上电初始化 nand 与sdram

nand.c     -->  Nand Flash 初始化函数

sdram.c   --> sdram 初始化函数

leds.c      -->  led 闪烁

start.s 源码:

.text
.global _start
_start:
        ldr sp,=4096
        bl  disable_watch_dog
        bl  sdram_init
        bl  nand_init
        ldr r0,=0x30000000
        mov r1,#4096
        mov r2,#2048
        bl  nand_read
        ldr sp,=0x34000000
        ldr lr,=loop1
        ldr pc,=0x30000000
loop1: 
      b loop1

nand.c 源码:

#define BUSY          1

#define NAND_SECTOR_SIZE_LP    2048
#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

typedef struct 
{
    int   NFCONF;
    int   NFCONT;
    int   NFCMD;
    int   NFADDR;
    int   NFDATA;
    int   NFMECCD0;
    int   NFMECCD1;
    int   NFSECCD;
    int   NFSTAT;
    int   NFESTAT0;
    int   NFESTAT1;
    int   NFMECC0;
    int   NFMECC1;
    int   NFSECC;
    int   NFSBLK;
    int   NFEBLK;
} S3C2440_NAND;

static S3C2440_NAND *s3c2440nand = (S3C2440_NAND *)0x4e000000;

/* 供外部调用的函数 */
void nand_init(void);
void nand_read(unsigned char *buf, unsigned long start_addr, int size);

/* S3C2440的NAND Flash处理函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);


/* 复位 */
static void nand_reset(void)
{
    nand_select_chip();
    write_cmd(0xff);  // 复位命令
    wait_idle();
    nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void wait_idle(void)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
    while(!(*p & BUSY))
        for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void nand_select_chip(void)
{
    int i;
    s3c2440nand->NFCONT &= ~(1<<1);
    for(i=0; i<10; i++);    
}

/* 取消片选信号 */
static void nand_deselect_chip(void)
{
    s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void write_cmd(int cmd)
{
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *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 & NAND_BLOCK_MASK_LP;
    page = addr / NAND_SECTOR_SIZE_LP;
    
    *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;
    return *p;
}


/* 初始化NAND Flash */
void nand_init(void)
{
        #define TACLS   0
        #define TWRPH0  3
        #define TWRPH1  0   

        
        /* 设置时序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0); 
        /* 复位NAND Flash */
        nand_reset();
}


/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP))
    {
        return ;    /* 地址或长度不对齐 */
    }
    /* 选中芯片 */
    nand_select_chip();
    for(i=start_addr; i < (start_addr + size);) 
    {
      /* 发出READ0命令 */
      write_cmd(0);
      /* Write Address */
      write_addr(i);
      write_cmd(0x30);        
      wait_idle();
      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) //一页2k
      {
         *buf = read_data();
          buf++;
      }
    }
    /* 取消片选信号 */
    nand_deselect_chip();
    return ;
}

sdram.c 源码:

void disable_watch_dog(void)
{
    (*(unsigned long *)0x53000000)=0;
}

void sdram_init(void)
{
    unsigned long p[]={    0x22011110,
                        0x00000700,
                        0x00000700,
                        0x00000700,
                        0x00000700,
                        0x00000700,
                        0x00000700,
                        0x00018005,
                        0x00018005,
                        0x008c07a3,
                        0x000000b1,
                        0x00000030,
                        0x00000030 };
    unsigned long *sdram_base=(unsigned long *)0x48000000;
    int i=0;
    for(;i<13;i++) sdram_base[i]=p[i];
}

leds.c 源码:

#define    GPFCON        (*(volatile unsigned long *)0x56000050)
#define    GPFDAT        (*(volatile unsigned long *)0x56000054)

#define    GPF4_out    (1<<(4*2))
#define    GPF5_out    (1<<(5*2))
#define    GPF6_out    (1<<(6*2))

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(80000);
        GPFDAT = (~(i<<4));         // 根据i的值,点亮LED1-3
        if(++i == 8)
            i = 0;
    }

    return 0;
}

链接脚本 nand.lds:

SECTIONS
{
 first  0x00000000 :{start.o sdram.o nand.o}
seconed 0x30000000 :AT(4096) {leds.o}
}

编译的Makefile:

objs:=start.o sdram.o nand.o leds.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 -o $@ -c $<
%.o:%.S
    arm-linux-gcc -o $@ -c $<

clean:
    rm *.o *.bin *.dis nand_elf
原文地址:https://www.cnblogs.com/zsy12138/p/10407887.html