历史上的今天
返回首页

历史上的今天

今天是:2025年10月28日(星期二)

正在发生

2022年10月28日 | 【JZ2440笔记】裸机实验使用NandFlash

2022-10-28 来源:csdn

一、前言

S3C2440芯片内部没有ROM可以放用户代码,所以用户代码需要被保存在外部的存储器当中,如果是NorFlash的话可以直接在NorFlash中运行程序,但是NorFlash比较贵,一般都用NandFlash作为存储介质,以SDRAM为代码的运行空间。JZ2440开发板上有一颗256MB容量的NandFlash芯片,记录下学习过程,代码是开发板自带的例程。


二、实验目标

在SRAM运行程序关闭看门狗,初始化SDRAM,初始化NandFlash控制器,随后将NandFlash块1中的main.c部分代码拷贝到SDRAM中运行,看到开发板上3个LED显示流水灯效果。


三、资源分析

NandFlash型号K9F2G08U0C,SLC三星颗粒,基本参数如下:

Page大小为2K+64Byte,意思是一个Page前2KB使用来存数据的,后面的64字节用来存ECC(错误纠正码)或者自定义的冗余数据。NandFlash由于其物理特性,一般都会有坏块的,而且NandFlash里面存的数据不像SRAM那样稳定,可能会出现位翻转现象,所以需要加入一些校验码(ECC)来纠正这些错误。其实因为这颗NandFlash是SLC的缘故,相比于MLC或者TLC的NandFlash来说稳定性高得多,一般环境条件下也是很少出现位翻转现象的。一个Page虽然真实是有2K+64Byte的数据量,但是一般是只使用2K的,当然如果非要用上后面的64Byte数据也是可以的,那样就用不了ECC了,这个东西只是建议用2K而已,具体想怎么个用法还是看自己的。


Block(块)大小为128K+4K,意思是一个Block有64个Page,写入的最小单位是Page,擦除的最小单位是Block。全盘有2048个Block。


NandFlash接口比SDRAM的简单,地址总线和数据总线是共用的。


大页模式下,发送地址时有5个周期,发送5个字节的地址。如下:

前两个字节是列地址,*L表示强制为0,所以列地址实际用了12个位来寻址,可以寻址0到4096的范围,是用来寻址Page内的字节偏移的,恰好够寻址2KB + 64Byte的数据量。


后三个字节是行地址,*L表示强制为0,所以行地址实际用了17个位来寻址,可以寻址0到128K的范围,是用来寻址Page序号的,64个Page X 2048个Block = 128K个Page,所以刚好17个位够用。


往S3C2440的几个NandFlash专用寄存器读写数据,NandFlash控制器就会将这些数据以命令或者数据的形式操作IO引脚控制NandFlash。如下:

四、程序代码

程序分为6个文件,分别如下:


head.S:启动文件,完成相关初始化。


init.c:初始化相关的C函数代码。


nand.c:NandFlash初始化及相关操作代码。


main.c:跑流水灯的代码,需要被拷贝到SDRAM中运行。


nand.lds:链接脚本,划分程序段。


Makefile:编译代码。


这些代码文件内容分别如下:


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      memsetup                @初始化SDRAM

            bl      nand_init               @初始化NAND Flash

                                            @将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

            ldr     sp, =0x34000000         @设置栈

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

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

halt_loop:

            b       halt_loop


init.c


/* WOTCH DOG register */

#define WTCON (*(volatile unsigned long *)0x53000000)

 

/* SDRAM regisers */

#define MEM_CTL_BASE 0x48000000

 

void disable_watch_dog();

void memsetup();

 

/*上电后,WATCH DOG默认是开着的,要把它关掉 */

void disable_watch_dog()

{

WTCON = 0;

}

 

/* 设置控制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];

}


其实SDRAM的初始化就配置BANK6相关的几个寄存器就可以了,例程这里配多了。


nand.c


#define LARGER_NAND_PAGE

 

#define GSTATUS1        (*(volatile unsigned int *)0x560000B0)

#define BUSY            1

 

#define NAND_SECTOR_SIZE    512

#define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)

 

#define NAND_SECTOR_SIZE_LP    2048

#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

 

typedef unsigned int S3C24X0_REG32;

 

/* NAND FLASH (see S3C2410 manual chapter 6) */

