摘要:串行Flash存储器因体积小、密度高、功耗低和易操作而倍受青睐。本文简单介绍Megawin公司生产的Flash存储器,讲述其特点、结构、指令集,并以MM36SB010为例给出它的读写程序。
关键词:MM36B512/010/B020 串行Flash Flash
1 概述
MM36SB512、MM36B010、MM36SB020是Megawin公司生产的低功耗、用于嵌入式系统的大容量串行Flash存储器。MM36SB512/010/020的存储空间分别为512Kbit/1Mbit/2Mbit,分别由512/1024/2048个页面组成,每个页面为128字节。此系列存储器都自带1个128字节数据缓冲区。
该系列芯片工作于2/3线串行总线方式。硬件检测和复位可不用,改用软件查询/控制。该系统产品的高性能价格比和串行控制特性使其在消费电子、通信、工业控制等领域都有广泛的应用。
2 特点
*2.4~3.6V和4.5~5.5V2种工作电压;
*SPI串行接口结构,2/3线输入输出;
*128字节数据缓冲区;
*支持页擦除和芯片擦除;
*MM36SB512工作频率最高可达4MHz;
MM36SB010/020工作频率最高可达8MHz;
*“BUSY”引脚(硬件检测编程/擦除是否完成),可不用,采用软件查询方式;
*硬件复位(可自上电复位,如用软件复位不用此引脚);
*低功耗
——4mA典型编程/擦除电流;
——1mA典型读/写电流;
——0.5μA典型Standby电流。
3 内部结构框图
图1是MM36SB010的内部结构图,MM36SB512和MM36SB020与此类似。状态寄存器第0位表示存储器的状态,“1”表示忙;其它位暂不使用。
MM36SB010引脚说明如下:
VDD——工作电源接入端;
VSS——接地端;
SMC——串行模式控制(SMC=VDD为2线,SMC=0为3线);
SCLK——串行时钟输入;
SDIO——串行数据输入/输出(当SMC=0时,此引脚为SDI);
SDO——串行数据输出(当SMC=VDD时,此引脚不用);
BUSY——状态输出(高为“忙”。如通过状态寄存器来查询,此引脚不用);
IEB——IEB=0,芯片使能;
RESB——芯片复位(内部自带上拉电阻,上电自动复位);
OSC——频率调节。
此系统芯片引脚少,封装简单,与控制器的典型接法如图2、3所示。
4 存储器控制
MM36SB010的控制指令如表1所列。
表1
| 指 令 | 操作码 | 地 址 | 数 据 | 说 明 |
| ERSC | 90F6H | 擦除整个芯片(Erase whole chip) | ||
| SRC(SREC) | FFFFFFFEH | 软件复位(software reset) | ||
| RSE | 94H | 读状态寄存器 | ||
| RBE | 98H | BA7~BA0 | 从指定缓冲区单元读1字节数据 | |
| RME | 9CH | PA15~PA0 BA7~BA0 | 从Flash存储器读1字节数据 | |
| RMEC | A0H | 从Flash存储器(地址自动增加)连续读1字节数据 | ||
| RMB | A4H | PA15~PA0 | 从Flash中读1页数据到缓冲区 | |
| WEB | A8H | BA7~BA0 | D7~D0 | 写1字节数据到缓冲区 |
| WEBC | ACH | D7~D0 | 连续写数据到缓冲区(地址自动增加) | |
| WBMEP | B0H | PA15~PA0 | 将缓冲区数据写存储器中指定页(先页擦除再编程) | |
| WBMP | B4H | PA15~PA0 | 将缓冲区数据写到存储器中指定页(直接编程不擦除) |
芯片上电以后,选通信号IEB保持低电平时,可向存储器传送指令、地址,写放或读出数据。所有指令、地址、数据的传送都是从低位(LSB)开始。有2个特殊指令:RMEC、WEBC。RMEC是从主存储器中连续读数据,它必须在指令RME执行之后,再输入RMEC指令,不输入地址,由RME的地址自动递增。WEBC指令也一样,必须在WEB指令执行之后执行。
下面给出从Flash存储器中连续读128字节,写128字节到内部缓冲区再送入Flash的参考程序,详细资料可从www.DSP-Memory.com下载。
#include<reg52.h>
#include<stdio.h>
#define RSE 0x94
#define RMEC 0xa0
#define RMB 0xa4
#define WEB 0xa8
#define WEBC 0xac
#define WBMEP 0xb0
#define LOW 0
#define HIGH 1
#define BUSY 2
#define OK 3
#define ARRAY_SIZE 128
#define Word unsigned int
#define Byte unsigned char sbit SCLK = 0x90;
/*SCLK=P1.0*/
sbit SDI=0x91; /*SDI=P1.1*/
sbit SDO=0x92; /*SDO=P1.2*/
Byte busy();
Byte read_one_bit();
Byte read_one_byte();
Void send_one_bit(Byte temp);
Void send_one_byte(Byte data);
Byte ReadData(Word p_addr,Byte b_addr,Byte array[]);
Byte SendData(Word p_addr,Byte array[]);
Byte read_one_bit() {
Byte temp;
SCLK=LOW;
SCLK=HIGH;
SDO=HIGH;
temp=SDO;
SCLK=LOW;
return temp;
}
Byte read_one_byte(){
Byte mark_data=0x01,data=0,i=0;
for(i=0;i<8;i++) {
if(read_one_bit()!=0)
data=data mark_data;
mark_data=mark_data<<1;
}
return data;
}
void send_one_bit(Byte temp){
SCLK=LOW;
if(temp)
SDI=HIGH;
Else
SDI=LOW;
SCLK=HIGH;
SCLK=LOW;
}
void send_one_byte(Byte data){
Byte temp=0;
Byte i=0;
for(i=0;i<8;i++){
if(data & 0x01)!=0) temp=1;
else temp=0;
send_one_bit(temp);
data=data>>1;
}
}
Byte busy(){ /*读状态命令*/
send_one_byte(RSE); /*送RSE命令*/
if(read_one_byte()&0x01)return 1;
else return 0;
}
Byte ReadData (Word p_addr,Byte b_addr,Byte array[])
/*p_addr为页地址,b_addr为页内地址,array[]为MCU内部存储空间*/
{
Byte i,temp=0;
if(busy()) return BUSY;
send_one_byte(RME); /*送RME命令*/
send_one_byte(b_addr); /*送页内地址*/
send_one_byte((Byte)(p_addr & 0x00FF)); /*送页低字节地址*/
send_one_byte((Byte)(p_addr & 0xFF00)); /*送页高字节地址*/
array[0]=read_one_byte(); /*读数据*/
for(i=1;i<ARRAY_SIZE;i++){ /*连续读数据*/
send_one_byte(RMEC);
array[i]=read_one_byte();
}
return OK;
}
Byte SendData(Word_addr,Byte array[])
/*p_addr为页地址,array[]为MCU内部存储空间*/
{
Byte i=0;
if(busy()) return BUSY;
send_one_byte(WEB); /*送WEB指令*/
send_one_byte(0x00); /*送页内首地址''0''*/
send_one_byte(array[0]); /*送1字节数据*/
for(i=1;i<ARRAY_SIZE;i++) {
send_one_byte(WEBC);
send_one_byte(array[i]);
}
send_one_byte(WEBC);
send_one_byte(array[i]);
}
send_one_byte(WBMEP); /*送WBMET指令*/
send_one_byte((Byte)(p_addr & 0x00FF)); /*送页低字节地址*/
send_one_byte((Byte)(p_addr & 0xFF00)); /*送页高字节地址*/
return OK;