加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

TQ210 —— NandFlash

发布时间:2020-12-15 20:00:40 所属栏目:百科 来源:网络整理
导读:TQ210 —— nandflash ? ? TQ210 开发板板载一片 1Gbyte 的 NAND FLASH——K9K8G08U0B,通过查询K9K8G08U0B 芯片手册可以得到如下信息:(理论知识不再介绍) K9K8G08U0B : (1G + 32M) x 8bit 总大小 Data Register : (2K + 64) x 8bit 数据寄存器 Page Prog
TQ210 —— nandflash

? ? TQ210 开发板板载一片 1Gbyte 的 NAND FLASH——K9K8G08U0B,通过查询K9K8G08U0B 芯片手册可以得到如下信息:(理论知识不再介绍)
K9K8G08U0B : (1G + 32M) x 8bit 总大小
Data Register : (2K + 64) x 8bit 数据寄存器
Page Program : (2K + 64)Byte 页编程
Block Erase : (128K + 4K)Byte 块擦除
Page Read: (2K + 64)Byte 页读
?


我们需要按上面这个地址周期表来发地址。
对NFDATA 寄存器的定义(参考 S5PV210 芯片手册 4.3.1.1 8-bit NAND Flash Memory Interface) ??
?#define NFDATA (*(volatile unsigned char *)0xB0E00010)
NFCONF 寄存器中 3 个时间参数稍微比计算的值大些(大 1 就可以),否则会出现读写不稳定
下面几种操作流程中对于发送地址的周期数:有的是 5 个周期,有的是 3 个周期,有的是 1 个周期。
1、 擦除流程
(1)片选
(2)发命令 0x60
(3)发页地址(块对齐,3 个周期)
(4)发命令 0xD0
(5)等待 NAND 空闲
(6)取消片选

2、 写数据
(1)片选
(2)发命令 0x80
(3)发地址(页对齐, 5 个周期)
(4)连续发送一页数据
(5)发命令 0x10
(6)等待 NAND 空闲
(7)取消片选

3、 读数据
1) 片选
2) 发命令 0x00
3) 发地址(页对齐, 5 个周期)
4) 发命令 0x30
5) 等待 NAND 空闲
6) 连续读一页数据
7) 取消片选

4、 读ID
1) 片选
2) 发命令 0x90
3) 发 0 地址( 1 个周期)
4) 连续读 5 个字节的 ID
5) 取消片选
#include "types.h"

#define	NFCONF  (*(volatile u32 *)0xB0E00000) 
#define	NFCONT  (*(volatile u32 *)0xB0E00004) 	
#define	NFCMMD  (*(volatile u32 *)0xB0E00008) 
#define	NFADDR  (*(volatile u32 *)0xB0E0000C)
#define	NFDATA  (*(volatile u8 *)0xB0E00010)
#define	NFSTAT  (*(volatile u32 *)0xB0E00028)

#define MP0_1CON  (*(volatile u32 *)0xE02002E0)
#define	MP0_3CON  (*(volatile u32 *)0xE0200320)
#define	MP0_6CON  (*(volatile u32 *)0xE0200380)

#define PAGE_SIZE	2048
#define BLOCK_SIZE	(PAGE_SIZE * 64)

/* 等待NAND准备好 */
static void inline nand_wait_ready()
{
	while(!(NFSTAT & (1 << 0)));
}

/* 片选 */
static void inline nand_select_chip()
{
	NFCONT &= ~(1 << 1);
}

/* 取消片选 */
static void inline nand_deselect_chip()
{
	NFCONT |= (1 << 1);
}

/* 发命令 */
static void inline nand_cmd(u32 cmd)
{
	NFCMMD = cmd;
}

/* 发地址(5个周期) */
static void nand_addr(u32 addr)
{
	u32 col = addr % PAGE_SIZE;	/* 页内偏移 */
	u32 row = addr / PAGE_SIZE;	/* 页地址 */
	
	NFADDR = col & 0xFF;
	NFADDR = (col >> 8) & 0x7;
	NFADDR = row & 0xFF;
	NFADDR = (row >> 8) & 0xFF;
	NFADDR = (row >> 16) & 0x07;
}

/* 读1byte数据 */
static u8 inline nand_read()
{
	return NFDATA;
}

/* 写1byte数据 */
static void inline nand_write(u8 data)
{
	NFDATA = data;
}

/* 复位NAND */
static void nand_reset()
{
	nand_select_chip();
	nand_cmd(0xFF);
	nand_wait_ready();
	nand_deselect_chip();
}