typedef struct {

    S3C24X0_REG32   NFCONF;

    S3C24X0_REG32   NFCMD;

    S3C24X0_REG32   NFADDR;

    S3C24X0_REG32   NFDATA;

    S3C24X0_REG32   NFSTAT;

    S3C24X0_REG32   NFECC;

} S3C2410_NAND;

 

/* 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   NFDATA;

    S3C24X0_REG32   NFMECCD0;

    S3C24X0_REG32   NFMECCD1;

    S3C24X0_REG32   NFSECCD;

    S3C24X0_REG32   NFSTAT;

    S3C24X0_REG32   NFESTAT0;

    S3C24X0_REG32   NFESTAT1;

    S3C24X0_REG32   NFMECC0;

    S3C24X0_REG32   NFMECC1;

    S3C24X0_REG32   NFSECC;

    S3C24X0_REG32   NFSBLK;

    S3C24X0_REG32   NFEBLK;

} S3C2440_NAND;


typedef struct {

    void (*nand_reset)(void);

    void (*wait_idle)(void);

    void (*nand_select_chip)(void);

    void (*nand_deselect_chip)(void);

    void (*write_cmd)(int cmd);

    void (*write_addr)(unsigned int addr);

    unsigned char (*read_data)(void);

}t_nand_chip;

 

static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;

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

 

static t_nand_chip nand_chip;

 

/* 供外部调用的函数 */

void nand_init(void);

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

 

/* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */

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

 

/* S3C2410的NAND Flash处理函数 */

static void s3c2410_nand_reset(void);

static void s3c2410_wait_idle(void);

static void s3c2410_nand_select_chip(void);

static void s3c2410_nand_deselect_chip(void);

static void s3c2410_write_cmd(int cmd);

static void s3c2410_write_addr(unsigned int addr);

static unsigned char s3c2410_read_data();

 

/* S3C2440的NAND Flash处理函数 */

static void s3c2440_nand_reset(void);

static void s3c2440_wait_idle(void);

static void s3c2440_nand_select_chip(void);

static void s3c2440_nand_deselect_chip(void);

推荐阅读

史海拾趣

GAPTEC Electronic GmbH & Co. KG公司的发展小趣事

背景:随着全球对环保和可持续发展的重视,Galaxy Microelectronics也开始关注其生产过程中的环保问题。

发展:公司投入巨资建设绿色工厂,采用先进的环保技术和设备,减少生产过程中的能源消耗和废弃物排放。同时,Galaxy Microelectronics还积极推广环保理念,与供应商和客户共同构建绿色供应链。这些举措不仅提升了公司的社会形象,还为其在竞争激烈的市场中赢得了更多客户的青睐。

Chips And Technologies Inc公司的发展小趣事

Chips And Technologies Inc的创业之路始于1984年,由Gordon A. Campbell和Dado Banatao在加利福尼亚州的米尔皮塔斯共同创立。作为一家早期的无晶圆厂半导体公司,C&T凭借对技术的深刻理解和市场的前瞻性,成功推出了首款四芯片EGA芯片组,这款产品能够处理增强型图形适配器上19个IBM专有芯片的功能,为当时的个人电脑制造商提供了强大的支持。

Gulf Semiconductor公司的发展小趣事

在创立初期,C&T就展现出了强大的技术创新能力。公司不断推出新产品,这些产品不仅性能卓越,而且具有高度的集成性和稳定性,深受市场欢迎。此外,C&T还积极与业界合作,推动技术标准的制定和完善,为整个行业的发展做出了重要贡献。

Automatic Connector公司的发展小趣事

