nandflash裸机程序分析

发布者:陈熙琼最新更新时间:2016-12-03 来源: eefocus关键字:nandflash  裸机程序 手机看文章 扫描二维码
随时随地手机看文章

它包含7个文件:

head.S

init.c

main.c

Makefile

nand.c

nand.lds

我们之前的程序都是在nandflash的前4k放代码,上电后自动拷贝到SRAM中,之后将SRAM中的代码拷贝到SDRAM中。可是当我们的程序太大超过4k的时候就不行了,因为无法将nandflash的代码完全拷贝到SRAM中去,这时就需要从nandflash中拷贝代码了。

本程序里面我们要实现的就是:将一部分代码放在nandflash的4096之后,上电后,前面一部分代码自动拷贝到SRAM中,在这段代码里面将nandflash的4096之后的程序拷贝到SDRAM中。

我们从入口函数开始分析:

@******************************************************************************

@ 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      memsetup                    @初始化SDRAM,主要是设置控制SDRAM的13个寄存器

            bl      nand_init                       @初始化NAND Flas,见注释1


                                                          @将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中

                                                          @nand_read_ll函数需要3个参数:

            ldr     r0,     =0x30000000      @1. 目标地址=0x30000000,这是SDRAM的起始地址

            mov     r1,     #4096               @2.  源地址   = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处

            mov     r2,     #2048               @3.  复制长度= 2048(bytes),对于本实验的main.c,这是足够了

            bl      nand_read                    @调用C函数nand_read,见注释2


            ldr     sp, =0x34000000         @设置栈

            ldr     lr, =halt_loop                 @设置返回地址

            ldr     pc, =main                     @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转

halt_loop:

            b       halt_loop


注释1:

void nand_init(void)

{

#define TACLS   0

#define TWRPH0  3

#define TWRPH1  0

    /* 判断是S3C2410还是S3C2440 */

    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))//这里表示是2410

    {

        nand_chip.nand_reset         = s3c2410_nand_reset;

        nand_chip.wait_idle          = s3c2410_wait_idle;

        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;

        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;

        nand_chip.write_cmd          = s3c2410_write_cmd;

        nand_chip.write_addr         = s3c2410_write_addr;

        nand_chip.read_data          = s3c2410_read_data;

 /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */

        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

    }

    else

    {   /* 定义了各种操作函数 */

        nand_chip.nand_reset         = s3c2440_nand_reset; //见注释1-1

        nand_chip.wait_idle          = s3c2440_wait_idle;         //见注释1-2

        nand_chip.nand_select_chip   = s3c2440_nand_select_chip; //见注释1-3

        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip; //见注释1-4

        nand_chip.write_cmd          = s3c2440_write_cmd; //见注释1-5

#ifdef LARGER_NAND_PAGE

        nand_chip.write_addr         = s3c2440_write_addr_lp;//大页写地址,见注释1-6

#else

 nand_chip.write_addr   = s3c2440_write_addr;//小页写地址,见注释1-7

#endif

        nand_chip.read_data          = s3c2440_read_data;  //读数据,见注释1-8

/* 设置时序 */

        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);//这个东东在linux编程里面说过了,不再重复

        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */

        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

    }

    

    /* 复位NAND Flash */

    nand_reset();//见注释1-9

}

注释1-1:

/* 复位 */

static void s3c2440_nand_reset(void)

{

    s3c2440_nand_select_chip();        //选中芯片

    s3c2440_write_cmd(0xff);             // ffh是复位命令,将这个命令写入命令寄存器即可

    s3c2440_wait_idle();                     //等待就绪

    s3c2440_nand_deselect_chip();  //不选中芯片

}


注释1-2:

/* 等待NAND Flash就绪 */

static void s3c2440_wait_idle(void)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

    while(!(*p & BUSY))//根据NFSTAT第0位判断是否就绪,1表示就绪

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

}

注释1-3:

/* 发出片选信号 */

static void s3c2440_nand_select_chip(void)

{

    int i;

    s3c2440nand->NFCONT &= ~(1<<1);//NFCONT寄存器的第1位用于选中芯片,0表示选中

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

}


见注释1-4:

/* 取消片选信号 */

static void s3c2440_nand_deselect_chip(void)

{

    s3c2440nand->NFCONT |= (1<<1);//参考注释1-3

}


注释1-5:

/* 发出命令 */

static void s3c2440_write_cmd(int cmd)

{

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;

    *p = cmd;//就是将命令写到命令寄存器里面,很简单

}


注释1-6:

/* 大页写地址,分5个周期写入 */

static void s3c2440_write_addr_lp(unsigned int addr)

{

int i;

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

int col, page;

         //#define NAND_SECTOR_SIZE_LP    2048

         //#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

col = addr & NAND_BLOCK_MASK_LP;  //收下地址前11位,屏蔽高位

page = addr / NAND_SECTOR_SIZE_LP;//屏蔽地址前11位,收下高位

        /* 分5个周期将地址写到地址寄存器里面 */

*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++);

}

注释1-7:

/*小页写地址,分4个周期写入*/

static void s3c2440_write_addr(unsigned int addr)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    

    *p = addr & 0xff;

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

    *p = (addr >> 9) & 0xff;

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

    *p = (addr >> 17) & 0xff;

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

    *p = (addr >> 25) & 0xff;

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

}


注释1-8:

/* 读取数据 */

static unsigned char s3c2440_read_data(void)

{

    /* 很简单,就是将数据从数据寄存器里面读出来 */

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;

    return *p;

}


注释1-9:

/* 在第一次使用NAND Flash前,复位一下NAND Flash */

static void nand_reset(void)

{

    nand_chip.nand_reset();//不解释

}

注释2:

首先要知道的是,r0、r1、r2保存着nand_read函数的三个参数,依次对应

目标、源、大小

/* 读函数 */

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

{

    int i, j;


#ifdef LARGER_NAND_PAGE

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {

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

    }

#else

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

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

    }

#endif


    /* 选中芯片 */

    nand_select_chip();

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

      /* 发出READ0命令 */

      write_cmd(0);


      /* Write Address */

      write_addr(i);

#ifdef LARGER_NAND_PAGE

      write_cmd(0x30);  

#endif

      wait_idle();


#ifdef LARGER_NAND_PAGE

      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {

#else

  for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

#endif

          *buf = read_data();//读走一页数据到buf中

          buf++;

      }

    }


    /* 取消片选信号 */

    nand_deselect_chip();

    

    return ;

}


总结一下:

(1)选中芯片

(2)发送00h

(3)发出地址

(4)发30h

(5)等待就绪

(6)读一页数据

完全是按着时序图来的哦!


接着我们跳到主函数里面:

发现还是那个点灯的程序,好吧!掠过!


我们最后来看一看连接文件和Makefile文件:

