在单片机flash上实现内存拷贝函数 Flash_Memcpy

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;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值