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接口信号

图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根据所接口的存储器的宽度,自动对逻辑地址进行移位产生,逻辑地址与物理地址之间的关系如下表所示:

图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的最高有效位。如下图所示:

图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 命令定义表

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);)

图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。

图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。

图4.6 flash写入流程

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

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

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

图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读数过程:

图5.2 读数时序图

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

图5.3 读数延时表

Flash写数时序:

图5.4 写数时序图

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

图5.5 写数延时表

Flash擦除时序:

图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 <stdio.h>

#include <csl.h>

#include <csl_irq.h>

#include <csl_chip.h>

#include <csl_emif.h>

#include <csl_irq.h>

#include <DEC6713_FLASH.h>

#include <math.h>

/*    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);

}

}

6713_EMIF操作外部flash相关推荐

  1. QCC300x笔记(5) -- 外部Flash的读写操作

    哈喽大家好,这是该系列博文的第五篇~ 篇~ <<[系列博文索引]快速通道 > 1.    QCC300X 外部Flash的读写         QCC300x是使用外部Flash片子 ...

  2. 智能设备逆向工程之外部Flash读取与分析篇

    唐朝实验室 · 2015/10/19 11:19 author: rayxcp 0x00 前言 目前智能家居设备的种类很多,本文内容以某智能豆浆机为例完成对其的固件提取和分析. 究其分析内部逻辑的原因 ...

  3. esp32 s3 外部flash和外部psram配置

    1. 标准spi 主从都在自己的数据线上发送/接收数据,主机如果需要接收数据,则需要单独发一段数据才能触发从机应答,从而接收从机数据 CPOL 时钟极性 CPOL =0 表示时钟空闲为低电平,下降沿采 ...

  4. 【单片机笔记】基于STM32F103C8的 USB 外部flash虚拟U盘

    学习stm32已经很长时间了,但是一直没有过多的学习stm32的USB部分,因为实际工作还是用的比较少.说起USB那就有的说了,因为USB的功能很强大,这里主要重点记录一下STM32的USB部分,这个 ...

  5. 【FlashDB】第二步 FlashDB 移植 STM32L475 使用QSPI驱动外部 flash W25Q64之 SFUD 移植

    第一步写好了FAL移植,那么进行第二步 SFUD 移植 [FlashDB]第一步 FlashDB 移植到 STM32L475 使用QSPI驱动外部 flash W25Q64之FAL移植 准备工作 1. ...

  6. Flash----读写外部Flash

    目录 前言 Flash相关API Flash工程 首先定义下flash扇区大小 定义下扇区操作编号及定义了将要写入flash数据的数组和用来缓存flash数据的数组 接下来我们从0x77000地址起, ...

  7. STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

  8. STM32CubeMX学习笔记(48)——USB接口使用(MSC基于外部Flash模拟U盘)

    一.USB简介 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在 PC 领域的接口技术.USB 接口支持设备的即插即用和 ...

  9. 学习日记——ESP8266读写外部Flash(2020.5.26)

    一.Falsh布局 ⽬前 ESP8266EX 模组采⽤的 demo Flash 为 SPI Flash,ROM[硬盘,用来存储和保存数据] ⼤⼩:2 MB,封装为SOP8 (208 mil). (SP ...

最新文章

  1. 哈尔滨理工大学软件与微电子学院程序设计竞赛 题解
  2. 除了数据,生活中还有这些......
  3. 最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用35
  4. [洛谷P4012] [网络流24题] 深海机器人问题
  5. 分布式架构的水平和垂直扩容
  6. joo工作流_不要错过使用jOOλ或jOOQ编写Java 8 SQL单行代码的机会
  7. 计算机网络应用层笔记--域名系统DNS
  8. 《大数据》第1期“聚焦”——对大数据的再认识
  9. python 内置变量
  10. Visual Studio 2005 提示“试图运行项目时出错:无法启动调试。绑定句柄无效”~[解决方案]...
  11. 武汉大学计算机学院 工程硕士,武汉大学计算机学院在职人员攻读工程硕士学位招生专业介绍...
  12. adobe cs4系列套装及注册机下载
  13. Python科学计算的瑞士军刀——Anaconda 安装与配置
  14. 谈谈我对 iPhone5 全景照相机 的理解
  15. 用git统计代码提交行数
  16. 【STM32笔记】低功耗模式下的RTC唤醒(非闹钟唤醒,而是采用RTC_WAKEUPTIMER)
  17. [GAN]老照片修复Bringing Old Photos Back to Life论文总结
  18. [STM32F4]STM32F407 ADC采集+DMA传输
  19. 如何创建index.php文件,index.html是什么意思/文件,index.html怎么创建/打开
  20. Json diff 定制化需求

热门文章

  1. LVM与磁盘配额原理及配置
  2. 乐山计算机学校电话号码,乐山计算机学校网站网址联系方式
  3. matlab一次二阶矩法正态分布,一次二阶矩法.ppt
  4. 使用James搭建一个自己的邮箱服务器
  5. Linux之awk命令详解
  6. mysql 14067_wiondows XP/2003下面IIS PHP MySQL Zend phpmyadmin安装
  7. 提示用户提供数值输出时,常出现的一个问题
  8. 记录 Ubuntu 下 Audio Jack(耳机插孔) 引起的 kworker CPU 高占用Bug
  9. java切割输入流_IO流之切割合并文件
  10. rsync和inotify