/* NAND初始化 */
void nand_init()
{
	/* HCLK_PSYS=133MHz(7.5ns) */
	NFCONF =	(0x1 << 23) |	/* Disable 1-bit and 4-bit ECC */
				/* 下面3个时间参数稍微比计算出的值大些(我这里依次加1),否则读写不稳定 */
				(0x3 << 12) |	/* 7.5ns * 2 > 12ns tALS tCLS */
				(0x2 << 8) | 	/* (1+1) * 7.5ns > 12ns (tWP) */
				(0x1 << 4) | 	/* (0+1) * 7.5 > 5ns (tCLH/tALH) */
				(0x0 << 3) | 	/* SLC NAND Flash */
				(0x0 << 2) |	/* 2KBytes/Page */
				(0x1 << 1);		/* 5 address cycle */
				
	/* 
	** The setting all nCE[3:0] zero can not be allowed. Only 
	** one nCE can be asserted to enable external NAND flash 
	** memory. The lower bit has more priority when user set all 
	** nCE[3:0] zeros. 
	*/
	NFCONT =	(0x1 << 1) |	/* Disable chip select */
				(0x1 << 0);		/* Enable NAND Flash Controller */
					
	/*
	** Port Map
	** CE1->Xm0CSn2-> MP01_2
	** CE2->Xm0CSn3-> MP01_3
	** CE3->Xm0CSn4-> MP01_4
	** CE4->Xm0CSn5-> MP01_5
	** CLE->Xm0FCLE-> MP03_0
	** ALE->Xm0FALE-> MP03_1
	** WE->Xm0FWEn->  MP03_2
	** RE->Xm0FREn->  MP03_3
	** RB1->Xm0FRnB0->MP03_4
	** RB2->Xm0FRnB1->MP03_5
	** RB3->Xm0FRnB2->MP03_6
	** RB4->Xm0FRnB3->MP03_7
	** IO[7:0]->Xm0DATA[7:0]->MP0_6[7:0]
	*/
	MP0_1CON &= ~(0xFFFF << 8);
	MP0_1CON |= (0x3333 << 8);
	MP0_3CON = 0x22222222;
	MP0_6CON = 0x22222222;

	nand_reset();
}

/* 读NAND ID */
void nand_read_id(u8 id[])
{
	int i;
	nand_select_chip();
	nand_cmd(0x90);
	NFADDR = 0x00;
	for (i = 0; i < 5; i++)
		id[i] = nand_read();

	nand_deselect_chip();
}

/* 擦除一个块 */
void nand_erase(u32 addr)
{	
	if (addr & (BLOCK_SIZE - 1))
	{
		printf("not block alignn");
		return;
	}
	u32 row = addr / PAGE_SIZE;
	
	nand_select_chip();
	nand_cmd(0x60);
	
	NFADDR = row & 0xff;			
	NFADDR = (row >> 8) & 0xff;
	NFADDR = (row >> 16) & 0x07;
	
	nand_cmd(0xD0);
	nand_wait_ready();
	nand_deselect_chip();
}

/* 读一页数据 */
void nand_read_page(u8 *buf,u32 addr)
{
	if (addr & (PAGE_SIZE - 1))
	{
		printf("not page alignn");
		return;
	}
	
	int i;
	nand_select_chip();
	nand_cmd(0);
	nand_addr(addr);
	nand_cmd(0x30);
	nand_wait_ready();
	
	for(i = 0; i < PAGE_SIZE; i++)
	{
		*buf++ = nand_read();
	}
	nand_deselect_chip();
}

/* 随机读:从任意地址读任意字节的数据 */
void nand_read_random(u8 *buf,u32 addr,u32 size)
{	
	nand_select_chip();
	nand_cmd(0);
	nand_addr(addr);
	nand_cmd(0x30);
	nand_wait_ready();
	
	int i;
	u32 col = addr % PAGE_SIZE;	/* 页内偏移 */

	for(i = col; i < size + col; i++)
	{
		nand_cmd(0x05);
		NFADDR = i & 0xFF;
		NFADDR = (i >> 8) & 0x7;
		nand_cmd(0xE0);
		*buf++ = nand_read();
	}
	
	nand_deselect_chip();
}

/* 写一页数据 */
void nand_write_page(u8 *buf,u32 addr)
{
	if (addr & (PAGE_SIZE - 1))
	{
		printf("not page alignn");
		return;
	}
	
	int i;
	nand_select_chip();
	nand_cmd(0x80);
	nand_addr(addr);
	nand_wait_ready();
	
	for(i = 0; i < PAGE_SIZE; i++)
	{
		nand_write(*buf++);
	}
	nand_cmd(0x10);
	nand_wait_ready();
	nand_deselect_chip();
}
#include "types.h"
#include "uart.h" // 这个文件前面UART串口博客有

void bzero(u8 *s,int size)
{
	int i = 0;
	for (; i < size; i++)
		s[i] = 0;
}

void main()
{	
	u8 buf[2048];
	int i;
	
	bzero(buf,2048);

	nand_read_id(buf);
	printf("nID:");
	for (i = 0; i < 5; i++)
	{
		printf("%X ",buf[i]);
	}
	putchar('n');
	
	nand_erase(0x80000);			/* 擦除以0x80000地址开始的一个块 */
	
	for (i = 0; i < 2048; i++)
		buf[i] = i % 255;
	
	nand_write_page(buf,0x80000);	/* 写入1页数据到0x80000地址 */
	
	bzero(buf,2048);
	nand_read_page(buf,0x80000);	/* 从0x80000地址读取一页数据 */
	
	/* 打印读取到的数据,与写入的数据一致 */
	for (i = 0; i < 100; i++)
	{
		if (i % 16 == 0)
			putchar('n');
		printf("%X ",buf[i]);
	}
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读