nor flash 擦除都是一整块的,你看现的flash都有均衡算法,楼主我自己设计的板子上外挂了一个spi的norflash,内部操作大同小异,可以实现任意地位置写数据,不影响其他的数据。代码如下,供参考
int w25qxxwrite(uint8_t * buff , uint32_t writeAddr , uint16_t count)
{
/*
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
*/
/*
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
*/
uint8_t w25qxxbuff[4096]; //一个块的数据缓存
uint32_t sectorpos = writeAddr/4096; //计算sector地址
uint16_t secotroff = writeAddr%4096; //计算sector偏移地址
//下面先计算写入的数量占用了多个个sector
uint32_t sectormain = secotroff + count ;
uint16_t sectorcount= sectormain / 4096; //sector整数量
uint16_t sectorwoff = sectormain % 4096; //sector余数数量
stc_qspi_comm_protocol_t stcQspiCommProtocol;
MEM_ZERO_STRUCT(stcQspiCommProtocol);
//先判断sector地址是否刚好等于falsh的sector开始地址
if(secotroff == 0) //这表示刚好等于falsh sector的开始地址
{
uint8_t eraseflashsector = 0 ;
for(uint16_t i = 0 ; i < sectorcount ; i += 1)
{
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 + i * 4096,4096); //读取整个sector
for(uint16_t j = 0 ; j < 4096 ; j += 1)
{
if(w25qxxbuff[j] != 0xff) //该sector需要擦除
{
eraseflashsector = 1 ;
break;
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
if(eraseflashsector) QspiFlash_Erase4KbSector(sectorpos * 4096 + i * 4096 ); //擦除整个secotr
for(uint8_t k = 0 ; k < 16 ; k += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + i * 4096 + k * 256 ,buff,256); //这里的buff要随着写入数据的偏移而偏移
buff += 256;
}
}
if(sectorwoff != 0 ) //整个sector操作结束后,要判断有没有下一个sector要操作还不是整个sector
{
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 + sectorcount * 4096,4096); //读取整个sector
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
QspiFlash_Erase4KbSector(sectorpos * 4096 + sectorcount * 4096); //擦除整个secotr
//下面修改数据
for(uint16_t i = 0 ; i < sectorwoff ; i += 1)
{
w25qxxbuff[i] = *(buff++);
}
//下面把修改好的数据分16次写入flash
for(uint8_t i = 0 ; i < 16 ; i += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + sectorcount * 4096 + i * 256 ,w25qxxbuff + i * 256,256); //这里的w25qxxbuff要随着写入数据的偏移而偏移
}
}
}
else //这是地址位置不是在sector的头地址
{
if(sectorcount == 0 || (sectorcount == 1 && sectorwoff == 0)) //只有一个secotr时的操作
{
uint8_t eraseflashsector = 0 ;
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 ,4096); //读取整个sector
for(uint16_t j = 0 ; j < 4096 ; j += 1)
{
if(w25qxxbuff[j] != 0xff) //该sector需要擦除
{
eraseflashsector = 1 ;
break;
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
if(eraseflashsector) QspiFlash_Erase4KbSector(sectorpos * 4096); //擦除整个secotr
//下面修改数据
for(uint16_t j = secotroff ; j < sectormain ; j += 1)
{
w25qxxbuff[j] = *(buff++);
}
//下面把修改好的数据分16次写入flash
for(uint8_t j = 0 ; j < 16 ; j += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + j * 256 ,w25qxxbuff + j * 256,256); //这里的w25qxxbuff要随着写入数据的偏移而偏移
}
}
else //这是不止一个sector的时候处理
{
//下面操作第一个sector
uint8_t eraseflashsector = 0 ;
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 ,4096); //读取整个sector
for(uint16_t j = 0 ; j < 4096 ; j += 1)
{
if(w25qxxbuff[j] != 0xff) //该sector需要擦除
{
eraseflashsector = 1 ;
break;
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
if(eraseflashsector) QspiFlash_Erase4KbSector(sectorpos * 4096); //擦除整个secotr
//下面修改数据
for(uint16_t j = secotroff ; j < 4096 ; j += 1)
{
w25qxxbuff[j] = *(buff++);
}
//下面把修改好的数据分16次写入flash
for(uint8_t j = 0 ; j < 16 ; j += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + j * 256 ,w25qxxbuff + j * 256,256); //这里的w25qxxbuff要随着写入数据的偏移而偏移
}
//下面处理后面的sector
for(uint16_t i = 1 ; i < sectorcount ; i += 1)
{
//下面操作sector
eraseflashsector = 0 ;
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 + i * 4096,4096); //读取整个sector
for(uint16_t j = 0 ; j < 4096 ; j += 1)
{
if(w25qxxbuff[j] != 0xff) //该sector需要擦除
{
eraseflashsector = 1 ;
break;
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
if(eraseflashsector) QspiFlash_Erase4KbSector(sectorpos * 4096 + i * 4096); //擦除整个secotr
for(uint8_t j = 0 ; j < 16 ; j += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + i * 4096 + j * 256 ,buff,256); //这里的w25qxxbuff要随着写入数据的偏移而偏移
buff += 256;
}
}
//处理剩余的数据
if(sectorwoff != 0)
{
eraseflashsector = 0 ;
//先回到读取模式,这里的目的是判断sector是否要擦除
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
flashnoreading = 0 ; //读取模式
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
w25qxxread(w25qxxbuff,sectorpos * 4096 + sectorcount * 4096 ,4096); //读取整个sector
for(uint16_t j = 0 ; j < 4096 ; j += 1)
{
if(w25qxxbuff[j] != 0xff) //该sector需要擦除
{
eraseflashsector = 1 ;
break;
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
flashnoreading = 1 ; //flash 禁止读取
QSPI_CommProtocolConfig(&stcQspiCommProtocol); //切换为写falsh模式,禁止读取
if(eraseflashsector) QspiFlash_Erase4KbSector(sectorpos * 4096 + sectorcount * 4096); //擦除整个secotr
//下面修改数据
for(uint16_t j = 0 ; j < sectorwoff ; j += 1)
{
w25qxxbuff[j] = *(buff++);
}
//下面把修改好的数据分16次写入flash
for(uint8_t j = 0 ; j < 16 ; j += 1) //分16次写入数据,因为qspi flash 一次只能写入256个数据;
{
QspiFlash_WritePage(sectorpos * 4096 + sectorcount * 4096 + j * 256 ,w25qxxbuff + j * 256,256); //这里的w25qxxbuff要随着写入数据的偏移而偏移
}
}
}
}
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresOutput;
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
flashnoreading = 0 ; //这里重新回到读取模式
return 0 ;
}
|