zoukankan      html  css  js  c++  java
  • Tiny6410之NAND FLASH驱动

    一、NAND FLASH的特点

    S3C6410的NAND FLASH控制器有如下特点

    1、自导入模式:复位后,引导代码被送入到8KB的STEPPINGSTONE中,引导代码移动完毕,引导代码将在STEPPINGSTONE中执行。导入期间,NAND FLASH控制器不支持ECC矫正。

    2、NAND FLSH 控制器I/F:支持512字节和2KB页

    3、软件模式:用户可以直接访问nand flash 控制器,该特性可以用于读/檫/编程nand flash 存储器。

    1)写命令寄存器=NAND FLASH存储器命令周期

    2)写地址寄存器=NAND FLASH存储器地址周期

    3)写数据寄存器=写数据到NAND FLASH存储器(写周期)

    4)读数据寄存器=从NAND FLASH 存储器数据(读周期)

    5)读主ECC寄存器和备用ECC寄存器=从NAND FLASH存储器读数据

    4、接口:8位NAND FLASH存储器接口总线

    5、硬件:ECC产生、检测和标志(软件纠正)

    6、支持SLC和MLC的NAND FLASH控制器:1位ECC用于SLC,4位ECC用于MLC的NAND FLASH

    7、特殊功能寄存器I/F:支持字节/半字/字数据访问ECC的数据寄存器,用字来访问其他寄存器

    8、STEPPINGSTONE I/F:支持字节/半字/字数据的访问

    9、8KB的内部SRAM的缓冲器STEPPINGSTONE,在NAND FLASH引导后可做其他用途使用

    该Tiny6410 开发板使用的NAND FLASH的类型为MLC大小为2G,型号K9GA08U0E-S

    二、驱动设计

    第一步:设置NAND FLASH的控制寄存器

      通过S3C6410数据手册可知NNAD FLASH的控制寄存器为NFCONF

    寄存器       地址

    NFCONF   0x70200000

      在NFCONF寄存器中主要用到TACLS、TWRPH0、TWRPH1,这三个变量。这三个变量用于配置nand flash 的时序。通过时序图

      由上图可知,TACLS为CLE/ALE 有效到nWE有效之间的持续时间。TWRPH0 位nWE的有效持续时间。TWRPH1为nWE无效到CLE/ALE 无效之间的持续时间。这些时间都是以HCLK为单位的。

      通过K9F2G08U0E数据手册(如下图)可知tWp 和TWRPH0相对应,(tcls-twp)与TALS相对应,tCLH与TWRPH1相对应。

      K9F2G08U0给出的值都是最小值。故在取值是只要满足该最小值就可以了。因此在这里我将TACLS、TWRPH0、TWRPH1分别取值为0x2、0xF和0x7。

    故将NFCONF寄存器的设值为((0x2<<12)|(0xf<<8)|(0x7<<4))

    第二步:使能NAND FLASH

      通过S3C6410的诗句手册可以知道使能NAND FLASH的寄存器为NFCONT

    寄存器      地址

    NFCONT   0x7020004

      由寄存器的描述可知,NFCONT的bit0位是控制NAND FLASH的。故将NFCONT的第零位设值为1即使能了NAND FLASH。

    第三步:读操作(页读)

    如下图可知读操作主要分五步走

      1、发片选:即设置NFCONT的bit1为0

      2、发命令:0x00,即往NFCMD写0x00

      3、发地址:由下图知地址需要分5个时钟周期来发送的,即往NFADDR写入地址,因为NFADDR一次只能接受8bit的数据

      4、发读命令:0x30,即往NFCMD写0x30

      5、连续读2048个字节,即连续读NFDATA寄存器2048次。

    第四步:拷贝

      调用NAND FLASH的读操作,直到把.bin文件完全的从NAND FLASH中拷贝到 DRAM中。

    第五步:编码运行

    主要代码实现如下

    //start.S
    .global _start
    _start
    	//把外设告诉CPU
    	ldr r0, =0x70000000
    	orr r0,r0,#0x13
    	mcr p15,0,r0,c15,c2,4
    	//官看门狗
    	ldr r0,=0x7E004000
    	mov r1,#0
    	str r1,[r0]
    	//设置栈
    	ldr sp,=0x0c002000
    	//开启icaches
    #ifdef CONFIG_SYS_ICACHE_OFF
    	bic r0,r0,#0x00001000
    #else
    	orr r0,r0,#0x00001000
    	mcr p15,0,r0,c1,c0,0x00001000
    #endif
    	//设置时钟
    	bl clock_init
    	
    	//初始换sdram
    	bl sdram_init
    	
    	//初始化nand flash
    	
    	bl nand_init
    	
    	//重定位,把代码、数据复制到他的链接中去
    	adr r0,_start    @_start的当前地址
    	ldr r1,=_star    @_start的链接地址
    	ldr r2,=bss_start
    	sub r2,r2,r1
    	cmp r0,r1
    	beq clean_bss
    	
    	bl copy2ddr
    	
    	cmp r0,#0
    	bne halt
    	
    	//清理bss段,把bss对应的内存清零
    clean_bss:
    		ldr r0,=bss_start
    		ldr r1,=bss_end
    		mov r3,#0
    		cmp r0,r1
    		beq on_ddr
    clean_loop:
    	str r3,[r0],#4
    	cmp r0,r1
    	bne clean_loop
    	
    	//跳转
    on_ddr:
    	ldr pc,=main
    halt:
    	b halt
    
    //nand.c
    #include "Tiny6410Addr.h"
    //nand flash 的命令
    #define NAND_CMD_READ0		0
    #define NAND_CMD_READ1		1
    #define NAND_CMD_RNDOUT		5
    #define NAND_CMD_PAGEPROG	0x10
    #define NAND_CMD_READOOB	0x50
    #define NAND_CMD_ERASE1		0x60
    #define NAND_CMD_STATUS		0x70
    #define NAND_CMD_STATUS_MULTI	0x71
    #define NAND_CMD_SEQIN		0x80
    #define NAND_CMD_RNDIN		0x85
    #define NAND_CMD_READID		0x90
    #define NAND_CMD_ERASE2		0xd0
    #define NAND_CMD_RESET		0xff
    /*
    typedef struct{
    	void (*nand_reset)(void);
    	void (*nand_select_chip)(void);
    	void (*nand_deselect_chip)(void);
    	void (*write_cmd)(int Cmd);
    	void (*read_cmd)(int Cmd);
    	void (*wait_idle)(void);
    	void (*write_addr)(unsigned int addr);
    	 
    }NAND_CHIP;
    static NAND_CHIP nand_chip;
    */
    void nand_init(void);
     
    
    
    
    //Tiny6410 nand Flash 的操作函数申明
    static void Tiny6410_nand_reset(void); 				//重启
    static void Tiny6410_nand_select_chip(void); 		//片选使能
    static void Tiny6410_nand_diselect_chip(void);		//关闭片选
    static void Tiny6410_write_cmd(int cmd); 			//写命令
    static void Tiny6410_read_cmd(int cmd); 			//读命令
    static void Tiny6410_wait_idle(void);  				//等待
    static void Tiny6410_write_addr(unsigned int addr); //写地址
    /////////////////////////////////////////
    
    //Tiny6410 nand Flash 的操作函数实现
    static void Tiny6410_nand_reset(void)
    {
    	Tiny6410_nand_select_chip();
    	Tiny6410_write_cmd(int cmd);
    	Tiny6410_wait_idle();
    	Tiny6410_nand_diselect_chip();
    	
    }
    //片选使能
    static void Tiny6410_nand_select_chip(void)
    {
    	NFCONT &= ~(1 << 1);
    }
    //取消片选
    static void Tiny6410_nand_diselect_chip(void)
    {
    	NFCONT |= (1 << 1);
    }
    static void Tiny6410_write_cmd(int cmd)
    {
    	
    }
    //等待数据
    static void Tiny6410_wait_idle(void)
    {
    	do { 
    	while(!(NFSTAT & (1 << 0))); 
    	} while(0)
    	
    }
    //读命令
    static void Tiny6410_read_cmd(int cmd)
    {
    	NFCMD = cmd;
    }
    //写命令
    static void Tiny6410_write_cmd(int cmd)
    {
    	//NFCMD = cmd;
    }
    static void Tiny6410_write_addr(unsigned long addr)
    {
    	NFADDR = 0;
    	NFADDR = 0;
    	NFADDR = (addr) & 0xff;
    	NFADDR = (addr >> 8) & 0xff;
    	NFADDR = (addr >> 16) & 0xff;
    }
    
    ///////////////////////////////////////
    //nand flash 初始化
    void init_nand(void)
    {
    	//设置NAND FLASH 控制器
    	NFCONF = ((0x2 << 12)|(0xf << 8)|(0x7 << 4));
    	NFCONT |= ((0x3 << 0));
    	
    }
     
    //读以页数据
    static int nand_read_page(unsigned char *buf,unsigned long addr)
    {
    	int i;
    
    	
    	//发出片选
    	Tiny6410_nand_select_chip();
    	//发送读命令
    	Tiny6410_read_cmd(NAND_CMD_READ0);
    	//发送地址
    	Tiny6410_write_addr(addr);
    	//发送读命令
    	Tiny6410_read_cmd(NAND_CMD_READSTART);
    	//等待数据
    	Tiny6410_wait_idle();
    	//连续读取2048个字节
    	for(i=0; i < page_size; i++)
    	{
    		*buf++ = NFDATA8_REG;
    	}
    	//取消片选
    	Tiny6410_nand_diselect_chip();
    	return 0;
    }
    
    //从NAND 中拷贝到DRAM
    int copy2dram(unsigned int nand_start,unsigned int dram_start,unsigned int len)
    {
    	unsigned char *buf = (unsigned char *)ddr_start;
    	int i;
    	unsigned int page_shift = 11;
    	//发片选
    	Tiny6410_nand_select_chip();
    		
    	// 使len为2048的整数倍
    	len = (len/2048+1)*2048;
    	
    	// 循环拷贝,每次拷贝一页数据
    	for (i = 0; i < (len>>page_shift); i++, buf+=(1<<page_shift))
    	{
    		// 读一页,即2048byte
    		nandll_read_page(buf, i);
    	}
    
    	return 0;
    }
    
    //nand.lds
    SECTIONS {
        . = 0x50000000;
        
    	.text : {
    			start.o
    			clock.o
    			sdram.o
    			nand.o
    			* (.text)
    	}
    
    	.rodata : {
    			* (.rodata)
    	}
    
    	.data : {
    			* (.data)
    	}
    
        bss_start = .;
        .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
        bss_end = .;
    }
    
    //TinyAddr.h
    #ifndef _Tiny6410Addr_H
    #define _Tiny6410Addr_H
    //GPK 
    #define GPKIO_BASE (0x7F008800)
    #define rGPKCON0 		(*((volatile unsigned long *)(GPKIO_BASE+0x00)))
    #define rGPKDAT  		(*((volatile unsigned long *)(GPKIO_BASE+0x08)))
    
    //CLOCK
    #define APLL_LOCK 		(*((volatile unsigned long *)0x7E00F000))
    #define MPLL_LOCK 		(*((volatile unsigned long *)0x7E00F004))
    #define EPLL_LOCK 		(*((volatile unsigned long *)0x7E00F008))
    #define OTHERS    		(*((volatile unsigned long *)0x7e00f900))
    #define CLK_DIV0  		(*((volatile unsigned long *)0x7E00F020))
    #define APLL_CON  		(*((volatile unsigned long *)0x7E00F00C))
    #define MPLL_CON  		(*((volatile unsigned long *)0x7E00F010))
    #define CLK_SRC   		(*((volatile unsigned long *)0x7E00F01C))
    
    
    
    //GPA /uart
    #define ULCON0     		(*((volatile unsigned long *)0x7F005000))
    #define UCON0      		(*((volatile unsigned long *)0x7F005004))
    #define UFCON0     		(*((volatile unsigned long *)0x7F005008))
    #define UMCON0     		(*((volatile unsigned long *)0x7F00500C))
    #define UTRSTAT0   		(*((volatile unsigned long *)0x7F005010))
    #define UFSTAT0    		(*((volatile unsigned long *)0x7F005018))
    #define UTXH0      		(*((volatile unsigned char *)0x7F005020))
    #define URXH0      		(*((volatile unsigned char *)0x7F005024))
    #define UBRDIV0    		(*((volatile unsigned short *)0x7F005028))
    #define UDIVSLOT0  		(*((volatile unsigned short *)0x7F00502C))
    #define GPACON     		(*((volatile unsigned long *)0x7F008000))
    
    //Sdram
    #define P1MEMSTAT		(*((volatile unsigned long *)0x7e001000))
    #define P1MEMCCMD		(*((volatile unsigned long *)0x7e001004))
    #define P1DIRECTCMD		(*((volatile unsigned long *)0x7e001008))
    //#define MEMCCMD		(*((volatile unsigned long *)0x7e001004))
    #define P1REFRESH		(*((volatile unsigned long *)0x7e001010))
    #define P1CASLAT		(*((volatile unsigned long *)0x7e001014))
    #define MEM_SYS_CFG		(*((volatile unsigned long *)0x7e00f120))
    #define P1MEMCFG		(*((volatile unsigned long *)0x7e00100c))
    #define P1T_DQSS		(*((volatile unsigned long *)0x7e001018))
    #define P1T_MRD			(*((volatile unsigned long *)0x7e00101c))
    #define P1T_RAS			(*((volatile unsigned long *)0x7e001020))
    #define P1T_RC			(*((volatile unsigned long *)0x7e001024))
    #define P1T_RCD			(*((volatile unsigned long *)0x7e001028))
    #define P1T_RFC			(*((volatile unsigned long *)0x7e00102c))
    #define P1T_RP			(*((volatile unsigned long *)0x7e001030))
    #define P1T_RRD			(*((volatile unsigned long *)0x7e001034))
    #define P1T_WR			(*((volatile unsigned long *)0x7e001038))
    #define P1T_WTR			(*((volatile unsigned long *)0x7e00103c))
    #define P1T_XP			(*((volatile unsigned long *)0x7e001040))
    #define P1T_XSR			(*((volatile unsigned long *)0x7e001044))
    #define P1T_ESR			(*((volatile unsigned long *)0x7e001048))
    #define P1MEMCFG2		(*((volatile unsigned long *)0X7e00104c))
    #define P1_chip_0_cfg	(*((volatile unsigned long *)0x7e001200))
    
    //Nand
    #define NAND_BASE (0x70200000)
    #define NFCONF      	(*((volatile unsigned long *)NAND_BASE + 0x00)) 
    #define NFCONT      	(*((volatile unsigned long *)NAND_BASE + 0x04))
    #define NFCMMD      	(*((volatile unsigned long *)NAND_BASE + 0x08))
    #define NFADDR      	(*((volatile unsigned long *)NAND_BASE + 0x0c))
    #define NFDATA      	(*((volatile unsigned long *)NAND_BASE + 0x10))
    #define NFMECCDATA0     (*((volatile unsigned long *)NAND_BASE + 0x14))
    #define NFMECCDATA1     (*((volatile unsigned long *)NAND_BASE + 0x18))
    #define NFSECCDATA0     (*((volatile unsigned long *)NAND_BASE + 0x1c))
    #define NFSBLK      	(*((volatile unsigned long *)NAND_BASE + 0x20))
    #define NFEBLK      	(*((volatile unsigned long *)NAND_BASE + 0x24))
    #define NFSTAT      	(*((volatile unsigned long *)NAND_BASE + 0x28))
    #define NFESTAT0      	(*((volatile unsigned long *)NAND_BASE + 0x2c))
    #define NFESTAT1      	(*((volatile unsigned long *)NAND_BASE + 030))
    #define NFMECC0      	(*((volatile unsigned long *)NAND_BASE + 0x34))
    #define NFMECC1      	(*((volatile unsigned long *)NAND_BASE + 0x38))
    #define NFSECC      	(*((volatile unsigned long *)NAND_BASE + 0x3c))
    #define NFMLCBITPT      (*((volatile unsigned long *)NAND_BASE + 0x40)) 
    /*#define NF8ECCERR0      (*((volatile unsigned long *)NAND_BASE + 0x44)) 
    #define NF8ECCERR1      (*((volatile unsigned long *)NAND_BASE + 0x48)) 
    #define NF8ECCERR2      (*((volatile unsigned long *)NAND_BASE + 0x4c)) 
    #define NFM8ECC0      	(*((volatile unsigned long *)NAND_BASE + 0x50)) 
    #define NFM8ECC1      	(*((volatile unsigned long *)NAND_BASE + 0x54)) 
    #define NFM8ECC2      	(*((volatile unsigned long *)NAND_BASE + 0x58)) 
    #define NFM8ECC3      	(*((volatile unsigned long *)NAND_BASE + 0x5c)) 
    #define NFMLC8BITPT0    (*((volatile unsigned long *)NAND_BASE + 0x60)) 
    #define NFMLC8BITPT1    (*((volatile unsigned long *)NAND_BASE + 0x64)) 
     */
    
    
    #endif
    

    总结:

      综上所述主要分为两个大步。

      第一步:读S3C6410数据手册,了解NANDfLASH 的操作流程。

      第二步:读NAND FLASH数据手册,了解各个寄存器的具体设置。

      

    海阔凭鱼跃,天高任鸟飞。
  • 相关阅读:
    dotnet core 获取 MacAddress 地址方法
    dotnet core 获取 MacAddress 地址方法
    dotnet core 发布只带必要的依赖文件
    dotnet core 发布只带必要的依赖文件
    Developing Universal Windows Apps 开发UWA应用 问答
    Developing Universal Windows Apps 开发UWA应用 问答
    cmd 如何跨驱动器移动文件夹
    cmd 如何跨驱动器移动文件夹
    C++ 驱动开发 error LNK2019
    C++ 驱动开发 error LNK2019
  • 原文地址:https://www.cnblogs.com/chenshikun/p/5988081.html
Copyright © 2011-2022 走看看