电子工程师名片——SPI Flash

        使用了MX25L512的SPI接口的Flash

电子工程师名片——SPI Flash_第1张图片

电路连接图:

电子工程师名片——SPI Flash_第2张图片

总的大小512kb,即64kB,sector的大小为256 Bytes,block的大小为4k Bytes


调试时出现的问题:

1、Flash只能读数据,不能写数据

        根源在于Flash的软件写保护没有去掉,这样,写、擦除,甚至写状态寄存器都不能执行。

1)Hardware Protection

Hardware Protection Mode(HPM):by using WP# going low to protect the BP0-BP1 bits and SRWD bit from data change

因为WP#是高电平,所以没有硬件保护,再来看软件保护


2)Software Protection

Software Protection Mode(SPM):by using BP0-BP1 bits to set the part of flash protected from data change

通过下面几幅图可知,在WP#高电平情况下write status register可以改变SRWD、BP0、BP1的值为0,从而去掉软件写保护。


电子工程师名片——SPI Flash_第3张图片


电子工程师名片——SPI Flash_第4张图片


3)代码实现去除保护

//在所有需要修改的操作之前必须去除软件保护BP0,BP1
//FLASH的状态寄存器
//bit7		bit6	bit5	bit4	bit3	bit2	bit1			bit0
//SRWD		0	 	0	  	0		BP1		BP0		WEL				WIP
// 1=status write disable							1=write enable	1=write in process
#define MASK_CLEAR_BPX 0x73	//掩码,设置使能写状态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS()	 //主要是清除保护,可以写数据
{
	unsigned char status=0;	
	SPI_WRITE_ENABLE();	//设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
	status=SPI_READ_STATUS();
	
	NSSMD0=0;
	SPI0DAT=FLASH_WRITE_STATUS;
	while(!SPIF);
	SPIF=0;

	SPI0DAT=status&MASK_CLEAR_BPX;
	while(!SPIF);
	SPIF=0;

	NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed

	do		//query until WIP convert from 1 to 0 when write status register cycle is finished
	{
		status=SPI_READ_STATUS();
		status=status&0x01;
	}while(status);
}


2、sector大小为256 Bytes,但是连续写256 Bytes,只有最后的32 Bytes写进去了

        在测试MX25L512的扇区的时候,老是遇到一个问题,写入256个字节,但是读出的是最后32个Bytes,前面的总是0xFF,于是就怀疑是不是扇区

的大小没有datasheet所说的那么大呢?最后测试发现扇区的大小只有32Bytes,如果连续写入的字节数大于32 Bytes,就会把除最后32 Bytes之外

的数据丢弃,只写最后的32 Bytes。仔细翻看datasheet,发现MX25L512MC-12G的扇区为256 Bytes,而MX25L512IE的扇区只有32Bytes原来具体

芯片规格和元件后缀名也有关系。

说明:sector是读写数据的最小单元,block是擦除的最小单元。(有时候sector概念类似于page,要看具体的芯片)

扇区被擦除后内部的数据变为0xFF。


3、SPI接口波形不对

虽然C8051F320已经交叉配置为串口和SPI接口,但是实际情况是还是要在输出的管脚PushPull,

P0MDOUT=0x1D;//0001 1101

否则可能SPI口的OUT输出驱动不了,导致波形都没有。


贴上Flash操作的代码:

#ifndef _SPI_CMD_H_
#define _SPI_CMD_H_

#include"misc.h"
////////////////////////////////////////////////
//////////////////MX25L512的flash说明///////////////////
//page:256byte
//sector:4kbyte
//注意MX25L512MC-12G page为256 bytes
//MX25L512IE.. page为32 bytes
///////////////////////////////////////////////

#define FLASH_READ_ID			0x9F 	//读设备ID
#define FLASH_WRITE_ENABLE 	0x06	//写使能
#define FLASH_WRITE_DISABLE 	0x04	//写禁止
#define FLASH_READ_STATUS 		0x05	//读状态寄存器
#define FLASH_WRITE_STATUS	0x01	//写状态寄存器
#define FLASH_READ_DATA		0x03	//读数据
#define FLASH_WRITE_DATA 		0x02	//写数据
#define FLASH_SECTOR_ERASE 	0x20	//擦除一个扇区

extern unsigned char xdata buff[256];//缓冲区全局变量,可以保存一个page的256字节
//在头文件中只是申明一下,不能定义,定义变量要在相应的C文件中定义
//以上不然会报错:multiple public definitions

void SPI_READ_ID();
void SPI_WRITE_ENABLE();
void SPI_WRITE_DISABLE();
unsigned char SPI_READ_STATUS();
void SPI_WRITE_STATUS();
void SPI_SECTOR_ERASE(unsigned char sectors);
void SPI_READ_Page(unsigned char sectors,unsigned char pages);
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages);
void FillDBR();

#endif

#include"SPI_CMD.h"

//#define SPI0INT(x) {SPI0DAT=x;while(!SPIF);SPIF=0;}
//可以用这个定义来取代以下一大段的代码
//SPI0DAT=FLASH_READ_ID;
//while(!SPIF);		       ----->SPI0DAT=FLASH_READ_ID;
//SPIF=0;
void SPI_READ_ID()
{
	NSSMD0=0;
	
	SPI0DAT=FLASH_READ_ID;
	while(!SPIF);
	SPIF=0;

	SPI0DAT=0;	//dummy write to output serial clock
	while(!SPIF); //wait for value to be read
	SPIF=0;
	sendChar(SPI0DAT);
	
	SPI0DAT=0;
	while(!SPIF);
	SPIF=0;
	sendChar(SPI0DAT);	

	SPI0DAT=0;
	while(!SPIF);
	SPIF=0;
	sendChar(SPI0DAT);

	NSSMD0=1;
}

void SPI_WRITE_ENABLE()
{
	NSSMD0=0;
	SPI0DAT=FLASH_WRITE_ENABLE;
	while(!SPIF);
	SPIF=0;
	NSSMD0=1;	
}

void SPI_WRITE_DISABLE()
{
	NSSMD0=0;
	SPI0DAT=FLASH_WRITE_DISABLE;
	while(!SPIF);
	SPIF=0;
	NSSMD0=1;	
}

unsigned char SPI_READ_STATUS()
{
	NSSMD0=0;
	SPI0DAT=FLASH_READ_STATUS;//可以将类似的这种形式做成一个宏定义
	while(!SPIF);
	SPIF=0;

	SPI0DAT=0;
	while(!SPIF);
	SPIF=0;
	NSSMD0=1;

	return SPI0DAT;
}

//在所有需要修改的操作之前必须去除软件保护BP0,BP1
//FLASH的状态寄存器
//bit7		bit6	bit5	bit4	bit3	bit2	bit1			bit0
//SRWD		0	 	0	  	0		BP1		BP0		WEL				WIP
// 1=status write disable							1=write enable	1=write in process
#define MASK_CLEAR_BPX 0x73	//掩码,设置使能写状态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS()	 //主要是清除保护,可以写数据
{
	unsigned char status=0;	
	SPI_WRITE_ENABLE();	//设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
	status=SPI_READ_STATUS();
	
	NSSMD0=0;
	SPI0DAT=FLASH_WRITE_STATUS;
	while(!SPIF);
	SPIF=0;

	SPI0DAT=status&MASK_CLEAR_BPX;
	while(!SPIF);
	SPIF=0;

	NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed

	do		//query until WIP convert from 1 to 0 when write status register cycle is finished
	{
		status=SPI_READ_STATUS();
		status=status&0x01;
	}while(status);
}

void SPI_SECTOR_ERASE(unsigned char sectors)
{
	unsigned char status=0;
	SPI_WRITE_ENABLE();
		
	NSSMD0=0;
	
	SPI0DAT=FLASH_SECTOR_ERASE;
	while(!SPIF);
	SPIF=0;
	
	//any address in the sector,but i choose the first address of sector
	SPI0DAT=0x00;			//high address 
	while(!SPIF);
	SPIF=0;
	SPI0DAT=sectors<<4;		//middle address
	while(!SPIF);
	SPIF=0;
	SPI0DAT=0x00;			//low address
	while(!SPIF);
	SPIF=0;

	NSSMD0=1;

	do		//query until WIP convert from 1 to 0 when write status register cycle is finished
	{
		status=SPI_READ_STATUS();
		status=status&0x01;
	}while(status);
}

unsigned char xdata buff[256];
//读一页256 bytes
void SPI_READ_Page(unsigned char sectors,unsigned char pages)
{
	unsigned int i=0;
	NSSMD0=0;
	SPI0DAT=FLASH_READ_DATA; //command
	while(!SPIF);
	SPIF=0;

	SPI0DAT=0x00;			 //read address
	while(!SPIF);
	SPIF=0;
	SPI0DAT=(sectors<<4) + pages;
	while(!SPIF);
	SPIF=0;
	SPI0DAT=0x00;
	while(!SPIF);
	SPIF=0;

	for(i=0;i<256;i++)			//read a page 256 bytes
	{						//实测每页的数据只有32byte,所以一次连续写32byte
		SPI0DAT=0;				 //read datas out
		while(!SPIF);
		SPIF=0;
		buff[i]=SPI0DAT;
	}
	NSSMD0=1;
}

//写一页256 bytes
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages)
{
	unsigned int i=0;
	unsigned char status=0;
	SPI_WRITE_ENABLE();	  //在改变数据之前都要进行写使能操作
	NSSMD0=0;
	SPI0DAT=FLASH_WRITE_DATA; //write command
	while(!SPIF);
	SPIF=0;

	SPI0DAT=0x00;			 //write address
	while(!SPIF);				//最高地址默认为0x00,所以不用传他的参数
	SPIF=0;
	SPI0DAT=(sectors<<4) + pages;
	while(!SPIF);
	SPIF=0;
	SPI0DAT=0x00;
	while(!SPIF);
	SPIF=0;

	for(i=0;i<256;i++)		//write a page 256 bytes
	{
		SPI0DAT=str[i];	//write data in
		while(!SPIF);
		SPIF=0;
	}
	
	NSSMD0=1;

	do		//query until WIP convert from 1 to 0 when write cycle is finished
	{
		status=SPI_READ_STATUS();
		status=status&0x01;
	}while(status);
}

你可能感兴趣的:(电路)