Nor Flash 学习笔记

来源:互联网 发布:伺服编程 编辑:程序博客网 时间:2024/05/21 06:28

Nor Flash 学习笔记

实验验平台: TQ2440

CPU:             S3C2440A(ARM9)

开发环境:           ADS/MDK

NorFlash型号 :AM29LV160DB

 

(1)   Nor Flash 工作模式

Nor Flash上电后处于数据读取状态(Reading Array Data)。此状态可以进行正常的读。这和读取SDRAM/SRAM/ROM一样。(要是不一样的话,芯片上电后如何从NorFlash中读取启动代码。~)

一般再对Flash进行操作前都要读取芯片信息比如设备ID号。这样做的主要目的是为了判断自己写的程序是否支持该设备。    Nor Flash支持2种方式获取ID号。一种是编程器所用的方法需要高电压(11.5V-12.5V)。另一种方法就是所谓的in-system方法,就是在系统中通过NorFlash的命令寄存器来完成。本文中只对in-system方法进行说明。此时需要切换到自动选择(Autoselect Command,这要通过发送命令来完成。命令类型见下图。注意:

   进入自动选择(Autoselect Command模式后需要发送复位命令才能回到数据读取状态(Reading Array Data)。

在完成信息获取后一般就要擦除数据。 NorFlash支持扇区擦(Sector Erase)除和整片擦除(Chip Erase)。这2种模式都有对应的命令序列。在完成擦除命令后会自动返回到数据读取(Reading Array Data状态。在返回前可查询编程的状态。

完成擦除后就需要对芯片进行写入操作也就是编程。这就需要进入编程(Program)状态。在完成编程命令后会自动返回到数据读取(Reading Array Data状态。在返回前可查询编程的状态。注意:编程前一定要先擦除。因为编程只能将’1’改写为’0’,通过擦写可以将数据全部擦写为‘1’。

以上是主要的操作其他操作还有写保护等,请参考芯片数据手册。

 

点击看大图


1-1 命令与模式

(2) Nor Flash 硬件连接

点击看大图
2-1 Nor Flash 引脚

 


2-2 TQ2440中实际连接


上图中要注意的几个地方:

1.       引脚47 BYTE# :当其为高电平时数据输出为16bit模式(此时地址线为A19:A0).低电平为8bit模式. (此时地址线为A19:A1)上图中Pin47VCC选用的是16bit模式有效地址线为A19:A0.

2.       对于16bit模式要16bit对齐因此S3C2440ALADDR1要与A0连接.此时要注意的是NorFlash片内地址0x555对应S3C2440A的地址为baseaddr+0x555*2;其中baseaddrNorFlash映射的地址有关。一般NorFlash放在Bank0.所以baseaddr=0,但是开启mmubaseaddr=地址0映射到的新地址。0x555*2的原因是LADDR1A0连接。也就是0x555表示片内第0x555word(16bit).

3.       引脚15RYBY#输出引脚。用于输出ReadyBusy信号。实际用时可以不接。可用命令查询NorFlash状态代替.

 

(3) Nor Flash 模式编程


1.     ID

点击看大图

上图中表明 id共有4个指令周期,3个为周期,最后一个为周期;

#define flash_base      0x00000000  //flash接到bank0

#define    CMD_ADDR0            *((volatile U16 *)(0x555*2+flash_base))

#define    CMD_ADDR1            *((volatile U16 *)(0x2aa*2+flash_base))

#define    CMD_ADDR2            *((volatile U16 *)(0xaaa*2+flash_base))

 

/*** 读取 Am29LV800D ID ***/

U32  Get_Am29LV800D_ID(void)

{

       U32 i="0";

      

       CMD_ADDR0 = 0xaa;   CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x90; 

       i  = (*(U16 *)(0*2+flash_base))<<16;//Manufacturer ID = 01

      

       CMD_ADDR0 = 0xaa;   CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x90; 

       i  |=  *(U16 *)(1*2+flash_base);//device ID = 2249

       return i;

}

 

2. 扇区擦除(Sector Erase)

 点击看大图

扇区擦除命令序列的每个周期均为写周期。

void  Am29LV800D_SectorErase(U32 SA)

{

       CMD_ADDR0 = 0xAA; CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x80;

       CMD_ADDR0 = 0xAA; CMD_ADDR1 = 0x55;//Word 模式命令序列

       *((volatile U16 *)(SA)) = 0x30;

       Waitfor_endofprg();//状态查询

      

}

 

 


3. 编程(Program)

编程 命令序列的每个周期均为写周期。

int  Am29LV800D_WordProg (U32 PA,U16 PD)

{

       CMD_ADDR0 = 0xAA;  CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0xA0;

*((volatile U16 *)(PA)) = PD;// word模式,以上为4个命令周期

       return(Waitfor_endofprg());//状态查询

}

 

4.       写操作状态(WRITE OPERATION STATUS)

 点击看大图

NorFlash 提供几个数据位来确定一个写操作的状态,它们分别是: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY#. 如上图所示。其中DQ7, RY/BY#引脚, DQ6 中的每一个都提供了一种方法来判断一个编程或者擦除操作是否已经完成或正在进行中。实际编程中只需要使用其中的一种。

DQ7Data# Polling bitDQ7在编程时的状态变化.

编程过程中从正在编程的地址中读出的数据的DQ7为要写入数据的补码。比如写入的数据为0x0000,及输入的DQ7为‘0’,则在编程中读出的数据为‘1’;当编程完成时读出的数据又变回输入的数据即’0’.

在擦除过程中DQ7输出为’0’;擦除完成后输出为’1’;注意读取的地址必须是擦除范围内的地址。

 

RY/BY#高电平表示‘就绪’,低电平表示‘忙’。

 

DQ6轮转位1Toggle Bit 1)。

在编程和擦除期间,读任意地址都会导致DQ6轮转(01间相互变换).。当操作完成后,DQ6停止转换。

 

DQ2轮转位2Toggle 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,是可以添加附加的扇区用于多扇区擦除。

 

以上讲了这些状态为,实际只需要使用几个就行,比较简单的就是选择DQ5,DQ6/DQ2.如下例。

 

/****** Am29LV800D 的检测 ******/

int Waitfor_endofprg(void)

{

       volatile U16 flashStatus,old;

       old=*((volatile U16 *)0x0);//先读一次状态

 

    while(1)

       {

           flashStatus=*((volatile U16 *)0x0);//再读一次状态

        if( (old&0x40) == (flashStatus&0x40) ) break;//比较DQ6.相同说明设备已经就绪

        if( flashStatus&0x20 )  //判断DQ5,为‘1’则超时

           {

                  old=*((volatile U16 *)0x0);

                  flashStatus=*((volatile U16 *)0x0);//在读取比较一次。因为可能在超时前刚好玩

//成操作。

                  if( (old&0x40) == (flashStatus&0x40) )

                      return 1;

                  else return 0;

           }

          

           old=flashStatus;

    }

   return 1;

}

原创粉丝点击