在电子连接器行业,品质是决定企业生死存亡的关键。Automatic Connector公司深知这一点,因此在生产过程中严格执行品质管理标准。公司引进了先进的生产设备和质量检测仪器,确保每一件产品都符合高标准的质量要求。同时,公司还建立了完善的售后服务体系,及时解决客户在使用过程中遇到的问题。凭借卓越的品质和优质的服务,Automatic Connector赢得了客户的信赖和好评。

EXCELTA公司的发展小趣事

随着科技的不断进步和市场的不断变化,Excelta始终将技术创新作为公司发展的核心驱动力。公司投入大量资金和资源进行技术研发和产品创新,不断推出具有竞争力的新产品。其中,一款高性能的微型连接器产品凭借其出色的性能和稳定性在市场上取得了巨大成功。此外,Excelta还积极探索新的应用领域和市场机会,为公司的持续发展注入了新的活力。

DEVCON公司的发展小趣事

随着DEVCON品牌知名度的提升和产品线的不断丰富,公司开始将目光投向更广阔的市场。通过与国际知名企业的合作和代理,DEVCON的产品逐渐进入全球电子制造和维修领域。同时,公司还积极开拓新兴市场,如汽车电子、安防监控等领域,进一步扩大了市场份额。这种市场扩张的策略不仅带来了丰厚的回报,也为DEVCON公司的长期发展奠定了坚实基础。

问答坊 | AI 解惑

输入阻抗和输出阻抗小结

一、输入阻抗 输入阻抗是指一个电路输入端的等效阻抗。在输入端上加上一个电压源U,测量输入端的电流I,则输入阻抗Rin就是U/I。你可以把输入端想象成一个电阻的两端,这个电阻的阻值,就是输入阻抗。 输入阻抗跟一个普通的电抗元件没什么两样 ...…

查看全部问答>

在SBUF处设置0xAA, 运行到switch(a)处就返回了,不能进如 switch(a)内,

while(1)     {         if(RI)          {             RI = 0;             a& ...…

查看全部问答>

哪位大虾能告诉在下虚拟机到底是干什么用的

经常听到虚拟机这个词确从来没有接触过…………不知道它到底有哪用?和微软的XP,win7 有啥不同的功能…

查看全部问答>

uboot中的dm9000aep驱动

在移植完uboot1.1.6后,除了网络功能其它都没问题了 可是现在ping不通,也就不能使用tftp 板子上是DM9000AEP芯片,网友说是uboot自带驱动与AEP并不兼容 请问一下如何修改驱动以使DM9000AEP 芯片正常工作? 谢谢,祝好!…

查看全部问答>

i2c设备驱动程序编译不过去

各位大哥:     最近在做i2c的设备驱动程序。在网上找了些资料。针对自己的设备写了一个驱动程序。但编译不过去。    提示variable \'ds2746_driver\' has initializer but incomplete type.    unknow field \'o ...…

查看全部问答>

市场调研公司公布2006年全球半导体供应商排名,ST稳坐第五

在iSuppli研究的250家半导体公司中,有190家或76%在2006年实现成长。其中,128家的销售额实现了两位数的增长。在五大半导体供应商中,除了英特尔以外,2006年都超过了半导体市场的平均增长率,至少增长了11%。…

查看全部问答>

单片机交流群, 群号 72787489,随便问个问题

     DS18B20_writeonechar(0x33);      for(b=0;b<8;b++)      {      a= DS18B20_readonechar();      } &nb ...…

查看全部问答>

ULN2003A中COM端为啥可以悬空?

ULN2003A中COM端为啥可以悬空?可以接高电平吗?接高电平时可以接多大的电压?COM端与各输出端之间的反向二极管起什么作用?当COM端悬空时,该二极管还能发挥作用吗?…

查看全部问答>

FPGA开发板 哪个好!!!!

我想学习一下FPGA,cyclone系列的,我只有一点调试经验,没自己设计过,哪个开发板好啊?多谢!!!…

查看全部问答>

基于Hercules的踏板控制器DIY(四):打个酱油,调节下上个小四轴全家福

这周主要在搞小四轴,下周补上吧,不过这个小四轴有进展了,上个全家福 …

查看全部问答>