6713_EMIF操作外部flash

6713EMIF操作FLASH

1. 6713EMIF的特点

Ø       数据总线宽度:32位,有32条数据线D[31:0]

Ø       存储空间:4个,#CE0-#CE3,对应地址为0x80000000、0x90000000、0xA0000000、0xB0000000

Ø       每个存储空间的寻址范围:256M

Ø       时钟:外部ECLKIN引脚输入或内部SYSCLK3提供,最高时钟频率为100MHZ

Ø       可访问的数据宽度:8/16/32位

Ø       支持的存储器类型:SDRAM/SBSRAM/异步存储器(SRAM、Flash等)

Ø       各类存储器控制信号:复用引脚,自动切换

2. 6713EMIF接口信号

6713_EMIF操作外部flash_第1张图片

图2.1 EMIF接口信号

ECLKIN:     EMIF外部时钟输入;

ECLKOUT:  EMIF工作时钟(有2 个来源:ECLKIN 和SYSCLK3 由EKSRC(DEVCFG.[4])                     选择 EKSRC = 0 时,选中SYSCLK3(默认) EKSRC = 1 时,选中ECLKIN)

ED[31:0]:   32-位数据总线;

EA[21:2]:   20-位地址总线;

:   4-个存储空间选通信号,低电平有效;

:   4-个字节使能信号,低电平有效;

:   异步存储器读出使能信号/SDRAM 行选通信号/SBSRAM读                                      出使能信号,低电平有效;

:异步存储器读使能信号/SDRAM 列选通信号/SBSRAM地址                                      选通信号,低电平有效;

:   异步存储器写使能信号/SDRAM 写使能信号/SBSRAM写使                                    能信号,低电平有效;

ARDY:        异步存储器数据就绪信号,高电平有效;

:     EMIF总线保持请求信号,低电平有效;

:   EMIF总线已保持确认信号,低电平有效;

BUSREQ:   EMIF总线请求标志信号,高电平有效;

3. 存储器宽度和字节对齐

C6713 能直接与8/16/32位存储器无缝接口,内部以字节进行编址(逻辑地址),外部存储器地址(物理地址),由EMIF根据所接口的存储器的宽度,自动对逻辑地址进行移位产生,逻辑地址与物理地址之间的关系如下表所示:

6713_EMIF操作外部flash_第2张图片

图3.1 逻辑地址和物理地址的关系

对小于32位的外部存储器进行访问时,EMIF 将自动完成数据打包和拆包。例如,对8位存储器进行读操作时,EMIF自动读字节地址 N、N+1、N+2、N+3中的4个8位数据打包成32-位的数据;而对 16-位存储器进行写操作时,EMIF自动将32位数据拆包成2个16位数据分别写入字地址N、N+1中。8位与16位数据与EMIF的32位数据总线之间的对应关系由Endian模式决定,在LittleEndian模式时,对齐EMIF的最低有效位,在 Big Endian模式时,对齐EMIF的最高有效位。如下图所示:

6713_EMIF操作外部flash_第3张图片

图3.2 位宽对其方式

4.6713EMIF外扩FLASH分析

4.1 地址定义

一般地,我们会用CPLD或者FPGA对这些外设进行译码,分别给各个外设的片选分配一个唯一的地址。这个地址是物理地址,是用CEx和EA[21:2]硬线做译码得到的。而DSP要操作这个地址,必须使用逻辑地址(字节地址),这就要求有一个物理地址和逻辑地址的对应关系。在建立这种关系的时候,我们要明确地指出某个CEx的数据宽度,是8位还是16位。我们所选用的FLASH为S29AL016J(如果BYTE#引脚被设置为1,那么为16位宽度,如果BYTE#被设置为0,那么为8位宽度),并且其与EMIF连接的存储空间为CE1,所以其基地址设置为FLASH_BASE1 = (unsignedint *)0x90000000;由于选择的是16位数据宽度,所以对Flash 而言其物理地址以16位为单位进行编址,而程序中使用的逻辑地址是以字节为单位进行编址的,二者之间的关系如下:

逻辑地址 =  物理地址 << 1

volatile Uint16 *FLASH_555 = (volatile Uint16 *) (0x90000000 +(0x555<<1));

volatile Uint16 *FLASH_2AA = (volatile Uint16 *) (0x90000000 +(0x2AA<<1));

4.2 操作Flash

对于Flash的操作主要是flash擦除,flash读和flash写。DSP通过EMIF的CE1存储空间外扩flash,根据Flash的数据手册可以得到Flash的相应操作的命令定义表:

表4.1 Flash 命令定义表

6713_EMIF操作外部flash_第4张图片

4.2.1  flash擦除函数

图4.1 擦除规范

函数原型:

Uint32Flash_Erase(Uint32 addr, Uint16 type)

参数addr表示擦除Flash的基地址,参数type表示擦除类型,有擦除扇区和擦除整个芯片两种,0x30表示擦除扇区,0x10表示擦除整个chip。

整片擦除:由于是16位宽度,所以擦除命令为word这一行,也就是向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 +(0x555<<1)))写入AA->((volatile Uint16 *) (0x90000000 +(0x2AA<<1)))写入55->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入80->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入AA->向flash的地址FLASH_2AA((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入55->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入10。擦除过程中Data#会将DQ7的值拉低为0,擦除完成Data#会将DQ7拉高为1(while((*(Uint16 *)addr & 0x80) != 0x80);)。

扇区擦除:由于是16位宽度,所以擦除命令为word这一行,也就是向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 +(0x555<<1)))写入AA->((volatile Uint16 *) (0x90000000 +(0x2AA<<1)))写入55->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入80->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入AA->向flash的地址FLASH_2AA((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入55->向给定地址addr中写入30。擦除过程中Data#会将DQ7的值拉低为0,擦除完成Data#会将DQ7拉高为1。(       while((*(Uint16 *)addr& 0x80) != 0x80);)

 

 6713_EMIF操作外部flash_第5张图片

图4.2 flash擦除函数流程

4.2.2 flash单个读取函数

函数原型:

Uint32Flash_Reads(Uint32 addr)

返回读取到的当个地址中的数据,参数addr表示读取当个数据的地址。

直接返回地址中的数据(return (*(Uint32 *)addr);)。

4.2.3 读取flash函数

函数原型:

voidFlah_Readm(Uint32 addr,Uint16 *ptr,Uint32 length)

参数addr表示读取flash数据的首地址,ptr表示目标buff的地址,length表示读取长度。

流程:根据length的大小以for循环的形式从首地址中逐次读取flash中数据到目标地址中,由于目标地址中数据类型是Uint16,而源地址中数据是Uint32,所以在读取时,数据长度应该×2。

6713_EMIF操作外部flash_第6张图片

图4.3 flash读取流程

4.2.4 flash单个写入函数

图4.4 flash写入规范

函数原型:

voidFlash_Writes(Uint32 addr,Uint16 data)

参数addr表示写入flash的写入地址,data表示写入的单个数据。

由于是16位宽度,所以擦除命令为word这一行,也就是向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 +(0x555<<1)))写入AA->((volatile Uint16 *) (0x90000000 +(0x2AA<<1)))写入55->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入a0。接着向给定地址addr中写入data。

4.2.5 flash写入函数

图4.5 flash写入规范

函数原型:

voidFlash_Writem(Uint32 src, Uint32 dst,unsigned short length)

参数src表示源地址,dst表示写入的目标地址,length表示写入的长度。

定义相关变量,判断输入长度是否正确,不正确退出,长度大于0则进行写入操作,先将源地址和目标地址数据转换成Uint16类型,然后根据长度逐个将数据写入到flash对应的地址中:FLASH_555((volatile Uint16 *) (0x90000000 +(0x555<<1)))写入AA->((volatile Uint16 *) (0x90000000 +(0x2AA<<1)))写入55->向flash的地址FLASH_555((volatile Uint16 *) (0x90000000 + (0x555<<1)))写入a0。然后以while循环将数据写入到flash。

6713_EMIF操作外部flash_第7张图片

图4.6 flash写入流程

5 FLASH寄存器设置和时序控制

5.1 Flash总线设置内部命令寄存器

Flash通过相应链接线路上的电平时序变化产生相应的操作命令,入下表所示:

6713_EMIF操作外部flash_第8张图片

图5.1 flash总线操作

