FLASH写入出错问题记录
程序员文章站
2022-03-11 15:48:12
一、按页写入函数 ,不可跨页,根据地址写入注意:地址+写入字节数 跨页了会写入出错!!!/********************************************************************************名称: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
上一篇: 100 个必须要学会的 Linux Shell 命令
下一篇: stm32F10xx_点灯进阶