sst25vf016b是以块2Mbyte大小的存储芯片总共分为啦512块,每块4K,来进行管理,
首先介绍全局变量:
unsigned char Flag_Key12=0;
标志是否为最后一块
unsigned char Flag_Read=0;
标志读完整块flash,
unsigned int Flag_16Num=0;
写数据,读数据时的控制器
unsigned int Block_MuluNow=0;
保存当前正在操作的目录
unsigned int Table_Block[64];
每两个Bit表示一个块,每8个块压缩正一个字节,64个字节,正好对应512个块,每个块有3种状态,00空,01占用,10脏块
unsigned char Table_Block_1[8];
把一个字节展开放入此数组,查找的时候更快速
unsigned int Next_Block=0;
下一块
unsigned char block_n=1;
记录当前操作块的下一块,以此来实现擦出的轮番使用,不会应为某一块的过度擦除而导致整块flash损坏
unsigned char Name_Front=0;
记录管理的条目,本系统设置是不超过146个条目
unsigned char Name_Empty=0;
记录要删除的条目
flash管理的总体规划:
flash的存储管理就是按照实现安排的内容来进行管理的.
函数说明:
/*
功能:检查目录,开机进行
*/
unsigned char Flash_JCmulu()
{
unsigned int i=0;
unsigned char Table[2]={0,0};
unsigned long int Block_MuluAdd=0;
unsigned char Table_Block_H=0,Table_Block_L=0;
for(i=0;i<512;i++)
{
Block_MuluAdd=i<<12; //首先i进行右移12位,总是乘以4096,即4K,达到对 Read_Byte_Cont(Block_MuluAdd,Table,2); //512 块的循环
if((Table[0]==0)&&(Table[1])==0) //首先查找目录块
{
Block_MuluNow=i;
break;
}
else if(i==511) return 0;
}
Block_MuluAdd=Block_MuluNow<<12; //赋值给Block_MuluAdd,来进行保存Block_MuluNow
Name_Front=Read_Byte(Block_MuluAdd+1024);//的值
//读取64字节的Table_Block的内容
for(i=0;i<64;i++)
{
Table_Block_H=Read_Byte(Block_MuluAdd+1024+1+i);
Table_Block_L=Read_Byte(Block_MuluAdd+1024+2+i);
Table_Block[i]=(Table_Block_H<<8)|Table_Block_L;
}
//按照上表来进行读取相关内容
Read_Byte_Cont(Block_MuluAdd+1024+1+128,Table_Block_1,8);
Next_Block=Read_Byte(Block_MuluAdd+1024+1+128+8+2);
block_n=Read_Byte(Block_MuluAdd+1024+1+128+8+3);
return 1;
}
//给新的条目分配空间,同时更新目录,当然只有第一次使用时不需要更新,以后使用每次都更新目录
unsigned char Flash_AllocateSpace(unsigned char *Table_Time)
{
unsigned long int Block_MuluAdd=0;
unsigned int Block=0;
if(Name_Front!=146)
{
Block_MuluAdd=(Block_MuluNow<<12);
Block=Search_Block(); //搜寻空块
if(Block==512)return 0;
else Block_MuluNow=Block; //作为本次操作使用
Block=Search_Block(); //搜寻空块,作为下次操作使用
if(Block==512)return 0;
else Next_Block=Block;
Write_Byte(Block_MuluNow<<12,0); //标志为目录
Write_Byte((Block_MuluNow<<12)+1,0);
//向里面写入Table_Time数据,以及下一块的标号
Write_Byte_Cont((Block_MuluNow<<12)+2+Name_Front*7,Table_Time,5);
Write_Byte((Block_MuluNow<<12)+2+Name_Front*7+5,(Next_Block>>8)&&0xff);
Write_Byte((Block_MuluNow<<12)+2+Name_Front*7+6,Next_Block&0xff);
//第一次时,不需要更新,以后每次都更新目录,并且相应目录块标志为11(分配空间时标志为1,后更新目录时又和2相或,故为3)
if(Block_MuluAdd!=(Block_MuluNow<<12))
Mulu_InformationUpdate(Block_MuluAdd,WRITE);
//条目加1
Name_Front++;
//同时当前操作块表为1,占用块,此为有用数据
Table_Block[Block_MuluNow/8]|=0x0001<<((Block_MuluNow%8)*2);
//当然下一块也要更新为占用块,以免下次查找到同一块
Table_Block[Next_Block/8] |= 0x0001<<((Next_Block%8)*2);
return 1;
}
return 0;
}
void Flash_Write(unsigned char*Table,unsigned char Flag_Key12)
{
unsigned long int Next_Block_MuluAdd=0;
unsigned long int Next_BlockAdd=0;
unsigned int Block=0;
//每次写入16字节,Flag_16Num为256时,写满一个块
Next_BlockAdd=(Next_Block<<12)+16*Flag_16Num;
Write_Byte_Cont(Next_BlockAdd,Table,16);
Flag_16Num++;
//当写满一个块时,查询下一块,并写入Next_Block_MuluAdd这个地址,然后向下一空块继续写入数据
if(Flag_16Num==256)
{
Flag_16Num=0;
Next_Block_MuluAdd=(Block_MuluNow<<12)+3072+Next_Block*2;
Block=Search_Block();
if(Block==512)return;
else Next_Block=Block;
Table_Block[Next_Block/8] |=0x0001<<((Next_Block%8)*2);
Write_Byte(Next_Block_MuluAdd,(Next_Block&0xff00)>>8);
Write_Byte(Next_Block_MuluAdd+1,Next_Block&0xff);
}
//如果是向末块,即512写入,就写如512,表示用完
if(Flag_Key12)
{
if(Flag_16Num!=0)
Next_Block_MuluAdd=(Block_MuluNow<<12)+3072+Next_Block*2;
Write_Byte(Next_Block_MuluAdd,0x02);
Write_Byte(Next_Block_MuluAdd+1,0x00);
Flag_16Num=0;
}
}
//搜寻空块
unsigned int Search_Block()
{
unsigned char i=0;
unsigned char num=block_n-1; //block_n记录当前操作Table_Block字节的下一字节
//即返回操作块的标号
for(i=0;i<8;i++)
{
if(Table_Block_1[i]==0)
{
Table_Block_1[i]=3;
return num*8+i;
}
}
num=Search_Table();
for(i=0;i<8;i++)
{
if(Table_Block_1[i]==0)
{
Table_Block_1[i]=3;
return num*8+i;
}
}
return 512;
}
//搜寻Table_Block中的空块,并展开到Table_Block_1
unsigned int Search_Table()
{
unsigned char num=0;
unsigned char i=0;
unsigned char Flag_0=0;
for(num=block_n;num<64;num++)
{
for(i=0;i<8;i++)
{
Table_Block_1[i]=(Table_Block[num]>>(i*2))&0x0003;
if(Table_Block_1[i]==0) Flag_0=1; //只要有一个空块,Flag_0就为1
}
if(Flag_0==1)
{
block_n=num+1; //操作block_n指向下一要操作的8个块,即
if(block_n==64)block_n=0; //Table_Block对应的下一字节
return num;
}
}
for(num=0;num<block_n;num++)
{
for(i=0;i<8;i++)
{
Table_Block_1[i]=(Table_Block[num]>>(i*2))&0x0003;
if(Table_Block_1[i]==0) Flag_0=1;
}
if(Flag_0==1)
{
block_n=num+1;
if(block_n==64)block_n=0;
return num;
}
}
return 64;
}
//擦除空块
void Flash_DirtyBlock()
{
unsigned int i=0;
unsigned char num=0;
for(num=0;num<64;num++)
{
for(i=0;i<8;i++)
{
if(2==((Table_Block[num]>>(i*2))&0x0003))
{
Block_Erase_4K((num*8+i)<<12);
Table_Block[(num*8+i)/8]&=0xfffc<<(((num*8+i)%8)*2);
}
}
}
}
//把全局变量更新到目录中,
void Process_TableBlock()
{
unsigned char i;
Write_Byte((Block_MuluNow<<12)+1024,Name_Front);
for(i=0;i<64;i++)
{
Write_Byte((Block_MuluNow<<12)+1024+1+i,(Table_Block[i]>>8)&0xff);
}
for(i=0;i<64;i++)
{
Write_Byte((Block_MuluNow<<12)+1024+1+64+i,(Table_Block[i]>>8)&0xff);
}
Write_Byte_Cont((Block_MuluNow<<12)+1024+1+128,Table_Block_1,8);
Write_Byte((Block_MuluNow<<12)+1024+1+128+8,Block_MuluNow);
Write_Byte((Block_MuluNow<<12)+1024+1+128+8+1,Next_Block);
Write_Byte((Block_MuluNow<<12)+1024+1+128+8+2,block_n);
}
//目录更新
//WRITE:把Name_Front中的条目直接复制即可
READ:把Name_Empty记录的条目删除
void Mulu_InformationUpdate(unsigned long int Block_MuluAdd,unsigned char Flag_Write_Read)
{
unsigned char num=0;
unsigned char i=0;
unsigned char SST_Read[7]={0};
if(Flag_Write_Read==WRITE)
{
for(i=0;i<Name_Front;i++)
{
Read_Byte_Cont(Block_MuluAdd+2+i*7,SST_Read,7);
Write_Byte_Cont((Block_MuluNow<<12)+2+i*7,SST_Read,7);
}
}
else if(Flag_Write_Read==READ)
{
for(i=0;i<Name_Front;i++)
{
if(i<Name_Empty)
{
Read_Byte_Cont(Block_MuluAdd+2+i*7,SST_Read,7);
Write_Byte_Cont((Block_MuluNow<<12)+2+i*7,SST_Read,7);
}
else if(i>Name_Empty)
{
Read_Byte_Cont(Block_MuluAdd+2+i*7,SST_Read,7);
Write_Byte_Cont((Block_MuluNow<<12)+2+(i-1)*7,SST_Read,7);
}
}
Name_Front--;
}
for(num=0;num<64;num++)
{
for(i=0;i<8;i++)
{
if(1==(Table_Block[i]>>(i*2))&0x0003)
{
Read_Byte_Cont(Block_MuluAdd+3072+(num*8+i)*2,SST_Read,2);
Write_Byte_Cont((Block_MuluNow<<12)+3072+(num*8+i)*2,SST_Read,2);
}
}
}
//擦出原来的目录,并置位脏块
Block_Erase_4K(Block_MuluAdd);
Table_Block[(Block_MuluAdd>>12)/8]|=0x0002<<(((Block_MuluAdd>>12)%8)*2);
}
经过验证可以使用..
并且读取依靠的是链表,当存储的数据大于一个块时,每个块的末尾存储着下一块的号码,可以继续读写.