📄 flashfile.c
字号:
//获取文件所属芯片
chip = DBX_flash_tag->chip;
//读出文件的目录项
__DFFSD_read_FDT_item(DBX_flash_tag,(uint32_t)fp->file_medium_tag,&FDT_item);
//从目录项中取文件首块块号
loop = __pick_little_32bit(FDT_item.fstart_dson,0);
do
{
next_block = loop;
loop = DBX_flash_tag->DDR_MAT[next_block].next;
}while(loop != next_block);
return next_block;
}
//----获取文件访问信息---------------------------------------------------------
//功能: 提取用于访问文件所需的位置信息,包括读位置块号,写位置块号,文件占用块
// 数,以及文件最后一块的块号。
//参数: DBX_flash_tag,被操作的flash文件柜的存储媒体标签
// fp,文件指针,调用方需确保是文件而不是目录
// access_tag,用于返回结果的指针
//返回: 在access_tag中返回各种参数
//----------------------------------------------------------------------------
void __DFFSD_get_access_info(struct st_DBX_flash_tag *DBX_flash_tag,
struct file_rsc *fp,
struct file_access_tag *access_tag)
{
uint32_t block,next_block,r_block,w_block,blocks=0;
struct flash_chip *chip;
struct fdt_info FDT_item;
//获取文件所属芯片
chip = DBX_flash_tag->chip;
r_block = fp->read_ptr / chip->block_size;
w_block = fp->write_ptr / chip->block_size;
//读出文件的目录项
__DFFSD_read_FDT_item(DBX_flash_tag,(uint32_t)fp->file_medium_tag,&FDT_item);
//从目录项中取文件首块块号
next_block = __pick_little_32bit(FDT_item.fstart_dson,0);
//读文件真实尺寸,为防止符号扩展导致不必要的麻烦,按无符号数移位。
//true_size只反映flash中的数据,不包括写缓冲区中的数据
access_tag->true_size = __pick_little_32bit(FDT_item.file_size,0)
+((uint64_t)__pick_little_32bit(FDT_item.file_size,1)<<32);
do
{
block = next_block;
if(blocks == r_block)
access_tag->read_block_no = block;
if(blocks == w_block)
access_tag->write_block_no = block;
blocks++;
next_block = DBX_flash_tag->DDR_MAT[next_block].next;
}while(block != next_block);
access_tag->last_block_no = block;
return ;
}
//----写操作后同步文件缓冲区---------------------------------------------------
//功能: 执行文件写操作之后,调用本函数同步缓冲区。
//参数: DBX_flash_tag,被操作的flash文件柜的存储媒体标签
// fp,目标文件指针
// write_len,实际写入长度
//返回: true=成功,false=有错误
//-----------------------------------------------------------------------------
bool_t __DFFSD_sync_buf_after_write(struct st_DBX_flash_tag *DBX_flash_tag,
djyfs_file *fp,uint32_t write_len)
{
switch(fp->open_mode)
{
case enum_r_rb: //只读文件,无需操作
{
}break;
case enum_w_wb: //只写文件,无需操作
{
}break;
case enum_a_ab: //只写文件,无需操作
{
}break;
case enum_r_rb_plus: //读写位置相同,若读缓冲区有数据,删掉write_len长度
case enum_w_wb_plus: //的数据量。
{
ring_dumb_read(fp->p_read_buf,write_len);
}break;
case enum_a_ab_plus: //读写位置可以不同,读前调用__sync_buf_before_read
{ //函数已经保证写缓冲区不会与读缓冲区冲突,新写入的
//数据肯定不会覆盖读缓冲区中原有数据,故无需处理。
}break;
default:break;
}
return true;
}
//----改写一块:覆盖数据--------------------------------------------------------
//功能: 把芯片块缓冲区的内容写入flash中某块,覆盖被写入的位置的原有数据,如果
// 在写入时遇到坏块,申请一个新块替换之,并把坏块登记到MAT表中(并不把MAT写
// 入到flash中),返回替换后的块号。写入前,先看看是否需要擦除,如果需要擦除
// 则要看该块是否已经在busy[8]区,如是,还要用"释放-重新申请-擦写"的过程进
// 行块替换。待写入的数据是块缓冲区从offset开始的size个字节。
//参数: DBX_flash_tag,被操作的flash文件柜的存储媒体标签
// block_no,目标块号
// offset,起始地址在块内的偏移量
// size,写入缓冲区长度
//返回: 写入成功则返回实际写入的块号,
// 写入失败返回cn_limit_uint32,空间不足或者连续遇到10个坏块会导致失败
//-----------------------------------------------------------------------------
uint32_t __DFFSD_write_update_block(struct st_DBX_flash_tag *DBX_flash_tag,
uint32_t block_no,uint32_t offset,uint32_t size)
{
uint32_t fail_counter; //如果连续分配10块均不能正确写入,则返回
uint32_t write_result,result_block,DBX_start_block;
struct flash_chip *chip = DBX_flash_tag->chip;
uint8_t *buf;
bool_t block_ready,write_success;
buf = chip->block_buf;
DBX_start_block = DBX_flash_tag->start_block;
fail_counter = 0;
result_block = block_no;
if(DBX_flash_tag->nand_ecc)
block_ready = chip->query_block_ready_with_ecc(
result_block+DBX_start_block,
offset,buf+offset,size);
else
block_ready = chip->query_block_ready_no_ecc(
result_block+DBX_start_block,
offset,buf+offset,size);
if(offset != 0)
//把目标块的数据读到块缓冲区中,先读offset以前的部分
chip->read_data_with_ecc(block_no+DBX_start_block,
0,buf,offset);
if(offset+size != chip->block_size)
//再读有效部分以后的部分
chip->read_data_with_ecc(block_no+DBX_start_block,
offset+size,buf+offset+size,
chip->block_size-offset-size);
//把数据写入到掉电恢复块,
chip->write_PCRB(DBX_flash_tag->PCRB_no+DBX_start_block,
block_no + DBX_start_block,buf);
do //因写入过程可能产生坏块,故需要用循环,直到正确写入才退出
{
if((fail_counter == 0) && (block_ready)) //无需擦除的情况
{
write_result = chip->write_data_with_ecc(
result_block + DBX_start_block,
offset,buf+offset,size);
if(write_result == size)
write_success = true;
else
write_success = false;
}else //需要擦除的情况
{
chip->erase_block(result_block+DBX_start_block);//擦除块
//写入目标块,整块写入
write_result = chip->write_data_with_ecc(
result_block + DBX_start_block,
0,buf,chip->block_size);
if(write_result == chip->block_size)
{
//磨损次数增量
__DFFSD_inc_abrasion_times(DBX_flash_tag,result_block);
write_success = true;
}else
write_success = false;
}
if(!write_success) //写入失败,坏块
{
fail_counter++; //写入失败次数增量
//登记坏块到磨损表
__DFFSD_register_invalid(DBX_flash_tag,result_block);
//分配新块,必须使用简易分配法,否则容易造成连环套
result_block = __DFFSD_allocate_block_simple(DBX_flash_tag);
//注意,掉电恢复块的目标块号无需修改,因为此时MAT表以及可能需要修改
//的FDT还没有改变。
if(result_block == cn_limit_uint32) //分配失败(无空闲块)
{
return cn_limit_uint32; //返回错误
}
}else //成功写入
{
break;
}
}while(fail_counter <= 10); //以连续遇到10个坏块为异常退出条件
if(fail_counter > 10) //因10次坏块而结束do-while循环
return cn_limit_uint32;
else //数据已经正确写入
return result_block;
}
//----改写一块:添加数据--------------------------------------------------------
//功能: 把芯片块缓冲区的内容写入flash中某块,被写入的位置原来没有有效数据,如果
// 在写入时遇到坏块,申请一个新块替换之,并把坏块登记到MAT表中(并不把MAT写
// 入到flash中),返回替换后的块号。写入前,先看看是否需要擦除,如果需要擦除
// 则要看该块是否已经在busy[8]区,如是,还要用"释放-重新申请-擦写"的过程进
// 行块替换。待写入的数据是块缓冲区从offset开始的size个字节。
//参数: DBX_flash_tag,被操作的flash文件柜的存储媒体标签
// block_no,目标块号
// offset,起始地址在块内的偏移量
// size,写入缓冲区长度
//返回: 写入成功则返回实际写入的块号,
// 写入失败返回cn_limit_uint32,空间不足或者连续遇到10个坏块会导致失败
//-----------------------------------------------------------------------------
uint32_t __DFFSD_write_append_block(struct st_DBX_flash_tag *DBX_flash_tag,
uint32_t block_no,uint32_t offset,uint32_t size)
{
uint32_t fail_counter; //如果连续分配10块均不能正确写入,则返回
uint32_t write_result,result_block,DBX_start_block;
struct flash_chip *chip = DBX_flash_tag->chip;
uint8_t *buf;
bool_t block_ready,PCRB_writed=false,write_success;
buf = chip->block_buf;
DBX_start_block = DBX_flash_tag->start_block;
fail_counter = 0;
result_block = block_no;
if(DBX_flash_tag->nand_ecc)
block_ready = chip->query_block_ready_with_ecc(
result_block+DBX_start_block,
offset,buf+offset,size);
else
block_ready = chip->query_block_ready_no_ecc(
result_block+DBX_start_block,
offset,buf+offset,size);
do //因写入过程可能产生坏块,故需要用循环,直到正确写入才退出
{
if((fail_counter == 0) && (block_ready))
{
write_result = chip->write_data_with_ecc(
result_block + DBX_start_block,
offset,buf+offset,size);
if(write_result == size)
write_success = true;
else
write_success = false;
}else
{
if(!PCRB_writed)
{
if(offset != 0)
//把目标块的数据读到块缓冲区中,先读offset以前的部分
chip->read_data_with_ecc(block_no+DBX_start_block,
0,buf,offset);
if(offset+size != chip->block_size)
//再读有效部分以后的部分
chip->read_data_with_ecc(block_no+DBX_start_block,
offset+size,buf+offset+size,
chip->block_size-offset-size);
//把数据写入到掉电恢复块,
chip->write_PCRB(DBX_flash_tag->PCRB_no+DBX_start_block,
block_no + DBX_start_block,buf);
PCRB_writed = true;
}
chip->erase_block(result_block+DBX_start_block);
//写入目标块,整块写入
write_result = chip->write_data_with_ecc(
result_block + DBX_start_block,
0,buf,chip->block_size);
if(write_result == chip->block_size)
{
//磨损次数增量
__DFFSD_inc_abrasion_times(DBX_flash_tag,result_block);
write_success = true;
}else
write_success = false;
}
if(!write_success) //写入失败,坏块
{
fail_counter++; //写入失败次数增量
//登记坏块到磨损表
__DFFSD_register_invalid(DBX_flash_tag,result_block);
//分配新块,必须使用简易分配法,否则容易造成连环套
result_block = __DFFSD_allocate_block_simple(DBX_flash_tag);
//注意,掉电恢复块的目标块号无需修改,因为此时MAT表以及可能需要修改
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -