📄 sst39vf1601.c
字号:
/****************************************************************************
* 文件名:SST39VF1601.C
* 功能:对SST39VF1601进行控制
* 说明:对flash读、写、擦除,并实现文件管理
****************************************************************************/
#include "config.h"
// FLASH的起始地址(分配为Bank1块)
uint8 Date[8];
uint8 Set_Date[8]={0x15,0x58,0x23,0x20,0x08,0x08,0x01,0x20};
//日期BCD码格式----秒---分---时---日---月---年---星期---年
uint8 IP[4]={192,168,1,2};
uint8 size;
uint8 X1226_Setb=1;
uint16 dat;
void Gettime(void)
{
IRcvStr(X1226_CCR|read,0x0030,2,Date,8);
if(Date[5]>=0x80)
{
Date[5]-=0x80;
}
}
/****************************************************************************
* 名称:DelayNS()
* 功能:长软件延时。
* 入口参数:dly 延时参数,值越大,延时越久
* 出口参数:无
****************************************************************************/
void DelayNS(uint32 dly)
{ uint32 i;
for(; dly>0; dly--)
for(i=0; i<5000; i++);
}
/****************************************************************************
* 名称:WordRead()
* 功能:半字(16位)数据读。
* 入口参数:Addr 回读地址(SST39VF1601内部地址)
*
* 出口参数:返回Addr地址16位数据
****************************************************************************/
uint16 WordRead(uint32 Addr)
{
volatile uint16 *ip;
uint16 temp1,temp2;
if(Addr>MaxAddr)
return FALSE;
ip = GetAddr(Addr);
while(1)
{
temp1 = *ip;
temp2 = *ip;
if (temp1 == temp2)
{
return temp1;
}
}
}
/****************************************************************************
* 名称:WordProgram()
* 功能:半字(16位)数据编程。
* 入口参数:Addr 编程地址(SST39VF1601内部地址) 000000H-0FFFFFH Byte
* Data 编程数据
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
****************************************************************************/
uint8 WordProgram(uint32 Addr, uint16 Data)
{
volatile uint16 *ip;
uint16 temp1,temp2;
if(Addr>MaxAddr)
return FALSE;
//for test
/*
if(Addr==481*2*1024+7||Addr==481*2*1024+15)//Addr地址坏
{
return(FALSE);
}
if(Addr==496*2*1024+5||Addr==496*2*1024+15)//Addr地址坏
{
return(FALSE);
}
*/
ip = GetAddr(0x5555);// 转换地址0x5555
*ip = 0xaa; // 第一个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第二个写周期,地址0x2aaa,数据0x55
ip = GetAddr(0x5555);
*ip = 0xa0; // 第三个写周期,地址0x5555,数据0xA0
ip = (volatile uint16 *)(FLASH_ADDR|((Addr<<1)&0x1FFFFF));
*ip = Data; // 第四个写周期,地址Addr,数据Data
while (1) // 等待操作完成 (若编程操作没有完成,每次读操作DQ6会跳变)
{ temp1 = *ip;
temp2 = *ip;
if (temp1 == temp2)
{ if (temp1 != Data)
{
return(FALSE);
}
else
{
return(TRUE);
}
}
}
return(TRUE);
}
/****************************************************************************
* 名称:SectorErase()
* 功能:芯片扇区擦除。
* 入口参数:扇区0-511
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
****************************************************************************/
uint8 SectorErase(uint32 sector_index)
{
volatile uint16 *ip;
uint16 temp1,temp2;
if(sector_index>(MaxAddr/1024/2))
return FALSE;
ip = GetAddr(0x5555);
*ip = 0xaa; // 第一个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第二个写周期,地址0x2aaa,数据0x55
ip = GetAddr(0x5555);
*ip = 0x80; // 第三个写周期,地址0x5555,数据0x80
ip = GetAddr(0x5555);
*ip = 0xaa; // 第四个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第五个写周期,地址0x2aaa,数据0x55
ip = (uint16 *)(FLASH_ADDR|sector_index<<12);
*ip = 0x30; // 第六个写周期,扇区地址,数据0x30
while (1) // 等待操作完成 (若擦除操作没有完成,每次读操作DQ6会跳变)
{ temp1 = *ip;
temp2 = *ip;
if (temp1 == temp2)
{ if (temp1 != 0xffff)
{ return(FALSE);
}
else
{ return(TRUE);
}
}
}
return(TRUE);
}
/****************************************************************************
* 名称:BlockErase()
* 功能:芯片块擦除。
* 入口参数:块0-31
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
****************************************************************************/
uint8 BlockErase(uint8 block_index)
{
volatile uint16 *ip;
uint16 temp1,temp2;
if(block_index>(MaxAddr/1024/32))
return FALSE;
ip = GetAddr(0x5555);
*ip = 0xaa; // 第一个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第二个写周期,地址0x2aaa,数据0x55
ip = GetAddr(0x5555);
*ip = 0x80; // 第三个写周期,地址0x5555,数据0x80
ip = GetAddr(0x5555);
*ip = 0xaa; // 第四个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第五个写周期,地址0x2aaa,数据0x55
ip = (uint16 *)(FLASH_ADDR|block_index<<16);
*ip = 0x50; // 第六个写周期,块地址,数据0x30
while (1) // 等待操作完成 (若擦除操作没有完成,每次读操作DQ6会跳变)
{ temp1 = *ip;
temp2 = *ip;
if (temp1 == temp2)
{ if (temp1 != 0xffff)
{ return(FALSE);
}
else
{ return(TRUE);
}
}
}
return(TRUE);
}
/****************************************************************************
* 名称:ChipErase()
* 功能:芯片全片擦除。
* 入口参数:无
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
****************************************************************************/
uint8 ChipErase(void)
{
volatile uint16 *ip;
uint16 temp1,temp2;
ip = GetAddr(0x5555);
*ip = 0xaa; // 第一个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第二个写周期,地址0x2aaa,数据0x55
ip = GetAddr(0x5555);
*ip = 0x80; // 第三个写周期,地址0x5555,数据0x80
ip = GetAddr(0x5555);
*ip = 0xaa; // 第四个写周期,地址0x5555,数据0xAA
ip = GetAddr(0x2aaa);
*ip = 0x55; // 第五个写周期,地址0x2aaa,数据0x55
ip = GetAddr(0x5555);
*ip = 0x10; // 第六个写周期,地址0x5555,数据0x10
while (1) // 等待操作完成 (若擦除操作没有完成,每次读操作DQ6会跳变)
{ temp1 = *ip;
temp2 = *ip;
if (temp1 == temp2)
{ if (temp1 != 0xffff)
{ return(FALSE);
}
else
{ return(TRUE);
}
}
}
return(TRUE);
}
/****************************************************************************
* 名称:Ram_Flash_Copy()
* 功能:从ram中拷贝size个数据到flash
****************************************************************************/
/*
uint8 Ram_Flash_Copy( uint8* ram_ptr,uint16* flash_ptr, uint32 size )
{
uint32 cnt;
uint16 dat=0;
if( ( size % 2 ==1)) // size should be even
size++;
for(cnt =0 ;cnt< (size/2) ;cnt++)
{
dat = *ram_ptr++; // low byte
dat = dat + (*ram_ptr++)* 256;// high byte
WordProgram( flash_ptr ,dat);
flash_ptr++ ;
}
return 1;
}
*/
/****************************************************************************
* 名称:Create_log()
* 功能:创建一个日志
****************************************************************************/
uint8 Create_log(uint16 *array,uint8 len)
{
uint16 *p,
total_log=0,//日志总数
log_len=0;//待创建日志长度
uint32 w_addr,
index_start_address=0,//目录起始地址
old_index_start_address=0,//写出错时目录起始地址备份
index_address=0,//待创建日志目录地址
log_address=0;//待创建日志存储地址
uint16 i=0;
//查找目录起始地址和带创建日志存储地址
total_log=WordRead(480*2*1024);//第480 sector第一个Word为总日志数
if(total_log>Max_log)
{
total_log=0;
BlockErase(30);
BlockErase(31);
}
if(!total_log)
{
index_start_address=Log_index_Init_Addr;//目录起始地址为初始地址
log_address=Log_Init_Addr;//日志存储地址为初始地址
}
else
{
index_start_address=((uint32)WordRead(480*2*1024+1)<<16)+WordRead(480*2*1024+2);//读目录起始地址
if(index_start_address+(total_log-1)*3<496*2*1024-2)//查找最新日志存储地址
{
log_address=((uint32)WordRead(index_start_address+(total_log-1)*3)<<16)
+WordRead(index_start_address+1+(total_log-1)*3)
+WordRead(index_start_address+2+(total_log-1)*3);
}
else if(index_start_address+(total_log-1)*3==496*2*1024-2)
{
log_address=((uint32)WordRead(496*2*1024-2)<<16)
+WordRead(496*2*1024-1)
+WordRead(481*2*1024);
}
else if(index_start_address+(total_log-1)*3==496*2*1024-1)
{
log_address=((uint32)WordRead(496*2*1024-1)<<16)
+WordRead(491*2*1024)
+WordRead(481*2*1024+1);
}
else
{
log_address=((uint32)WordRead(index_start_address+(total_log-1)*3-(496-481)*2*1024)<<16)
+WordRead(index_start_address+1+(total_log-1)*3-(496-481)*2*1024)
+WordRead(index_start_address+2+(total_log-1)*3-(496-481)*2*1024);
}
if(log_address>512*2*1024-1)
{
log_address=Log_Init_Addr+(log_address-512*2*1024);
}
}
//将最新日志存储(496-511 sector),若遇到坏地址,跳过并将日志重新写入
if(len%2)
log_len=(len+1)/2;
else
log_len=len/2;
p=array;
w_addr=log_address;
for(i=0;i<log_len;)
{
if(!WordProgram(w_addr, *p))
{
w_addr++;
if(!(w_addr%(2*1024)))
{
if((w_addr/(2*1024))<512)
{
SectorErase(w_addr/(2*1024));
}
else
{
SectorErase(496);
w_addr=496*2*1024;
}
}
p=array;
i=0;
log_address=w_addr;
}
else
{
w_addr++;
if(!(w_addr%(2*1024)))
{
if((w_addr/(2*1024))<512)
{
SectorErase(w_addr/(2*1024));
}
else
{
SectorErase(496);
w_addr=496*2*1024;
}
}
p++;
i++;
}
}
//更新最新日志目录(481-495 sector),若遇到坏地址,将所有日志目录复制到连续空间
index_address=index_start_address+total_log*3;
if(index_address>496*2*1024-1)
{
index_address-=15*2*1024;
if(!(index_address%(2*1024)))
{
if((index_address/(2*1024))<496)
{
SectorErase(index_address/(2*1024));
}
else
{
SectorErase(481);
index_address=481*2*1024;
}
}
}
L1: if(!WordProgram(index_address,log_address>>16))//1.写新日志存储地址高16位到日志目录
{
old_index_start_address=index_start_address;
L2: if(!(++index_address%(2*1024)))
{
if((index_address/(2*1024))<496)
{
SectorErase(index_address/(2*1024));
}
else
{
SectorErase(481);
index_address=481*2*1024;
}
}
index_start_address=index_address;
for(i=0;i<total_log*3;i++)//将旧日志目录拷贝至好地址开始的连续空间
{
if(index_address==old_index_start_address)
{
return Flash_log_ERROR;//返回Flash_log_ERROR指示该flash日志不能使用
}
if(old_index_start_address+i<496*2*1024)
{
if(!WordProgram(index_address,WordRead(old_index_start_address+i)))
{
if(!(++index_address%(2*1024)))
{
if((index_address/(2*1024))<496)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -