#include "hal_flash.h"
#include "hc32_ll.h"


#define HC32_FLASH_BASE 0x00
#define HC32_SECTOR_SIZE 0x2000//8kb
static uint8_t internal_flash_data[HC32_SECTOR_SIZE];//最多是2K字节

 
int32_t hc32_flash_read(uint32_t u32Addr, uint8_t *pu8Buff, uint32_t u32Len)
{
	return EFM_ReadByte(u32Addr,pu8Buff, u32Len);
}


 
int32_t hc32_flash_read_sector(uint32_t u32Addr)
{
	return EFM_ReadByte(u32Addr,internal_flash_data,sizeof(internal_flash_data));//读取一个扇区的数据/8kb
}
 

 

 
int32_t hc32_flash_write(uint32_t write_addr,uint8_t *buffer,uint32_t number)	
{
	uint32_t i;
	uint32_t sector_page = write_addr/HC32_SECTOR_SIZE;
	uint32_t secpos;	   //扇区地址
	uint32_t secoff;	   //扇区内偏移地址
	uint32_t secremain;  //扇区内剩余地址 
	uint32_t offaddr;    //去掉0X08000000后的地址
  
	offaddr = write_addr-HC32_FLASH_BASE;					//实际偏移地址.
	secpos = offaddr/HC32_SECTOR_SIZE;						//扇区地址  0~32 for HC32F448MTCI
	secoff = (offaddr%HC32_SECTOR_SIZE);					//在扇区内的偏移
	secremain = HC32_SECTOR_SIZE-secoff;					//扇区剩余空间大小   
	if(number<=secremain)secremain=number;			  //不大于该扇区范围
 
	LL_PERIPH_WE(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_EFM | LL_PERIPH_SRAM);
	EFM_FWMC_Cmd(ENABLE);
	
	while(1)
	{
		/*读取当前扇区的数据*/
		hc32_flash_read(secpos*HC32_SECTOR_SIZE+HC32_FLASH_BASE,internal_flash_data,sizeof(internal_flash_data));
		
		for(i = 0;i < HC32_SECTOR_SIZE;i++)
		{
			if(internal_flash_data[i]!=0xff)
				break;
		}

		if(i < secremain)
		{
			EFM_SingleSectorOperateCmd(sector_page, ENABLE);//解除写保护
		 
			EFM_SectorErase(secpos*HC32_SECTOR_SIZE+HC32_FLASH_BASE);
			
			for(i=0;i<secremain;i++)//复制
			{
				internal_flash_data[secoff+i]=buffer[i];	  
			}
			
			EFM_Program(secpos*HC32_SECTOR_SIZE+HC32_FLASH_BASE, internal_flash_data, sizeof(internal_flash_data));
			EFM_SingleSectorOperateCmd(sector_page, DISABLE);
			
		}
		else 
		{
			EFM_SingleSectorOperateCmd(sector_page, ENABLE);//解除写保护
			EFM_Program(write_addr,buffer,secremain);
			EFM_SingleSectorOperateCmd(sector_page, DISABLE);
		}
		if(number==secremain)	break; //写入完成
		else
		{
			secpos++;							//扇区地址增1
			secoff=0;							//偏移位置为0 	 
		  buffer+=secremain;  	//指针偏移
			write_addr+=secremain;//写地址偏移	   
		  number-=secremain;		//字节(16位)数递减
			if(number>(HC32_SECTOR_SIZE)) 
				secremain=HC32_SECTOR_SIZE;//下一个扇区还是写不完
			else 
				secremain=number;//下一个扇区可以写完了
		}
  }
	 
	
	EFM_FWMC_Cmd(DISABLE);
	LL_PERIPH_WP(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_EFM | LL_PERIPH_SRAM);
}



 
