对Nor Flash的操作(S3C2440)

Nor Flash介绍
Nor Flash的连接线有地址线,数据线,片选信号读写信号等,Nor Flash的接口属于内存类接口,Nor Flash可以向内存一样读,但是不能像内存一样写,需要做一些特殊的操作才能进行写操作,读只需像内存一样读很简单。
nor 的原理图
在这里插入图片描述

FLASH简介
常用的Flash类型有Nor Flash和NAND Flash两种。

Nor Flash由Intel公司在1988年发明,以替代当时在市场上占据主要地位的EPROM和E2PROM。NAND Flash由Toshiba公司在1989年发明。两者的主要差别如下表:
在这里插入图片描述
Nor Flash支持XIP,即代码可以直接在Nor Flash上执行,无需复制到内存中。这是由于NorF lash的接口与RAM完全相同,可以随机访问任意地址的数据。Nor Flash进行读操作的效率非常高,但是擦除和写操作的效率很低,另外,Nor Flash的容量一般比较小。NAND Flash进行擦除和写操作的效率更高,并且容量更大。一般而言,Nor Flash用于存储程序,NAND Flash用于存储数据。基于NAND Flash的设备通常也要搭配Nor Flash以存储程字。

Flash存储器件由擦除单元(也称为块)组成,当要写某个块时,需要确保这个块己经 被擦除。Nor Flash的块大小范围为64kB、128kB:NAND Flash的块大小范围为8kB,64kB,擦/写一个Nor Flash块需4s,而擦/写一个NAND Flash块仅需2ms。Nor Flash的块太大,不仅增加了擦写时间,对于给定的写操作,Nor Flash也需要更多的擦除操作——特别是小文件,比如一个文件只有IkB,但是为了保存它却需要擦除人小为64kB—128kB的Nor Flash块。

Nor Flash的接口与RAM完全相同,可以随意访问任意地址的数据。而NAND Flash的 接口仅仅包含几个I/O引脚,需要串行地访问。NAND Flash一般以512字节为单位进行读写。这使得Nor Flash适合于运行程序,而NAND Flash更适合于存储数据。

容量相同的情况下,NAND Flash的体积更小,对于空间有严格要求的系统,NAND Flash可以节省更多空间。市场上Nor Flash的容量通常为IMB~4MB(也有32MB的Nor Flash),NAND Flash的容量为8MB~512MB。容量的差别也使得Nor Flash多用于存储程序,NAND Flash多用于存储数据。

对于Flash存储器件的可靠性需要考虑3点:位反转、坏块和可擦除次数。所有Flash器件都遭遇位反转的问题:由于Flash固有的电器特性,在读写数据过程中,偶然会产生一位或几位数据错误(这种概率很低),而NAND Flash出现的概率远大于Nor Flash,当位反转发生在关键的代码、数据上时,有可能导致系统崩溃。当仅仅是报告位反转,重新读取即可:如果确实发生了位反转,则必须有相应的错误检测/恢复措施。在NAND Flash上发生位反转的概率史高,推荐使用EDC/ECC进行错误检测和恢复。NAND Flash上面会有坏块随机分布在使用前需要将坏块扫描出来,确保不再使用它们,否则会使产品含有严重的故障。NAND Flash每块的可擦除次数通常在100000次左右,是Nor Flash的10倍。另外,因为NAND Flash的块大小通常是NorF lash的1/8,所以NAND Flash的寿命远远超过Nor Flash。

嵌入式Linux对Nor、NAND Flash的软件支持都很成熟。在Nor Flash上常用jffs2文 件系统,而在NAND Flash常用yaffs文件系统。在更底层,有MTD驱动程序实现对它们的读、写、擦除操仵,它也实现了EDC/ECC校验。

Nor Flash的操作
由电路原理图可以看出,CPU的ADDR1连接NOR Flash 的A0,为什么?
答:因为NOR Flash是16位存储器。

Nor Flash手册里会有一个命令的表格,如图:
在这里插入图片描述
由上图看出Read Silicon ID的步骤:

  1. 往地址555H写入AAH(解锁)
  2. 往地址2AAH写入55H(解锁)
  3. 往地址555H写入90H(命令)
  4. 读0地址得到厂家ID(C2H)
  5. 读1地址得到设备ID(22DAH或225BH)
  6. 退出读ID状态:给任意地址写F0H就可以了。

又因为CPU的ADDR1连接NOR Flash 的A0,所以
在这里插入图片描述
例如:2440发出(555H<<1)地址,Nor Flash才能收到555H这个地址。

Nor Flash的两种规范
通常内核里面要识别一个 Nor Flash 有两种方法:

一种是 jedec 探测,就是在内核里面事先定义一个数组,该数组里面放有不同厂家各个芯片的一些参数,探测的时候将 flash 的 ID 和数组里面的 ID 一一比较,如果发现相同的,就使用该数组的参数。 jedec 探测的优点就是简单,缺点是如果内核要支持的 flash 种类很多,这个数组就会很庞大。内核里面用 jedec 探测一个芯片时,是先通过发命令来获取 flash 的 ID,然后和数组比较,但是 flash.c 中连 ID 都是自己通过宏配置的。

一种是 CFI(common flash interface)探测,就是直接发各种命令来读取芯片的信息,比如 ID、容量等,芯片本身就包含了电压有多大,容量有有多少等信息。

下面的程序是用CFI探测,来读取芯片的信息。

编程


#include "nor_flash.h"

static void nor_write(unsigned int addr, unsigned int dat)
{
	volatile unsigned short *p = (volatile unsigned short *)(addr<<1);
	*p = dat;
}

