memcpy指的是C和C++使用的内存拷贝函数,函数原型为void *memcpy(void *destin, void *source, unsigned n);函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
由于Flash不支持指针写,只支持指针读,所以无法直接调用memcpy函数,需要自己实现。
例如,假设有flash地址 flash_addr = 0x11112345; 可以通过*flash_addr读出数据,但若通过*flash_addr = 123这样去赋值,则会失败。
根据Flash特性,写入新数据之前,先要擦除,即只有写入单元中的数据全为0xFF时,写入才会成功,否则,虽然写入了,但无法保证写入的数据就是我们想写入的。
但是,需要注意的是,flash擦除是按扇区擦除的,所以要想任意地址写入,那么必须保证两点:
1.要写入的地址都被擦除为0xFF
2.擦除扇区时,不在目标地址中的数据不受影响
对第2点,就需要在擦除某扇区前,将该扇区中不属于目标地址的数据保存在内存中,擦除完整个扇区后再恢复原状。
下面代码,主要是处理了一些边界
其中的Flsah_Write_String(dst,src,len)(应为Flash,厂家的代码)函数,是从内存src处写入len个字节到flash单元dst处。
uint8_t Flash_Memcpy(uint32_t dst,uint8_t* src,uint16_t Len)
{
uint8_t RamBuf[512];
uint16_t i;
uint16_t temp;
uint16_t flag = 0;
uint16_t first_sect,last_sect;
uint32_t cur_dst = dst;
uint32_t last_dst = dst+Len-1;
//如果待写入地址全部是0xFF,则直接调用flash写
for(i=0;i<Len;i++)
{
if(*(uint8_t*)(dst+i) != 0xFF)
{
flag = 1;
break;
}
}
if(flag == 0)
{
Flsah_Write_String(dst,src,Len);
return 0;
}
first_sect = dst/512; // 第一个字节所在块号
last_sect = last_dst/512; //最后一个字节所在块号
for(i=first_sect; i <= last_sect; i++)
{
memcpy(RamBuf, (void*)(i*512), 512);
Flash_Erase_Sector(i);
if(cur_dst%512!=0)
{
temp = dst-first_sect*512; //起始地址前面temp长度也被擦除了
Flsah_Write_String(first_sect*512,RamBuf,temp);
if(i == last_sect)
{
Flsah_Write_String(cur_dst,src,Len);
src += Len;
cur_dst += Len;
if(512-(temp+Len) > 0)
Flsah_Write_String(cur_dst,RamBuf+temp+Len,512-(temp+Len));
return 0;
}
Flsah_Write_String(cur_dst,src,512-temp);
src += 512 - temp;
cur_dst += 512 - temp;
}
else
{
if(last_dst-cur_dst+1 >= 512) //未写的数据大于等于512字节,则直接写512
{
Flsah_Write_String(cur_dst,src,512);
src += 512;
cur_dst += 512;
}
else
{
temp = last_dst-cur_dst+1;
Flsah_Write_String(cur_dst,src,temp);
cur_dst += temp;
Flsah_Write_String(cur_dst,RamBuf+temp,512-temp);
return 0;
}
}
}
return 0;
}