本文主要是关于NOR flash的相关介绍,并着重对NOR flash的识别及其工作原理进行了详尽的阐述。
NOR flash工作原理
Nor Flash 具有像内存一样的接口,它可以像内存一样读,却不可以像内存一样写,Nor Flash 的写、擦除都需要发出特定的命令。谈到 Nor Flash 通常就会涉及到 CFI ([Common Flash Interface) 接口,一般 Nor Flash 都支持发命令来读取厂家 ID 和 设备 ID 等基本信息,但并不是所有的 Nor
Flash 都支持发命令来获取和芯片本身容量大小、扇区数、擦除块大小等信息。为了让将来的 Nor Flash 兼容性更好,引进了 CFI 接口,将芯片有关的信息都写入芯片内部,通过 CFI 命令就可以获取这些信息。
Linux 内核中对各种型号的 Nor Flash 都有很好的支持 ,但是其组织复杂,不利于分析。这里选用 u-boot 里面的 Nor Flash 代码来分析。代码位于:u-boot-2010.06/board/samsung/smdk2410/flash.c 。
通常内核里面要识别一个 Nor Flash 有两种方法:一种是 jedec 探测,就是在内核里面事先定义一个数组,该数组里面放有不同厂家各个芯片的一些参数,探测的时候将 flash 的 ID 和数组里面的 ID 一一比较,如果发现相同的,就使用该数组的参数。另一种是 cfi 探测,就是直接发各种命令来读取芯片的信息,比如 ID、容量等。jedec 探测的优点就是简单,缺点是如果内核要支持的 flash 种类很多,这个数组就会很庞大。。。/samsung/smdk2410/flash.c 文件采用的是第一种方法,但是还是有些区别的,内核里面用
jedec 探测一个芯片时,是先通过发命令来获取 flash 的 ID,然后和数组比较,但是 flash.c 中连 ID 都是自己通过宏配置的。
unsigned long flash_init (void)
{
for (i = 0; i 《 CONFIG_SYS_MAX_FLASH_BANKS; i++)
{
ulong flashbase = 0;
//设置 flash_id ,这个标志保存厂家 ID 和 设备 ID
flash_info[i].flash_id =
#if defined(CONFIG_AMD_LV400)
(AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error “Unknown flash configured”
#endif
//设置 flash 大小和扇区数
flash_info[i].size = FLASH_BANK_SIZE;
flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
//对于 flash 的每个扇区,都需要保存扇区的首地址
for (j = 0; j 《 flash_info[i].sector_count; j++)
{
。。.。。.
flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE;
}
size += flash_info[i].size; //片外所有flash 的总大小
}
//对代码区的扇区设置写保护,这里只是软件的一种设定
flash_protect (FLAG_PROTECT_SET, CONFIG_SYS_FLASH_BASE,
CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
&flash_info[0]);
//如果环境变量保存在 nor 里面,还需对这些扇区设置写保护
flash_protect (FLAG_PROTECT_SET, CONFIG_ENV_ADDR,
CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
return size; //返回 flash 大小
}
flash_init() 函数主要是做一些 flash 的初始化,比如设置 flash 的 ID、大小、扇区数等来构造flash_info_t 结构体,但是从上面的代码可以看出,在该初始化函数中并没有做任何与硬件有关的初始化,所有的值都是通过外部赋值,也就是说我们可以给这些成员变量赋任何我们想要的值,哪怕这些值并不是
flash 真正的参数,虽然这些值并不影响本函数的调用,但是和下面这些函数就有密切关系。
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
//参看是否有写保护扇区,有直接返回错误
prot = 0;
for (sect = s_first; sect 《= s_last; ++sect)
{
if (info-》protect[sect])
prot++;
}
if (prot)
return ERR_PROTECTED;
//关闭中断等,防止擦除过程被中断
icache_disable ();
iflag = disable_interrupts ();
/* Start erase on unprotected sectors */
for (sect = s_first; sect 《= s_last && !ctrlc (); sect++)
{
printf (“Erasing sector %2d 。。. ”, sect);
/* arm simple, non interrupt dependent timer */
reset_timer_masked ();
if (info-》protect[sect] == 0) //此处的判断有点多余
{ /* not protected */
//取扇区的首地址
vu_short *addr = (vu_short *) (info-》start[sect]);
//发解锁和擦除扇区命令
MEM_FLASH_ADDR1 = CMD_UNLOCK1; //往地址 0x555《《1 写入 0xAA
MEM_FLASH_ADDR2 = CMD_UNLOCK2; //往地址 0x2AA《《1 写入 0x55
MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;//往地址 0x555《《1 写入 0x80
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
*addr = CMD_ERASE_CONFIRM; //往地址 0x555《《1 写入 0x30
/* wait until flash is ready */
chip = 0;
do
{
result = *addr; //读取该扇区首地址里面的值
/* check timeout */
if (get_timer_masked () 》 CONFIG_SYS_FLASH_ERASE_TOUT)
{
MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
chip = TMO;
break;
}
//BIT_ERASE_DONE = 0x80,即判断 DQ7 是否为 1
if (!chip && (result & 0xFFFF) & BIT_ERASE_DONE)
chip = READY;
//BIT_PROGRAM_ERROR = 0x20,即判断 DQ5 是否为 1
if (!chip && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
chip = ERR;
} while (!chip);
MEM_FLASH_ADDR1 = CMD_READ_ARRAY; //往地址 0x555《《1 写入 0xF0
。。.。。.
printf (“ok.n”);
}
else
{ /* it was protected */
printf (“protected!n”);
}
}
。。.。。.
/* allow flash to settle - wait 10 ms */
udelay_masked (10000);
return rc;
}
如何自动识别是NOR flash
Norflash启动时:
4K的内部SRAM都被映射到了0x40000000-0x40001000
Nandflash启动时:
4K的内部SRAM都被映射到了0x40000000,同时还被映射到了0x00000000-0x00001000
所有,我们可以通过判断0x0000003c处的数据是否和0x4000003c处的数据相等来判断是哪种启动方式。选择这个地址是因为这个地址处的值固定是0xdeadbeef
3c = 60 = 4*15
.globl _start_start: b start_code ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq .balignl 16,0xdeadbeef
在start.S里的代码如下
/***************** CHECK_BOOT_FLASH ******************************************/ ldr r1, =( (4《《28)|(3《《4)|(3《《2) ) /* address of Internal SRAM 0x4000003C*/ mov r0, #0 /* r0 = 0 */ str r0, [r1] mov r1, #0x3c /* address of men 0x0000003C*/ ldr r0, [r1] cmp r0, #0 bne relocate /* recovery */ ldr r0, =(0xdeadbeef) ldr r1, =( (4《《28)|(3《《4)|(3《《2) ) str r0, [r1]/***************** CHECK_BOOT_FLASH ******************************************/
Uboot里的流程:启动时先将0x4000003C处的数据清零,再读出0x0000003C处地址的数据,如果为0就意味着,这个地址是同时映射在0x4000003C处和0x0000003C处即为nandflash启动,不相等则为norflash启动。
但是最后有一点很重要:如果是Nand flash启动,必须要复原清零的数据。原因是:在nand boot过后,会核对内部SRAM中的4K程序,和从Nand中拷贝到SDRAM的前4K程序是否一致,如果不一致会进入死循环。
nor flash是如何读写数据的
(1) Nor Flash工作模式
Nor Flash上电后处于数据读取状态(Reading Array Data)。此状态可以进行正常的读。这和读取SDRAM/SRAM/ROM一样。(要是不一样的话,芯片上电后如何从Nor Flash中读取启动代码。~)
一般再对Flash进行操作前都要读取芯片信息比如设备ID号。这样做的主要目的是为了判断自己写的程序是否支持该设备。 Nor Flash支持2种方式获取ID号。一种是编程器所用的方法需要高电压(11.5V-12.5V)。另一种方法就是所谓的in-system方法,就是在系统中通过Nor Flash的命令寄存器来完成。本文中只对in-system方法进行说明。此时需要切换到自动选择(Autoselect Command),这要通过发送命令来完成。命令类型见下图。注意:
进入自动选择(Autoselect Command)模式后需要发送复位命令才能回到数据读取状态(Reading Array Data)。
在完成信息获取后一般就要擦除数据。 Nor Flash支持扇区擦(Sector Erase)除和整片擦除(Chip Erase)。这2种模式都有对应的命令序列。在完成擦除命令后会自动返回到数据读取(Reading Array Data)状态。在返回前可查询编程的状态。
完成擦除后就需要对芯片进行写入操作也就是编程。这就需要进入编程(Program)状态。在完成编程命令后会自动返回到数据读取(Reading Array Data)状态。在返回前可查询编程的状态。注意:编程前一定要先擦除。因为编程只能将’1’改写为’0’,通过擦写可以将数据全部擦写为‘1’。
(2)Nor Flash 硬件连接
1. 引脚47 为BYTE# :当其为高电平时数据输出为16bit模式(此时地址线为A19:A0)。低电平为8bit模式。 (此时地址线为A19:A1)上图中Pin47加VCC选用的是16bit模式有效地址线为A19:A0.
2. 对于16bit模式要16bit对齐因此S3C2440A的LADDR1要与A0连接。此时要注意的是NorFlash片内地址0x555对应S3C2440A的地址为baseaddr+0x555*2;其中baseaddr与NorFlash映射的地址有关。一般NorFlash放在Bank0.所以baseaddr=0,但是开启mmu后baseaddr=地址0映射到的新地址。0x555*2的原因是LADDR1与A0连接。也就是0x555表示片内第0x555个word(16bit)。
3. 引脚15为RYBY#输出引脚。用于输出Ready与Busy信号。实际用时可以不接。可用命令查询NorFlash状态代替。
( 3) Nor Flash 模式编程
1. 读ID
2. 扇区擦除(Sector Erase)
扇区擦除命令序列的每个周期均为写周期。
3. 编程(Program)
4. 写操作状态(WRITE OPERATION STATUS)
Nor Flash 提供几个数据位来确定一个写操作的状态,它们分别是: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY#. 如上图所示。其中DQ7, RY/BY#引脚, 和 DQ6 中的每一个都提供了一种方法来判断一个编程或者擦除操作是否已经完成或正在进行中。实际编程中只需要使用其中的一种。
DQ7:Data# Polling bit,DQ7在编程时的状态变化。
在编程过程中从正在编程的地址中读出的数据的DQ7为要写入数据的补码。比如写入的数据为0x0000,及输入的DQ7为‘0’,则在编程中读出的数据为‘1’;当编程完成时读出的数据又变回输入的数据即’0’。在擦除过程中DQ7输出为’0’;擦除完成后输出为’1’;注意读取的地址必须是擦除范围内的地RY/BY#:高电平表示‘就绪’,低电平表示‘忙’。
DQ6:轮转位1(Toggle Bit 1)。
编程和擦除期间,读任意地址都会导致DQ6的轮转(0,1间相互变换)。。当操作完成后,DQ6停止转换。
DQ2:轮转位2(Toggle Bit 2)。当某个扇区被选中擦除时,读有效地址(地址都在擦除的扇区范围内)会导致DQ2的轮转。
注意:DQ2只能判断一个特定的扇区是否被选中擦除。但不能区分这个快是否正在擦除中或者正处于擦除暂停状态。相比之下,DQ6可以区分NorFlash是否处于擦除中或者擦除状态,但不能区分哪个快被选中擦除。因此需要这2个位来确定扇区和模式状态信息。
DQ5: 超时位(Exceeded Timing Limits),当编程或擦除操作超过了一个特定内部脉冲计数是DQ5=1;这表明操作失败。当编程时把’0’改为’1’就会导致DQ5=1,因为只有擦除擦做才能把’0’改为’1’。当错误发生后需要执行复位命令(见图1-1)才能返回到读数据状态。
DQ3: (扇区擦除计时位)Sector Erase Timer,只在扇区擦除指令时起作用。当擦除指令真正开始工作是DQ3=1,此时输入的命令(除擦除暂停命令外)都被忽略。DQ3=0,是可以添加附加的扇区用于多扇区擦除
结语
关于NOR flash的相关介绍就到这了,如有不足之处欢迎指正。
-
存储器
+关注
关注
38文章
7481浏览量
163753 -
NOR flash
+关注
关注
2文章
90浏览量
22994
发布评论请先 登录
相关推荐
评论