📄 samsung_nand.c
字号:
*pg_nand_address = (uint8_t)(address >> 9); // A9 ~ A16
*pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
address_end(); //完成写入地址
__wait_ready_2808( ); //等待芯片内部操作完成
for(loop=0; loop < read_size; loop++)
{
data = *pg_nand_address; //读取数据
if((data | buf[completed]) != buf[completed]) //查看有否0->1的位
{
ce_inactive(); //关闭片选
return false; //有0->1的位,返回需要擦除
}
completed++;
}
ce_inactive(); //关闭片选
address += read_size;
start_offset = 0; //从第二个扇区开始,肯定从0开始读
}
return true;
}
//----查询是否需要擦除(buf)-----------------------------------------------
//功能: flash中的原来的内容在org_data中,如果要改成如new_data中的数据,查看是否
// 需要擦除。
//参数: new_data,新数据缓冲区
// new_data,数据缓冲区
// size,数据尺寸
//返回: flase = 需要擦除,true = 已准备好,不需要擦除
//-----------------------------------------------------------------------------
bool_t query_ready_with_data_2808(uint8_t *new_data,uint8_t *org_data,
uint32_t size)
{
uint32_t loop;
if(org_data == NULL)
return false;
if(new_data != NULL)
{
for(loop = 0; loop < size; loop++)
{
if((org_data[loop] | new_data[loop]) != org_data[loop])
return false; //如果存在由0改1的数据,返回false
}
}else
{
for(loop = 0; loop < size; loop++)
{
if(org_data[loop] != 0xFF)
return false;
}
}
return true;
}
//坏块标记算法:
//1、三星出厂时,坏块OOB的头两页第6个字节被写入非0xFF数据,好块则保证是0xFF。
//2、使用过程中的新增坏块,也在头两页的第6字节写入0.
//3、永远不要擦除坏块,否则用于坏块标记的第6字节也被擦除。
//----有效块检查--------------------------------------------------------------
//功能: 检查一个块是否有效块,参考坏块标记算法。
//参数: block_no,块号
//返回: true=好块,false=坏块。
//----------------------------------------------------------------------------
bool_t check_block_2808(uint32_t block_no)
{
uint16_t j;
uint32_t address;
uint8_t data;
ce_active();
for(j=0; j<2; j++)
{
address = tg_samsung_nand.block_size * block_no + 0x200 * j + 517;
__write_command_2808(cn_2808_select_oob);
address_start();
*pg_nand_address = (uint8_t)address; // A0 ~ A7
*pg_nand_address = (uint8_t)(address >> 9); // A9 ~ A16
*pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
address_end();
__wait_ready_2808( ); //等待芯片内部操作完成
data = *pg_nand_address;
if(data != 0xFF)
{
ce_inactive();
return false;
}
}
ce_inactive();
return true;
}
//----标记一个坏块-----------------------------------------------------------
//功能:在读、写、擦除等函数中调用,如果操作过程中发现某块是坏块,立即调用本函数
// 把它标记为坏块,即把首扇区的第517字节写0.
//参数: block_no,块号
//返回: true=成功标记,false=标记失败。
//----------------------------------------------------------------------------
bool_t __mark_invalid_block(uint32_t block)
{
uint16_t j,k;
uint32_t address;
__write_command_2808(cn_2808_select_oob);
for(j=0; j<2; j++)
{
ce_active();
__write_command_2808(cn_2808_page_program);
address_start();
address = tg_samsung_nand.block_size * block + 0x200 * j + 517;
*pg_nand_address = (uint8_t)address; // A0 ~ A7
*pg_nand_address = (uint8_t)(address >> 9); // A9 ~ A16
*pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
address_end();
__wait_ready_2808( ); //等待芯片内部操作完成
for(k = 0; k< 16;k++)
*pg_nand_address = k;
// *pg_nand_address = 0x00;
__write_command_2808(cn_2808_startup_write);
__wait_ready_2808_slow(cn_wait_page_write); //等待芯片内部操作完成
if(__read_status_2808() & cn_2808_failure)
{
ce_inactive();
return -1;
}
}
ce_inactive();
return true;
}
//----查flash中好块数量--------------------------------------------------------
//功能: 查flash中好块数量
//参数: 无
//返回: 好块数量
//-----------------------------------------------------------------------------
uint32_t __check_all_ss(void)
{
uint32_t i, j,sum = 0;
uint32_t address;
uint8_t data;
for(i=0; i<tg_samsung_nand.block_sum; i++)
{
ce_active();
for(j=0; j<2; j++)
{
address = tg_samsung_nand.block_size * i + 0x200 * j + 517;
__write_command_2808(cn_2808_select_oob);
address_start();
*pg_nand_address = (uint8_t)address; // A0 ~ A7
*pg_nand_address = (uint8_t)(address >> 9); // A9 ~ A16
*pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
address_end();
__wait_ready_2808( ); //等待芯片内部操作完成
data = *pg_nand_address;
if(data != 0xFF)
{
sum++;
break;
}
}
}
ce_inactive();
return sum;
}
//----计算扇区ecc码-----------------------------------------------------------
//功能: data中包含256字节数据,计算它的ecc码
//参数: data,数据缓冲区
// ecc: 3字节的缓冲区,返回ecc码
//返回: 无
//-----------------------------------------------------------------------------
void __make_sector_ecc(const uint8_t *data,uint8_t *ecc)
{
uint32_t i;
for(i = 0; i < cn_sector_size/256; i++)
{
ecc_make_256(data + i*256, ecc + i*3);
}
}
//----读flash 芯片id-----------------------------------------------------------
//功能: 读取flash芯片的id
//参数: 无
//返回: 芯片id
//-----------------------------------------------------------------------------
bool_t __read_chip_id (uint32_t *vendor_id,uint32_t *chip_id)
{
ce_active();
__write_command_2808(cn_2808_reset);
__wait_ready_2808(); //等待芯片内部操作完成
__write_command_2808(cn_2808_read_id);
address_start();
*pg_nand_address = 0; // Address. 1cycle
address_end();
*vendor_id=*pg_nand_address;
*chip_id=*pg_nand_address;
ce_inactive();
return true ;
}
//----复位芯片-----------------------------------------------------------------
//功能: 复位芯片
//参数: 无
//返回: 无
//-----------------------------------------------------------------------------
void __reset_2808(void)
{
ce_active();
__write_command_2808(cn_2808_reset);
__wait_ready_2808_slow(cn_wait_reset); //等待芯片内部操作完成
ce_inactive();
}
//----初始化2808文件系统------------------------------------------------------
//功能:初始化2808文件系统,建立文件柜。
//参数: 无
//返回: true= 成功,false=失败
//-----------------------------------------------------------------------------
bool_t module_init_fs_samsung_flash(void)
{
uint32_t vendor_id,chip_id;
//初始化timer4作为等候flash内部操作完成的中断,无需ISR
int_setto_asyn_signal(cn_irq_line_timer4); //设为异步信号
timer_set_clk_source(4,0); //主频的1/2分频
timer_set_precale(2,cn_timer_clk/8-1); //预分频数:事定时器输入时钟约1Mhz
timer_set_type(4,1); //设置定时器连续工作
int_restore_line(cn_irq_line_timer4);//启动中断,
__reset_2808();
__read_chip_id(&vendor_id,&chip_id);
switch(chip_id)
{
default:
{
u32g_sectors_per_block = 32;
tg_samsung_nand.block_sum = cn_blocks_sum;
tg_samsung_nand.block_size = cn_block_size;
tg_samsung_nand.DBX_read_buf_size = cn_fs_buf_len;
tg_samsung_nand.DBX_write_buf_size = cn_fs_buf_len;
}break;
}
pg_sector_buf = (uint8_t*)m_malloc_gbl(
tg_samsung_nand.block_size / u32g_sectors_per_block,0);
if(pg_sector_buf == NULL)
{
return false;
}
tg_samsung_nand.query_block_ready_with_ecc= query_block_ready_ss_with_ecc;
tg_samsung_nand.query_block_ready_no_ecc = query_block_ready_2808_no_ecc;
tg_samsung_nand.query_ready_with_data = query_ready_with_data_2808;
tg_samsung_nand.erase_block = erase_block_2808;
tg_samsung_nand.check_block = check_block_2808;
tg_samsung_nand.read_data_with_ecc = read_block_ss_with_ecc;
tg_samsung_nand.write_data_with_ecc = write_block_ss_with_ecc;
tg_samsung_nand.read_data_no_ecc = read_block_ss_no_ecc;
tg_samsung_nand.write_data_no_ecc = write_block_ss_no_ecc;
tg_samsung_nand.write_PCRB = write_PCRB_2808;
tg_samsung_nand.restore_PCRB = restore_PCRB_2808;
tg_samsung_nand.chip_name = "samsung little block nand flash";
if(DFFSD_install_chip(&tg_samsung_nand,cn_reserve_blocks))
return true;
else
{
m_free(pg_sector_buf);
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -