s3c2440 Nand flash


本文是基于韦东山视频的学习笔记

汇总点这

总汇

YONG这里是引用
R/B - 状态引脚
CLE - (COMMAND LATCH ENABLE)高电平时传输命令
nCE - (CHIP ENABLE)片选
ALE - (ADDRESS LATCH ENABLE)高电平时传输地址
nWE - (WRITE ENABLE)
nRE - (READ ENABLE)
nWP - (WRITE PROTECT)
CLE & ALE - 都为高电平时,传输数据这里是引用
CLE/ALE 都拉高后,需要等待TACLS后,才能拉低WE。WE动作持续TWRPH0。WE动作完后,需要等待TWRPH1后,才能把WE拉高。

在这里插入图片描述
ALE/CLE 动作后(tCLS - tWP = 12-12=0=TACLS) 后,WE才能动作。WE动作持续tWP=12=TWRPH0。WE动作完,(tCLH/tALH=5=TWRPH1)后,ALE/CLE 才能动作。

寄存器

[NFCONF] NAND flash configuration register - 需要配置
[NFCONT] NAND flash control register - 需要配置
[NFCMMD] NAND flash command set register - 命令寄存器,写命令
[NFADDR] NAND flash address set register - 地址寄存器,写地址
[NFDATA] NAND flash data register - 数据寄存器,读写数据
[NFSTAT] NAND flash operation status register - 操作寄存器

NFCONF NAND flash configuration register 0x4E000000

  • [13:12] = 0 : Duration = 0 = HCLK x TACLS =10ns x 0
  • [10:8] = 1 :Duration = 12 ≤ 20 = HCLK x ( TWRPH0 + 1 ) = 10ns x (1+1)
  • [6:4] = 0 :Duration = 5 ≤ 10 = HCLK x ( TWRPH1 + 1 ) = 10ns x (0+1)

NFCONT NAND flash control register 0x4E000004

  • [0] = 1 :NAND flash controller enable
  • [1] = 1 :Reg_nCE 片选信号(初始化先禁止片选,要用才片选)
  • [4] = 1 :InitECC (Initialize ECC decoder/encoder(Write-only))

NFCMMD 命令寄存器 0x4E000008
NFADDR 地址寄存器 0x4E00000C
NFDATA 数据寄存器 0x4E000010
NFSTAT 状态寄存器 0x4E000020

  • [0] 0: NAND Flash memory busy
  • [0] 1: NAND Flash memory ready to operate

读数据

这里是引用
col 是 0~2047
row 是 0~0x1F400 (128k)

在这里插入图片描述
片选CE拉低动作后,CLE命令引脚拉高……其实这一切都有nand控制器帮我们做这些时序。实际上我们输送0x00命令,然后传入地址(2col x 3row),然后输送0x30命令,等R/B引脚就绪后,就可以读数据了。

擦除

这里是引用

写操作

这里是引用

void nand_write(unsigned char addr, unsigned char *buf, unsigned int len)
{
	unsigned int i = 0;
	unsigned int col = addr & (2048 - 1);		//相等于addr % 2047
	unsigned int page = addr / 2048;
	
	nand_select();

	while(i < len)
	{

		nand_cmd(0x80); 	//set up write cmd
		
		nand_addr_byte((col) & 0xFF);			//col的低8位 
		nand_addr_byte((col>>8) & 0xFF);		//col的高8位 
		nand_addr_byte((page) & 0xFF);			//page的低8位
		nand_addr_byte((page>>8) & 0xFF);		//page的高8位
		nand_addr_byte((page>>16) & 0xFF);		//page的8-16位


		for (; (col < 2048) && (i < len); col++)
		{
			nand_w_data(buf[i++]);
		}
		col = 0;			//写完了一页重置col
		page++;				//读下一页
		
		nand_cmd(0x10);		//end write cmd
		wait_ready();
}	

	nand_deselect();
}

!!!

需要注意的是,Makefile的编译顺序,要把sdram的初始化放在nand前面,nand也要尽量放前,不然就不是在4k内存以内了。

!

执行读操作,发现是这样的… (数据应该是www.baidu.com)

77 00 00 00 77 00 00 00 77 00 00 00 2e 00 00 00 ; w…w…w…
62 00 00 00 61 00 00 00 69 00 00 00 64 00 00 00 ; b…a…i…d…
75 00 00 00 2e 00 00 00 63 00 00 00 6f 00 00 00 ; u…c…o…
6d 00 00 00 00 00 00 00 ff 00 00 00 ff 00 00 00 ; m…