BYTE#引脚决定flash选择8位宽度数据配置还是16位宽度。如果设置为逻辑1,那么falsh配置为16位宽度,DQ15-DQ0为数据IO口,由CE#和OE#控制。如果设置为逻辑0,那么flash配置为8位宽度,DQ0-DQ7为数据IO口,由CE#和OE#控制,并且DQ15位设置为数据地址的最低有效位。

读数据的时候系统必须设置CE#和OE#为逻辑低电平,CE#作为片选引脚,OE#是读控制使能引脚。WE#得设置为逻辑高电平。标准的微处理器读数过程是给flash的地址线输入有效地址,falsh通过数据线输出有效数据,在命令寄存器设置没有改变时一直保持读数状态。

写命令或者命令序列(对flssh进行写入操作或者擦除操作)的时候必须设置WE#和CE#为逻辑低电平,OE#为逻辑高电平。开启旁路模式的时候能更快的将数据写入到flash,因为它只要两个写入周期就能写一个数据,正常的需要4个写入周期。擦除操作分一个扇区擦除,多个扇区擦除以及整个片擦除。在擦除或者写入操作的过程中,系统会检查DQ7-DQ0上的状态位确定当期操作状态(擦除完或者写完)。

当系统没有读或者写flash的时候会让flash进入备用模式,在这种模式下功耗非常低,所有的输出都将被设置为高阻态。进入这种模式时CE#和RESET#全部保持在VCC+-0.3v。

当OE#设置为逻辑低电平,所有的输出被禁止,输出口全部被设置为高阻态。

 

5.2 FLASH读写时序

Flash读数过程:

6713_EMIF操作外部flash_第9张图片

图5.2 读数时序图

Flash芯片读数过程主要由芯片上的片选信号CE#和读使能信号OE#控制,写使能信号WE#为逻辑低电平,当CE#和OE#中后到来的下降沿(此时CE#和OE#都为低电平),开始读取对应地址中的数据,读数的时候会有时序图的一些延时,如下表:

6713_EMIF操作外部flash_第10张图片

图5.3 读数延时表

Flash写数时序:

 6713_EMIF操作外部flash_第11张图片

图5.4 写数时序图

Flash芯片读数过程主要由芯片上的片选信号CE#和写使能信号WE#控制,地址信息用CE#和WE#中后到来的下降沿(此时CE#和WE#都为低)来获得,数据信息用CE#和WE#中先到来的上升沿(此时CE#和WE#只有一个为高)来获得,读数的时候会有时序图的一些延时,如下表:

6713_EMIF操作外部flash_第12张图片

图5.5 写数延时表

 

Flash擦除时序:

6713_EMIF操作外部flash_第13张图片

图5.6 flash擦除时序

Flash芯片读数过程主要由芯片上的片选信号CE#和写使能信号WE#控制,地址信息用CE#和WE#中后到来的下降沿(此时CE#和WE#都为低)来获得,数据信息用CE#和WE#中先到来的上升沿(此时CE#和WE#只有一个为高)来获得,经过5写入个周期后,由DQ7是否为逻辑高电平来确定擦除有没有完成(completed)。

6 附录,程序

Flash.h

#define           FLASH_UL1  0xAA

#define           FLASH_UL2  0x55

#define           FLASH_UL3  0x80

#define           FLASH_UL4  0xAA

#define           FLASH_UL5  0x55

#define           FLASH_SECTOR_UL6 0x30

#define           FLASH_CHIP_UL6             0x10

#define           FLASH_PROGRAM     0xA0

 

// #define     SECTOR_SIZE 0x40000    //256K*16bit

#define    SECTOR_SIZE 0x8000    //32K*16bit

#define           CHIP_SIZE    0x100000  //1M*16bit

 

volatile Uint16 *FLASH_555 = (volatileUint16 *) (0x90000000 + (0x555<<1));

volatile Uint16 *FLASH_2AA = (volatileUint16 *) (0x90000000 + (0x2AA<<1));

/********************************************************************************/

Uint32 Flash_Erase(Uint32 addr,Uint16type);

void Flash_Readm(Uint32 addr,Uint16*ptr,Uint32 length);

Uint32 Flash_Reads(Uint32 addr);