static unsigned int nor_read(unsigned int addr)
{
	volatile unsigned short *p = (volatile unsigned short *)(addr<<1);
	return *p;
}

static void wait_ready(unsigned int addr)
{
	unsigned int val;
	unsigned int pre;

	pre = nor_read(addr>>1);
	val = nor_read(addr>>1);
	while ((val & (1<<6)) != (pre & (1<<6)))
	{
		pre = val;
		val = nor_read(addr>>1);		
	}
}

static void scan_nor_flash(void)
{
	unsigned int id[2];
	unsigned int size;
	int i, j, cnt, region_num, blocks_per_region, region_base_cmd, block_size; 
	int block_addr;
	/* 打印厂家ID、设备ID */
	nor_write(0x555, 0xaa);		
	nor_write(0x2aa, 0x55);		/* 解锁 */
	nor_write(0x555, 0x90);
	id[0] = nor_read(0);		//读厂家ID
	id[1] = nor_read(1);		//读设备ID
	
	printf("Manufacturer ID : 0x%x, Device ID : 0x%x, ",id[0],id[1]);
	
	/* 打印容量 */
	nor_write(0x55, 0x98);		//进入CFI模式
	size = nor_read(0x27);
	printf("nor flash size: %dM\n\r", 2^size/1024/1024);
	/* 打印各个扇区的起始地址 */
	region_num = nor_read(0x2c);
	region_base_cmd = 0x2d;
	block_addr = 0;
	cnt = 0;
	for (i=0; i<region_num; i++)
	{
		blocks_per_region = 1 + nor_read(region_base_cmd) + (nor_read(region_base_cmd+1)<<8);
		block_size = 256*(nor_read(region_base_cmd+2) + (nor_read(region_base_cmd+3)<<8));
		region_base_cmd += 4;
		
		for (j=0; j<blocks_per_region; j++)
		{
			printHex(block_addr);
			puts(" ");
			block_addr += block_size;
			cnt++;
			if (cnt%5 == 0)
				puts("\n\r");
			
		}
		
	}
	nor_write(0, 0xf0);			//退出
}


static void read_nor_flash(void)
{
	unsigned int addr;
	volatile unsigned char *p;
	int i, j;
	unsigned char c, str[16];
	printf("Press address to read:");
	addr = get_uint();
	
	
	p =(volatile unsigned char *)addr;

	
	for (i=0; i<4; i++)
	{
		// 每行打印16个数据
		for (j = 0; j < 16; j++)
		{
			//先打印数值
			c = *p++;
			str[j] = c;
			printf("%02x ", c);
		}

		printf("   ; ");

		for (j = 0; j < 16; j++)
		{
			//后打印字符
			if (str[j] < 0x20 || str[j] > 0x7e)  //不可视字符
				putchar('.');
			else
				putchar(str[j]);
		}
		puts("\n\r");
		
	}
	nor_write(0, 0xf0);			//退出
}

static void erase_nor_flash(void)
{
	unsigned int addr;
	
	printf("Press address to erase:");
	addr = get_uint();	
	printf("eraseing...\n\r");
	
	nor_write(0x555, 0xaa);		
	nor_write(0x2aa, 0x55);		/* 解锁 */
	nor_write(0x555, 0x80);
	nor_write(0x555, 0xaa);		
	nor_write(0x2aa, 0x55);
	nor_write(addr>>1, 0x30);
	wait_ready(addr);
	
	nor_write(0, 0xf0);			//退出
}

static void write_nor_flash(void)
{
	unsigned int addr;
	char str[100];
	int i = 0, j = 1;
	unsigned short val;
	/* 获得地址 */
	printf("Enter the address of sector to write: ");
	addr = get_uint();

	/* 获取数据 */
	printf("Enter the string to write: ");
	gets(str);
	
	/* str[0],str[1]==>16bit 
	 * str[2],str[3]==>16bit 
	 */
	
	while (str[i] && str[j])
	{
		val = (str[i]+(str[j]<<8));
		nor_write(0x555, 0xaa);		
		nor_write(0x2aa, 0x55);		/* 解锁 */
		nor_write(0x555, 0xa0);		/* program cmd */
		nor_write(addr>>1, val);	/* write */
		wait_ready(addr);
		i += 2;
		j += 2;
		
		addr += 2;
	}
	val = (unsigned short)str[i];
	nor_write(0x555, 0xaa);		
	nor_write(0x2aa, 0x55);		/* 解锁 */
	nor_write(0x555, 0xa0);		/* program cmd */
	nor_write(addr>>1, val);	/* write */
	wait_ready(addr);
	
	
}

void nor_flash_test(void)
{
	char c;
	
	while (1)
	{
		/* 打印菜单, 供我们选择测试内容 */
		printf("[s] Scan nor flash\n\r");
		printf("[e] Erase nor flash\n\r");
		printf("[w] Write nor flash\n\r");
		printf("[r] Read nor flash\n\r");
		printf("[q] quit\n\r");
		printf("Enter selection: ");
		
		c = (char)getchar();
		putchar(c);
		
		puts("\n\r");
		
		switch (c)
		{
			case 'q':
			case 'Q':
				return;
				break;
			
			case 's':
			case 'S':
				scan_nor_flash();
				break;
			case 'r':
			case 'R':
				read_nor_flash();
				break;
			case 'e':
			case 'E':
				erase_nor_flash();
				break;
			case 'w':
			case 'W':
				write_nor_flash();
				break;
			default:
				break;
		}
		
	}
	
}

wait_ready函数分析:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值