找了半个小时bug,原来是nand_read函数的unsigned char buf,写成了unsigned int*buf*,导致每次读数据都读4字节,醉了。。

undefined reference to `memset’

在编译的时候说什么

nand_flash.o(.text+0x694): In function do_read_nand_flash': : undefined reference tomemset’
Makefile:2: recipe for target ‘all’ failed
make: *** [all] Error 1

这样的一大堆东东,但是我并没有使用memset函数啊。
查找后发现,原来是数组赋初值这里用到了。

unsigned char buf[64] = {0};

但是是库文件没有这个函数喔,那写一个呗。

void *memset(void *str, int c, unsigned int n)
{
	char *p = (char *)str;		

	if (str == NULL || n < 0)		//如果是空则退出
		return NULL;
	
	while (n--)
		{*p++ = c;}					//逐一赋值
	

	return p;

}

代码

/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))void nand_init()
{
	
/*
	**NFCONF** NAND flash configuration register 0x4E000000
	 - [13:12] = 0 : Duration = 0 = HCLK x TACLS =10ns x 0
	 - [10:8] = 1 :Duration = 12 ≤ 20 = HCLK x ( TWRPH0 + 1 ) = 10ns x (1+1) 
	 - [6:4] = 0 :Duration = 5 ≤ 10 = HCLK x ( TWRPH1 + 1 ) = 10ns x (0+1) 
	**NFCONT** NAND flash control register 0x4E000004
	- [0] = 1 :NAND flash controller enable
	- [1] = 1 :Reg_nCE 片选信号(初始化先禁止片选,要用才片选)
	- [4] = 1 :InitECC (Initialize ECC decoder/encoder(Write-only)
	 */

	NFCONF = ((0<<12) | (1<<8) | (0<<4));		//设置时序
	NFCONT = (( 1<<0) | (1<<1) | (1<<4));		//初始化
}

void wait_ready()
{
	/*
	**NFSTAT** 状态寄存器 0x4E000020
	- [0] 0: NAND Flash memory busy
	- [0] 1: NAND Flash memory ready to operate
	 */


	while(!(NFSTAT & 1));		//当[0]不等于1一直等待
}
void nand_select()
{
	
NFCONT &=  ~(1<<1);
}
void nand_deselect()
{
	
NFCONT |=   (1<<1);
}
unsigned char nand_data()
{
	return	NFDATA;
}
void nand_w_data(unsigned char val)
{
	NFDATA = val;
}

void nand_cmd(unsigned char cmd)	//8位的寄存器
{
	int i = 0;
	
NFCCMD = cmd;
	for(i=0; i<10; i++); 			//延时一会保证命令完成
}
void nand_addr_byte(unsigned char addr)			//8位的寄存器
{
	int i = 0;
	
NFADDR = addr;
	for(i=0; i<10; i++); 			//延时一会保证命令完成
}

void read_id()
{
	unsigned char buf[5] = {0};

	
nand_select();
	nand_cmd(0x90);				
	nand_addr_byte(0X00);		//读id的命令

	buf[0] = nand_data();
	buf[1] = nand_data();
	buf[2] = nand_data();
	buf[3] = nand_data();
	buf[4] = nand_data();

	puts("\n\r");
	puts("maker   id  =");print_hex(buf[0]);puts("\n\r");
	puts("device  id  =");print_hex(buf[1]);puts("\n\r");
 	puts("3th     id  =");print_hex(buf[2]);puts("\n\r");
 	puts("4th     id  =");print_hex(buf[3]);puts("\n\r");
	puts("Page Size   =");print_hex(1<<(buf[3] & 0x3));puts("\n\r");
	puts("Block Size  =");print_hex(64<<((buf[3]>>4) & 0x3));puts("\n\r");
	puts("5th     id  =");print_hex(buf[4]);

	nand_deselect();
	
}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{

	/* col 是0~0x2FF    (2047)	
	 * page是0~0x1F400 (128k)
	 */
	unsigned int i = 0;
	unsigned int col = addr & (2048 - 1);		//相等于addr % 2047
	unsigned int page = addr / 2048;



	nand_select();

	while(i < len)
	{
		nand_cmd(0x00);

		nand_addr_byte((col) & 0xFF);			//col的低8位	
		nand_addr_byte((col>>8) & 0xFF);		//col的高8位	
		nand_addr_byte((page) & 0xFF);			//page的低8位
		nand_addr_byte((page>>8) & 0xFF);		//page的高8位
		nand_addr_byte((page>>16) & 0xFF);		//page的8-16位
		
		nand_cmd(0x30);							//读命令

		wait_ready();
		for (; (col < 2048) && (i < len); col++)
		{
			buf[i++] = nand_data();			
		}



		col = 0;			//读完了一页重置col
		page++;				//读下一页
	}
	
nand_deselect();
}

int nand_erase(unsigned int addr)
{
	unsigned int page = addr / 2048;

	nand_select();

	nand_cmd(0x60);		//set up cmd
	
	/* 块擦除,只输入行地址 */
	nand_addr_byte((page) & 0xFF);			//page的低8位
	nand_addr_byte((page>>8) & 0xFF);		//page的高8位
	nand_addr_byte((page>>16) & 0xFF);		//page的8-16位

	nand_cmd(0xD0);		//erase cmd
	wait_ready();

	nand_cmd(0x70);		//获取擦除状态
	if ((nand_data() & 0x01))	//0: success, 1: error
	{
		nand_deselect();
		return -1;
	}
	
	nand_deselect();
	return 0;
}
void nand_write(unsigned char addr, unsigned char *buf, unsigned int len)
{
	unsigned int i = 0;
	unsigned int col = addr & (2048 - 1);		//相等于addr % 2047
	unsigned int page = addr / 2048;
	
	nand_select();

	while(i < len)
	{

		nand_cmd(0x80); 	//set up write cmd
		
		nand_addr_byte((col) & 0xFF);			//col的低8位 
		nand_addr_byte((col>>8) & 0xFF);		//col的高8位 
		nand_addr_byte((page) & 0xFF);			//page的低8位
		nand_addr_byte((page>>8) & 0xFF);		//page的高8位
		nand_addr_byte((page>>16) & 0xFF);		//page的8-16位


		for (; (col < 2048) && (i < len); col++)
		{
			nand_w_data(buf[i++]);
		}
		col = 0;			//写完了一页重置col
		page++;				//读下一页
		
		nand_cmd(0x10);		//end write cmd
		wait_ready();
}	

	nand_deselect();
}
void do_read_nand_flash()
{


	unsigned int i = 0, j = 0;
	unsigned char addr, c;
	unsigned char str[16];
	unsigned char buf[64];
	volatile unsigned char *p;

	puts("Input addr: ");
	addr = get_uint();
	
	nand_read(addr, buf, 64);
	p = (volatile unsigned char *)buf;
	for (i=0; i<4; i++)								//打印四行
	{
		for (j=0; j<16; j++)						//每行16个数据
		{
			c = *p++;
			str[j] = c;
			printf("%02x ", c);
			
		
}
		puts("   ; ");
		for (j=0; j<16; j++)
		{
			if (str[j] < 0x20 || str[j] > 0x7e)		//不可视字符
			{
				puts(".");
			}
			else									//打印字符
			{
				putchar(str[j]);

			}
		
}
		puts("\n\r");								//每行换行
	}

}

void do_erase_nand_flash()
{
	unsigned char addr=0;

	puts("Input addr: ");
	addr = get_uint();	
	
	if (nand_erase(addr) == 0)
	{
		puts("Erase successful.\n\r");
	
}
	else
		puts("Erase error.\n\r");
}

void do_write_nand_flash()
{
	unsigned char addr=0;
	unsigned char str[100];

	puts("Input addr: ");
	addr = get_uint();	
	
	
puts("Input string: ");
	gets(str);

	puts("Write...\n\r");
	nand_write(addr, str, strlen(str)+1);
}


void nand_flash_test(void)
{
	char c;

	while (1)
	{
		/* 打印菜单, 供我们选择测试内容 */
		puts("\n\r");
		puts("[s] Scan nand flash\n\r");
		puts("[e] Erase nand flash\n\r");
		puts("[w] Write nand flash\n\r");
		puts("[r] Read nand flash\n\r");
		puts("[q] quit\n\r");
		puts("Enter selection: ");

		c = getchar();
		putchar(c);
		puts("\n\r");
		/* 测试内容:
		 * 1. 识别nor flash
		 * 2. 擦除nor flash某个扇区
		 * 3. 编写某个地址
		 * 4. 读某个地址
		 */
		switch (c)		 
		{
			case 'q':
			case 'Q':
				return;
				break;
				
			case 's':
			case 'S':
				read_id();
				break;

			case 'e':
			case 'E':
				do_erase_nand_flash();
				break;

			case 'w':
			case 'W':
				do_write_nand_flash();
				break;

			case 'r':
			case 'R':
				do_read_nand_flash();
				break;
			
			default:
				break;
		}


	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值