void Flash_Writem(Uint32 src,Uint32 dst,unsignedshort length);

void Flash_Writes(Uint32 addr,Uint16 data);

 

Flash.c

#include

#include

#include

#include

#include

#include

#include

#include

 

 

/*    Flashfunction difine. */

/********************************************************************************/

/* Flash erase function. */

/********************************************************************************/

Uint32 Flash_Erase(Uint32 addr,Uint16 type)

{

       Uint32i,j;

       *FLASH_555= FLASH_UL1;     //first

       *FLASH_2AA= FLASH_UL2;    //second

       *FLASH_555= FLASH_UL3;     //third

       *FLASH_555= FLASH_UL4;

       *FLASH_2AA= FLASH_UL5;

/*    *FLASH_555= type;

       while(((*FLASH_555)& 0x80) != 0x80);

       for(i= 0; i < CHIP_SIZE; i++)

       {

              if(*(Uint16 *)(addr + i) != 0xffff)

              {

                     break;

              }

       }

 

}*/  

      

       switch(type)

       {

       /*    case 0x50:             //block erase

                     *(Uint16*)addr = type;

                     while((*(Uint16*)addr & 0x80) != 0x80);

                     for(i= 0; i < BLOCK_SIZE; i++)

                     {

                            if(*(Uint16 *)(addr + i) != 0xffff)

                            {

                                   j= 0;

                                   break;

                            }

                     }

                     j= 1;

                     break;

       */   

              case 0x30:             //sector erase

                     *(Uint16*)addr = type;

                     while((*(Uint16*)addr & 0x80) != 0x80);

                     for(i= 0; i < SECTOR_SIZE; i++)

                     {

                            if(*(Uint16 *)(addr + i) != 0xffff)

                            {

                                   j= 0;

                                   break;

                            }

                     }

                     j= 1;

                     break;

                    

              case 0x10:             //chip erase

                     *FLASH_555= type;

                     DSP_wait(1000);

                     while((*FLASH_555 & 0x80) != 0x80);

                     for(i= 0; i < CHIP_SIZE; i++)

                     {

                            if(*(Uint16 *)(addr + i) != 0xffff)

                            {

                                   j= 0;

                                   break;

                            }

                     }

                     j= 1;

                     break;

             

              default:

                     break;

       }

       return(j);

}

 

/********************************************************************************/

/* Write a single data. */

/********************************************************************************/

void Flash_Writes(Uint32 addr,Uint16 data)

{

       //Uint16TempData=0;

       *FLASH_555= FLASH_UL1;

       *FLASH_2AA= FLASH_UL2;

       *FLASH_555= FLASH_PROGRAM;

   //for(;;)

   //{

       *(Uint16*)addr = data;

       //TempData= *(Uint16 *)(addr);

       //}

       //TempData= *(Uint16 *)(addr);

       while(*(Uint16*)addr != data);

}

 

/********************************************************************************\

\* Write the certain length data. *\

\********************************************************************************/

void Flash_Writem(Uint32 src,Uint32dst,unsigned short length)

{

   Uint16 *psrc, *pdst;

   unsigned short i;

   if (length<=0)return;

   /* Establish source and destination */

   psrc = (Uint16 *)src;

   pdst = (Uint16 *)dst;

   for (i = 0; i < length; i++)

    {

       // Program one 16-bit word

           *FLASH_555 = FLASH_UL1;

           *FLASH_2AA = FLASH_UL2;

           *FLASH_555 = FLASH_PROGRAM;

       *pdst = *psrc;

       // Wait for operation to complete

       while(1)

              {

               if(*pdst == *psrc)

                {

                break;

                }

              }

 

       pdst++;

       psrc++;

 

 

       }

}

 

/********************************************************************************\

\* Read a single data. *\

\********************************************************************************/

Uint32 Flash_Reads(Uint32 addr)

{

       return(*(Uint32 *)addr);

}

 

/********************************************************************************\

\* Read the certain length data. *\

\********************************************************************************/

void Flash_Readm(Uint32 addr,Uint16*ptr,Uint32 length)

{

       Uint32i;

       for(i= 0; i < length; i++)

       {

              *(ptr + i) = Flash_Reads(addr+2*i);

       }

}

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(TI_DSP学习)