SECTIONS { 

  firtst   0x00000000 : { head.o init.o nand.o}

  second  0x30000000 : AT(4096) { main.o }

我们看到这个程序被分成两段,第一段从0地址开始,第二段加载地址是4096处开始的,也就是从4k之后开始的,它不会被自动加载到SRAM中。


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 -Wall -c -O2 -o $@ $<  @所有的.c文件只编译不连接


%.o:%.S

arm-linux-gcc -Wall -c -O2 -o $@ $<  @所有的.S文件只编译不连接


clean:

rm -f  nand.dis nand.bin nand_elf *.o


关键字:nandflash  裸机程序 引用地址:nandflash裸机程序分析

上一篇:USB系统设备模型建立流程
下一篇:U-Boot中SMDK2410的NAND Flash驱动

推荐阅读最新更新时间:2024-03-16 15:23

S3C2440裸机------异常与中断__swi异常模示程序示例
一般来说,我们的app运行于用户模式,用户模式是一种受限的模式,不能访问硬件,如果app想访问硬件,必须切换模式,当发生中断或者异常时会自动切换模式,但是中断和异常时可遇不可求的,这时候我们通过软中断切换模式。 1.start.S 由于复位之后cpu处于svc管理模式,所以我们先修改cpsr让cpu处于用户模式,然后设置用户模式下的栈。 .text .global _start _start: b reset /* vector 0 : reset */ ldr pc, und_addr /* vector 4 : und */ ldr pc, swi_addr /* vector 8 :
[单片机]
S3C2440<font color='red'>裸机</font>------异常与中断__swi异常模示<font color='red'>程序</font>示例
基于Nandflash的Bootloader的设计与实现
0 引言     Bootloader通常称为系统引导加载程序,是系统加电或复位后执行第一段代码 。一般它只在系统启动时运行非常短时间,但对于嵌入式系统来说,这是一个非常重要系统组成部分。通过这段小程序,可以初始化硬件设备、建立内存空间映射图,从而将系统软硬件环境带到一个合适状态,以便为调用操作系统内核准备好正确环境,并同时提供基本输入、输出系统监控功能和程序调试功能。     Bootloader是严重地依赖于硬件而实现。每种不同体系结构处理器都有不同Bootloader。除了依赖于处理器体系结构以外,Bootloader实际上也依赖于具体嵌入式板级设备配置,也就是说,对于两块不同嵌入式板而言,即使它们是基于同一种处理器
[嵌入式]
u-boot-2016.09移植(7)-nandflash
一、uboot中增加NANDFLASH 由第二节分析得知,硬件初始化在board_init_r中,我们到这里找到nand的初始化: u-boot-2016.09$ vim common/board_r.c 看这里知道首先我们需要定义宏CONFIG_CMD_NAND,屏蔽CONFIG_CMD_ONENAND,才可以调用nand的初始化函数,在include/conifgs/tq210.h中定义宏: #define CONFIG_CMD_NAND 编译,发现没有定义CONFIG_SYS_MAX_NAND_DEVICE,由于我们的板子上只有一个nandflash,所以在tq210.h中定义宏: #define C
[单片机]
u-boot-2016.09移植(7)-<font color='red'>nandflash</font>
S3C2440裸机程序【2】串口uart程序
学习ARM7芯片stm32时,裸机程序开发可以很方便的根据库函数在工程模板上进行开发,而ARM9主要是移植Linux开发,很少有裸机程序开发,因此在玩S3C2440希望最终形成一个keil环境下的模板。用的淘宝上的JZ2440v2板子,因为是裸机程序开发其他板子都一样。 S3C2440.s是keil自动生成的启动文件,其他都是按stm32库函数模板写的,技术很差,自学娱乐,若有需求可自行改动。 main.c文件: #include S3C2440Reg.h #include S3C2440Init.h #include led.h #include uart.h void delay(int t) {
[单片机]
S3C2440<font color='red'>裸机</font><font color='red'>程序</font>【2】串口uart<font color='red'>程序</font>
ARM裸机程序——跑马灯
最近看了一些启动代码的分析,还有很多不懂的地方,打算后面再写关于启动代码的分析。先跑了一些无操作系统裸机程序,来熟悉硬件。开发板用的是FL2440。 先看这样一段C代码 #define GPBCON (*(volatile unsigned long *)0x56000010) //这是寄存器的定义,由于GPB引脚在硬件上连接到了LED上,所以 用到GPB引脚,那么就要定义相关寄存器,该寄存器定义了GPB相关引脚的工作方式。 #define GPBDAT (*(volatile unsigned long *)0x56000014) //该寄存器用来给引脚上的数据。 int main() { GPBCON=0x0000
[单片机]
s3c2440裸机-nandflash编程(二. nand控制器和nand访问时序)
一.Steppingstone 我们知道nand没有独立地址线,cpu无法直接访问nand上的指令,所以nand不能片上执行。那么为何程序还能支持nand启动的呢? 为了支持NAND启动,S3C2440A配备了一个称为“ Steppingstone”的内部SRAM缓冲区,容量为4K。 开机时,Nandflash中的前4K数据将被加载到Steppingstone中,而引导代码将被加载到SRAM中将被执行,如下图所示: 我们知道s3c2440支持2种boot方式,nand或者nor,那么需要配置OM引脚来设置引导方式,如下图: 内存控制器的地址映射表如下: 我们得知OM1接地,OM0接了一个开关SW2,那么我们的OM
[单片机]
s3c2440<font color='red'>裸机</font>-<font color='red'>nandflash</font>编程(二. nand控制器和nand访问时序)
cc2530裸机编程系列笔记1--定时器Timer1模模式的程序设计
定时器/计数器是单片机的几大重要资源之一,而cc2530的定时器/计数器与普通的51系列单片机相比,工作模式增加了。通过学习手册可知cc2530的定时器/计数器有三种工作模式,风别为自由模式、模模式和正计数/倒计数模式。无论哪种模式,均可以采用查询和中断两种方式使用定时器的。本专题讲述cc2530定时器/计数器处于模模式时的编程方法。 首先是用查询的方式来使用Timer1定时器。使用Timer定时器时,首先要对该定时器进行初始化,代码如下: void INIT_Timer1() { T1CTL = 0x00; //1分频、停止运行 T1CTL = 0x0e; //128分频 模模式 T1CCTL0 |= 0
[单片机]
cc2530<font color='red'>裸机</font>编程系列笔记1--定时器Timer1模模式的<font color='red'>程序</font>设计
S5PV210的NandFlash应用(二)
准备分析 《S5PV210的NandFlash应用(一)》有很多bug,为了文章完整性就不在原文上进行修改了。(一)是在调试nand_cp.c的时候,程序运行过之后,灯立即亮了起来,让我误以为我的NandFlash读操作正常了,最后在往下进行大文件拷贝的时候出现异常,我不得不重新回到这个Nand_cp.c这里来。这次结合Uart打印出NandFlash读出的数据,和210.bin文件进行对比,发现后边错误很多,但是我的程序也能运行。总结出了(一)里边的bug有:1.nand_cp.c中应该调用board_init_f_nand(),而非copy_uboot_to_ram_nand()。2.board_init_f_nand中的
[单片机]
S5PV210的<font color='red'>NandFlash</font>应用(二)
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved