欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

FLASH写入出错问题记录

程序员文章站 2022-06-22 19:13:57
一、按页写入函数 ,不可跨页,根据地址写入注意:地址+写入字节数 跨页了会写入出错!!!/********************************************************************************名称:SPI_Flash_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)*输入:pBuffer :数据存储区 WriteAddr...

一、按页写入函数 ,不可跨页,根据地址写入

注意:地址+写入字节数 跨页了会写入出错!!!

/*******************************************************************************
*名称:SPI_Flash_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
*输入:pBuffer        :数据存储区
	   WriteAddr      :开始写入的地址
	   NumByteToWrite :要写入的字节数(最大256),不可超过该页剩余字节数
*输出:pBuffer 数据存储区
*返回:无
*功能:在指定地址开始写入最大256字节的数据
*说明:SPI在一页(0~16384)内写入少于256个字节的数据
*******************************************************************************/	 					
void SPI_Flash_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
	uint16_t i;
	SPI_Flash_Wait_Busy();
	SPI_FLASH_Write_Enable();                  //使能写操作 
	//SPI_FLASH_Write_unProtect();
	W25Qxx_CS_LOW();                           //使能器件   
	SPI_ReadWriteByte(SPI1,W25X_PageProgram);      //发送写页命令   
	SPI_ReadWriteByte(SPI1,(uint8_t)((WriteAddr)>>16)); //发送24bit地址    
	SPI_ReadWriteByte(SPI1,(uint8_t)((WriteAddr)>>8));   
	SPI_ReadWriteByte(SPI1,(uint8_t)WriteAddr); 
	if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
	{
		NumByteToWrite = SPI_FLASH_PerWritePageSize;
	}
	for(i=0;i<NumByteToWrite;i++)				//循环写数
		SPI_ReadWriteByte(SPI1,pBuffer[i]);			  
	W25Qxx_CS_HIGH();							//取消片选 
	SPI_Flash_Wait_Busy();						//等待写入结束
} 

 

二、按地址写入函数 ,自动换页写入,不校验数据,不带擦除功能

写入前要确保该地址bit位数据为 1

/*****************************************
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
******************************************/
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
	uint16_t pageremain;
	pageremain=256-WriteAddr%256; //单页剩余的字节数
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{
		SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)	break;		//写入结束了
		else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;

			NumByteToWrite-=pageremain;				//减去已经写入了的字节数
			if(NumByteToWrite>256)pageremain=256;	//一次可以写入256个字节
			else pageremain=NumByteToWrite; 		//不够256个字节了
		}
	}; 

}

 

三、按地址写入函数 ,自动换页写入,带擦除功能

该函数会校验从写入地址到扇区尾的数据是否为0xFF,不是0xFF则先擦除扇区

/*****************************************
//写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
******************************************/
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
	uint32_t secpos;
	uint16_t secoff;
	uint16_t secremain;
	uint16_t i;

	secpos=WriteAddr/4096;	//扇区地址
	secoff=WriteAddr%4096;	//在扇区内的偏移
	secremain=4096-secoff;	//扇区剩余空间大小

	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
	while(1)
	{
		W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除
		}
		if(i<secremain)//需要擦除
		{
			SPI_Flash_Erase_Sector(secpos*4096);	//擦除这个扇区
			for(i=0;i<secremain;i++)		//复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];
			}
			W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区
		}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
		if(NumByteToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;					//扇区地址增1
			secoff=0;					//偏移位置为0

			pBuffer+=secremain; 		//指针偏移
			WriteAddr+=secremain;		//写地址偏移
			NumByteToWrite-=secremain;	//字节数递减
			if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
			else secremain=NumByteToWrite;			//下一个扇区可以写完了
		}
	};
}

 

本文地址:https://blog.csdn.net/p1279030826/article/details/107634747

相关标签: 单片机开发